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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/CMakeLists.txt1
-rw-r--r--source/blender/avi/intern/avi_rgb.c11
-rw-r--r--source/blender/avi/intern/avi_rgb32.c2
-rw-r--r--source/blender/blenfont/BLF_api.h56
-rw-r--r--source/blender/blenfont/CMakeLists.txt4
-rw-r--r--source/blender/blenfont/SConscript6
-rw-r--r--source/blender/blenfont/intern/blf.c23
-rw-r--r--source/blender/blenfont/intern/blf_font.c36
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c5
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h2
-rw-r--r--source/blender/blenfont/intern/blf_lang.c10
-rw-r--r--source/blender/blenfont/intern/blf_util.c1
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h16
-rw-r--r--source/blender/blenkernel/BKE_action.h8
-rw-r--r--source/blender/blenkernel/BKE_anim.h5
-rw-r--r--source/blender/blenkernel/BKE_animsys.h5
-rw-r--r--source/blender/blenkernel/BKE_armature.h1
-rw-r--r--source/blender/blenkernel/BKE_blender.h14
-rw-r--r--source/blender/blenkernel/BKE_brush.h6
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h8
-rw-r--r--source/blender/blenkernel/BKE_context.h1
-rw-r--r--source/blender/blenkernel/BKE_crazyspace.h5
-rw-r--r--source/blender/blenkernel/BKE_curve.h5
-rw-r--r--source/blender/blenkernel/BKE_customdata.h21
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h9
-rw-r--r--source/blender/blenkernel/BKE_displist.h1
-rw-r--r--source/blender/blenkernel/BKE_editmesh_bvh.h13
-rw-r--r--source/blender/blenkernel/BKE_fcurve.h9
-rw-r--r--source/blender/blenkernel/BKE_font.h1
-rw-r--r--source/blender/blenkernel/BKE_freestyle.h13
-rw-r--r--source/blender/blenkernel/BKE_idprop.h26
-rw-r--r--source/blender/blenkernel/BKE_image.h3
-rw-r--r--source/blender/blenkernel/BKE_key.h4
-rw-r--r--source/blender/blenkernel/BKE_lattice.h1
-rw-r--r--source/blender/blenkernel/BKE_library.h10
-rw-r--r--source/blender/blenkernel/BKE_linestyle.h59
-rw-r--r--source/blender/blenkernel/BKE_main.h5
-rw-r--r--source/blender/blenkernel/BKE_material.h3
-rw-r--r--source/blender/blenkernel/BKE_mball.h1
-rw-r--r--source/blender/blenkernel/BKE_mesh.h6
-rw-r--r--source/blender/blenkernel/BKE_mesh_mapping.h3
-rw-r--r--source/blender/blenkernel/BKE_modifier.h5
-rw-r--r--source/blender/blenkernel/BKE_multires.h3
-rw-r--r--source/blender/blenkernel/BKE_node.h14
-rw-r--r--source/blender/blenkernel/BKE_object.h12
-rw-r--r--source/blender/blenkernel/BKE_paint.h33
-rw-r--r--source/blender/blenkernel/BKE_particle.h2
-rw-r--r--source/blender/blenkernel/BKE_pbvh.h10
-rw-r--r--source/blender/blenkernel/BKE_rigidbody.h3
-rw-r--r--source/blender/blenkernel/BKE_scene.h5
-rw-r--r--source/blender/blenkernel/BKE_screen.h7
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h17
-rw-r--r--source/blender/blenkernel/BKE_shrinkwrap.h51
-rw-r--r--source/blender/blenkernel/BKE_text.h1
-rw-r--r--source/blender/blenkernel/BKE_tracking.h3
-rw-r--r--source/blender/blenkernel/BKE_unit.h28
-rw-r--r--source/blender/blenkernel/CMakeLists.txt13
-rw-r--r--source/blender/blenkernel/SConscript8
-rw-r--r--source/blender/blenkernel/intern/CCGSubSurf.c4
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c116
-rw-r--r--source/blender/blenkernel/intern/action.c82
-rw-r--r--source/blender/blenkernel/intern/anim.c13
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c117
-rw-r--r--source/blender/blenkernel/intern/armature.c25
-rw-r--r--source/blender/blenkernel/intern/blender.c64
-rw-r--r--source/blender/blenkernel/intern/bpath.c19
-rw-r--r--source/blender/blenkernel/intern/brush.c98
-rw-r--r--source/blender/blenkernel/intern/bvhutils.c294
-rw-r--r--source/blender/blenkernel/intern/camera.c6
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c515
-rw-r--r--source/blender/blenkernel/intern/cloth.c8
-rw-r--r--source/blender/blenkernel/intern/collision.c2
-rw-r--r--source/blender/blenkernel/intern/colortools.c4
-rw-r--r--source/blender/blenkernel/intern/constraint.c89
-rw-r--r--source/blender/blenkernel/intern/context.c16
-rw-r--r--source/blender/blenkernel/intern/crazyspace.c33
-rw-r--r--source/blender/blenkernel/intern/curve.c426
-rw-r--r--source/blender/blenkernel/intern/customdata.c151
-rw-r--r--source/blender/blenkernel/intern/deform.c55
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c104
-rw-r--r--source/blender/blenkernel/intern/displist.c251
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c7
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c11
-rw-r--r--source/blender/blenkernel/intern/editmesh_bvh.c86
-rw-r--r--source/blender/blenkernel/intern/effect.c9
-rw-r--r--source/blender/blenkernel/intern/fcurve.c90
-rw-r--r--source/blender/blenkernel/intern/font.c232
-rw-r--r--source/blender/blenkernel/intern/freestyle.c20
-rw-r--r--source/blender/blenkernel/intern/gpencil.c2
-rw-r--r--source/blender/blenkernel/intern/idcode.c13
-rw-r--r--source/blender/blenkernel/intern/idprop.c6
-rw-r--r--source/blender/blenkernel/intern/image.c86
-rw-r--r--source/blender/blenkernel/intern/implicit.c11
-rw-r--r--source/blender/blenkernel/intern/ipo.c8
-rw-r--r--source/blender/blenkernel/intern/key.c104
-rw-r--r--source/blender/blenkernel/intern/lamp.c3
-rw-r--r--source/blender/blenkernel/intern/lattice.c154
-rw-r--r--source/blender/blenkernel/intern/library.c64
-rw-r--r--source/blender/blenkernel/intern/library_query.c54
-rw-r--r--source/blender/blenkernel/intern/linestyle.c208
-rw-r--r--source/blender/blenkernel/intern/mask.c12
-rw-r--r--source/blender/blenkernel/intern/mask_rasterize.c2
-rw-r--r--source/blender/blenkernel/intern/material.c137
-rw-r--r--source/blender/blenkernel/intern/mball.c58
-rw-r--r--source/blender/blenkernel/intern/mesh.c59
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c174
-rw-r--r--source/blender/blenkernel/intern/mesh_mapping.c17
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c57
-rw-r--r--source/blender/blenkernel/intern/modifier.c32
-rw-r--r--source/blender/blenkernel/intern/modifiers_bmesh.c14
-rw-r--r--source/blender/blenkernel/intern/movieclip.c21
-rw-r--r--source/blender/blenkernel/intern/multires.c55
-rw-r--r--source/blender/blenkernel/intern/navmesh_conversion.c4
-rw-r--r--source/blender/blenkernel/intern/nla.c14
-rw-r--r--source/blender/blenkernel/intern/node.c25
-rw-r--r--source/blender/blenkernel/intern/object.c186
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c67
-rw-r--r--source/blender/blenkernel/intern/packedFile.c2
-rw-r--r--source/blender/blenkernel/intern/paint.c136
-rw-r--r--source/blender/blenkernel/intern/particle.c75
-rw-r--r--source/blender/blenkernel/intern/particle_system.c51
-rw-r--r--source/blender/blenkernel/intern/pbvh.c38
-rw-r--r--source/blender/blenkernel/intern/pbvh_bmesh.c392
-rw-r--r--source/blender/blenkernel/intern/pointcache.c11
-rw-r--r--source/blender/blenkernel/intern/report.c2
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c235
-rw-r--r--source/blender/blenkernel/intern/sca.c14
-rw-r--r--source/blender/blenkernel/intern/scene.c162
-rw-r--r--source/blender/blenkernel/intern/screen.c26
-rw-r--r--source/blender/blenkernel/intern/seqcache.c87
-rw-r--r--source/blender/blenkernel/intern/seqeffects.c403
-rw-r--r--source/blender/blenkernel/intern/sequencer.c188
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c80
-rw-r--r--source/blender/blenkernel/intern/smoke.c19
-rw-r--r--source/blender/blenkernel/intern/softbody.c6
-rw-r--r--source/blender/blenkernel/intern/sound.c4
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c63
-rw-r--r--source/blender/blenkernel/intern/text.c288
-rw-r--r--source/blender/blenkernel/intern/texture.c282
-rw-r--r--source/blender/blenkernel/intern/tracking.c103
-rw-r--r--source/blender/blenkernel/intern/tracking_region_tracker.c48
-rw-r--r--source/blender/blenkernel/intern/tracking_stabilize.c8
-rw-r--r--source/blender/blenkernel/intern/tracking_util.c2
-rw-r--r--source/blender/blenkernel/intern/treehash.c4
-rw-r--r--source/blender/blenkernel/intern/unit.c147
-rw-r--r--source/blender/blenkernel/intern/world.c3
-rw-r--r--source/blender/blenkernel/intern/writeavi.c2
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c30
-rw-r--r--source/blender/blenlib/BLI_array.h36
-rw-r--r--source/blender/blenlib/BLI_bitmap.h66
-rw-r--r--source/blender/blenlib/BLI_buffer.h6
-rw-r--r--source/blender/blenlib/BLI_callbacks.h9
-rw-r--r--source/blender/blenlib/BLI_compiler_compat.h5
-rw-r--r--source/blender/blenlib/BLI_compiler_typecheck.h379
-rw-r--r--source/blender/blenlib/BLI_dial.h59
-rw-r--r--source/blender/blenlib/BLI_dynstr.h76
-rw-r--r--source/blender/blenlib/BLI_edgehash.h8
-rw-r--r--source/blender/blenlib/BLI_fileops.h21
-rw-r--r--source/blender/blenlib/BLI_fileops_types.h10
-rw-r--r--source/blender/blenlib/BLI_ghash.h23
-rw-r--r--source/blender/blenlib/BLI_gsqueue.h13
-rw-r--r--source/blender/blenlib/BLI_heap.h22
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h4
-rw-r--r--source/blender/blenlib/BLI_linklist_stack.h18
-rw-r--r--source/blender/blenlib/BLI_listbase.h24
-rw-r--r--source/blender/blenlib/BLI_math_base.h50
-rw-r--r--source/blender/blenlib/BLI_math_color_blend.h36
-rw-r--r--source/blender/blenlib/BLI_math_geom.h51
-rw-r--r--source/blender/blenlib/BLI_math_interp.h20
-rw-r--r--source/blender/blenlib/BLI_math_matrix.h72
-rw-r--r--source/blender/blenlib/BLI_math_vector.h5
-rw-r--r--source/blender/blenlib/BLI_md5.h2
-rw-r--r--source/blender/blenlib/BLI_path_util.h12
-rw-r--r--source/blender/blenlib/BLI_polyfill2d.h10
-rw-r--r--source/blender/blenlib/BLI_rand.h39
-rw-r--r--source/blender/blenlib/BLI_smallhash.h4
-rw-r--r--source/blender/blenlib/BLI_sort.h11
-rw-r--r--source/blender/blenlib/BLI_stack.h36
-rw-r--r--source/blender/blenlib/BLI_stackdefines.h88
-rw-r--r--source/blender/blenlib/BLI_strict_flags.h6
-rw-r--r--source/blender/blenlib/BLI_string.h13
-rw-r--r--source/blender/blenlib/BLI_string_utf8.h4
-rw-r--r--source/blender/blenlib/BLI_sys_types.h124
-rw-r--r--source/blender/blenlib/BLI_task.h12
-rw-r--r--source/blender/blenlib/BLI_threads.h2
-rw-r--r--source/blender/blenlib/BLI_utildefines.h177
-rw-r--r--source/blender/blenlib/BLI_winstuff.h5
-rw-r--r--source/blender/blenlib/CMakeLists.txt4
-rw-r--r--source/blender/blenlib/intern/BLI_args.c12
-rw-r--r--source/blender/blenlib/intern/BLI_array.c15
-rw-r--r--source/blender/blenlib/intern/BLI_dial.c100
-rw-r--r--source/blender/blenlib/intern/BLI_dynstr.c63
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c111
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c102
-rw-r--r--source/blender/blenlib/intern/BLI_kdtree.c30
-rw-r--r--source/blender/blenlib/intern/BLI_linklist.c15
-rw-r--r--source/blender/blenlib/intern/BLI_mempool.c4
-rw-r--r--source/blender/blenlib/intern/boxpack2d.c2
-rw-r--r--source/blender/blenlib/intern/buffer.c18
-rw-r--r--source/blender/blenlib/intern/callbacks.c6
-rw-r--r--source/blender/blenlib/intern/convexhull2d.c2
-rw-r--r--source/blender/blenlib/intern/easing.c6
-rw-r--r--source/blender/blenlib/intern/edgehash.c60
-rw-r--r--source/blender/blenlib/intern/fileops.c93
-rw-r--r--source/blender/blenlib/intern/gsqueue.c35
-rw-r--r--source/blender/blenlib/intern/listbase.c64
-rw-r--r--source/blender/blenlib/intern/math_color.c221
-rw-r--r--source/blender/blenlib/intern/math_color_blend_inline.c860
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c16
-rw-r--r--source/blender/blenlib/intern/math_geom.c381
-rw-r--r--source/blender/blenlib/intern/math_interp.c195
-rw-r--r--source/blender/blenlib/intern/math_matrix.c420
-rw-r--r--source/blender/blenlib/intern/math_rotation.c89
-rw-r--r--source/blender/blenlib/intern/math_vector.c57
-rw-r--r--source/blender/blenlib/intern/math_vector_inline.c64
-rw-r--r--source/blender/blenlib/intern/md5.c687
-rw-r--r--source/blender/blenlib/intern/path_util.c147
-rw-r--r--source/blender/blenlib/intern/polyfill2d.c751
-rw-r--r--source/blender/blenlib/intern/rand.c51
-rw-r--r--source/blender/blenlib/intern/scanfill.c3
-rw-r--r--source/blender/blenlib/intern/scanfill_utils.c6
-rw-r--r--source/blender/blenlib/intern/smallhash.c52
-rw-r--r--source/blender/blenlib/intern/sort.c13
-rw-r--r--source/blender/blenlib/intern/stack.c226
-rw-r--r--source/blender/blenlib/intern/storage.c51
-rw-r--r--source/blender/blenlib/intern/string.c153
-rw-r--r--source/blender/blenlib/intern/string_utf8.c46
-rw-r--r--source/blender/blenlib/intern/task.c112
-rw-r--r--source/blender/blenlib/intern/timecode.c3
-rw-r--r--source/blender/blenlib/intern/winstuff.c7
-rw-r--r--source/blender/blenlib/intern/winstuff_dir.c9
-rw-r--r--source/blender/blenloader/BLO_readfile.h3
-rw-r--r--source/blender/blenloader/intern/readfile.c157
-rw-r--r--source/blender/blenloader/intern/versioning_250.c3
-rw-r--r--source/blender/blenloader/intern/versioning_260.c8
-rw-r--r--source/blender/blenloader/intern/versioning_270.c200
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c74
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c4
-rw-r--r--source/blender/blenloader/intern/writefile.c230
-rw-r--r--source/blender/bmesh/CMakeLists.txt4
-rw-r--r--source/blender/bmesh/bmesh.h4
-rw-r--r--source/blender/bmesh/bmesh_class.h17
-rw-r--r--source/blender/bmesh/bmesh_tools.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_construct.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_core.c180
-rw-r--r--source/blender/bmesh/intern/bmesh_core.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_edgeloop.c10
-rw-r--r--source/blender/bmesh/intern/bmesh_error.h25
-rw-r--r--source/blender/bmesh/intern/bmesh_inline.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_interp.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.c42
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators.h27
-rw-r--r--source/blender/bmesh/intern/bmesh_iterators_inline.h28
-rw-r--r--source/blender/bmesh/intern/bmesh_log.c50
-rw-r--r--source/blender/bmesh/intern/bmesh_log.h3
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c34
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.h9
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c132
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh_conv.c10
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.c619
-rw-r--r--source/blender/bmesh/intern/bmesh_mods.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c283
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h8
-rw-r--r--source/blender/bmesh/intern/bmesh_operators.c55
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c185
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h10
-rw-r--r--source/blender/bmesh/intern/bmesh_private.h11
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c124
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h186
-rw-r--r--source/blender/bmesh/intern/bmesh_queries_inline.h12
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.c53
-rw-r--r--source/blender/bmesh/intern/bmesh_structure.h41
-rw-r--r--source/blender/bmesh/intern/bmesh_structure_inline.h20
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.c5
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers.h31
-rw-r--r--source/blender/bmesh/intern/bmesh_walkers_impl.c137
-rw-r--r--source/blender/bmesh/operators/bmo_bevel.c14
-rw-r--r--source/blender/bmesh/operators/bmo_bisect_plane.c4
-rw-r--r--source/blender/bmesh/operators/bmo_bridge.c4
-rw-r--r--source/blender/bmesh/operators/bmo_connect.c103
-rw-r--r--source/blender/bmesh/operators/bmo_connect_nonplanar.c33
-rw-r--r--source/blender/bmesh/operators/bmo_connect_pair.c72
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c225
-rw-r--r--source/blender/bmesh/operators/bmo_dupe.c11
-rw-r--r--source/blender/bmesh/operators/bmo_edgenet.c4
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c85
-rw-r--r--source/blender/bmesh/operators/bmo_fill_attribute.c2
-rw-r--r--source/blender/bmesh/operators/bmo_fill_grid.c4
-rw-r--r--source/blender/bmesh/operators/bmo_inset.c215
-rw-r--r--source/blender/bmesh/operators/bmo_normals.c2
-rw-r--r--source/blender/bmesh/operators/bmo_poke.c2
-rw-r--r--source/blender/bmesh/operators/bmo_primitive.c34
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c15
-rw-r--r--source/blender/bmesh/operators/bmo_smooth_laplacian.c2
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide.c84
-rw-r--r--source/blender/bmesh/operators/bmo_subdivide_edgering.c13
-rw-r--r--source/blender/bmesh/operators/bmo_triangulate.c158
-rw-r--r--source/blender/bmesh/operators/bmo_utils.c5
-rw-r--r--source/blender/bmesh/tools/bmesh_beautify.c13
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.c412
-rw-r--r--source/blender/bmesh/tools/bmesh_bevel.h3
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.c45
-rw-r--r--source/blender/bmesh/tools/bmesh_bisect_plane.h7
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_collapse.c16
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c8
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c2
-rw-r--r--source/blender/bmesh/tools/bmesh_edgenet.c22
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c1302
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.h35
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.c1511
-rw-r--r--source/blender/bmesh/tools/bmesh_region_match.h33
-rw-r--r--source/blender/bmesh/tools/bmesh_wireframe.c13
-rw-r--r--source/blender/collada/AnimationImporter.cpp6
-rw-r--r--source/blender/collada/ControllerExporter.cpp10
-rw-r--r--source/blender/collada/DocumentImporter.cpp52
-rw-r--r--source/blender/collada/DocumentImporter.h2
-rw-r--r--source/blender/collada/EffectExporter.cpp25
-rw-r--r--source/blender/collada/MeshImporter.cpp2
-rw-r--r--source/blender/collada/SkinInfo.cpp6
-rw-r--r--source/blender/collada/TransformWriter.cpp2
-rw-r--r--source/blender/collada/collada.cpp20
-rw-r--r--source/blender/compositor/CMakeLists.txt9
-rw-r--r--source/blender/compositor/COM_compositor.h2
-rw-r--r--source/blender/compositor/COM_defines.h9
-rw-r--r--source/blender/compositor/SConscript4
-rw-r--r--source/blender/compositor/intern/COM_ChunkOrder.cpp2
-rw-r--r--source/blender/compositor/intern/COM_Converter.cpp4
-rw-r--r--source/blender/compositor/intern/COM_Debug.cpp2
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cpp202
-rw-r--r--source/blender/compositor/intern/COM_NodeConverter.cpp18
-rw-r--r--source/blender/compositor/intern/COM_NodeConverter.h11
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.cpp45
-rw-r--r--source/blender/compositor/intern/COM_NodeGraph.h3
-rw-r--r--source/blender/compositor/intern/COM_NodeOperation.h4
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cpp30
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.h12
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.cpp8
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.h2
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp6
-rw-r--r--source/blender/compositor/intern/COM_compositor.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_BlurNode.cpp3
-rw-r--r--source/blender/compositor/nodes/COM_SocketProxyNode.cpp6
-rw-r--r--source/blender/compositor/nodes/COM_SocketProxyNode.h9
-rw-r--r--source/blender/compositor/nodes/COM_SplitViewerNode.cpp7
-rw-r--r--source/blender/compositor/nodes/COM_SunBeamsNode.cpp42
-rw-r--r--source/blender/compositor/nodes/COM_SunBeamsNode.h37
-rw-r--r--source/blender/compositor/nodes/COM_SwitchNode.cpp4
-rw-r--r--source/blender/compositor/nodes/COM_ViewerNode.cpp7
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_BlurBaseOperation.h7
-rw-r--r--source/blender/compositor/operations/COM_BokehImageOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_CropOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cpp12
-rw-r--r--source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp14
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp121
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.h7
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp14
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp14
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp7
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp65
-rw-r--r--source/blender/compositor/operations/COM_GaussianXBlurOperation.h14
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp66
-rw-r--r--source/blender/compositor/operations/COM_GaussianYBlurOperation.h14
-rw-r--r--source/blender/compositor/operations/COM_KeyingBlurOperation.cpp38
-rw-r--r--source/blender/compositor/operations/COM_KeyingClipOperation.cpp35
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.cpp21
-rw-r--r--source/blender/compositor/operations/COM_KeyingScreenOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.cpp9
-rw-r--r--source/blender/compositor/operations/COM_MathBaseOperation.h4
-rw-r--r--source/blender/compositor/operations/COM_MixOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.cpp45
-rw-r--r--source/blender/compositor/operations/COM_MovieDistortionOperation.h20
-rw-r--r--source/blender/compositor/operations/COM_OpenCLKernels.cl63
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp19
-rw-r--r--source/blender/compositor/operations/COM_SocketProxyOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_SocketProxyOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cpp320
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.h48
-rw-r--r--source/blender/compositor/operations/COM_TranslateOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_WrapOperation.cpp13
-rw-r--r--source/blender/datatoc/CMakeLists.txt2
-rw-r--r--source/blender/datatoc/datatoc_icon.c3
-rw-r--r--source/blender/editors/animation/CMakeLists.txt4
-rw-r--r--source/blender/editors/animation/SConscript6
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c21
-rw-r--r--source/blender/editors/animation/anim_channels_edit.c406
-rw-r--r--source/blender/editors/animation/anim_deps.c58
-rw-r--r--source/blender/editors/animation/anim_filter.c17
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c2
-rw-r--r--source/blender/editors/animation/anim_markers.c304
-rw-r--r--source/blender/editors/animation/anim_ops.c3
-rw-r--r--source/blender/editors/animation/drivers.c78
-rw-r--r--source/blender/editors/animation/keyframes_draw.c6
-rw-r--r--source/blender/editors/animation/keyframes_edit.c72
-rw-r--r--source/blender/editors/animation/keyframes_general.c18
-rw-r--r--source/blender/editors/animation/keyframing.c68
-rw-r--r--source/blender/editors/armature/CMakeLists.txt4
-rw-r--r--source/blender/editors/armature/SConscript6
-rw-r--r--source/blender/editors/armature/armature_add.c9
-rw-r--r--source/blender/editors/armature/armature_edit.c29
-rw-r--r--source/blender/editors/armature/armature_intern.h2
-rw-r--r--source/blender/editors/armature/armature_relations.c2
-rw-r--r--source/blender/editors/armature/armature_select.c39
-rw-r--r--source/blender/editors/armature/armature_skinning.c35
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c12
-rw-r--r--source/blender/editors/armature/meshlaplacian.c13
-rw-r--r--source/blender/editors/armature/pose_edit.c8
-rw-r--r--source/blender/editors/armature/pose_group.c14
-rw-r--r--source/blender/editors/armature/pose_lib.c10
-rw-r--r--source/blender/editors/armature/pose_select.c154
-rw-r--r--source/blender/editors/armature/pose_slide.c2
-rw-r--r--source/blender/editors/armature/pose_transform.c13
-rw-r--r--source/blender/editors/curve/editcurve.c94
-rw-r--r--source/blender/editors/curve/editcurve_add.c8
-rw-r--r--source/blender/editors/curve/editfont.c50
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt2
-rw-r--r--source/blender/editors/datafiles/SConscript2
-rw-r--r--source/blender/editors/gpencil/CMakeLists.txt4
-rw-r--r--source/blender/editors/gpencil/SConscript5
-rw-r--r--source/blender/editors/gpencil/drawgpencil.c19
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c18
-rw-r--r--source/blender/editors/gpencil/gpencil_buttons.c6
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c38
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c27
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c2
-rw-r--r--source/blender/editors/include/BIF_gl.h22
-rw-r--r--source/blender/editors/include/BIF_glutil.h12
-rw-r--r--source/blender/editors/include/ED_anim_api.h38
-rw-r--r--source/blender/editors/include/ED_armature.h14
-rw-r--r--source/blender/editors/include/ED_curve.h1
-rw-r--r--source/blender/editors/include/ED_datafiles.h6
-rw-r--r--source/blender/editors/include/ED_gpencil.h23
-rw-r--r--source/blender/editors/include/ED_image.h3
-rw-r--r--source/blender/editors/include/ED_lattice.h1
-rw-r--r--source/blender/editors/include/ED_mball.h2
-rw-r--r--source/blender/editors/include/ED_mesh.h3
-rw-r--r--source/blender/editors/include/ED_numinput.h4
-rw-r--r--source/blender/editors/include/ED_object.h16
-rw-r--r--source/blender/editors/include/ED_paint.h65
-rw-r--r--source/blender/editors/include/ED_render.h13
-rw-r--r--source/blender/editors/include/ED_screen.h3
-rw-r--r--source/blender/editors/include/ED_screen_types.h3
-rw-r--r--source/blender/editors/include/ED_sculpt.h40
-rw-r--r--source/blender/editors/include/ED_space_api.h1
-rw-r--r--source/blender/editors/include/ED_transform.h1
-rw-r--r--source/blender/editors/include/ED_util.h2
-rw-r--r--source/blender/editors/include/ED_uvedit.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h19
-rw-r--r--source/blender/editors/include/UI_icons.h16
-rw-r--r--source/blender/editors/include/UI_interface.h42
-rw-r--r--source/blender/editors/include/UI_resources.h9
-rw-r--r--source/blender/editors/interface/CMakeLists.txt3
-rw-r--r--source/blender/editors/interface/SConscript5
-rw-r--r--source/blender/editors/interface/interface.c259
-rw-r--r--source/blender/editors/interface/interface_anim.c5
-rw-r--r--source/blender/editors/interface/interface_draw.c30
-rw-r--r--source/blender/editors/interface/interface_handlers.c909
-rw-r--r--source/blender/editors/interface/interface_icons.c2
-rw-r--r--source/blender/editors/interface/interface_intern.h77
-rw-r--r--source/blender/editors/interface/interface_layout.c247
-rw-r--r--source/blender/editors/interface/interface_ops.c213
-rw-r--r--source/blender/editors/interface/interface_panel.c103
-rw-r--r--source/blender/editors/interface/interface_regions.c711
-rw-r--r--source/blender/editors/interface/interface_style.c22
-rw-r--r--source/blender/editors/interface/interface_templates.c269
-rw-r--r--source/blender/editors/interface/interface_utils.c4
-rw-r--r--source/blender/editors/interface/interface_widgets.c477
-rw-r--r--source/blender/editors/interface/resources.c119
-rw-r--r--source/blender/editors/interface/view2d.c24
-rw-r--r--source/blender/editors/interface/view2d_ops.c45
-rw-r--r--source/blender/editors/io/io_collada.c63
-rw-r--r--source/blender/editors/mask/CMakeLists.txt4
-rw-r--r--source/blender/editors/mask/SConscript6
-rw-r--r--source/blender/editors/mask/mask_add.c20
-rw-r--r--source/blender/editors/mask/mask_draw.c58
-rw-r--r--source/blender/editors/mask/mask_edit.c2
-rw-r--r--source/blender/editors/mask/mask_intern.h8
-rw-r--r--source/blender/editors/mask/mask_ops.c195
-rw-r--r--source/blender/editors/mask/mask_select.c2
-rw-r--r--source/blender/editors/mesh/CMakeLists.txt5
-rw-r--r--source/blender/editors/mesh/SConscript5
-rw-r--r--source/blender/editors/mesh/editface.c12
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c154
-rw-r--r--source/blender/editors/mesh/editmesh_extrude.c184
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c88
-rw-r--r--source/blender/editors/mesh/editmesh_intersect.c400
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c416
-rw-r--r--source/blender/editors/mesh/editmesh_knife_project.c2
-rw-r--r--source/blender/editors/mesh/editmesh_loopcut.c299
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c21
-rw-r--r--source/blender/editors/mesh/editmesh_rip_edge.c252
-rw-r--r--source/blender/editors/mesh/editmesh_select.c225
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c69
-rw-r--r--source/blender/editors/mesh/editmesh_utils.c11
-rw-r--r--source/blender/editors/mesh/mesh_data.c24
-rw-r--r--source/blender/editors/mesh/mesh_intern.h6
-rw-r--r--source/blender/editors/mesh/mesh_navmesh.c2
-rw-r--r--source/blender/editors/mesh/mesh_ops.c15
-rw-r--r--source/blender/editors/mesh/meshtools.c2
-rw-r--r--source/blender/editors/metaball/mball_edit.c29
-rw-r--r--source/blender/editors/object/CMakeLists.txt5
-rw-r--r--source/blender/editors/object/object_add.c61
-rw-r--r--source/blender/editors/object/object_bake.c3
-rw-r--r--source/blender/editors/object/object_bake_api.c646
-rw-r--r--source/blender/editors/object/object_constraint.c2
-rw-r--r--source/blender/editors/object/object_edit.c53
-rw-r--r--source/blender/editors/object/object_group.c108
-rw-r--r--source/blender/editors/object/object_hook.c5
-rw-r--r--source/blender/editors/object/object_intern.h3
-rw-r--r--source/blender/editors/object/object_lattice.c19
-rw-r--r--source/blender/editors/object/object_lod.c11
-rw-r--r--source/blender/editors/object/object_modifier.c8
-rw-r--r--source/blender/editors/object/object_ops.c3
-rw-r--r--source/blender/editors/object/object_relations.c709
-rw-r--r--source/blender/editors/object/object_select.c172
-rw-r--r--source/blender/editors/object/object_shapekey.c89
-rw-r--r--source/blender/editors/object/object_transform.c59
-rw-r--r--source/blender/editors/object/object_vgroup.c63
-rw-r--r--source/blender/editors/physics/CMakeLists.txt4
-rw-r--r--source/blender/editors/physics/SConscript6
-rw-r--r--source/blender/editors/physics/particle_edit.c100
-rw-r--r--source/blender/editors/physics/particle_object.c55
-rw-r--r--source/blender/editors/physics/physics_fluid.c6
-rw-r--r--source/blender/editors/physics/physics_intern.h1
-rw-r--r--source/blender/editors/physics/physics_ops.c1
-rw-r--r--source/blender/editors/physics/rigidbody_object.c78
-rw-r--r--source/blender/editors/render/CMakeLists.txt3
-rw-r--r--source/blender/editors/render/SConscript5
-rw-r--r--source/blender/editors/render/render_intern.h1
-rw-r--r--source/blender/editors/render/render_internal.c146
-rw-r--r--source/blender/editors/render/render_opengl.c60
-rw-r--r--source/blender/editors/render/render_ops.c1
-rw-r--r--source/blender/editors/render/render_preview.c32
-rw-r--r--source/blender/editors/render/render_shading.c128
-rw-r--r--source/blender/editors/render/render_update.c12
-rw-r--r--source/blender/editors/render/render_view.c2
-rw-r--r--source/blender/editors/screen/CMakeLists.txt3
-rw-r--r--source/blender/editors/screen/SConscript5
-rw-r--r--source/blender/editors/screen/area.c216
-rw-r--r--source/blender/editors/screen/glutil.c85
-rw-r--r--source/blender/editors/screen/screen_edit.c108
-rw-r--r--source/blender/editors/screen/screen_intern.h2
-rw-r--r--source/blender/editors/screen/screen_ops.c190
-rw-r--r--source/blender/editors/sculpt_paint/CMakeLists.txt4
-rw-r--r--source/blender/editors/sculpt_paint/SConscript5
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c176
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c787
-rw-r--r--source/blender/editors/sculpt_paint/paint_hide.c12
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c670
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c879
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c1325
-rw-r--r--source/blender/editors/sculpt_paint/paint_intern.h66
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c122
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c186
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c558
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c57
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c324
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c176
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c480
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_intern.h7
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c32
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c28
-rw-r--r--source/blender/editors/space_action/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_action/SConscript8
-rw-r--r--source/blender/editors/space_action/action_draw.c6
-rw-r--r--source/blender/editors/space_action/action_edit.c187
-rw-r--r--source/blender/editors/space_action/action_ops.c3
-rw-r--r--source/blender/editors/space_action/action_select.c41
-rw-r--r--source/blender/editors/space_action/space_action.c9
-rw-r--r--source/blender/editors/space_api/spacetypes.c19
-rw-r--r--source/blender/editors/space_buttons/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_buttons/SConscript7
-rw-r--r--source/blender/editors/space_buttons/buttons_context.c32
-rw-r--r--source/blender/editors/space_buttons/buttons_ops.c4
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c8
-rw-r--r--source/blender/editors/space_buttons/space_buttons.c6
-rw-r--r--source/blender/editors/space_clip/CMakeLists.txt5
-rw-r--r--source/blender/editors/space_clip/SConscript7
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c4
-rw-r--r--source/blender/editors/space_clip/clip_dopesheet_ops.c4
-rw-r--r--source/blender/editors/space_clip/clip_draw.c32
-rw-r--r--source/blender/editors/space_clip/clip_editor.c67
-rw-r--r--source/blender/editors/space_clip/clip_graph_ops.c18
-rw-r--r--source/blender/editors/space_clip/clip_ops.c156
-rw-r--r--source/blender/editors/space_clip/space_clip.c6
-rw-r--r--source/blender/editors/space_clip/tracking_ops.c6
-rw-r--r--source/blender/editors/space_clip/tracking_select.c2
-rw-r--r--source/blender/editors/space_console/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_console/SConscript7
-rw-r--r--source/blender/editors/space_console/console_ops.c11
-rw-r--r--source/blender/editors/space_console/space_console.c13
-rw-r--r--source/blender/editors/space_file/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_file/SConscript6
-rw-r--r--source/blender/editors/space_file/file_draw.c33
-rw-r--r--source/blender/editors/space_file/file_ops.c5
-rw-r--r--source/blender/editors/space_file/file_panels.c5
-rw-r--r--source/blender/editors/space_file/filesel.c24
-rw-r--r--source/blender/editors/space_file/fsmenu.c9
-rw-r--r--source/blender/editors/space_file/space_file.c2
-rw-r--r--source/blender/editors/space_graph/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_graph/SConscript6
-rw-r--r--source/blender/editors/space_graph/graph_buttons.c46
-rw-r--r--source/blender/editors/space_graph/graph_draw.c15
-rw-r--r--source/blender/editors/space_graph/graph_edit.c292
-rw-r--r--source/blender/editors/space_graph/graph_ops.c5
-rw-r--r--source/blender/editors/space_graph/graph_select.c20
-rw-r--r--source/blender/editors/space_graph/graph_utils.c8
-rw-r--r--source/blender/editors/space_graph/space_graph.c2
-rw-r--r--source/blender/editors/space_image/CMakeLists.txt7
-rw-r--r--source/blender/editors/space_image/SConscript6
-rw-r--r--source/blender/editors/space_image/image_buttons.c103
-rw-r--r--source/blender/editors/space_image/image_draw.c45
-rw-r--r--source/blender/editors/space_image/image_edit.c42
-rw-r--r--source/blender/editors/space_image/image_intern.h5
-rw-r--r--source/blender/editors/space_image/image_ops.c244
-rw-r--r--source/blender/editors/space_image/space_image.c43
-rw-r--r--source/blender/editors/space_info/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_info/SConscript6
-rw-r--r--source/blender/editors/space_info/info_stats.c73
-rw-r--r--source/blender/editors/space_info/textview.c2
-rw-r--r--source/blender/editors/space_logic/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_logic/SConscript6
-rw-r--r--source/blender/editors/space_logic/logic_window.c104
-rw-r--r--source/blender/editors/space_nla/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_nla/SConscript6
-rw-r--r--source/blender/editors/space_nla/nla_buttons.c2
-rw-r--r--source/blender/editors/space_nla/nla_channels.c35
-rw-r--r--source/blender/editors/space_nla/nla_draw.c4
-rw-r--r--source/blender/editors/space_nla/nla_edit.c60
-rw-r--r--source/blender/editors/space_nla/nla_ops.c3
-rw-r--r--source/blender/editors/space_nla/nla_select.c14
-rw-r--r--source/blender/editors/space_node/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_node/SConscript6
-rw-r--r--source/blender/editors/space_node/drawnode.c107
-rw-r--r--source/blender/editors/space_node/node_buttons.c4
-rw-r--r--source/blender/editors/space_node/node_draw.c8
-rw-r--r--source/blender/editors/space_node/node_edit.c46
-rw-r--r--source/blender/editors/space_node/node_group.c2
-rw-r--r--source/blender/editors/space_node/node_intern.h5
-rw-r--r--source/blender/editors/space_node/node_ops.c9
-rw-r--r--source/blender/editors/space_node/node_relationships.c14
-rw-r--r--source/blender/editors/space_node/node_select.c226
-rw-r--r--source/blender/editors/space_node/node_templates.c1
-rw-r--r--source/blender/editors/space_node/space_node.c15
-rw-r--r--source/blender/editors/space_outliner/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_outliner/SConscript7
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c40
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c10
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c20
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c10
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c5
-rw-r--r--source/blender/editors/space_script/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_script/SConscript6
-rw-r--r--source/blender/editors/space_sequencer/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_sequencer/SConscript6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_add.c93
-rw-r--r--source/blender/editors/space_sequencer/sequencer_buttons.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c59
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c469
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h8
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c15
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c38
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c157
-rw-r--r--source/blender/editors/space_text/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_text/SConscript8
-rw-r--r--source/blender/editors/space_text/space_text.c19
-rw-r--r--source/blender/editors/space_text/text_draw.c15
-rw-r--r--source/blender/editors/space_text/text_ops.c12
-rw-r--r--source/blender/editors/space_time/CMakeLists.txt4
-rw-r--r--source/blender/editors/space_time/SConscript6
-rw-r--r--source/blender/editors/space_time/space_time.c1
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt3
-rw-r--r--source/blender/editors/space_view3d/SConscript6
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c73
-rw-r--r--source/blender/editors/space_view3d/drawmesh.c181
-rw-r--r--source/blender/editors/space_view3d/drawobject.c917
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c70
-rw-r--r--source/blender/editors/space_view3d/view3d_buttons.c479
-rw-r--r--source/blender/editors/space_view3d/view3d_camera_control.c32
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c261
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c278
-rw-r--r--source/blender/editors/space_view3d/view3d_fly.c2
-rw-r--r--source/blender/editors/space_view3d/view3d_header.c7
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h10
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c12
-rw-r--r--source/blender/editors/space_view3d/view3d_project.c33
-rw-r--r--source/blender/editors/space_view3d/view3d_ruler.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c78
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c217
-rw-r--r--source/blender/editors/space_view3d/view3d_walk.c66
-rw-r--r--source/blender/editors/transform/CMakeLists.txt4
-rw-r--r--source/blender/editors/transform/SConscript6
-rw-r--r--source/blender/editors/transform/transform.c322
-rw-r--r--source/blender/editors/transform/transform.h29
-rw-r--r--source/blender/editors/transform/transform_constraints.c5
-rw-r--r--source/blender/editors/transform/transform_conversions.c515
-rw-r--r--source/blender/editors/transform/transform_generics.c96
-rw-r--r--source/blender/editors/transform/transform_input.c19
-rw-r--r--source/blender/editors/transform/transform_manipulator.c105
-rw-r--r--source/blender/editors/transform/transform_ops.c37
-rw-r--r--source/blender/editors/transform/transform_orientations.c272
-rw-r--r--source/blender/editors/transform/transform_snap.c113
-rw-r--r--source/blender/editors/util/CMakeLists.txt5
-rw-r--r--source/blender/editors/util/SConscript7
-rw-r--r--source/blender/editors/util/ed_transverts.c4
-rw-r--r--source/blender/editors/util/ed_util.c64
-rw-r--r--source/blender/editors/util/numinput.c34
-rw-r--r--source/blender/editors/util/undo.c16
-rw-r--r--source/blender/editors/uvedit/CMakeLists.txt4
-rw-r--r--source/blender/editors/uvedit/SConscript5
-rw-r--r--source/blender/editors/uvedit/uvedit_buttons.c5
-rw-r--r--source/blender/editors/uvedit/uvedit_draw.c259
-rw-r--r--source/blender/editors/uvedit/uvedit_ops.c24
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c28
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c4
-rw-r--r--source/blender/freestyle/CMakeLists.txt14
-rw-r--r--source/blender/freestyle/FRS_freestyle.h7
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp100
-rw-r--r--source/blender/freestyle/intern/application/Controller.h11
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp40
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp401
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h19
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h8
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp79
-rw-r--r--source/blender/freestyle/intern/geometry/Grid.h2
-rw-r--r--source/blender/freestyle/intern/geometry/Polygon.h4
-rw-r--r--source/blender/freestyle/intern/python/BPy_Convert.cpp59
-rw-r--r--source/blender/freestyle/intern/python/BPy_Convert.h3
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp17
-rw-r--r--source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp125
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface0D.h2
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface1D.cpp10
-rw-r--r--source/blender/freestyle/intern/python/BPy_Interface1D.h2
-rw-r--r--source/blender/freestyle/intern/python/BPy_Operators.cpp35
-rw-r--r--source/blender/freestyle/intern/python/BPy_SShape.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_SShape.h2
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp16
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeAttribute.h2
-rw-r--r--source/blender/freestyle/intern/python/BPy_StrokeShader.cpp36
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewShape.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewShape.h2
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp8
-rw-r--r--source/blender/freestyle/intern/python/Director.cpp22
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp17
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp21
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp4
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp11
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp38
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp2
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp12
-rw-r--r--source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp7
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp13
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp6
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp46
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp135
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp2
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.cpp41
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.cpp9
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp122
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.h54
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.cpp143
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.h53
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureStepShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.cpp130
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.h53
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp128
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h54
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.cpp4
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.cpp114
-rw-r--r--source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.cpp110
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp19
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp26
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp10
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp10
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp12
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp12
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp10
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp12
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp10
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp11
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp11
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp14
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp10
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp8
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp20
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp10
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp21
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp12
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp15
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp19
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp11
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp11
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp16
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp12
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp6
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp9
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp8
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp4
-rw-r--r--source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp2
-rw-r--r--source/blender/freestyle/intern/scene_graph/FrsMaterial.h97
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneHash.cpp39
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneHash.h (renamed from source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.h)50
-rw-r--r--source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp73
-rw-r--r--source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp415
-rw-r--r--source/blender/freestyle/intern/stroke/BasicStrokeShaders.h317
-rw-r--r--source/blender/freestyle/intern/stroke/Chain.cpp2
-rw-r--r--source/blender/freestyle/intern/stroke/Chain.h4
-rw-r--r--source/blender/freestyle/intern/stroke/Curve.h14
-rw-r--r--source/blender/freestyle/intern/stroke/Operators.cpp48
-rw-r--r--source/blender/freestyle/intern/stroke/Operators.h2
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.cpp63
-rw-r--r--source/blender/freestyle/intern/stroke/Stroke.h40
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeIterators.h12
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRep.cpp36
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRep.h15
-rw-r--r--source/blender/freestyle/intern/system/PointerSequence.h2
-rw-r--r--source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp24
-rw-r--r--source/blender/freestyle/intern/view_map/FEdgeXDetector.h4
-rw-r--r--source/blender/freestyle/intern/view_map/Functions0D.h12
-rw-r--r--source/blender/freestyle/intern/view_map/Functions1D.cpp4
-rw-r--r--source/blender/freestyle/intern/view_map/Functions1D.h9
-rw-r--r--source/blender/freestyle/intern/view_map/Interface0D.cpp4
-rw-r--r--source/blender/freestyle/intern/view_map/Interface0D.h16
-rw-r--r--source/blender/freestyle/intern/view_map/Silhouette.h48
-rw-r--r--source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp44
-rw-r--r--source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h3
-rw-r--r--source/blender/freestyle/intern/view_map/SteerableViewMap.h4
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.cpp24
-rw-r--r--source/blender/freestyle/intern/view_map/ViewMap.h15
-rw-r--r--source/blender/freestyle/intern/winged_edge/Curvature.cpp2
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.cpp11
-rw-r--r--source/blender/freestyle/intern/winged_edge/WEdge.h14
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdge.h14
-rw-r--r--source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp5
-rw-r--r--source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp13
-rw-r--r--source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h2
-rw-r--r--source/blender/gpu/CMakeLists.txt9
-rw-r--r--source/blender/gpu/GPU_buffers.h9
-rw-r--r--source/blender/gpu/GPU_draw.h3
-rw-r--r--source/blender/gpu/GPU_extensions.h5
-rw-r--r--source/blender/gpu/GPU_glew.h37
-rw-r--r--source/blender/gpu/GPU_init_exit.h (renamed from source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.h)35
-rw-r--r--source/blender/gpu/GPU_material.h5
-rw-r--r--source/blender/gpu/GPU_select.h61
-rw-r--r--source/blender/gpu/SConscript6
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c141
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c16
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h10
-rw-r--r--source/blender/gpu/intern/gpu_draw.c114
-rw-r--r--source/blender/gpu/intern/gpu_extensions.c185
-rw-r--r--source/blender/gpu/intern/gpu_extensions_private.h32
-rw-r--r--source/blender/gpu/intern/gpu_init_exit.c68
-rw-r--r--source/blender/gpu/intern/gpu_material.c84
-rw-r--r--source/blender/gpu/intern/gpu_select.c245
-rw-r--r--source/blender/gpu/intern/gpu_simple_shader.c2
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl109
-rw-r--r--source/blender/gpu/shaders/gpu_shader_simple_vert.glsl12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_vertex.glsl12
-rw-r--r--source/blender/ikplugin/intern/iksolver_plugin.c4
-rw-r--r--source/blender/ikplugin/intern/itasc_plugin.cpp4
-rw-r--r--source/blender/imbuf/CMakeLists.txt2
-rw-r--r--source/blender/imbuf/IMB_imbuf.h20
-rw-r--r--source/blender/imbuf/intern/cache.c16
-rw-r--r--source/blender/imbuf/intern/cineon/cineonlib.c4
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c4
-rw-r--r--source/blender/imbuf/intern/colormanagement.c27
-rw-r--r--source/blender/imbuf/intern/divers.c1
-rw-r--r--source/blender/imbuf/intern/imageprocess.c18
-rw-r--r--source/blender/imbuf/intern/metadata.c1
-rw-r--r--source/blender/imbuf/intern/moviecache.c2
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp77
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.h7
-rw-r--r--source/blender/imbuf/intern/png.c23
-rw-r--r--source/blender/imbuf/intern/readimage.c2
-rw-r--r--source/blender/imbuf/intern/rectop.c270
-rw-r--r--source/blender/imbuf/intern/scaling.c99
-rw-r--r--source/blender/imbuf/intern/thumbs.c21
-rw-r--r--source/blender/imbuf/intern/util.c8
-rw-r--r--source/blender/makesdna/DNA_ID.h24
-rw-r--r--source/blender/makesdna/DNA_actuator_types.h47
-rw-r--r--source/blender/makesdna/DNA_anim_types.h3
-rw-r--r--source/blender/makesdna/DNA_brush_types.h94
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h15
-rw-r--r--source/blender/makesdna/DNA_curve_types.h27
-rw-r--r--source/blender/makesdna/DNA_freestyle_types.h1
-rw-r--r--source/blender/makesdna/DNA_image_types.h6
-rw-r--r--source/blender/makesdna/DNA_lamp_types.h36
-rw-r--r--source/blender/makesdna/DNA_linestyle_types.h16
-rw-r--r--source/blender/makesdna/DNA_material_types.h18
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h4
-rw-r--r--source/blender/makesdna/DNA_node_types.h13
-rw-r--r--source/blender/makesdna/DNA_object_types.h10
-rw-r--r--source/blender/makesdna/DNA_scene_types.h60
-rw-r--r--source/blender/makesdna/DNA_screen_types.h31
-rw-r--r--source/blender/makesdna/DNA_sensor_types.h6
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h12
-rw-r--r--source/blender/makesdna/DNA_space_types.h4
-rw-r--r--source/blender/makesdna/DNA_texture_types.h36
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h38
-rw-r--r--source/blender/makesdna/DNA_vfont_types.h3
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h2
-rw-r--r--source/blender/makesdna/DNA_windowmanager_types.h13
-rw-r--r--source/blender/makesdna/intern/dna_genfile.c5
-rw-r--r--source/blender/makesrna/RNA_access.h25
-rw-r--r--source/blender/makesrna/SConscript12
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt15
-rw-r--r--source/blender/makesrna/intern/SConscript12
-rw-r--r--source/blender/makesrna/intern/makesrna.c37
-rw-r--r--source/blender/makesrna/intern/rna_ID.c12
-rw-r--r--source/blender/makesrna/intern/rna_access.c229
-rw-r--r--source/blender/makesrna/intern/rna_action.c2
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c165
-rw-r--r--source/blender/makesrna/intern/rna_armature.c2
-rw-r--r--source/blender/makesrna/intern/rna_brush.c406
-rw-r--r--source/blender/makesrna/intern/rna_color.c62
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c34
-rw-r--r--source/blender/makesrna/intern/rna_curve.c11
-rw-r--r--source/blender/makesrna/intern/rna_curve_api.c15
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c6
-rw-r--r--source/blender/makesrna/intern/rna_fluidsim.c3
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c4
-rw-r--r--source/blender/makesrna/intern/rna_image.c95
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c12
-rw-r--r--source/blender/makesrna/intern/rna_internal.h24
-rw-r--r--source/blender/makesrna/intern/rna_key.c8
-rw-r--r--source/blender/makesrna/intern/rna_lamp.c3
-rw-r--r--source/blender/makesrna/intern/rna_lattice_api.c9
-rw-r--r--source/blender/makesrna/intern/rna_linestyle.c528
-rw-r--r--source/blender/makesrna/intern/rna_main.c14
-rw-r--r--source/blender/makesrna/intern/rna_main_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_material.c133
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c15
-rw-r--r--source/blender/makesrna/intern/rna_meta_api.c8
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c26
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c104
-rw-r--r--source/blender/makesrna/intern/rna_object.c40
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c24
-rw-r--r--source/blender/makesrna/intern/rna_object_force.c19
-rw-r--r--source/blender/makesrna/intern/rna_packedfile.c18
-rw-r--r--source/blender/makesrna/intern/rna_particle.c250
-rw-r--r--source/blender/makesrna/intern/rna_pose.c57
-rw-r--r--source/blender/makesrna/intern/rna_render.c28
-rw-r--r--source/blender/makesrna/intern/rna_rigidbody.c13
-rw-r--r--source/blender/makesrna/intern/rna_scene.c274
-rw-r--r--source/blender/makesrna/intern/rna_screen.c13
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c204
-rw-r--r--source/blender/makesrna/intern/rna_sensor.c31
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c32
-rw-r--r--source/blender/makesrna/intern/rna_sequencer_api.c3
-rw-r--r--source/blender/makesrna/intern/rna_smoke.c8
-rw-r--r--source/blender/makesrna/intern/rna_space.c91
-rw-r--r--source/blender/makesrna/intern/rna_test.c4
-rw-r--r--source/blender/makesrna/intern/rna_tracking.c1
-rw-r--r--source/blender/makesrna/intern/rna_ui.c8
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c13
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c199
-rw-r--r--source/blender/makesrna/intern/rna_wm.c67
-rw-r--r--source/blender/makesrna/intern/rna_wm_api.c40
-rw-r--r--source/blender/makesrna/intern/rna_world.c3
-rw-r--r--source/blender/modifiers/CMakeLists.txt5
-rw-r--r--source/blender/modifiers/SConscript7
-rw-r--r--source/blender/modifiers/intern/MOD_array.c795
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c12
-rw-r--r--source/blender/modifiers/intern/MOD_boolean_util.c33
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c8
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c25
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c2
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c3
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c7
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c2
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_mdd.c4
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_pc2.c3
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c172
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c2
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c6
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c6
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c1
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c11
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c30
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c285
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c4
-rw-r--r--source/blender/modifiers/intern/MOD_util.c2
-rw-r--r--source/blender/modifiers/intern/MOD_weightvg_util.c6
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c19
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c9
-rw-r--r--source/blender/nodes/CMakeLists.txt11
-rw-r--r--source/blender/nodes/NOD_composite.h2
-rw-r--r--source/blender/nodes/NOD_shader.h4
-rw-r--r--source/blender/nodes/NOD_static_types.h11
-rw-r--r--source/blender/nodes/SConscript9
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c24
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_sunbeams.c63
-rw-r--r--source/blender/nodes/intern/node_common.c34
-rw-r--r--source/blender/nodes/intern/node_exec.c5
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c16
-rw-r--r--source/blender/nodes/shader/node_shader_util.c42
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c3
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_camera.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_math.c22
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_normal.c7
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_output_linestyle.c54
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c93
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c50
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_uvmap.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_vectMath.c4
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c12
-rw-r--r--source/blender/nodes/texture/node_texture_util.c18
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c14
-rw-r--r--source/blender/python/SConscript7
-rw-r--r--source/blender/python/bmesh/bmesh_py_ops_call.c2
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.c128
-rw-r--r--source/blender/python/bmesh/bmesh_py_types.h23
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c2
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_select.c4
-rw-r--r--source/blender/python/bmesh/bmesh_py_utils.c155
-rw-r--r--source/blender/python/generic/CMakeLists.txt4
-rw-r--r--source/blender/python/generic/bgl.c29
-rw-r--r--source/blender/python/generic/idprop_py_api.c2
-rw-r--r--source/blender/python/generic/py_capi_utils.c89
-rw-r--r--source/blender/python/generic/py_capi_utils.h2
-rw-r--r--source/blender/python/intern/CMakeLists.txt3
-rw-r--r--source/blender/python/intern/bpy.c15
-rw-r--r--source/blender/python/intern/bpy_app.c5
-rw-r--r--source/blender/python/intern/bpy_app_build_options.c4
-rw-r--r--source/blender/python/intern/bpy_app_ffmpeg.c2
-rw-r--r--source/blender/python/intern/bpy_app_handlers.c11
-rw-r--r--source/blender/python/intern/bpy_app_ocio.c2
-rw-r--r--source/blender/python/intern/bpy_app_oiio.c2
-rw-r--r--source/blender/python/intern/bpy_app_translations.c11
-rw-r--r--source/blender/python/intern/bpy_interface.c101
-rw-r--r--source/blender/python/intern/bpy_intern_string.c4
-rw-r--r--source/blender/python/intern/bpy_operator.c2
-rw-r--r--source/blender/python/intern/bpy_props.c146
-rw-r--r--source/blender/python/intern/bpy_rna.c40
-rw-r--r--source/blender/python/intern/bpy_utils_units.c332
-rw-r--r--source/blender/python/intern/bpy_utils_units.h32
-rw-r--r--source/blender/python/mathutils/mathutils.c6
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c23
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c230
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.h1
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c2
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c9
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c86
-rw-r--r--source/blender/python/mathutils/mathutils_kdtree.c4
-rw-r--r--source/blender/python/rna_dump.py38
-rw-r--r--source/blender/quicktime/apple/qtkit_import.m1
-rw-r--r--source/blender/render/CMakeLists.txt4
-rw-r--r--source/blender/render/SConscript3
-rw-r--r--source/blender/render/extern/include/RE_bake.h31
-rw-r--r--source/blender/render/extern/include/RE_engine.h4
-rw-r--r--source/blender/render/extern/include/RE_pipeline.h12
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h2
-rw-r--r--source/blender/render/intern/include/render_result.h7
-rw-r--r--source/blender/render/intern/include/render_types.h8
-rw-r--r--source/blender/render/intern/include/renderpipeline.h2
-rw-r--r--source/blender/render/intern/raytrace/rayobject_octree.cpp2
-rw-r--r--source/blender/render/intern/source/bake.c4
-rw-r--r--source/blender/render/intern/source/bake_api.c276
-rw-r--r--source/blender/render/intern/source/convertblender.c96
-rw-r--r--source/blender/render/intern/source/envmap.c4
-rw-r--r--source/blender/render/intern/source/external_engine.c53
-rw-r--r--source/blender/render/intern/source/imagetexture.c187
-rw-r--r--source/blender/render/intern/source/initrender.c2
-rw-r--r--source/blender/render/intern/source/multires_bake.c8
-rw-r--r--source/blender/render/intern/source/occlusion.c20
-rw-r--r--source/blender/render/intern/source/pipeline.c326
-rw-r--r--source/blender/render/intern/source/pixelshading.c24
-rw-r--r--source/blender/render/intern/source/pointdensity.c2
-rw-r--r--source/blender/render/intern/source/rayshade.c24
-rw-r--r--source/blender/render/intern/source/render_result.c116
-rw-r--r--source/blender/render/intern/source/render_texture.c87
-rw-r--r--source/blender/render/intern/source/rendercore.c4
-rw-r--r--source/blender/render/intern/source/renderdatabase.c16
-rw-r--r--source/blender/render/intern/source/shadbuf.c10
-rw-r--r--source/blender/render/intern/source/shadeoutput.c50
-rw-r--r--source/blender/render/intern/source/sss.c10
-rw-r--r--source/blender/render/intern/source/strand.c2
-rw-r--r--source/blender/render/intern/source/sunsky.c6
-rw-r--r--source/blender/render/intern/source/texture_ocean.c2
-rw-r--r--source/blender/render/intern/source/volumetric.c2
-rw-r--r--source/blender/render/intern/source/zbuf.c6
-rw-r--r--source/blender/windowmanager/CMakeLists.txt6
-rw-r--r--source/blender/windowmanager/SConscript8
-rw-r--r--source/blender/windowmanager/WM_api.h41
-rw-r--r--source/blender/windowmanager/WM_keymap.h2
-rw-r--r--source/blender/windowmanager/WM_types.h13
-rw-r--r--source/blender/windowmanager/intern/wm.c3
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c2
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c19
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c8
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c174
-rw-r--r--source/blender/windowmanager/intern/wm_files.c74
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c2
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c45
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c149
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c322
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c63
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c37
-rw-r--r--source/blender/windowmanager/intern/wm_window.c134
-rw-r--r--source/blender/windowmanager/wm_event_system.h5
-rw-r--r--source/blender/windowmanager/wm_event_types.h585
-rw-r--r--source/blender/windowmanager/wm_window.h6
-rw-r--r--source/blenderplayer/CMakeLists.txt10
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c29
-rw-r--r--source/creator/CMakeLists.txt433
-rw-r--r--source/creator/creator.c73
-rw-r--r--source/creator/creator_launch_win.c90
-rw-r--r--source/creator/osx_locals.map5
-rw-r--r--source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp21
-rw-r--r--source/gameengine/BlenderRoutines/CMakeLists.txt3
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp6
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.h3
-rw-r--r--source/gameengine/BlenderRoutines/SConscript7
-rw-r--r--source/gameengine/Converter/BL_ArmatureObject.cpp8
-rw-r--r--source/gameengine/Converter/BL_BlenderDataConversion.cpp2
-rw-r--r--source/gameengine/Converter/BL_ShapeActionActuator.h2
-rw-r--r--source/gameengine/Converter/KX_BlenderSceneConverter.cpp47
-rw-r--r--source/gameengine/Converter/KX_ConvertActuators.cpp59
-rw-r--r--source/gameengine/Converter/KX_ConvertSensors.cpp13
-rw-r--r--source/gameengine/Expressions/BoolValue.cpp7
-rw-r--r--source/gameengine/Expressions/BoolValue.h1
-rw-r--r--source/gameengine/Expressions/EmptyValue.cpp7
-rw-r--r--source/gameengine/Expressions/EmptyValue.h1
-rw-r--r--source/gameengine/Expressions/ErrorValue.cpp7
-rw-r--r--source/gameengine/Expressions/ErrorValue.h1
-rw-r--r--source/gameengine/Expressions/Expression.cpp4
-rw-r--r--source/gameengine/Expressions/Expression.h4
-rw-r--r--source/gameengine/Expressions/FloatValue.cpp7
-rw-r--r--source/gameengine/Expressions/FloatValue.h1
-rw-r--r--source/gameengine/Expressions/IntValue.cpp11
-rw-r--r--source/gameengine/Expressions/IntValue.h1
-rw-r--r--source/gameengine/Expressions/ListValue.cpp7
-rw-r--r--source/gameengine/Expressions/ListValue.h1
-rw-r--r--source/gameengine/Expressions/StringValue.cpp7
-rw-r--r--source/gameengine/Expressions/StringValue.h1
-rw-r--r--source/gameengine/Expressions/Value.cpp17
-rw-r--r--source/gameengine/Expressions/Value.h14
-rw-r--r--source/gameengine/Expressions/VectorValue.cpp8
-rw-r--r--source/gameengine/Expressions/VectorValue.h1
-rw-r--r--source/gameengine/Expressions/VoidValue.h1
-rw-r--r--source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h2
-rw-r--r--source/gameengine/GameLogic/SCA_IActuator.h1
-rw-r--r--source/gameengine/GameLogic/SCA_IScene.cpp44
-rw-r--r--source/gameengine/GameLogic/SCA_IScene.h6
-rw-r--r--source/gameengine/GameLogic/SCA_PropertyActuator.cpp30
-rw-r--r--source/gameengine/GameLogic/SCA_PropertyActuator.h1
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.cpp39
-rw-r--r--source/gameengine/GameLogic/SCA_PropertySensor.h2
-rw-r--r--source/gameengine/GameLogic/SCA_PythonController.cpp13
-rw-r--r--source/gameengine/GamePlayer/common/CMakeLists.txt5
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.h2
-rw-r--r--source/gameengine/GamePlayer/common/SConscript7
-rw-r--r--source/gameengine/GamePlayer/ghost/CMakeLists.txt3
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Application.cpp7
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp6
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_Canvas.h2
-rw-r--r--source/gameengine/GamePlayer/ghost/GPG_ghost.cpp27
-rw-r--r--source/gameengine/GamePlayer/ghost/SConscript7
-rw-r--r--source/gameengine/Ketsji/BL_BlenderShader.cpp2
-rw-r--r--source/gameengine/Ketsji/BL_Shader.cpp2
-rw-r--r--source/gameengine/Ketsji/BL_Texture.cpp2
-rw-r--r--source/gameengine/Ketsji/CMakeLists.txt5
-rw-r--r--source/gameengine/Ketsji/KX_BlenderMaterial.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_Camera.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintWrapper.cpp7
-rw-r--r--source/gameengine/Ketsji/KX_ConstraintWrapper.h1
-rw-r--r--source/gameengine/Ketsji/KX_Dome.cpp6
-rw-r--r--source/gameengine/Ketsji/KX_Dome.h2
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp160
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h16
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.cpp122
-rw-r--r--source/gameengine/Ketsji/KX_KetsjiEngine.h48
-rw-r--r--source/gameengine/Ketsji/KX_Light.cpp4
-rw-r--r--source/gameengine/Ketsji/KX_MouseActuator.cpp531
-rw-r--r--source/gameengine/Ketsji/KX_MouseActuator.h127
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.cpp88
-rw-r--r--source/gameengine/Ketsji/KX_MouseFocusSensor.h20
-rw-r--r--source/gameengine/Ketsji/KX_NavMeshObject.cpp13
-rw-r--r--source/gameengine/Ketsji/KX_ObjectActuator.cpp1
-rw-r--r--source/gameengine/Ketsji/KX_PyConstraintBinding.cpp1
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp124
-rw-r--r--source/gameengine/Ketsji/KX_PythonInitTypes.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_RaySensor.h13
-rw-r--r--source/gameengine/Ketsji/KX_Scene.cpp71
-rw-r--r--source/gameengine/Ketsji/KX_Scene.h3
-rw-r--r--source/gameengine/Ketsji/KX_SteeringActuator.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_TouchEventManager.cpp7
-rw-r--r--source/gameengine/Ketsji/KX_TrackToActuator.cpp223
-rw-r--r--source/gameengine/Ketsji/KX_TrackToActuator.h16
-rw-r--r--source/gameengine/Ketsji/SConscript5
-rw-r--r--source/gameengine/Physics/Bullet/CMakeLists.txt4
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.cpp17
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsController.h2
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp159
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h1
-rw-r--r--source/gameengine/Physics/Bullet/SConscript6
-rw-r--r--source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp6
-rw-r--r--source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsController.h2
-rw-r--r--source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h2
-rw-r--r--source/gameengine/Rasterizer/CMakeLists.txt3
-rw-r--r--source/gameengine/Rasterizer/RAS_2DFilterManager.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_BucketManager.cpp38
-rw-r--r--source/gameengine/Rasterizer/RAS_BucketManager.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_ICanvas.h3
-rw-r--r--source/gameengine/Rasterizer/RAS_ILightObject.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt3
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp5
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp4
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h2
-rw-r--r--source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript5
-rw-r--r--source/gameengine/Rasterizer/SConscript6
-rw-r--r--source/gameengine/VideoTexture/CMakeLists.txt3
-rw-r--r--source/gameengine/VideoTexture/Exception.h2
-rw-r--r--source/gameengine/VideoTexture/ImageBase.cpp2
-rw-r--r--source/gameengine/VideoTexture/ImageBuff.cpp4
-rw-r--r--source/gameengine/VideoTexture/ImageRender.cpp4
-rw-r--r--source/gameengine/VideoTexture/ImageViewport.cpp2
-rw-r--r--source/gameengine/VideoTexture/SConscript6
-rw-r--r--source/gameengine/VideoTexture/Texture.cpp2
-rw-r--r--source/gameengine/VideoTexture/VideoFFmpeg.cpp11
-rw-r--r--source/tests/CMakeLists.txt360
-rw-r--r--source/tests/batch_import.py201
-rw-r--r--source/tests/bl_keymap_completeness.py84
-rw-r--r--source/tests/bl_load_addons.py111
-rw-r--r--source/tests/bl_load_py_modules.py167
-rw-r--r--source/tests/bl_mesh_modifiers.py866
-rw-r--r--source/tests/bl_mesh_validate.py161
-rw-r--r--source/tests/bl_pyapi_mathutils.py307
-rw-r--r--source/tests/bl_rna_wiki_reference.py144
-rw-r--r--source/tests/bl_rst_completeness.py159
-rw-r--r--source/tests/bl_run_operators.py490
-rw-r--r--source/tests/bl_test.py197
-rw-r--r--source/tests/check_deprecated.py149
-rw-r--r--source/tests/pep8.py154
-rw-r--r--source/tests/rna_array.py297
-rw-r--r--source/tests/rna_info_dump.py131
-rw-r--r--source/tests/rst_to_doctree_mini.py90
1312 files changed, 49730 insertions, 24176 deletions
diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt
index 391fdf42d28..c696719e650 100644
--- a/source/CMakeLists.txt
+++ b/source/CMakeLists.txt
@@ -29,4 +29,3 @@ if(WITH_GAMEENGINE)
add_subdirectory(gameengine)
endif()
-add_subdirectory(tests)
diff --git a/source/blender/avi/intern/avi_rgb.c b/source/blender/avi/intern/avi_rgb.c
index c6a78eccce2..632ecad61a6 100644
--- a/source/blender/avi/intern/avi_rgb.c
+++ b/source/blender/avi/intern/avi_rgb.c
@@ -123,13 +123,12 @@ void *avi_converter_to_avi_rgb(AviMovie *movie, int stream, unsigned char *buffe
(void)stream; /* unused */
- *size = movie->header->Height * movie->header->Width * 3;
- if (movie->header->Width % 2) *size += movie->header->Height;
-
- buf = MEM_mallocN(*size, "toavirgbbuf");
-
rowstride = movie->header->Width * 3;
- if (movie->header->Width % 2) rowstride++;
+ /* AVI files has uncompressed lines 4-byte aligned */
+ rowstride = (rowstride + 3) & ~3;
+
+ *size = movie->header->Height * rowstride;
+ buf = MEM_mallocN(*size, "toavirgbbuf");
for (y = 0; y < movie->header->Height; y++) {
memcpy(&buf[y * rowstride], &buffer[((movie->header->Height - 1) - y) * movie->header->Width * 3], movie->header->Width * 3);
diff --git a/source/blender/avi/intern/avi_rgb32.c b/source/blender/avi/intern/avi_rgb32.c
index 5c7a4889d97..c9cbcb05bb8 100644
--- a/source/blender/avi/intern/avi_rgb32.c
+++ b/source/blender/avi/intern/avi_rgb32.c
@@ -74,8 +74,8 @@ void *avi_converter_to_rgb32(AviMovie *movie, int stream, unsigned char *buffer,
(void)stream; /* unused */
- buf = MEM_mallocN(movie->header->Height * movie->header->Width * 4, "torgb32buf");
*size = movie->header->Height * movie->header->Width * 4;
+ buf = MEM_mallocN(*size, "torgb32buf");
memset(buf, 255, *size);
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h
index 2a27a3d6f4d..206345582b2 100644
--- a/source/blender/blenfont/BLF_api.h
+++ b/source/blender/blenfont/BLF_api.h
@@ -32,22 +32,26 @@
#ifndef __BLF_API_H__
#define __BLF_API_H__
+#include "BLI_compiler_attrs.h"
+
struct rctf;
struct ColorManagedDisplay;
int BLF_init(int points, int dpi);
void BLF_exit(void);
void BLF_default_dpi(int dpi);
+void BLF_default_set(int fontid);
void BLF_cache_clear(void);
-int BLF_load(const char *name);
-int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size);
+int BLF_load(const char *name) ATTR_NONNULL();
+int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
-int BLF_load_unique(const char *name);
-int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size);
+int BLF_load_unique(const char *name) ATTR_NONNULL();
+int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL();
-void BLF_unload(const char *name);
+void BLF_unload(const char *name) ATTR_NONNULL();
+void BLF_unload_id(int fontid);
/* Attach a file with metrics information from memory. */
void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size);
@@ -71,8 +75,8 @@ void BLF_size(int fontid, int size, int dpi);
void BLF_matrix(int fontid, const double m[16]);
/* Draw the string using the default font, size and dpi. */
-void BLF_draw_default(float x, float y, float z, const char *str, size_t len);
-void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len);
+void BLF_draw_default(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL();
+void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL();
/* Draw the string using the current font. */
void BLF_draw(int fontid, const char *str, size_t len);
@@ -80,45 +84,45 @@ void BLF_draw_ascii(int fontid, const char *str, size_t len);
int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth);
/* Get the string byte offset that fits within a given width */
-size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width);
+size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width) ATTR_NONNULL(2);
/* Same as BLF_width_to_strlen but search from the string end */
-size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width, float *r_width);
+size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width, float *r_width) ATTR_NONNULL(2);
/* This function return the bounding box of the string
* and are not multiplied by the aspect.
*/
-void BLF_boundbox(int fontid, const char *str, size_t len, struct rctf *box);
+void BLF_boundbox(int fontid, const char *str, size_t len, struct rctf *box) ATTR_NONNULL();
/* The next both function return the width and height
* of the string, using the current font and both value
* are multiplied by the aspect of the font.
*/
-float BLF_width(int fontid, const char *str, size_t len);
-float BLF_height(int fontid, const char *str, size_t len);
+float BLF_width(int fontid, const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BLF_height(int fontid, const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* Return dimensions of the font without any sample text. */
-float BLF_height_max(int fontid);
-float BLF_width_max(int fontid);
-float BLF_descender(int fontid);
-float BLF_ascender(int fontid);
+float BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT;
+float BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT;
+float BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT;
+float BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT;
/* The following function return the width and height of the string, but
* just in one call, so avoid extra freetype2 stuff.
*/
-void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height);
+void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height) ATTR_NONNULL();
/* For fixed width fonts only, returns the width of a
* character.
*/
-float BLF_fixed_width(int fontid);
+float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT;
/* and this two function return the width and height
* of the string, using the default font and both value
* are multiplied by the aspect of the font.
*/
-void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height);
-float BLF_width_default(const char *str, size_t len);
-float BLF_height_default(const char *str, size_t len);
+void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height) ATTR_NONNULL();
+float BLF_width_default(const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BLF_height_default(const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* Set rotation for default font. */
void BLF_rotation_default(float angle);
@@ -168,19 +172,19 @@ void BLF_buffer_col(int fontid, float r, float g, float b, float a);
/* Draw the string into the buffer, this function draw in both buffer, float and unsigned char _BUT_
* it's not necessary set both buffer, NULL is valid here.
*/
-void BLF_draw_buffer(int fontid, const char *str);
+void BLF_draw_buffer(int fontid, const char *str) ATTR_NONNULL();
/* Add a path to the font dir paths. */
-void BLF_dir_add(const char *path);
+void BLF_dir_add(const char *path) ATTR_NONNULL();
/* Remove a path from the font dir paths. */
-void BLF_dir_rem(const char *path);
+void BLF_dir_rem(const char *path) ATTR_NONNULL();
/* Return an array with all the font dir (this can be used for filesel) */
-char **BLF_dir_get(int *ndir);
+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);
+void BLF_dir_free(char **dirs, int count) ATTR_NONNULL();
#ifdef DEBUG
void BLF_state_print(int fontid);
diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt
index 2debe516dd7..346d5bc64b8 100644
--- a/source/blender/blenfont/CMakeLists.txt
+++ b/source/blender/blenfont/CMakeLists.txt
@@ -26,11 +26,13 @@ set(INC
../blenkernel
../blenlib
../editors/include
+ ../gpu
../makesdna
../makesrna
../python
../imbuf
../../../intern/guardedalloc
+ ../../../intern/glew-mx
../../../intern/locale
)
@@ -58,7 +60,7 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
-add_definitions(-DGLEW_STATIC)
+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 1c573fa4a59..b6cf052a980 100644
--- a/source/blender/blenfont/SConscript
+++ b/source/blender/blenfont/SConscript
@@ -35,10 +35,12 @@ incs = [
'intern',
'#/intern/guardedalloc',
'#/intern/locale',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../blenkernel',
'../blenlib',
'../editors/include',
+ '../gpu',
'../imbuf',
'../makesdna',
'../makesrna',
@@ -47,7 +49,7 @@ incs = [
incs.extend(Split(env['BF_FREETYPE_INC']))
-defs = ['GLEW_STATIC']
+defs = env['BF_GL_DEFINITIONS']
if sys.platform == 'win32' or env['OURPLATFORM'] == 'linuxcross':
defs.append('_WIN32')
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index e086ca4977e..cdccbe044bb 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -152,6 +152,14 @@ static int blf_search_available(void)
return -1;
}
+void BLF_default_set(int fontid)
+{
+ FontBLF *font = blf_get(fontid);
+ if (font || fontid == -1) {
+ global_font_default = fontid;
+ }
+}
+
static int blf_global_font_init(void)
{
if (global_font_default == -1) {
@@ -335,6 +343,15 @@ void BLF_unload(const char *name)
}
}
+void BLF_unload_id(int fontid)
+{
+ FontBLF *font = blf_get(fontid);
+ if (font) {
+ blf_font_free(font);
+ global_font[fontid] = NULL;
+ }
+}
+
void BLF_enable(int fontid, int option)
{
FontBLF *font = blf_get(fontid);
@@ -460,9 +477,6 @@ void BLF_blur(int fontid, int size)
void BLF_draw_default(float x, float y, float z, const char *str, size_t len)
{
- if (!str)
- return;
-
if (!blf_global_font_init())
return;
@@ -474,9 +488,6 @@ void BLF_draw_default(float x, float y, float z, const char *str, size_t len)
/* same as above but call 'BLF_draw_ascii' */
void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len)
{
- if (!str)
- return;
-
if (!blf_global_font_init())
return;
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 2bdae87dc83..4891c332c87 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -186,9 +186,9 @@ void blf_font_draw(FontBLF *font, const char *str, size_t len)
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
- if (c == BLI_UTF8_ERR)
+ if (UNLIKELY(c == BLI_UTF8_ERR))
break;
- if (g == NULL)
+ if (UNLIKELY(g == NULL))
continue;
if (has_kerning)
BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
@@ -196,7 +196,7 @@ void blf_font_draw(FontBLF *font, const char *str, size_t len)
/* do not return this loop if clipped, we want every character tested */
blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
- pen_x += (int)g->advance;
+ pen_x += g->advance_i;
g_prev = g;
}
}
@@ -224,7 +224,7 @@ void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len)
/* do not return this loop if clipped, we want every character tested */
blf_glyph_render(font, g, (float)pen_x, (float)pen_y);
- pen_x += (int)g->advance;
+ pen_x += g->advance_i;
g_prev = g;
}
}
@@ -244,9 +244,9 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
- if (c == BLI_UTF8_ERR)
+ if (UNLIKELY(c == BLI_UTF8_ERR))
break;
- if (g == NULL)
+ if (UNLIKELY(g == NULL))
continue;
/* do not return this loop if clipped, we want every character tested */
@@ -303,9 +303,9 @@ void blf_font_buffer(FontBLF *font, const char *str)
while (str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
- if (c == BLI_UTF8_ERR)
+ if (UNLIKELY(c == BLI_UTF8_ERR))
break;
- if (g == NULL)
+ if (UNLIKELY(g == NULL))
continue;
if (has_kerning)
BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
@@ -415,7 +415,7 @@ void blf_font_buffer(FontBLF *font, const char *str)
}
}
- pen_x += (int)g->advance;
+ pen_x += g->advance_i;
g_prev = g;
}
}
@@ -438,14 +438,14 @@ size_t blf_font_width_to_strlen(FontBLF *font, const char *str, size_t len, floa
while ((i_prev = i), (width_new = pen_x), ((i < len) && str[i])) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
- if (c == BLI_UTF8_ERR)
+ if (UNLIKELY(c == BLI_UTF8_ERR))
break;
- if (g == NULL)
+ if (UNLIKELY(g == NULL))
continue;
if (has_kerning)
BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
- pen_x += (int)g->advance;
+ pen_x += g->advance_i;
if (width_i < pen_x) {
break;
@@ -501,14 +501,14 @@ size_t blf_font_width_to_rstrlen(FontBLF *font, const char *str, size_t len, flo
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
- if (c == BLI_UTF8_ERR)
+ if (UNLIKELY(c == BLI_UTF8_ERR))
break;
- if (g == NULL)
+ if (UNLIKELY(g == NULL))
continue;
if (has_kerning)
BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
- pen_x += (int)g->advance;
+ pen_x += g->advance_i;
width_accum[width_accum_ofs][0] = (int)i;
width_accum[width_accum_ofs][1] = pen_x;
@@ -570,9 +570,9 @@ void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *box)
while ((i < len) && str[i]) {
BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table);
- if (c == BLI_UTF8_ERR)
+ if (UNLIKELY(c == BLI_UTF8_ERR))
break;
- if (g == NULL)
+ if (UNLIKELY(g == NULL))
continue;
if (has_kerning)
BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
@@ -588,7 +588,7 @@ void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *box)
if (gbox.xmax > box->xmax) box->xmax = gbox.xmax;
if (gbox.ymax > box->ymax) box->ymax = gbox.ymax;
- pen_x += (int)g->advance;
+ pen_x += g->advance_i;
g_prev = g;
}
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index 7c3cfa30e16..7978d28a4ef 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -153,7 +153,7 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc)
/* move the index. */
gc->cur_tex++;
- if (gc->cur_tex >= gc->ntex) {
+ if (UNLIKELY(gc->cur_tex >= gc->ntex)) {
gc->ntex *= 2;
gc->textures = (GLuint *)MEM_reallocN((void *)gc->textures, sizeof(GLuint) * gc->ntex);
}
@@ -279,6 +279,7 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
}
g->advance = ((float)slot->advance.x) / 64.0f;
+ g->advance_i = (int)g->advance;
g->pos_x = (float)slot->bitmap_left;
g->pos_y = (float)slot->bitmap_top;
g->pitch = slot->bitmap.pitch;
@@ -378,7 +379,7 @@ static void blf_texture3_draw(const float shadow_col[4], float uv[2][2], float x
static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y)
{
- rect->xmin = (float)floor(x + g->pos_x);
+ rect->xmin = floorf(x + g->pos_x);
rect->xmax = rect->xmin + (float)g->width;
rect->ymin = y + g->pos_y;
rect->ymax = y + g->pos_y - (float)g->height;
diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index c64b7e974e7..da756d65483 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -99,6 +99,8 @@ typedef struct GlyphBLF {
/* advance size. */
float advance;
+ /* avoid conversion to int while drawing */
+ int advance_i;
/* texture id where this glyph is store. */
GLuint tex;
diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c
index 2852b8161c8..12d71827136 100644
--- a/source/blender/blenfont/intern/blf_lang.c
+++ b/source/blender/blenfont/intern/blf_lang.c
@@ -235,15 +235,11 @@ void BLF_lang_set(const char *str)
else {
short_locale_utf8 = BLI_sprintfN("%s.UTF-8", short_locale);
}
+ bl_locale_set(short_locale_utf8);
+ MEM_freeN((void *)short_locale_utf8);
}
else {
- short_locale_utf8 = short_locale;
- }
-
- bl_locale_set(short_locale_utf8);
-
- if (short_locale[0]) {
- MEM_freeN((void *)short_locale_utf8);
+ bl_locale_set(short_locale);
}
#else
(void)str;
diff --git a/source/blender/blenfont/intern/blf_util.c b/source/blender/blenfont/intern/blf_util.c
index cb9b652b8ef..06309a944e9 100644
--- a/source/blender/blenfont/intern/blf_util.c
+++ b/source/blender/blenfont/intern/blf_util.c
@@ -37,6 +37,7 @@
#include "blf_internal.h"
+#include "BLI_utildefines.h"
#include "BLI_string_utf8.h"
unsigned int blf_next_p2(unsigned int x)
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index 1ab5ec51de8..229d2fc17cd 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -150,8 +150,10 @@ typedef DMDrawOption (*DMSetDrawOptions)(void *userData, int index);
typedef DMDrawOption (*DMSetDrawOptionsTex)(struct MTFace *tface, const bool has_vcol, int matnr);
typedef enum DMDrawFlag {
- DM_DRAW_USE_COLORS = 1,
- DM_DRAW_ALWAYS_SMOOTH = 2
+ DM_DRAW_USE_COLORS = (1 << 0),
+ DM_DRAW_ALWAYS_SMOOTH = (1 << 1),
+ DM_DRAW_USE_ACTIVE_UV = (1 << 2),
+ DM_DRAW_USE_TEXPAINT_UV = (1 << 3),
} DMDrawFlag;
typedef enum DMForeachFlag {
@@ -389,7 +391,7 @@ struct DerivedMesh {
void (*drawFacesTex)(DerivedMesh *dm,
DMSetDrawOptionsTex setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData);
+ void *userData, DMDrawFlag uvflag);
/** Draw all faces with GLSL materials
* o setMaterial is called for every different material nr
@@ -423,7 +425,7 @@ struct DerivedMesh {
void (*drawMappedFacesTex)(DerivedMesh *dm,
DMSetDrawOptions setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData);
+ void *userData, DMDrawFlag uvflag);
/** Draw mapped faces with GLSL materials
* - setMaterial is called for every different material nr
@@ -593,6 +595,8 @@ void DM_ensure_tessface(DerivedMesh *dm);
void DM_update_tessface_data(DerivedMesh *dm);
void DM_update_materials(DerivedMesh *dm, struct Object *ob);
+struct MTFace *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr);
+
/** interpolates vertex data from the vertices indexed by src_indices in the
* source mesh using the given weights and stores the result in the vertex
* indexed by dest_index in the dest mesh
@@ -647,6 +651,7 @@ void vDM_ColorBand_store(const struct ColorBand *coba, const char alert_color[4]
* In use now by vertex/weight paint and particles */
DMCoNo *mesh_get_mapped_verts_nors(struct Scene *scene, struct Object *ob);
#endif
+void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos);
/* */
DerivedMesh *mesh_get_derived_final(struct Scene *scene, struct Object *ob,
@@ -687,6 +692,9 @@ DerivedMesh *editbmesh_get_derived_cage(struct Scene *scene, struct Object *,
DerivedMesh *editbmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *,
struct BMEditMesh *em, DerivedMesh **r_final,
CustomDataMask dataMask);
+
+DerivedMesh *object_get_derived_final(struct Object *ob, const bool for_render);
+
float (*editbmesh_get_vertex_cos(struct BMEditMesh *em, int *r_numVerts))[3];
bool editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm);
void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct BMEditMesh *em,
diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h
index 517c0f7d58b..57ba6fd55ca 100644
--- a/source/blender/blenkernel/BKE_action.h
+++ b/source/blender/blenkernel/BKE_action.h
@@ -180,10 +180,12 @@ void framechange_poses_clear_unkeyed(void);
/* Bone Groups API --------------------- */
/* Adds a new bone-group */
-void BKE_pose_add_group(struct Object *ob);
+struct bActionGroup *BKE_pose_add_group(struct bPose *pose, const char *name);
-/* Remove the active bone-group */
-void BKE_pose_remove_group(struct Object *ob);
+/* Remove a bone-group */
+void BKE_pose_remove_group(struct bPose *pose, struct bActionGroup *grp, const int index);
+/* Remove the matching bone-group from its index */
+void BKE_pose_remove_group_index(struct bPose *pose, const int index);
/* Assorted Evaluation ----------------- */
diff --git a/source/blender/blenkernel/BKE_anim.h b/source/blender/blenkernel/BKE_anim.h
index e49fe98aa14..0d5078bc026 100644
--- a/source/blender/blenkernel/BKE_anim.h
+++ b/source/blender/blenkernel/BKE_anim.h
@@ -73,6 +73,7 @@ int count_duplilist(struct Object *ob);
typedef struct DupliExtraData {
float obmat[4][4];
+ unsigned int lay;
} DupliExtraData;
typedef struct DupliApplyData {
@@ -80,8 +81,8 @@ typedef struct DupliApplyData {
DupliExtraData *extra;
} DupliApplyData;
-DupliApplyData *duplilist_apply_matrix(struct ListBase *duplilist);
-void duplilist_restore_matrix(struct ListBase *duplilist, DupliApplyData *apply_data);
+DupliApplyData *duplilist_apply(struct Object *ob, struct ListBase *duplilist);
+void duplilist_restore(struct ListBase *duplilist, DupliApplyData *apply_data);
void duplilist_free_apply_data(DupliApplyData *apply_data);
#endif
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index 80d2750fe82..e79822daa4d 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -37,8 +37,10 @@ struct Main;
struct AnimData;
struct KeyingSet;
struct KS_Path;
+struct bContext;
struct PointerRNA;
+struct PropertyRNA;
struct ReportList;
struct bAction;
struct bActionGroup;
@@ -127,6 +129,9 @@ void BKE_animdata_separate_by_basepath(struct ID *srcID, struct ID *dstID, struc
/* Move F-Curves from src to destination if it's path is based on basepath */
void action_move_fcurves_by_basepath(struct bAction *srcAct, struct bAction *dstAct, const char basepath[]);
+char *BKE_animdata_driver_path_hack(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop,
+ char *base_path);
+
/* ************************************* */
/* Batch AnimData API */
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h
index 85329753844..fdf0795fe02 100644
--- a/source/blender/blenkernel/BKE_armature.h
+++ b/source/blender/blenkernel/BKE_armature.h
@@ -99,6 +99,7 @@ void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan);
/* get_objectspace_bone_matrix has to be removed still */
void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], int root, int posed);
void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3]);
+void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float mat[3][3]);
void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll);
/* Common Conversions Between Co-ordinate Spaces */
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index e4ebe0e0ed5..6c8f90c60ae 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 270
-#define BLENDER_SUBVERSION 5
+#define BLENDER_VERSION 272
+#define BLENDER_SUBVERSION 1
/* 262 was the last editmesh release but it has compatibility code for bmesh data */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5
@@ -69,10 +69,12 @@ int BKE_read_file(struct bContext *C, const char *filepath, struct ReportList *r
#define BKE_READ_FILE_OK 1 /* OK */
#define BKE_READ_FILE_OK_USERPREFS 2 /* OK, and with new user settings */
-int BKE_read_file_from_memory(struct bContext *C, const void *filebuf,
- int filelength, struct ReportList *reports, int update_defaults);
-int BKE_read_file_from_memfile(struct bContext *C, struct MemFile *memfile,
- struct ReportList *reports);
+bool BKE_read_file_from_memory(
+ struct bContext *C, const void *filebuf,
+ int filelength, struct ReportList *reports, bool update_defaults);
+bool BKE_read_file_from_memfile(
+ struct bContext *C, struct MemFile *memfile,
+ struct ReportList *reports);
int BKE_read_file_userdef(const char *filepath, struct ReportList *reports);
int BKE_write_file_userdef(const char *filepath, struct ReportList *reports);
diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h
index 104e80e815c..d48753590bb 100644
--- a/source/blender/blenkernel/BKE_brush.h
+++ b/source/blender/blenkernel/BKE_brush.h
@@ -81,7 +81,11 @@ unsigned int *BKE_brush_gen_texture_cache(struct Brush *br, int half_side, bool
/* radial control */
struct ImBuf *BKE_brush_gen_radial_control_imbuf(struct Brush *br, bool secondary);
-/* unified strength and size */
+/* 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);
+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);
void BKE_brush_size_set(struct Scene *scene, struct Brush *brush, int value);
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index dffc2b665c2..b0ade7bacdf 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -58,7 +58,13 @@ struct DerivedMesh *CDDM_from_bmesh(struct BMesh *bm, const bool use_mdisps);
DerivedMesh *CDDM_from_editbmesh(struct BMEditMesh *em, const bool use_mdisps, const bool use_tessface);
/* merge verts */
-DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap);
+/* Enum for merge_mode of CDDM_merge_verts.
+ * Refer to cdderivedmesh.c for details. */
+enum {
+ CDDM_MERGE_VERTS_DUMP_IF_MAPPED,
+ CDDM_MERGE_VERTS_DUMP_IF_EQUAL,
+};
+DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode);
/* creates a CDDerivedMesh from the given curve object */
struct DerivedMesh *CDDM_from_curve(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h
index e30c8ecee2b..877e376b343 100644
--- a/source/blender/blenkernel/BKE_context.h
+++ b/source/blender/blenkernel/BKE_context.h
@@ -234,7 +234,6 @@ int ctx_data_list_count(const bContext *C, int (*func)(const bContext *, ListBas
struct Main *CTX_data_main(const bContext *C);
struct Scene *CTX_data_scene(const bContext *C);
struct ToolSettings *CTX_data_tool_settings(const bContext *C);
-struct FreestyleLineStyle *CTX_data_linestyle_from_scene(struct Scene *scene);
const char *CTX_data_mode_string(const bContext *C);
int CTX_data_mode_enum(const bContext *C);
diff --git a/source/blender/blenkernel/BKE_crazyspace.h b/source/blender/blenkernel/BKE_crazyspace.h
index feed1594d90..98bcdc5cfaa 100644
--- a/source/blender/blenkernel/BKE_crazyspace.h
+++ b/source/blender/blenkernel/BKE_crazyspace.h
@@ -41,8 +41,9 @@ struct Mesh;
/* crazyspace.c */
float (*BKE_crazyspace_get_mapped_editverts(struct Scene *scene, struct Object *obedit))[3];
-void BKE_crazyspace_set_quats_editmesh(struct BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4],
- const bool use_select);
+void BKE_crazyspace_set_quats_editmesh(
+ struct BMEditMesh *em, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4],
+ const bool use_select);
void BKE_crazyspace_set_quats_mesh(struct Mesh *me, float (*origcos)[3], float (*mappedcos)[3], float (*quats)[4]);
int BKE_sculpt_get_first_deform_matrices(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]);
void BKE_crazyspace_build_sculpt(struct Scene *scene, struct Object *ob, float (**deformmats)[3][3], float (**deformcos)[3]);
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 0f9f8cb2f08..253d9edc3b5 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -49,6 +49,7 @@ struct rctf;
typedef struct CurveCache {
ListBase disp;
ListBase bev;
+ ListBase deformed_nurbs;
struct Path *path;
} CurveCache;
@@ -84,9 +85,12 @@ void BKE_curve_texspace_get(struct Curve *cu, float r_loc[3], float r_rot[3], fl
bool BKE_curve_minmax(struct Curve *cu, bool use_radius, float min[3], float max[3]);
bool BKE_curve_center_median(struct Curve *cu, float cent[3]);
bool BKE_curve_center_bounds(struct Curve *cu, float cent[3]);
+void BKE_curve_transform_ex(struct Curve *cu, float mat[4][4], bool do_keys, const float unit_scale);
+void BKE_curve_transform(struct Curve *cu, float mat[4][4], bool do_keys);
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);
ListBase *BKE_curve_nurbs_get(struct Curve *cu);
@@ -110,6 +114,7 @@ struct ListBase *BKE_curve_editNurbs_get(struct Curve *cu);
float *BKE_curve_make_orco(struct Scene *scene, struct Object *ob, int *r_numVerts);
float *BKE_curve_surf_make_orco(struct Object *ob);
+void BKE_curve_bevelList_free(struct ListBase *bev);
void BKE_curve_bevelList_make(struct Object *ob, struct ListBase *nurbs, bool for_render);
void BKE_curve_bevel_make(struct Scene *scene, struct Object *ob, struct ListBase *disp,
const bool for_render, const bool use_render_resolution);
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index 12a6be3e328..51c78948c70 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -81,29 +81,29 @@ void customData_mask_layers__print(CustomDataMask mask);
* Checks if the layer at physical offset \a layer_n (in data->layers) support math
* the below operations.
*/
-bool CustomData_layer_has_math(struct CustomData *data, int layer_n);
-bool CustomData_layer_has_interp(struct CustomData *data, int layer_n);
+bool CustomData_layer_has_math(const struct CustomData *data, int layer_n);
+bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n);
/**
* Checks if any of the customdata layers has math.
*/
-bool CustomData_has_math(struct CustomData *data);
-bool CustomData_has_interp(struct CustomData *data);
-bool CustomData_bmesh_has_free(struct CustomData *data);
+bool CustomData_has_math(const struct CustomData *data);
+bool CustomData_has_interp(const struct CustomData *data);
+bool CustomData_bmesh_has_free(const struct CustomData *data);
/* copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
* another, while not overwriting anything else (e.g. flags). probably only
* implemented for mloopuv/mloopcol, for now.*/
-void CustomData_data_copy_value(int type, void *source, void *dest);
+void CustomData_data_copy_value(int type, const void *source, void *dest);
/* compares if data1 is equal to data2. type is a valid CustomData type
* enum (e.g. CD_MLOOPUV). the layer type's equal function is used to compare
* the data, if it exists, otherwise memcmp is used.*/
-bool CustomData_data_equals(int type, void *data1, void *data2);
+bool CustomData_data_equals(int type, const void *data1, const void *data2);
void CustomData_data_initminmax(int type, void *min, void *max);
-void CustomData_data_dominmax(int type, void *data, void *min, void *max);
+void CustomData_data_dominmax(int type, const void *data, void *min, void *max);
void CustomData_data_multiply(int type, void *data, float fac);
-void CustomData_data_add(int type, void *data1, void *data2);
+void CustomData_data_add(int type, void *data1, const void *data2);
/* initializes a CustomData object with the same layer setup as source.
* mask is a bitfield where (mask & (1 << (layer type))) indicates
@@ -310,7 +310,7 @@ void CustomData_set_layer_flag(struct CustomData *data, int type, int flag);
void CustomData_bmesh_set_default(struct CustomData *data, void **block);
void CustomData_bmesh_free_block(struct CustomData *data, void **block);
-void CustomData_bmesh_free_block_data(struct CustomData *data, void **block);
+void CustomData_bmesh_free_block_data(struct CustomData *data, void *block);
/* copy custom data to/from layers as in mesh/derivedmesh, to editmesh
* blocks of data. the CustomData's must not be compatible */
@@ -327,6 +327,7 @@ int CustomData_sizeof(int type);
/* get the name of a layer type */
const char *CustomData_layertype_name(int type);
bool CustomData_layertype_is_singleton(int type);
+int CustomData_layertype_layers_max(const int type);
/* make sure the name of layer at index is unique */
void CustomData_set_layer_unique_name(struct CustomData *data, int index);
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
index 58903b76a15..27cf19d7d06 100644
--- a/source/blender/blenkernel/BKE_depsgraph.h
+++ b/source/blender/blenkernel/BKE_depsgraph.h
@@ -56,10 +56,15 @@ struct ListBase;
* which is needed for it's evaluation,
*/
typedef struct EvaluationContext {
- bool for_render; /* Set to true if evaluation shall be performed for render purposes,
- keep at false if update shall happen for the viewport. */
+ int mode; /* evaluation mode */
} EvaluationContext;
+typedef enum eEvaluationMode {
+ DAG_EVAL_VIEWPORT = 0, /* evaluate for OpenGL viewport */
+ DAG_EVAL_PREVIEW = 1, /* evaluate for render with preview settings */
+ DAG_EVAL_RENDER = 2, /* evaluate for render purposes */
+} eEvaluationMode;
+
/* DagNode->eval_flags */
enum {
/* Regardless to curve->path animation flag path is to be evaluated anyway,
diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h
index face19adc1e..0afc457f2b5 100644
--- a/source/blender/blenkernel/BKE_displist.h
+++ b/source/blender/blenkernel/BKE_displist.h
@@ -72,7 +72,6 @@ typedef struct DispList {
short col, rt; /* rt used by initrenderNurbs */
float *verts, *nors;
int *index;
- unsigned int *col1, *col2;
int charidx;
int totindex; /* indexed array drawing surfaces */
diff --git a/source/blender/blenkernel/BKE_editmesh_bvh.h b/source/blender/blenkernel/BKE_editmesh_bvh.h
index 355e817f621..168f700d132 100644
--- a/source/blender/blenkernel/BKE_editmesh_bvh.h
+++ b/source/blender/blenkernel/BKE_editmesh_bvh.h
@@ -43,9 +43,16 @@ struct Scene;
typedef struct BMBVHTree BMBVHTree;
-BMBVHTree *BKE_bmbvh_new_from_editmesh(struct BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free);
-BMBVHTree *BKE_bmbvh_new(struct BMesh *bm, struct BMLoop *(*looptris)[3], int looptris_tot, int flag,
- const float (*cos_cage)[3], const bool cos_cage_free);
+BMBVHTree *BKE_bmbvh_new_from_editmesh(
+ struct BMEditMesh *em, int flag,
+ const float (*cos_cage)[3], const bool cos_cage_free);
+BMBVHTree *BKE_bmbvh_new_ex(
+ struct BMesh *bm, struct BMLoop *(*looptris)[3], int looptris_tot, int flag,
+ const float (*cos_cage)[3], const bool cos_cage_free,
+ bool (*test_fn)(struct BMFace *, void *user_data), void *user_data);
+BMBVHTree *BKE_bmbvh_new(
+ struct BMesh *bm, struct BMLoop *(*looptris)[3], int looptris_tot, int flag,
+ const float (*cos_cage)[3], const bool cos_cage_free);
void BKE_bmbvh_free(BMBVHTree *tree);
struct BVHTree *BKE_bmbvh_tree_get(BMBVHTree *tree);
struct BMFace *BKE_bmbvh_ray_cast(BMBVHTree *tree, const float co[3], const float dir[3], const float radius,
diff --git a/source/blender/blenkernel/BKE_fcurve.h b/source/blender/blenkernel/BKE_fcurve.h
index 0e86be9b97c..c377769b271 100644
--- a/source/blender/blenkernel/BKE_fcurve.h
+++ b/source/blender/blenkernel/BKE_fcurve.h
@@ -43,6 +43,7 @@ struct DriverVar;
struct DriverTarget;
struct FCM_EnvelopeData;
+struct bContext;
struct bAction;
struct BezTriple;
struct StructRNA;
@@ -221,8 +222,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 */
-struct FCurve *rna_get_fcurve(struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex, struct bAction **action, bool *r_driven);
+/* find an f-curve based on an rna property. */
+struct FCurve *rna_get_fcurve(struct PointerRNA *ptr, struct PropertyRNA *prop, int rnaindex,
+ struct bAction **action, bool *r_driven);
+/* 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 bAction **action, bool *r_driven);
/* 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_font.h b/source/blender/blenkernel/BKE_font.h
index b60c833c686..e12ce3df476 100644
--- a/source/blender/blenkernel/BKE_font.h
+++ b/source/blender/blenkernel/BKE_font.h
@@ -93,6 +93,7 @@ bool BKE_vfont_to_curve_nubase(struct Main *bmain, struct Object *ob, int mode,
bool BKE_vfont_to_curve(struct Main *bmain, struct Object *ob, int mode);
int BKE_vfont_select_get(struct Object *ob, int *r_start, int *r_end);
+void BKE_vfont_select_clamp(struct Object *ob);
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/BKE_freestyle.h b/source/blender/blenkernel/BKE_freestyle.h
index a3fcdd667e8..bb909e4aa9d 100644
--- a/source/blender/blenkernel/BKE_freestyle.h
+++ b/source/blender/blenkernel/BKE_freestyle.h
@@ -39,20 +39,23 @@ extern "C" {
#endif
struct FreestyleConfig;
-struct FreestyleSettings;
struct FreestyleLineSet;
struct FreestyleModuleConfig;
+/* RNA aliases */
+typedef struct FreestyleSettings FreestyleSettings;
+typedef struct FreestyleModuleSettings FreestyleModuleSettings;
+
/* FreestyleConfig */
void BKE_freestyle_config_init(FreestyleConfig *config);
void BKE_freestyle_config_free(FreestyleConfig *config);
void BKE_freestyle_config_copy(FreestyleConfig *new_config, FreestyleConfig *config);
/* FreestyleConfig.modules */
-void BKE_freestyle_module_add(FreestyleConfig *config);
-void BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
-void BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
-void BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
+FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config);
+bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
+bool BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
+bool BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf);
/* FreestyleConfig.linesets */
FreestyleLineSet *BKE_freestyle_lineset_add(FreestyleConfig *config, const char *name);
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 3cf944fa236..2ab3d84dea5 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -121,13 +121,29 @@ void IDP_ClearProperty(IDProperty *prop);
void IDP_UnlinkProperty(struct IDProperty *prop);
#define IDP_Int(prop) ((prop)->data.val)
-#define IDP_Float(prop) (*(float *)&(prop)->data.val)
-#define IDP_Double(prop) (*(double *)&(prop)->data.val)
-#define IDP_String(prop) ((char *) (prop)->data.pointer)
#define IDP_Array(prop) ((prop)->data.pointer)
-#define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer)
+/* C11 const correctness for casts */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# define IDP_Float(prop) _Generic((prop), \
+ IDProperty *: (*(float *)&(prop)->data.val), \
+ const IDProperty *: (*(const float *)&(prop)->data.val))
+# define IDP_Double(prop) _Generic((prop), \
+ IDProperty *: (*(double *)&(prop)->data.val), \
+ const IDProperty *: (*(const double *)&(prop)->data.val))
+# define IDP_String(prop) _Generic((prop), \
+ IDProperty *: ((char *) (prop)->data.pointer), \
+ const IDProperty *: ((const char *) (prop)->data.pointer))
+# define IDP_IDPArray(prop) _Generic((prop), \
+ IDProperty *: ((IDProperty *) (prop)->data.pointer), \
+ const IDProperty *: ((const IDProperty *) (prop)->data.pointer))
+#else
+# define IDP_Float(prop) (*(float *)&(prop)->data.val)
+# define IDP_Double(prop) (*(double *)&(prop)->data.val)
+# define IDP_String(prop) ((char *) (prop)->data.pointer)
+# define IDP_IDPArray(prop) ((IDProperty *) (prop)->data.pointer)
+#endif
-#ifdef DEBUG
+#ifndef NDEBUG
/* for printout only */
void IDP_spit(IDProperty *prop);
#endif
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index db052f5d879..dc3d9f38b21 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -52,8 +52,9 @@ struct Main;
void BKE_images_init(void);
void BKE_images_exit(void);
+void BKE_image_free_buffers(struct Image *image);
/* call from library */
-void BKE_image_free(struct Image *me);
+void BKE_image_free(struct Image *image);
void BKE_imbuf_stamp_info(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf);
void BKE_stamp_buf(struct Scene *scene, struct Object *camera, unsigned char *rect, float *rectf, int width, int height, int channels);
diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h
index 6183df8666d..892c42b4588 100644
--- a/source/blender/blenkernel/BKE_key.h
+++ b/source/blender/blenkernel/BKE_key.h
@@ -97,6 +97,10 @@ float (*BKE_key_convert_to_vertcos(struct Object *ob, struct KeyBlock *kb))[3];
void BKE_key_convert_from_vertcos(struct Object *ob, struct KeyBlock *kb, float (*vertCos)[3]);
void BKE_key_convert_from_offset(struct Object *ob, struct KeyBlock *kb, float (*ofs)[3]);
+/* other management */
+bool BKE_keyblock_move(struct Object *ob, int org_index, int new_index);
+
+
/* key.c */
extern int slurph_opt;
diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h
index 8d8d3702634..5fb1053b53f 100644
--- a/source/blender/blenkernel/BKE_lattice.h
+++ b/source/blender/blenkernel/BKE_lattice.h
@@ -84,6 +84,7 @@ void BKE_lattice_minmax(struct Lattice *lt, float min[3], float max[3]);
void BKE_lattice_center_median(struct Lattice *lt, float cent[3]);
void BKE_lattice_center_bounds(struct Lattice *lt, float cent[3]);
void BKE_lattice_translate(struct Lattice *lt, float offset[3], bool do_keys);
+void BKE_lattice_transform(struct Lattice *lt, float mat[4][4], bool do_keys);
int BKE_lattice_index_from_uvw(struct Lattice *lt, const int u, const int v, const int w);
void BKE_lattice_index_to_uvw(struct Lattice *lt, const int index, int *r_u, int *r_v, int *r_w);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 55c71ff49cf..500c2813a75 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -71,19 +71,22 @@ void id_clear_lib_data(struct Main *bmain, struct ID *id);
struct ListBase *which_libbase(struct Main *mainlib, short type);
-#define MAX_LIBARRAY 41
-int set_listbasepointers(struct Main *main, struct ListBase **lb);
+#define MAX_LIBARRAY 35
+int set_listbasepointers(struct Main *main, struct ListBase *lb[MAX_LIBARRAY]);
void BKE_libblock_free(struct Main *bmain, void *idv);
void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user);
void BKE_libblock_free_us(struct Main *bmain, void *idv);
-void BKE_libblock_free_data(struct ID *id);
+void BKE_libblock_free_data(struct Main *bmain, struct ID *id);
/* Main API */
struct Main *BKE_main_new(void);
void BKE_main_free(struct Main *mainvar);
+void BKE_main_lock(struct Main *bmain);
+void BKE_main_unlock(struct Main *bmain);
+
void BKE_main_id_tag_idcode(struct Main *mainvar, const short type, const bool tag);
void BKE_main_id_tag_listbase(struct ListBase *lb, const bool tag);
void BKE_main_id_tag_all(struct Main *mainvar, const bool tag);
@@ -101,6 +104,7 @@ void test_idbutton(char *name);
void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagged_only);
+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 *) );
diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h
index 13d111cb93b..ae10ba4caab 100644
--- a/source/blender/blenkernel/BKE_linestyle.h
+++ b/source/blender/blenkernel/BKE_linestyle.h
@@ -35,6 +35,10 @@
#include "DNA_linestyle_types.h"
+#ifdef __cplusplus
+extern "C" {
+#endif
+
#define LS_MODIFIER_TYPE_COLOR 1
#define LS_MODIFIER_TYPE_ALPHA 2
#define LS_MODIFIER_TYPE_THICKNESS 3
@@ -43,34 +47,45 @@
struct Main;
struct Object;
struct ColorBand;
+struct bContext;
+
+FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main);
+void BKE_linestyle_free(FreestyleLineStyle *linestyle);
+FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle);
+
+FreestyleLineStyle *BKE_linestyle_active_from_scene(struct Scene *scene);
+
+LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
+LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
+LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
+LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type);
+
+LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-FreestyleLineStyle *BKE_new_linestyle(const char *name, struct Main *main);
-void BKE_free_linestyle(FreestyleLineStyle *linestyle);
-FreestyleLineStyle *BKE_copy_linestyle(FreestyleLineStyle *linestyle);
+int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
+int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
+int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
+int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
-LineStyleModifier *BKE_add_linestyle_color_modifier(FreestyleLineStyle *linestyle, int type);
-LineStyleModifier *BKE_add_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, int type);
-LineStyleModifier *BKE_add_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, int type);
-LineStyleModifier *BKE_add_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, int type);
+void BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+void BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+void BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-LineStyleModifier *BKE_copy_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-LineStyleModifier *BKE_copy_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-LineStyleModifier *BKE_copy_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m);
-LineStyleModifier *BKE_copy_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m);
+void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase);
+char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp);
-void BKE_remove_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
-void BKE_remove_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
-void BKE_remove_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
-void BKE_remove_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier);
+void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob);
-void BKE_move_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-void BKE_move_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-void BKE_move_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
-void BKE_move_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction);
+bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes);
-void BKE_list_modifier_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase);
-char *BKE_path_from_ID_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp);
+void BKE_linestyle_default_shader(const struct bContext *C, FreestyleLineStyle *linestyle);
-void BKE_unlink_linestyle_target_object(FreestyleLineStyle *linestyle, struct Object *ob);
+#ifdef __cplusplus
+}
+#endif
#endif /* __BKE_LINESTYLE_H__ */
diff --git a/source/blender/blenkernel/BKE_main.h b/source/blender/blenkernel/BKE_main.h
index 721866daff5..ec654ea4b71 100644
--- a/source/blender/blenkernel/BKE_main.h
+++ b/source/blender/blenkernel/BKE_main.h
@@ -48,6 +48,7 @@ extern "C" {
struct EvaluationContext;
struct Library;
+struct MainLock;
typedef struct Main {
struct Main *next, *prev;
@@ -86,6 +87,8 @@ typedef struct Main {
ListBase nodetree;
ListBase brush;
ListBase particle;
+ ListBase palettes;
+ ListBase paintcurves;
ListBase wm;
ListBase gpencil;
ListBase movieclip;
@@ -96,6 +99,8 @@ typedef struct Main {
/* Evaluation context used by viewport */
struct EvaluationContext *eval_ctx;
+
+ struct MainLock *lock;
} Main;
#define MAIN_VERSION_ATLEAST(main, ver, subver) \
diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h
index 89d310753fc..2f20505bea3 100644
--- a/source/blender/blenkernel/BKE_material.h
+++ b/source/blender/blenkernel/BKE_material.h
@@ -86,6 +86,9 @@ short find_material_index(struct Object *ob, struct Material *ma);
bool object_add_material_slot(struct Object *ob);
bool object_remove_material_slot(struct Object *ob);
+void BKE_texpaint_slot_refresh_cache(struct Scene *scene, struct Material *ma);
+void BKE_texpaint_slots_refresh_object(struct Scene *scene, struct Object *ob);
+
/* rna api */
void BKE_material_resize_id(struct ID *id, short totcol, bool do_id_user);
void BKE_material_append_id(struct ID *id, struct Material *ma);
diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h
index 56ea44fa6e9..c021960e730 100644
--- a/source/blender/blenkernel/BKE_mball.h
+++ b/source/blender/blenkernel/BKE_mball.h
@@ -63,6 +63,7 @@ bool BKE_mball_minmax_ex(struct MetaBall *mb, float min[3], float max[3],
float obmat[4][4], const short flag);
bool BKE_mball_center_median(struct MetaBall *mb, float r_cent[3]);
bool BKE_mball_center_bounds(struct MetaBall *mb, float r_cent[3]);
+void BKE_mball_transform(struct MetaBall *mb, float mat[4][4]);
void BKE_mball_translate(struct MetaBall *mb, const float offset[3]);
struct MetaElem *BKE_mball_element_add(struct MetaBall *mb, const int type);
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index 587dea5095c..b2b9e37f500 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -133,6 +133,7 @@ struct Mesh *BKE_mesh_new_from_object(struct Main *bmain, struct Scene *sce, str
/* vertex level transformations & checks (no derived mesh) */
bool BKE_mesh_minmax(struct Mesh *me, float r_min[3], float r_max[3]);
+void BKE_mesh_transform(struct Mesh *me, float mat[4][4], bool do_keys);
void BKE_mesh_translate(struct Mesh *me, const float offset[3], const bool do_keys);
void BKE_mesh_ensure_navmesh(struct Mesh *me);
@@ -212,6 +213,10 @@ bool BKE_mesh_center_median(struct Mesh *me, float cent[3]);
bool BKE_mesh_center_bounds(struct Mesh *me, float cent[3]);
bool BKE_mesh_center_centroid(struct Mesh *me, float cent[3]);
+void BKE_mesh_calc_volume(struct MVert *mverts, int numVerts,
+ struct MFace *mfaces, int numFaces,
+ float *r_vol, float *r_com);
+
/* tessface */
void BKE_mesh_loops_to_mface_corners(
struct CustomData *fdata, struct CustomData *ldata,
@@ -283,6 +288,7 @@ void BKE_mesh_calc_relative_deform(
int BKE_mesh_validate(struct Mesh *me, const int do_verbose);
void BKE_mesh_cd_validate(struct Mesh *me);
+int BKE_mesh_validate_material_indices(struct Mesh *me);
bool BKE_mesh_validate_arrays(
struct Mesh *me,
diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h
index f3f6b556a07..ed7e506941c 100644
--- a/source/blender/blenkernel/BKE_mesh_mapping.h
+++ b/source/blender/blenkernel/BKE_mesh_mapping.h
@@ -131,7 +131,8 @@ int *BKE_mesh_calc_smoothgroups(
/* No good (portable) way to have exported inlined functions... */
#define BKE_MESH_TESSFACE_VINDEX_ORDER(_mf, _v) ( \
- (CHECK_TYPE_INLINE(_mf, MFace *), CHECK_TYPE_INLINE(_v, unsigned int)), \
+ (CHECK_TYPE_INLINE(_mf, MFace *), \
+ CHECK_TYPE_INLINE(&(_v), unsigned int *)), \
((_mf->v1 == _v) ? 0 : \
(_mf->v2 == _v) ? 1 : \
(_mf->v3 == _v) ? 2 : \
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 3b2bafa799f..75616b9df78 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -111,7 +111,10 @@ typedef enum ModifierApplyFlag {
MOD_APPLY_RENDER = 1 << 0, /* Render time. */
MOD_APPLY_USECACHE = 1 << 1, /* Result of evaluation will be cached, so modifier might
* want to cache data for quick updates (used by subsurf) */
- MOD_APPLY_ORCO = 1 << 2 /* Modifier evaluated for undeformed texture coordinates */
+ MOD_APPLY_ORCO = 1 << 2, /* Modifier evaluated for undeformed texture coordinates */
+ MOD_APPLY_IGNORE_SIMPLIFY = 1 << 3, /* Ignore scene simplification flag and use subdivisions
+ * level set in multires modifier.
+ */
} ModifierApplyFlag;
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h
index aa09fe1ce8d..11d81a149b1 100644
--- a/source/blender/blenkernel/BKE_multires.h
+++ b/source/blender/blenkernel/BKE_multires.h
@@ -65,7 +65,8 @@ void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, st
typedef enum {
MULTIRES_USE_LOCAL_MMD = 1,
MULTIRES_USE_RENDER_PARAMS = 2,
- MULTIRES_ALLOC_PAINT_MASK = 4
+ MULTIRES_ALLOC_PAINT_MASK = 4,
+ MULTIRES_IGNORE_SIMPLIFY = 8
} MultiresFlags;
struct DerivedMesh *multires_make_derived_from_derived(struct DerivedMesh *dm,
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 13a32ee1528..cb96538ad81 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -342,7 +342,7 @@ struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char
/* copy/free funcs, need to manage ID users */
void ntreeFreeTree_ex(struct bNodeTree *ntree, const bool do_id_user);
void ntreeFreeTree(struct bNodeTree *ntree);
-struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, const bool do_id_user);
+struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user);
struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree);
void ntreeSwitchID_ex(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to, const bool do_id_user);
void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to);
@@ -585,6 +585,9 @@ void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufu
void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *));
void node_type_compatibility(struct bNodeType *ntype, short compatibility);
+/* ************** GENERIC NODE FUNCTIONS *************** */
+bool BKE_node_is_connected_to_output(struct bNodeTree *ntree, struct bNode *node);
+
/* ************** COMMON NODES *************** */
#define NODE_UNDEFINED -2 /* node type is not registered */
@@ -727,7 +730,7 @@ struct ShadeResult;
#define SH_NODE_BRIGHTCONTRAST 165
#define SH_NODE_LIGHT_FALLOFF 166
#define SH_NODE_OBJECT_INFO 167
-#define SH_NODE_PARTICLE_INFO 168
+#define SH_NODE_PARTICLE_INFO 168
#define SH_NODE_TEX_BRICK 169
#define SH_NODE_BUMP 170
#define SH_NODE_SCRIPT 171
@@ -746,7 +749,11 @@ struct ShadeResult;
#define SH_NODE_COMBHSV 184
#define SH_NODE_BSDF_HAIR 185
#define SH_NODE_LAMP 186
-#define SH_NODE_UVMAP 187
+#define SH_NODE_UVMAP 187
+#define SH_NODE_SEPXYZ 188
+#define SH_NODE_COMBXYZ 189
+#define SH_NODE_OUTPUT_LINESTYLE 190
+#define SH_NODE_UVALONGSTROKE 191
/* custom defines options for Material node */
#define SH_NODE_MAT_DIFF 1
@@ -889,6 +896,7 @@ void ntreeGPUMaterialNodes(struct bNodeTree *ntree, struct GPUMateria
#define CMP_NODE_GLARE 301
#define CMP_NODE_TONEMAP 302
#define CMP_NODE_LENSDIST 303
+#define CMP_NODE_SUNBEAMS 304
#define CMP_NODE_COLORCORRECTION 312
#define CMP_NODE_MASK_BOX 313
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index c0da816ca59..1bfd26d4f8c 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -103,6 +103,8 @@ void BKE_object_make_local(struct Object *ob);
bool BKE_object_is_libdata(struct Object *ob);
bool BKE_object_obdata_is_libdata(struct Object *ob);
+void BKE_object_obdata_size_init(struct Object *ob, const float scale);
+
void BKE_object_scale_to_mat3(struct Object *ob, float mat[3][3]);
void BKE_object_rot_to_mat3(struct Object *ob, float mat[3][3], bool use_drot);
void BKE_object_mat3_to_rot(struct Object *ob, float mat[3][3], bool use_compat);
@@ -124,14 +126,18 @@ void BKE_object_where_is_calc_mat4(struct Scene *scene, struct Object *ob, float
/* possibly belong in own moduke? */
struct BoundBox *BKE_boundbox_alloc_unit(void);
void BKE_boundbox_init_from_minmax(struct BoundBox *bb, const float min[3], const float max[3]);
-bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], const float ray_normal[3],
- float *r_lambda);
+bool BKE_boundbox_ray_hit_check(
+ const struct BoundBox *bb,
+ const float ray_start[3], const float ray_normal[3],
+ float *r_lambda);
+void BKE_boundbox_calc_center_aabb(const struct BoundBox *bb, float r_cent[3]);
+void BKE_boundbox_calc_size_aabb(const struct BoundBox *bb, float r_size[3]);
struct BoundBox *BKE_object_boundbox_get(struct Object *ob);
void BKE_object_dimensions_get(struct Object *ob, float vec[3]);
void BKE_object_dimensions_set(struct Object *ob, const float value[3]);
void BKE_object_empty_draw_type_set(struct Object *ob, const int value);
-void BKE_object_boundbox_flag(struct Object *ob, int flag, int set);
+void BKE_object_boundbox_flag(struct Object *ob, int flag, const bool set);
void BKE_object_minmax(struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
bool BKE_object_minmax_dupli(struct Scene *scene, struct Object *ob, float r_min[3], float r_max[3], const bool use_hidden);
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index 0061280684f..b080ca37e67 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -40,18 +40,24 @@ struct CurveMapping;
struct MDisps;
struct MeshElemMap;
struct GridPaintMask;
+struct Main;
struct MFace;
struct MultireModifierData;
struct MVert;
struct Object;
struct Paint;
+struct PaintCurve;
+struct Palette;
+struct PaletteColor;
struct PBVH;
+struct ReportList;
struct Scene;
struct Sculpt;
struct StrokeCache;
struct Tex;
struct ImagePool;
struct UnifiedPaintSettings;
+struct wmOperator;
enum OverlayFlags;
@@ -91,6 +97,18 @@ OverlayControlFlags BKE_paint_get_overlay_flags(void);
void BKE_paint_reset_overlay_invalid(OverlayControlFlags flag);
void BKE_paint_set_overlay_override(enum OverlayFlags flag);
+/* palettes */
+void BKE_palette_free(struct Palette *palette);
+struct Palette *BKE_palette_add(struct Main *bmain, const char *name);
+struct 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);
+
+/* paint curves */
+struct PaintCurve *BKE_paint_curve_add(struct Main *bmain, const char *name);
+void BKE_paint_curve_free(struct PaintCurve *pc);
+
void BKE_paint_init(struct Paint *p, const char col[3]);
void BKE_paint_free(struct Paint *p);
void BKE_paint_copy(struct Paint *src, struct Paint *tar);
@@ -100,6 +118,12 @@ struct Paint *BKE_paint_get_active_from_context(const struct bContext *C);
PaintMode BKE_paintmode_get_active_from_context(const struct bContext *C);
struct Brush *BKE_paint_brush(struct Paint *paint);
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_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);
/* testing face select mode
* Texture paint could be removed since selected faces are not used
@@ -117,7 +141,10 @@ bool paint_is_bmesh_face_hidden(struct BMFace *f);
/* paint masks */
float paint_grid_paint_mask(const struct GridPaintMask *gpm, unsigned level,
unsigned x, unsigned y);
+
+/* stroke related */
void paint_calculate_rake_rotation(struct UnifiedPaintSettings *ups, const float mouse_pos[2]);
+
/* Session data (mode-specific) */
typedef struct SculptSession {
@@ -146,7 +173,7 @@ typedef struct SculptSession {
struct PBVH *pbvh;
bool show_diffuse_color;
- /* Paiting on deformed mesh */
+ /* Painting on deformed mesh */
bool modifiers_active; /* object is deformed with some modifiers */
float (*orig_cos)[3]; /* coords of undeformed mesh */
float (*deform_cos)[3]; /* coords of deformed mesh but without stroke displacement */
@@ -178,10 +205,10 @@ void BKE_free_sculptsession_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,
- bool need_pmap, bool need_mask);
+ bool need_pmap, bool need_mask);
struct MultiresModifierData *BKE_sculpt_multires_active(struct Scene *scene, struct Object *ob);
int BKE_sculpt_mask_layers_ensure(struct Object *ob,
- struct MultiresModifierData *mmd);
+ struct MultiresModifierData *mmd);
enum {
SCULPT_MASK_LAYER_CALC_VERT = (1 << 0),
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index 6b8e50494c7..f84a6378fb3 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -403,7 +403,7 @@ void psys_particle_on_dm(struct DerivedMesh *dm, int from, int index, int index_
float orco[3], float ornor[3]);
/* particle_system.c */
-void initialize_particle(struct ParticleData *pa);
+void initialize_particle(struct ParticleSimulationData *sim, struct ParticleData *pa);
void psys_calc_dmcache(struct Object *ob, struct DerivedMesh *dm, struct ParticleSystem *psys);
int psys_particle_dm_face_lookup(struct Object *ob, struct DerivedMesh *dm, int index, const float fw[4], struct LinkNode *node);
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 619b1afe765..c8c693fc342 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -89,9 +89,10 @@ void BKE_pbvh_search_gather(PBVH *bvh,
* it's up to the callback to find the primitive within the leaves that is
* hit first */
-void BKE_pbvh_raycast(PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data,
- const float ray_start[3], const float ray_normal[3],
- int original);
+void BKE_pbvh_raycast(
+ PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data,
+ const float ray_start[3], const float ray_normal[3],
+ bool original);
bool BKE_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco,
const float ray_start[3], const float ray_normal[3],
@@ -166,6 +167,7 @@ typedef enum {
void BKE_pbvh_node_mark_update(PBVHNode *node);
void BKE_pbvh_node_mark_rebuild_draw(PBVHNode *node);
void BKE_pbvh_node_mark_redraw(PBVHNode *node);
+void BKE_pbvh_node_mark_normals_update(PBVHNode *node);
void BKE_pbvh_node_mark_topology_update(PBVHNode *node);
void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden);
@@ -293,7 +295,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
vi.mask = vi.key->has_mask ? CCG_elem_mask(vi.key, vi.grid) : NULL; \
vi.grid = CCG_elem_next(vi.key, vi.grid); \
if (vi.gh) { \
- if (BLI_BITMAP_GET(vi.gh, vi.gy * vi.gridsize + vi.gx)) \
+ if (BLI_BITMAP_TEST(vi.gh, vi.gy * vi.gridsize + vi.gx)) \
continue; \
} \
} \
diff --git a/source/blender/blenkernel/BKE_rigidbody.h b/source/blender/blenkernel/BKE_rigidbody.h
index 86be3bfe770..c946f3ac9e8 100644
--- a/source/blender/blenkernel/BKE_rigidbody.h
+++ b/source/blender/blenkernel/BKE_rigidbody.h
@@ -69,6 +69,9 @@ void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw);
/* 'validate' (i.e. make new or replace old) Physics-Engine objects */
void BKE_rigidbody_validate_sim_world(struct Scene *scene, struct RigidBodyWorld *rbw, bool rebuild);
+void BKE_rigidbody_calc_volume(struct Object *ob, float *r_vol);
+void BKE_rigidbody_calc_center_of_mass(struct Object *ob, float r_com[3]);
+
/* -------------- */
/* Utilities */
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index a10a3f3f59f..1bfe0eeea0b 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -48,6 +48,7 @@ struct RenderData;
struct SceneRenderLayer;
struct Scene;
struct Text;
+struct UnitSettings;
struct Main;
#define SCE_COPY_NEW 0
@@ -84,6 +85,7 @@ typedef struct SceneBaseIter {
struct ListBase *duplilist;
struct DupliObject *dupob;
float omat[4][4];
+ struct Object *dupli_refob;
int phase;
} SceneBaseIter;
@@ -129,6 +131,7 @@ int get_render_shadow_samples(struct RenderData *r, int samples);
float get_render_aosss_error(struct RenderData *r, float error);
bool BKE_scene_use_new_shading_nodes(struct Scene *scene);
+bool BKE_scene_uses_blender_internal(struct Scene *scene);
void BKE_scene_disable_color_management(struct Scene *scene);
bool BKE_scene_check_color_management_enabled(const struct Scene *scene);
@@ -137,6 +140,8 @@ bool BKE_scene_check_rigidbody_active(const struct Scene *scene);
int BKE_scene_num_threads(const struct Scene *scene);
int BKE_render_num_threads(const struct RenderData *r);
+double BKE_scene_unit_scale(const struct UnitSettings *unit, const int unit_type, double value);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 4cbd7e966f2..188b8e22815 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -53,6 +53,8 @@ struct wmNotifier;
struct wmWindow;
struct wmWindowManager;
+#include "BLI_compiler_attrs.h"
+
#include "RNA_types.h"
/* spacetype has everything stored to get an editor working, it gets initialized via
@@ -280,6 +282,11 @@ struct ARegion *BKE_area_find_region_type(struct ScrArea *sa, int type);
struct ARegion *BKE_area_find_region_active_win(struct ScrArea *sa);
struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min);
+unsigned int BKE_screen_view3d_layer_active_ex(
+ const struct View3D *v3d, const struct Scene *scene, bool use_localvd) ATTR_NONNULL(2);
+unsigned int BKE_screen_view3d_layer_active(
+ const struct View3D *v3d, const struct Scene *scene) ATTR_NONNULL(2);
+
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 17193bbefbf..bbc4fd05256 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -217,6 +217,10 @@ void BKE_sequence_clipboard_pointers_free(struct Sequence *seq);
void BKE_sequence_clipboard_pointers_store(struct Sequence *seq);
void BKE_sequence_clipboard_pointers_restore(struct Sequence *seq, struct Main *bmain);
+void BKE_sequencer_base_clipboard_pointers_free(struct ListBase *seqbase);
+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);
const char *BKE_sequence_give_name(struct Sequence *seq);
void BKE_sequence_calc(struct Scene *scene, struct Sequence *seq);
@@ -308,7 +312,7 @@ void BKE_sequencer_offset_animdata(struct Scene *scene, struct Sequence *seq, in
void BKE_sequencer_dupe_animdata(struct Scene *scene, const char *name_src, const char *name_dst);
bool BKE_sequence_base_shuffle(struct ListBase *seqbasep, struct Sequence *test, struct Scene *evil_scene);
bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, struct Scene *evil_scene);
-bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase);
+bool BKE_sequence_base_isolated_sel_check(struct ListBase *seqbase, bool one_only);
void BKE_sequencer_free_imbuf(struct Scene *scene, struct ListBase *seqbasep, bool for_render);
struct Sequence *BKE_sequence_dupli_recursive(struct Scene *scene, struct Scene *scene_to, struct Sequence *seq, int dupe_flag);
int BKE_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str);
@@ -326,7 +330,9 @@ void BKE_sequencer_update_sound(struct Scene *scene, struct bSound *sound);
void BKE_sequencer_refresh_sound_length(struct Scene *scene);
void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, struct Sequence *seq);
-void BKE_sequence_base_dupli_recursive(struct Scene *scene, struct Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, int dupe_flag);
+void BKE_sequence_base_dupli_recursive(
+ struct Scene *scene, struct Scene *scene_to, ListBase *nseqbase, ListBase *seqbase,
+ int dupe_flag);
bool BKE_sequence_is_valid_check(struct Sequence *seq);
void BKE_sequencer_clear_scene_in_allseqs(struct Main *bmain, struct Scene *sce);
@@ -340,11 +346,14 @@ typedef struct SeqLoadInfo {
int channel;
int flag; /* use sound, replace sel */
int type;
- int tot_success;
- int tot_error;
int len; /* only for image strips */
char path[1024]; /* 1024 = FILE_MAX */
+
+ /* return values */
char name[64];
+ struct Sequence *seq_sound; /* for movie's */
+ int tot_success;
+ int tot_error;
} SeqLoadInfo;
/* SeqLoadInfo.flag */
diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h
index 59de43af907..070cd4a9cf0 100644
--- a/source/blender/blenkernel/BKE_shrinkwrap.h
+++ b/source/blender/blenkernel/BKE_shrinkwrap.h
@@ -31,52 +31,6 @@
* \ingroup bke
*/
-/* mesh util */
-
-//TODO: move this somewhere else
-#include "BKE_customdata.h"
-struct DerivedMesh;
-struct Object;
-struct DerivedMesh *object_get_derived_final(struct Object *ob, bool for_render);
-
-
-/* SpaceTransform stuff */
-/*
- * TODO: move this somewhere else
- *
- * this structs encapsulates all needed data to convert between 2 coordinate spaces
- * (where conversion can be represented by a matrix multiplication)
- *
- * This is used to reduce the number of arguments to pass to functions that need to perform
- * this kind of operation and make it easier for the coder, as he/she doenst needs to recode
- * the matrix calculation.
- *
- * A SpaceTransform is initialized using:
- * SPACE_TRANSFORM_SETUP( &data, ob1, ob2 )
- *
- * After that the following calls can be used:
- * space_transform_apply (&data, co); //converts a coordinate in ob1 coords space to the corresponding ob2 coords
- * space_transform_invert(&data, co); //converts a coordinate in ob2 coords space to the corresponding ob1 coords
- *
- * //Same Concept as space_transform_apply and space_transform_invert, but no is normalized after conversion
- * space_transform_apply_normal (&data, &no);
- * space_transform_invert_normal(&data, &no);
- *
- */
-struct Object;
-
-typedef struct SpaceTransform {
- float local2target[4][4];
- float target2local[4][4];
-
-} SpaceTransform;
-
-void space_transform_from_matrixs(struct SpaceTransform *data, float local[4][4], float target[4][4]);
-void space_transform_apply(const struct SpaceTransform *data, float co[3]);
-void space_transform_invert(const struct SpaceTransform *data, float co[3]);
-
-#define SPACE_TRANSFORM_SETUP(data, local, target) space_transform_from_matrixs(data, (local)->obmat, (target)->obmat)
-
/* Shrinkwrap stuff */
#include "BKE_bvhutils.h"
@@ -100,6 +54,7 @@ struct MDeformVert;
struct ShrinkwrapModifierData;
struct MDeformVert;
struct BVHTree;
+struct SpaceTransform;
typedef struct ShrinkwrapCalcData {
@@ -115,7 +70,7 @@ typedef struct ShrinkwrapCalcData {
int vgroup; //Vertex group num
struct DerivedMesh *target; //mesh we are shrinking to
- SpaceTransform local2target; //transform to move between local and target space
+ struct SpaceTransform local2target; //transform to move between local and target space
float keepDist; //Distance to keep above target surface (units are in local space)
@@ -136,7 +91,7 @@ void shrinkwrapModifier_deform(struct ShrinkwrapModifierData *smd, struct Object
*/
bool BKE_shrinkwrap_project_normal(
char options, const float vert[3], const float dir[3],
- const SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit,
+ const struct SpaceTransform *transf, BVHTree *tree, BVHTreeRayHit *hit,
BVHTree_RayCastCallback callback, void *userdata);
/*
diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h
index 4f77e4f5a23..1e79eaa8431 100644
--- a/source/blender/blenkernel/BKE_text.h
+++ b/source/blender/blenkernel/BKE_text.h
@@ -85,6 +85,7 @@ void txt_delete_char (struct Text *text);
void txt_delete_word (struct Text *text);
void txt_delete_selected (struct Text *text);
void txt_sel_all (struct Text *text);
+void txt_sel_clear (struct Text *text);
void txt_sel_line (struct Text *text);
char *txt_sel_to_buf (struct Text *text);
void txt_insert_buf (struct Text *text, const char *in_buffer);
diff --git a/source/blender/blenkernel/BKE_tracking.h b/source/blender/blenkernel/BKE_tracking.h
index 6d155ba37de..8bc619c1b27 100644
--- a/source/blender/blenkernel/BKE_tracking.h
+++ b/source/blender/blenkernel/BKE_tracking.h
@@ -193,7 +193,8 @@ struct ImBuf *BKE_tracking_undistort_frame(struct MovieTracking *tracking, struc
struct ImBuf *BKE_tracking_distort_frame(struct MovieTracking *tracking, struct ImBuf *ibuf,
int calibration_width, int calibration_height, float overscan);
-void BKE_tracking_max_undistortion_delta_across_bound(struct MovieTracking *tracking, struct rcti *rect, float delta[2]);
+void BKE_tracking_max_distortion_delta_across_bound(struct MovieTracking *tracking, struct rcti *rect,
+ bool undistort, float delta[2]);
/* **** Image sampling **** */
struct ImBuf *BKE_tracking_sample_pattern(int frame_width, int frame_height,
diff --git a/source/blender/blenkernel/BKE_unit.h b/source/blender/blenkernel/BKE_unit.h
index 07aeceda474..b351bc6fe3e 100644
--- a/source/blender/blenkernel/BKE_unit.h
+++ b/source/blender/blenkernel/BKE_unit.h
@@ -37,7 +37,7 @@ extern "C" {
size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system, int type, bool split, bool pad);
/* replace units with values, used before python button evaluation */
-int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type);
+bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type);
/* make string keyboard-friendly: 10µm --> 10um */
void bUnit_ToUnitAltName(char *str, int len_max, const char *orig_str, int system, int type);
@@ -49,7 +49,7 @@ double bUnit_ClosestScalar(double value, int system, int type);
double bUnit_BaseScalar(int system, int type);
/* return true is the unit system exists */
-int bUnit_IsValid(int system, int type);
+bool bUnit_IsValid(int system, int type);
/* loop over scales, coudl add names later */
//double bUnit_Iter(void **unit, char **name, int system, int type);
@@ -61,17 +61,19 @@ const char *bUnit_GetNameDisplay(void *usys_pt, int index);
double bUnit_GetScaler(void *usys_pt, int index);
/* aligned with PropertyUnit */
-#define B_UNIT_NONE 0
-#define B_UNIT_LENGTH 1
-#define B_UNIT_AREA 2
-#define B_UNIT_VOLUME 3
-#define B_UNIT_MASS 4
-#define B_UNIT_ROTATION 5
-#define B_UNIT_TIME 6
-#define B_UNIT_VELOCITY 7
-#define B_UNIT_ACCELERATION 8
-#define B_UNIT_CAMERA 9
-#define B_UNIT_TYPE_TOT 10
+enum {
+ B_UNIT_NONE = 0,
+ B_UNIT_LENGTH = 1,
+ B_UNIT_AREA = 2,
+ B_UNIT_VOLUME = 3,
+ B_UNIT_MASS = 4,
+ B_UNIT_ROTATION = 5,
+ B_UNIT_TIME = 6,
+ B_UNIT_VELOCITY = 7,
+ B_UNIT_ACCELERATION = 8,
+ B_UNIT_CAMERA = 9,
+ B_UNIT_TYPE_TOT = 10,
+};
#ifdef __cplusplus
}
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 9696ab30eaa..6f42254a494 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -38,6 +38,7 @@ set(INC
../nodes
../render/extern/include
../../../intern/guardedalloc
+ ../../../intern/glew-mx
../../../intern/iksolver/extern
../../../intern/memutil
../../../intern/mikktspace
@@ -79,8 +80,8 @@ set(SRC
intern/colortools.c
intern/constraint.c
intern/context.c
- intern/crazyspace.c
- intern/curve.c
+ intern/crazyspace.c
+ intern/curve.c
intern/customdata.c
intern/customdata_file.c
intern/deform.c
@@ -193,7 +194,7 @@ set(SRC
BKE_colortools.h
BKE_constraint.h
BKE_context.h
- BKE_crazyspace.h
+ BKE_crazyspace.h
BKE_curve.h
BKE_customdata.h
BKE_customdata_file.h
@@ -273,7 +274,7 @@ set(SRC
intern/pbvh_intern.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_AUDASPACE)
list(APPEND INC
@@ -308,6 +309,10 @@ if(WITH_IMAGE_TIFF)
add_definitions(-DWITH_TIFF)
endif()
+if(WITH_OPENIMAGEIO)
+ add_definitions(-DWITH_OPENIMAGEIO)
+endif()
+
if(WITH_IMAGE_OPENJPEG)
add_definitions(-DWITH_OPENJPEG)
endif()
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index 7558409c8bb..1389cd0241c 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -45,7 +45,8 @@ incs = [
'#/intern/raskter',
'#/intern/rigidbody',
'#/extern/bullet2/src',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/audaspace/intern',
'#/intern/elbeem/extern',
'#/intern/iksolver/extern',
@@ -66,14 +67,11 @@ incs = [
'../nodes',
'../render/extern/include',
'../windowmanager',
- env['BF_OPENGL_INC'],
env['BF_ZLIB_INC'],
]
incs = ' '.join(incs)
-defs = [
- 'GLEW_STATIC',
- ]
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_SMOKE']:
defs.append('WITH_SMOKE')
diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c
index 6cda0a1bc33..623fb50b62c 100644
--- a/source/blender/blenkernel/intern/CCGSubSurf.c
+++ b/source/blender/blenkernel/intern/CCGSubSurf.c
@@ -119,7 +119,7 @@ static void _ehash_insert(EHash *eh, EHEntry *entry)
eh->buckets[hash] = entry;
eh->numEntries++;
- if (eh->numEntries > (numBuckets * 3)) {
+ if (UNLIKELY(eh->numEntries > (numBuckets * 3))) {
EHEntry **oldBuckets = eh->buckets;
eh->curSize = kHashSizes[++eh->curSizeIdx];
@@ -1274,7 +1274,7 @@ CCGError ccgSubSurf_syncFace(CCGSubSurf *ss, CCGFaceHDL fHDL, int numVerts, CCGV
CCGFace *f = NULL, *fNew;
int j, k, topologyChanged = 0;
- if (numVerts > ss->lenTempArrays) {
+ if (UNLIKELY(numVerts > ss->lenTempArrays)) {
ss->lenTempArrays = (numVerts < ss->lenTempArrays * 2) ? ss->lenTempArrays * 2 : numVerts;
ss->tempVerts = MEM_reallocN(ss->tempVerts, sizeof(*ss->tempVerts) * ss->lenTempArrays);
ss->tempEdges = MEM_reallocN(ss->tempEdges, sizeof(*ss->tempEdges) * ss->lenTempArrays);
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 5339c3fc5d5..81c03d8081b 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -37,12 +37,14 @@
#include "DNA_cloth_types.h"
#include "DNA_key_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
+#include "BLI_bitmap.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_linklist.h"
@@ -70,11 +72,10 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
#include "BLI_sys_types.h" /* for intptr_t support */
-#include "GL/glew.h"
-
#include "GPU_buffers.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_glew.h"
#include "GPU_material.h"
/* very slow! enable for testing only! */
@@ -501,11 +502,36 @@ void DM_update_materials(DerivedMesh *dm, Object *ob)
dm->mat = MEM_callocN(totmat * sizeof(*dm->mat), "DerivedMesh.mat");
- for (i = 1; i < totmat; i++) {
- dm->mat[i] = give_current_material(ob, i);
+ /* we leave last material as empty - rationale here is being able to index
+ * the materials by using the mf->mat_nr directly and leaving the last
+ * material as NULL in case no materials exist on mesh, so indexing will not fail */
+ for (i = 0; i < totmat - 1; i++) {
+ dm->mat[i] = give_current_material(ob, i + 1);
}
}
+MTFace *DM_paint_uvlayer_active_get(DerivedMesh *dm, int mat_nr)
+{
+ MTFace *tf_base;
+
+ BLI_assert(mat_nr < dm->totmat);
+
+ if (dm->mat[mat_nr] && dm->mat[mat_nr]->texpaintslot &&
+ dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname)
+ {
+ tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE,
+ dm->mat[mat_nr]->texpaintslot[dm->mat[mat_nr]->paint_active_slot].uvname);
+ /* This can fail if we have changed the name in the UV layer list and have assigned the old name in the material
+ * texture slot.*/
+ if (!tf_base)
+ tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+ }
+ else {
+ tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+ }
+
+ return tf_base;
+}
void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask)
{
@@ -615,7 +641,8 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob, CustomDataMask mask)
MEM_freeN(me->mselect);
}
- *me = tmp;
+ /* skip the listbase */
+ MEMCPY_STRUCT_OFS(me, &tmp, id.prev);
}
void DM_to_meshkey(DerivedMesh *dm, Mesh *me, KeyBlock *kb)
@@ -1107,7 +1134,7 @@ static void weightpaint_color(unsigned char r_col[4], DMWeightColorInfo *dm_wcin
static void calc_weightpaint_vert_color(
unsigned char r_col[4],
- MDeformVert *dv,
+ const MDeformVert *dv,
DMWeightColorInfo *dm_wcinfo,
const int defbase_tot, const int defbase_act,
const bool *defbase_sel, const int defbase_sel_tot,
@@ -1122,7 +1149,7 @@ static void calc_weightpaint_vert_color(
bool was_a_nonzero = false;
unsigned int i;
- MDeformWeight *dw = dv->dw;
+ const MDeformWeight *dw = dv->dw;
for (i = dv->totweight; i != 0; i--, dw++) {
/* in multipaint, get the average if auto normalize is inactive
* get the sum if it is active */
@@ -1213,14 +1240,15 @@ static void calc_weightpaint_vert_array(Object *ob, DerivedMesh *dm, int const d
}
}
else {
- int col_i;
+ unsigned char col[4];
if (draw_flag & (CALC_WP_GROUP_USER_ACTIVE | CALC_WP_GROUP_USER_ALL)) {
- col_i = 0;
+ copy_v3_v3_char((char *)col, dm_wcinfo->alert_color);
+ col[3] = 255;
}
else {
- weightpaint_color((unsigned char *)&col_i, dm_wcinfo, 0.0f);
+ weightpaint_color(col, dm_wcinfo, 0.0f);
}
- fill_vn_i((int *)r_wtcol_v, numVerts, col_i);
+ fill_vn_i((int *)r_wtcol_v, numVerts, *((int *)col));
}
}
@@ -1994,9 +2022,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
previewmd = modifiers_getLastPreview(scene, md, required_mode);
/* even if the modifier doesn't need the data, to make a preview it may */
if (previewmd) {
- if (do_mod_wmcol) {
- previewmask = CD_MASK_MDEFORMVERT;
- }
+ previewmask = CD_MASK_MDEFORMVERT;
}
}
@@ -2472,6 +2498,28 @@ DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em)
return getEditDerivedBMesh(em, obedit, NULL);
}
+/***/
+
+/* get derived mesh from an object, using editbmesh if available. */
+DerivedMesh *object_get_derived_final(Object *ob, const bool for_render)
+{
+ Mesh *me = ob->data;
+ BMEditMesh *em = me->edit_btmesh;
+
+ if (for_render) {
+ /* TODO(sergey): use proper derived render here in the future. */
+ return ob->derivedFinal;
+ }
+
+ if (em) {
+ DerivedMesh *dm = em->derivedFinal;
+ return dm;
+ }
+
+ return ob->derivedFinal;
+}
+
+
/* UNUSED */
#if 0
@@ -2532,6 +2580,44 @@ DMCoNo *mesh_get_mapped_verts_nors(Scene *scene, Object *ob)
#endif
+/* same as above but for vert coords */
+typedef struct {
+ float (*vertexcos)[3];
+ BLI_bitmap *vertex_visit;
+} MappedUserData;
+
+static void make_vertexcos__mapFunc(void *userData, int index, const float co[3],
+ const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+ MappedUserData *mappedData = (MappedUserData *)userData;
+
+ if (BLI_BITMAP_TEST(mappedData->vertex_visit, index) == 0) {
+ /* we need coord from prototype vertex, not from copies,
+ * assume they stored in the beginning of vertex array stored in DM
+ * (mirror modifier for eg does this) */
+ copy_v3_v3(mappedData->vertexcos[index], co);
+ BLI_BITMAP_ENABLE(mappedData->vertex_visit, index);
+ }
+}
+
+void mesh_get_mapped_verts_coords(DerivedMesh *dm, float (*r_cos)[3], const int totcos)
+{
+ if (dm->foreachMappedVert) {
+ MappedUserData userData;
+ memset(r_cos, 0, sizeof(*r_cos) * totcos);
+ userData.vertexcos = r_cos;
+ userData.vertex_visit = BLI_BITMAP_NEW(totcos, "vertexcos flags");
+ dm->foreachMappedVert(dm, make_vertexcos__mapFunc, &userData, DM_FOREACH_NOP);
+ MEM_freeN(userData.vertex_visit);
+ }
+ else {
+ int i;
+ for (i = 0; i < totcos; i++) {
+ dm->getVertCo(dm, i, r_cos[i]);
+ }
+ }
+}
+
/* ******************* GLSL ******************** */
typedef struct {
@@ -3089,7 +3175,7 @@ static void navmesh_drawColored(DerivedMesh *dm)
static void navmesh_DM_drawFacesTex(DerivedMesh *dm,
DMSetDrawOptionsTex setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData)
+ void *userData, DMDrawFlag UNUSED(flag))
{
(void) setDrawOptions;
(void) compareDrawOptions;
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 3219219bee5..c6dcca576fb 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -315,7 +315,7 @@ bActionGroup *action_groups_add_new(bAction *act, const char name[])
void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
{
/* sanity checks */
- if (ELEM3(NULL, act, agrp, fcurve))
+ if (ELEM(NULL, act, agrp, fcurve))
return;
/* if no channels anywhere, just add to two lists at the same time */
@@ -417,7 +417,7 @@ void action_groups_remove_channel(bAction *act, FCurve *fcu)
bActionGroup *BKE_action_group_find_name(bAction *act, const char name[])
{
/* sanity checks */
- if (ELEM3(NULL, act, act->groups.first, name) || (name[0] == 0))
+ if (ELEM(NULL, act, act->groups.first, name) || (name[0] == 0))
return NULL;
/* do string comparisons */
@@ -526,7 +526,7 @@ bPoseChannel *BKE_pose_channel_active(Object *ob)
bArmature *arm = (ob) ? ob->data : NULL;
bPoseChannel *pchan;
- if (ELEM3(NULL, ob, ob->pose, arm)) {
+ if (ELEM(NULL, ob, ob->pose, arm)) {
return NULL;
}
@@ -952,52 +952,52 @@ void framechange_poses_clear_unkeyed(void)
/* ************************** Bone Groups ************************** */
-/* Adds a new bone-group */
-void BKE_pose_add_group(Object *ob)
+/* Adds a new bone-group (name may be NULL) */
+bActionGroup *BKE_pose_add_group(bPose *pose, const char *name)
{
- bPose *pose = (ob) ? ob->pose : NULL;
bActionGroup *grp;
- if (ELEM(NULL, ob, ob->pose))
- return;
+ if (!name) {
+ name = DATA_("Group");
+ }
grp = MEM_callocN(sizeof(bActionGroup), "PoseGroup");
- BLI_strncpy(grp->name, DATA_("Group"), sizeof(grp->name));
+ BLI_strncpy(grp->name, name, sizeof(grp->name));
BLI_addtail(&pose->agroups, grp);
- BLI_uniquename(&pose->agroups, grp, DATA_("Group"), '.', offsetof(bActionGroup, name), sizeof(grp->name));
+ BLI_uniquename(&pose->agroups, grp, name, '.', offsetof(bActionGroup, name), sizeof(grp->name));
pose->active_group = BLI_countlist(&pose->agroups);
+
+ return grp;
}
-/* Remove the active bone-group */
-void BKE_pose_remove_group(Object *ob)
+/* Remove the given bone-group (expects 'virtual' index (+1 one, used by active_group etc.))
+ * index might be invalid ( < 1), in which case it will be find from grp. */
+void BKE_pose_remove_group(bPose *pose, bActionGroup *grp, const int index)
{
- bPose *pose = (ob) ? ob->pose : NULL;
- bActionGroup *grp = NULL;
bPoseChannel *pchan;
+ int idx = index;
- /* sanity checks */
- if (ELEM(NULL, ob, pose))
- return;
- if (pose->active_group <= 0)
- return;
+ if (idx < 1) {
+ idx = BLI_findindex(&pose->agroups, grp) + 1;
+ }
- /* get group to remove */
- grp = BLI_findlink(&pose->agroups, pose->active_group - 1);
- if (grp) {
- /* adjust group references (the trouble of using indices!):
- * - firstly, make sure nothing references it
- * - also, make sure that those after this item get corrected
- */
- for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (pchan->agrp_index == pose->active_group)
- pchan->agrp_index = 0;
- else if (pchan->agrp_index > pose->active_group)
- pchan->agrp_index--;
- }
-
- /* now, remove it from the pose */
- BLI_freelinkN(&pose->agroups, grp);
+ BLI_assert(idx > 0);
+
+ /* adjust group references (the trouble of using indices!):
+ * - firstly, make sure nothing references it
+ * - also, make sure that those after this item get corrected
+ */
+ for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (pchan->agrp_index == idx)
+ pchan->agrp_index = 0;
+ else if (pchan->agrp_index > idx)
+ pchan->agrp_index--;
+ }
+
+ /* now, remove it from the pose */
+ BLI_freelinkN(&pose->agroups, grp);
+ if (pose->active_group >= idx) {
pose->active_group--;
if (pose->active_group < 0 || BLI_listbase_is_empty(&pose->agroups)) {
pose->active_group = 0;
@@ -1005,6 +1005,18 @@ void BKE_pose_remove_group(Object *ob)
}
}
+/* Remove the indexed bone-group (expects 'virtual' index (+1 one, used by active_group etc.)) */
+void BKE_pose_remove_group_index(bPose *pose, const int index)
+{
+ bActionGroup *grp = NULL;
+
+ /* get group to remove */
+ grp = BLI_findlink(&pose->agroups, index - 1);
+ if (grp) {
+ BKE_pose_remove_group(pose, grp, index);
+ }
+}
+
/* ************** F-Curve Utilities for Actions ****************** */
/* Check if the given action has any keyframes */
diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c
index 4cce69dc824..aff99d3e1bf 100644
--- a/source/blender/blenkernel/intern/anim.c
+++ b/source/blender/blenkernel/intern/anim.c
@@ -125,12 +125,13 @@ void animviz_free_motionpath(bMotionPath *mpath)
/* ------------------- */
-/* Setup motion paths for the given data
- * - Only used when explicitly calculating paths on bones which may/may not be consider already
+/**
+ * Setup motion paths for the given data.
+ * \note Only used when explicitly calculating paths on bones which may/may not be consider already
*
- * < scene: current scene (for frame ranges, etc.)
- * < ob: object to add paths for (must be provided)
- * < pchan: posechannel to add paths for (optional; if not provided, object-paths are assumed)
+ * \param scene Current scene (for frame ranges, etc.)
+ * \param ob Object to add paths for (must be provided)
+ * \param pchan Posechannel to add paths for (optional; if not provided, object-paths are assumed)
*/
bMotionPath *animviz_verify_motionpaths(ReportList *reports, Scene *scene, Object *ob, bPoseChannel *pchan)
{
@@ -512,7 +513,7 @@ void calc_curvepath(Object *ob, ListBase *nurbs)
dist = (float *)MEM_mallocN(sizeof(float) * (tot + 1), "calcpathdist");
/* all lengths in *dist */
- bevp = bevpfirst = (BevPoint *)(bl + 1);
+ bevp = bevpfirst = bl->bevpoints;
fp = dist;
*fp = 0.0f;
for (a = 0; a < tot; a++) {
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 6a9c4c851b2..2fb832dc72d 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -51,18 +51,23 @@
#include "DNA_material_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "DNA_texture_types.h"
#include "DNA_world_types.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_nla.h"
#include "BKE_global.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_library.h"
#include "BKE_report.h"
+#include "BKE_texture.h"
#include "RNA_access.h"
@@ -244,7 +249,7 @@ void BKE_free_animdata(ID *id)
}
}
-/* Freeing -------------------------------------------- */
+/* Copying -------------------------------------------- */
/* Make a copy of the given AnimData - to be used when copying datablocks */
AnimData *BKE_copy_animdata(AnimData *adt, const bool do_action)
@@ -381,10 +386,12 @@ void BKE_relink_animdata(AnimData *adt)
/* Sub-ID Regrouping ------------------------------------------- */
-/* helper heuristic for determining if a path is compatible with the basepath
- * < path: (str) full RNA-path from some data (usually an F-Curve) to compare
- * < basepath: (str) shorter path fragment to look for
- * > returns (bool) whether there is a match
+/**
+ * Helper heuristic for determining if a path is compatible with the basepath
+ *
+ * \param path Full RNA-path from some data (usually an F-Curve) to compare
+ * \param basepath Shorter path fragment to look for
+ * \return Whether there is a match
*/
static bool animpath_matches_basepath(const char path[], const char basepath[])
{
@@ -403,7 +410,7 @@ void action_move_fcurves_by_basepath(bAction *srcAct, bAction *dstAct, const cha
FCurve *fcu, *fcn = NULL;
/* sanity checks */
- if (ELEM3(NULL, srcAct, dstAct, basepath)) {
+ if (ELEM(NULL, srcAct, dstAct, basepath)) {
if (G.debug & G_DEBUG) {
printf("ERROR: action_partition_fcurves_by_basepath(%p, %p, %p) has insufficient info to work with\n",
(void *)srcAct, (void *)dstAct, (void *)basepath);
@@ -549,6 +556,74 @@ void BKE_animdata_separate_by_basepath(ID *srcID, ID *dstID, ListBase *basepaths
}
}
+/**
+ * Temporary wrapper for driver operators for buttons to make it easier to create
+ * such drivers by rerouting all paths through the active object instead so that
+ * they will get picked up by the dependency system.
+ *
+ * \param C Context pointer - for getting active data
+ * \param[in,out] ptr RNA pointer for property's datablock. May be modified as result of path remapping.
+ * \param prop RNA definition of property to add for
+ * \return MEM_alloc'd string representing the path to the property from the given #PointerRNA
+ */
+char *BKE_animdata_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *prop, char *base_path)
+{
+ ID *id = (ID *)ptr->id.data;
+ ScrArea *sa = CTX_wm_area(C);
+
+ /* get standard path which may be extended */
+ char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop);
+ char *path = basepath; /* in case no remapping is needed */
+
+ /* Remapping will only be performed in the Properties Editor, as only this
+ * restricts the subspace of options to the 'active' data (a manageable state)
+ */
+ /* TODO: watch out for pinned context? */
+ if ((sa) && (sa->spacetype == SPACE_BUTS)) {
+ Object *ob = CTX_data_active_object(C);
+
+ if (ob && id) {
+ /* only id-types which can be remapped to go through objects should be considered */
+ switch (GS(id->name)) {
+ case ID_TE: /* textures */
+ {
+ Material *ma = give_current_material(ob, ob->actcol);
+ Tex *tex = give_current_material_texture(ma);
+
+ /* assumes: texture will only be shown if it is active material's active texture it's ok */
+ if ((ID *)tex == id) {
+ char name_esc_ma[(sizeof(ma->id.name) - 2) * 2];
+ char name_esc_tex[(sizeof(tex->id.name) - 2) * 2];
+
+ BLI_strescape(name_esc_ma, ma->id.name + 2, sizeof(name_esc_ma));
+ BLI_strescape(name_esc_tex, tex->id.name + 2, sizeof(name_esc_tex));
+
+ /* create new path */
+ // TODO: use RNA path functions to construct step by step instead?
+ // FIXME: maybe this isn't even needed anymore...
+ path = BLI_sprintfN("material_slots[\"%s\"].material.texture_slots[\"%s\"].texture.%s",
+ name_esc_ma, name_esc_tex, basepath);
+
+ /* free old one */
+ if (basepath != base_path)
+ MEM_freeN(basepath);
+ }
+ break;
+ }
+ }
+
+ /* fix RNA pointer, as we've now changed the ID root by changing the paths */
+ if (basepath != path) {
+ /* rebase provided pointer so that it starts from object... */
+ RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
+ }
+ }
+ }
+
+ /* the path should now have been corrected for use */
+ return path;
+}
+
/* Path Validation -------------------------------------------- */
/* Check if a given RNA Path is valid, by tracing it from the given ID, and seeing if we can resolve it */
@@ -984,8 +1059,8 @@ void BKE_all_animdata_fix_paths_rename(ID *ref_id, const char *prefix, const cha
AnimData *adt = BKE_animdata_from_id(id); \
NtId_Type *ntp = (NtId_Type *)id; \
if (ntp->nodetree) { \
- AnimData *adt2 = BKE_animdata_from_id((ID *)ntp); \
- BKE_animdata_fix_paths_rename((ID *)ntp, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \
+ AnimData *adt2 = BKE_animdata_from_id((ID *)ntp->nodetree); \
+ BKE_animdata_fix_paths_rename((ID *)ntp->nodetree, adt2, ref_id, prefix, oldName, newName, 0, 0, 1); \
} \
BKE_animdata_fix_paths_rename(id, adt, ref_id, prefix, oldName, newName, 0, 0, 1); \
} (void)0
@@ -1060,7 +1135,7 @@ KS_Path *BKE_keyingset_find_path(KeyingSet *ks, ID *id, const char group_name[],
KS_Path *ksp;
/* sanity checks */
- if (ELEM3(NULL, ks, rna_path, id))
+ if (ELEM(NULL, ks, rna_path, id))
return NULL;
/* loop over paths in the current KeyingSet, finding the first one where all settings match
@@ -1166,7 +1241,7 @@ KS_Path *BKE_keyingset_add_path(KeyingSet *ks, ID *id, const char group_name[],
/* just copy path info */
/* TODO: should array index be checked too? */
- ksp->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
+ ksp->rna_path = BLI_strdup(rna_path);
ksp->array_index = array_index;
/* store flags */
@@ -2232,9 +2307,12 @@ void nladata_flush_channels(ListBase *channels)
/* ---------------------- */
-/* NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels"
- * ! This is exported so that keyframing code can use this for make use of it for anim layers support
- * > echannels: (list<NlaEvalChannels>) evaluation channels with calculated values
+/**
+ * NLA Evaluation function - values are calculated and stored in temporary "NlaEvalChannels"
+ *
+ * \note This is exported so that keyframing code can use this for make use of it for anim layers support
+ *
+ * \param[out] echannels Evaluation channels with calculated values
*/
static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData *adt, float ctime)
{
@@ -2333,6 +2411,17 @@ static void animsys_evaluate_nla(ListBase *echannels, PointerRNA *ptr, AnimData
/* 3. free temporary evaluation data that's not used elsewhere */
BLI_freelistN(&estrips);
+
+ /* Tag ID as updated so render engines will recognize changes in data
+ * which is animated but doesn't have actions.
+ */
+ if (ptr->id.data != NULL) {
+ ID *id = ptr->id.data;
+ if (!(id->flag & LIB_ANIM_NO_RECALC)) {
+ id->flag |= LIB_ID_RECALC;
+ DAG_id_type_tag(G.main, GS(id->name));
+ }
+ }
}
/* NLA Evaluation function (mostly for use through do_animdata)
@@ -2387,7 +2476,7 @@ static void animsys_evaluate_overrides(PointerRNA *ptr, AnimData *adt)
/* Overview of how this system works:
* 1) Depsgraph sorts data as necessary, so that data is in an order that means
- * that all dependencies are resolved before dependants.
+ * that all dependencies are resolved before dependents.
* 2) All normal animation is evaluated, so that drivers have some basis values to
* work with
* a. NLA stacks are done first, as the Active Actions act as 'tweaking' tracks
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index fda252e81fd..bb05b5de8a6 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -505,7 +505,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
invert_m3_m3(imat3, mat3);
mul_m3_m3m3(mat3, result, imat3); /* the matrix transforming vec_roll to desired roll */
- roll1 = (float)atan2(mat3[2][0], mat3[2][2]);
+ roll1 = atan2f(mat3[2][0], mat3[2][2]);
}
}
else {
@@ -543,7 +543,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
invert_m3_m3(imat3, mat3);
mul_m3_m3m3(mat3, imat3, result); /* the matrix transforming vec_roll to desired roll */
- roll2 = (float)atan2(mat3[2][0], mat3[2][2]);
+ roll2 = atan2f(mat3[2][0], mat3[2][2]);
/* and only now negate handle */
mul_v3_fl(h2, -hlength2);
@@ -574,7 +574,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB
if (do_scale) {
/* correct for scaling when this matrix is used in scaled space */
- mul_serie_m4(result_array[a].mat, iscalemat, result_array[a].mat, scalemat, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(result_array[a].mat, iscalemat, result_array[a].mat, scalemat);
}
}
}
@@ -622,8 +622,7 @@ static void pchan_b_bone_defmats(bPoseChannel *pchan, bPoseChanDeform *pdef_info
invert_m4_m4(tmat, b_bone_rest[a].mat);
- mul_serie_m4(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat,
- NULL, NULL, NULL);
+ mul_m4_series(b_bone_mats[a + 1].mat, pchan->chan_mat, bone->arm_mat, b_bone[a].mat, tmat, b_bone_mats[0].mat);
if (use_quaternion)
mat4_to_dquat(&b_bone_dual_quats[a], bone->arm_mat, b_bone_mats[a + 1].mat);
@@ -1042,7 +1041,7 @@ void armature_deform_verts(Object *armOb, Object *target, DerivedMesh *dm, float
if (!use_quaternion) /* quaternion already is scale corrected */
mul_m3_fl(smat, armature_weight / contrib);
- mul_serie_m3(defMats[i], tmpmat, pre, smat, post, NULL, NULL, NULL, NULL);
+ mul_m3_series(defMats[i], post, smat, pre, tmpmat);
}
}
@@ -1482,17 +1481,14 @@ void mat3_to_vec_roll(float mat[3][3], float r_vec[3], float *r_roll)
* M* = 1 / (x^2 + z^2) * │ │
* └ -2 * x * z, x^2 - z^2 ┘
*/
-void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3])
+void vec_roll_to_mat3_normalized(const float nor[3], const float roll, float mat[3][3])
{
#define THETA_THRESHOLD_NEGY 1.0e-9f
#define THETA_THRESHOLD_NEGY_CLOSE 1.0e-5f
- float nor[3];
float theta;
float rMatrix[3][3], bMatrix[3][3];
- normalize_v3_v3(nor, vec);
-
theta = 1.0f + nor[1];
/* With old algo, 1.0e-13f caused T23954 and T31333, 1.0e-6f caused T27675 and T30438,
@@ -1543,6 +1539,13 @@ void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3])
#undef THETA_THRESHOLD_NEGY_CLOSE
}
+void vec_roll_to_mat3(const float vec[3], const float roll, float mat[3][3])
+{
+ float nor[3];
+
+ normalize_v3_v3(nor, vec);
+ vec_roll_to_mat3_normalized(nor, roll, mat);
+}
/* recursive part, calculates restposition of entire tree of children */
/* used by exiting editmode too */
@@ -1877,7 +1880,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos
*/
/* only happens on reload file, but violates depsgraph still... fix! */
- if (ELEM3(NULL, ikData->tar->curve_cache, ikData->tar->curve_cache->path, ikData->tar->curve_cache->path->data)) {
+ 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]*/
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 8b87f5b0cea..adfe43cb2a3 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -80,6 +80,7 @@
#include "BKE_sound.h"
#include "RE_pipeline.h"
+#include "RE_render_ext.h"
#include "BLF_api.h"
@@ -119,6 +120,7 @@ void free_blender(void)
DAG_exit();
BKE_brush_system_exit();
+ RE_exit_texture_rng();
BLI_callback_global_finalize();
@@ -170,7 +172,7 @@ static void clear_global(void)
static bool clean_paths_visit_cb(void *UNUSED(userdata), char *path_dst, const char *path_src)
{
strcpy(path_dst, path_src);
- BLI_clean(path_dst);
+ BLI_path_native_slash(path_dst);
return !STREQ(path_dst, path_src);
}
@@ -182,7 +184,7 @@ static void clean_paths(Main *main)
BKE_bpath_traverse_main(main, clean_paths_visit_cb, BKE_BPATH_TRAVERSE_SKIP_MULTIFILE, NULL);
for (scene = main->scene.first; scene; scene = scene->id.next) {
- BLI_clean(scene->r.pic);
+ BLI_path_native_slash(scene->r.pic);
}
}
@@ -197,29 +199,38 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
bScreen *curscreen = NULL;
Scene *curscene = NULL;
int recover;
- char mode;
-
- /* 'u' = undo save, 'n' = no UI load */
- if (BLI_listbase_is_empty(&bfd->main->screen)) mode = 'u';
- else if (G.fileflags & G_FILE_NO_UI) mode = 'n';
- else mode = 0;
+ enum {
+ LOAD_UI = 1,
+ LOAD_UI_OFF,
+ LOAD_UNDO,
+ } mode;
+
+ if (BLI_listbase_is_empty(&bfd->main->screen)) {
+ mode = LOAD_UNDO;
+ }
+ else if (G.fileflags & G_FILE_NO_UI) {
+ mode = LOAD_UI_OFF;
+ }
+ else {
+ mode = LOAD_UI;
+ }
recover = (G.fileflags & G_FILE_RECOVER);
/* Free all render results, without this stale data gets displayed after loading files */
- if (mode != 'u') {
+ if (mode != LOAD_UNDO) {
RE_FreeAllRenderResults();
}
/* Only make filepaths compatible when loading for real (not undo) */
- if (mode != 'u') {
+ if (mode != LOAD_UNDO) {
clean_paths(bfd->main);
}
/* XXX here the complex windowmanager matching */
/* no load screens? */
- if (mode) {
+ if (mode != LOAD_UI) {
/* comes from readfile.c */
SWAP(ListBase, G.main->wm, bfd->main->wm);
SWAP(ListBase, G.main->screen, bfd->main->screen);
@@ -263,7 +274,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
}
/* case G_FILE_NO_UI or no screens in file */
- if (mode) {
+ if (mode != LOAD_UI) {
/* leave entire context further unaltered? */
CTX_data_scene_set(C, curscene);
}
@@ -277,6 +288,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
CTX_wm_area_set(C, NULL);
CTX_wm_region_set(C, NULL);
CTX_wm_menu_set(C, NULL);
+ curscene = bfd->curscene;
}
/* this can happen when active scene was lib-linked, and doesn't exist anymore */
@@ -290,6 +302,9 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
curscene = CTX_data_scene(C);
}
+ BLI_assert(curscene == CTX_data_scene(C));
+
+
/* special cases, override loaded flags: */
if (G.f != bfd->globalf) {
const int flags_keep = (G_SWAP_EXCHANGE | G_SCRIPT_AUTOEXEC | G_SCRIPT_OVERRIDE_PREF);
@@ -332,7 +347,7 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
/* baseflags, groups, make depsgraph, etc */
/* first handle case if other windows have different scenes visible */
- if (mode == 0) {
+ if (mode == LOAD_UI) {
wmWindowManager *wm = G.main->wm.first;
if (wm) {
@@ -340,14 +355,14 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
for (win = wm->windows.first; win; win = win->next) {
if (win->screen && win->screen->scene) /* zealous check... */
- if (win->screen->scene != CTX_data_scene(C))
+ if (win->screen->scene != curscene)
BKE_scene_set_background(G.main, win->screen->scene);
}
}
}
- BKE_scene_set_background(G.main, CTX_data_scene(C));
+ BKE_scene_set_background(G.main, curscene);
- if (mode != 'u') {
+ if (mode != LOAD_UNDO) {
IMB_colormanagement_check_file_config(G.main);
}
@@ -384,6 +399,7 @@ void BKE_userdef_free(void)
wmKeyMapItem *kmi;
wmKeyMapDiffItem *kmdi;
bAddon *addon, *addon_next;
+ uiFont *font;
for (km = U.user_keymaps.first; km; km = km->next) {
for (kmdi = km->diff_items.first; kmdi; kmdi = kmdi->next) {
@@ -413,6 +429,12 @@ void BKE_userdef_free(void)
MEM_freeN(addon);
}
+ for (font = U.uifonts.first; font; font = font->next) {
+ BLF_unload_id(font->blf_id);
+ }
+
+ BLF_default_set(-1);
+
BLI_freelistN(&U.autoexec_paths);
BLI_freelistN(&U.uistyles);
@@ -459,7 +481,9 @@ int BKE_read_file(bContext *C, const char *filepath, ReportList *reports)
return (bfd ? retval : BKE_READ_FILE_FAIL);
}
-int BKE_read_file_from_memory(bContext *C, const void *filebuf, int filelength, ReportList *reports, int update_defaults)
+bool BKE_read_file_from_memory(
+ bContext *C, const void *filebuf, int filelength,
+ ReportList *reports, bool update_defaults)
{
BlendFileData *bfd;
@@ -476,7 +500,9 @@ int BKE_read_file_from_memory(bContext *C, const void *filebuf, int filelength,
}
/* memfile is the undo buffer */
-int BKE_read_file_from_memfile(bContext *C, MemFile *memfile, ReportList *reports)
+bool BKE_read_file_from_memfile(
+ bContext *C, MemFile *memfile,
+ ReportList *reports)
{
BlendFileData *bfd;
@@ -661,7 +687,7 @@ void BKE_write_undo(bContext *C, const char *name)
counter = counter % U.undosteps;
BLI_snprintf(numstr, sizeof(numstr), "%d.blend", counter);
- BLI_make_file_string("/", filepath, BLI_temporary_dir(), numstr);
+ BLI_make_file_string("/", filepath, BLI_temp_dir_session(), numstr);
/* success = */ /* UNUSED */ BLO_write_file(CTX_data_main(C), filepath, fileflags, NULL, NULL);
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index d0883728a71..3cd26dacebd 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -94,7 +94,8 @@ static bool checkMissingFiles_visit_cb(void *userdata, char *UNUSED(path_dst), c
/* high level function */
void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
{
- BKE_bpath_traverse_main(bmain, checkMissingFiles_visit_cb, BKE_BPATH_TRAVERSE_ABS, reports);
+ BKE_bpath_traverse_main(bmain, checkMissingFiles_visit_cb,
+ BKE_BPATH_TRAVERSE_ABS | BKE_BPATH_TRAVERSE_SKIP_PACKED, reports);
}
typedef struct BPathRemap_Data {
@@ -106,7 +107,7 @@ typedef struct BPathRemap_Data {
int count_failed;
} BPathRemap_Data;
-static bool makeFilesRelative_visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool bpath_relative_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
{
BPathRemap_Data *data = (BPathRemap_Data *)userdata;
@@ -132,6 +133,7 @@ static bool makeFilesRelative_visit_cb(void *userdata, char *path_dst, const cha
void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports)
{
BPathRemap_Data data = {NULL};
+ const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
if (basedir[0] == '\0') {
printf("%s: basedir='', this is a bug\n", __func__);
@@ -141,14 +143,14 @@ void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *re
data.basedir = basedir;
data.reports = reports;
- BKE_bpath_traverse_main(bmain, makeFilesRelative_visit_cb, 0, (void *)&data);
+ BKE_bpath_traverse_main(bmain, bpath_relative_convert_visit_cb, flag, (void *)&data);
BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO,
"Total files %d | Changed %d | Failed %d",
data.count_tot, data.count_changed, data.count_failed);
}
-static bool makeFilesAbsolute_visit_cb(void *userdata, char *path_dst, const char *path_src)
+static bool bpath_absolute_convert_visit_cb(void *userdata, char *path_dst, const char *path_src)
{
BPathRemap_Data *data = (BPathRemap_Data *)userdata;
@@ -175,6 +177,7 @@ static bool makeFilesAbsolute_visit_cb(void *userdata, char *path_dst, const cha
void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports)
{
BPathRemap_Data data = {NULL};
+ const int flag = BKE_BPATH_TRAVERSE_SKIP_LIBRARY;
if (basedir[0] == '\0') {
printf("%s: basedir='', this is a bug\n", __func__);
@@ -184,7 +187,7 @@ void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *re
data.basedir = basedir;
data.reports = reports;
- BKE_bpath_traverse_main(bmain, makeFilesAbsolute_visit_cb, 0, (void *)&data);
+ BKE_bpath_traverse_main(bmain, bpath_absolute_convert_visit_cb, flag, (void *)&data);
BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO,
"Total files %d | Changed %d | Failed %d",
@@ -210,7 +213,7 @@ static int findFileRecursive(char *filename_new,
/* file searching stuff */
DIR *dir;
struct dirent *de;
- struct stat status;
+ BLI_stat_t status;
char path[FILE_MAX];
int size;
bool found = false;
@@ -421,7 +424,7 @@ 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 (ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
+ 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);
@@ -695,7 +698,7 @@ bool BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *pa
/* -------------------------------------------------------------------- */
/**
* Backup/Restore/Free functions,
- * \note These functions assume the data won't chane order.
+ * \note These functions assume the data won't change order.
*/
struct PathStore {
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 967e89e0dd1..ae6ae6087af 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -83,6 +83,7 @@ static void brush_defaults(Brush *brush)
brush->plane_trim = 0.5f;
brush->clone.alpha = 0.5f;
brush->normal_weight = 0.0f;
+ brush->fill_threshold = 0.2f;
brush->flag |= BRUSH_ALPHA_PRESSURE;
/* BRUSH PAINT TOOL SETTINGS */
@@ -90,6 +91,8 @@ static void brush_defaults(Brush *brush)
brush->rgb[1] = 1.0f;
brush->rgb[2] = 1.0f;
+ zero_v3(brush->secondary_rgb);
+
/* BRUSH STROKE SETTINGS */
brush->flag |= (BRUSH_SPACE | BRUSH_SPACE_ATTEN);
brush->spacing = 10; /* how far each brush dot should be spaced as a percentage of brush diameter */
@@ -161,6 +164,9 @@ Brush *BKE_brush_copy(Brush *brush)
if (brush->mask_mtex.tex)
id_us_plus((ID *)brush->mask_mtex.tex);
+ if (brush->paint_curve)
+ id_us_plus((ID *)brush->paint_curve);
+
if (brush->icon_imbuf)
brushn->icon_imbuf = IMB_dupImBuf(brush->icon_imbuf);
@@ -180,11 +186,9 @@ Brush *BKE_brush_copy(Brush *brush)
/* not brush itself */
void BKE_brush_free(Brush *brush)
{
- if (brush->mtex.tex)
- brush->mtex.tex->id.us--;
-
- if (brush->mask_mtex.tex)
- brush->mask_mtex.tex->id.us--;
+ id_us_min((ID *)brush->mtex.tex);
+ id_us_min((ID *)brush->mask_mtex.tex);
+ id_us_min((ID *)brush->paint_curve);
if (brush->icon_imbuf)
IMB_freeImBuf(brush->icon_imbuf);
@@ -192,6 +196,9 @@ void BKE_brush_free(Brush *brush)
BKE_previewimg_free(&(brush->preview));
curvemapping_free(brush->curve);
+
+ if (brush->gradient)
+ MEM_freeN(brush->gradient);
}
static void extern_local_brush(Brush *brush)
@@ -199,6 +206,7 @@ static void extern_local_brush(Brush *brush)
id_lib_extern((ID *)brush->mtex.tex);
id_lib_extern((ID *)brush->mask_mtex.tex);
id_lib_extern((ID *)brush->clone.image);
+ id_lib_extern((ID *)brush->paint_curve);
}
void BKE_brush_make_local(Brush *brush)
@@ -742,10 +750,23 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
}
+ CLAMP(intensity, 0.0f, 1.0f);
+
+ switch (br->mask_pressure) {
+ case BRUSH_MASK_PRESSURE_CUTOFF:
+ intensity = ((1.0f - intensity) < ups->size_pressure_value) ? 1.0f : 0.0f;
+ break;
+ case BRUSH_MASK_PRESSURE_RAMP:
+ intensity = ups->size_pressure_value + intensity * (1.0f - ups->size_pressure_value);
+ break;
+ default:
+ break;
+ }
+
return intensity;
}
-/* Unified Size and Strength */
+/* Unified Size / Strength / Color */
/* XXX: be careful about setting size and unprojected radius
* because they depend on one another
@@ -760,6 +781,29 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
* In any case, a better solution is needed to prevent
* inconsistency. */
+
+float *BKE_brush_color_get(const struct Scene *scene, 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)
+{
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+ return (ups->flag & UNIFIED_PAINT_COLOR) ? ups->secondary_rgb : brush->secondary_rgb;
+}
+
+void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float color[3])
+{
+ UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
+
+ if (ups->flag & UNIFIED_PAINT_COLOR)
+ copy_v3_v3(ups->rgb, color);
+ else
+ copy_v3_v3(brush->rgb, color);
+}
+
void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
{
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
@@ -886,39 +930,27 @@ void BKE_brush_scale_size(int *r_brush_size,
void BKE_brush_jitter_pos(const Scene *scene, Brush *brush, const float pos[2], float jitterpos[2])
{
- int use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ?
- (brush->jitter_absolute != 0) : (brush->jitter != 0);
+ float rand_pos[2];
+ float spread;
+ int diameter;
- /* jitter-ed brush gives weird and unpredictable result for this
- * kinds of stroke, so manually disable jitter usage (sergey) */
- use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0;
+ do {
+ rand_pos[0] = BLI_rng_get_float(brush_rng) - 0.5f;
+ rand_pos[1] = BLI_rng_get_float(brush_rng) - 0.5f;
+ } while (len_squared_v2(rand_pos) > SQUARE(0.5f));
- if (use_jitter) {
- float rand_pos[2];
- float spread;
- int diameter;
- do {
- rand_pos[0] = BLI_rng_get_float(brush_rng) - 0.5f;
- rand_pos[1] = BLI_rng_get_float(brush_rng) - 0.5f;
- } while (len_squared_v2(rand_pos) > (0.5f * 0.5f));
-
-
- if (brush->flag & BRUSH_ABSOLUTE_JITTER) {
- diameter = 2 * brush->jitter_absolute;
- spread = 1.0;
- }
- else {
- diameter = 2 * BKE_brush_size_get(scene, brush);
- spread = brush->jitter;
- }
- /* find random position within a circle of diameter 1 */
- jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * spread;
- jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread;
+ if (brush->flag & BRUSH_ABSOLUTE_JITTER) {
+ diameter = 2 * brush->jitter_absolute;
+ spread = 1.0;
}
else {
- copy_v2_v2(jitterpos, pos);
+ diameter = 2 * BKE_brush_size_get(scene, brush);
+ spread = brush->jitter;
}
+ /* find random position within a circle of diameter 1 */
+ jitterpos[0] = pos[0] + 2 * rand_pos[0] * diameter * spread;
+ jitterpos[1] = pos[1] + 2 * rand_pos[1] * diameter * spread;
}
void BKE_brush_randomize_texture_coordinates(UnifiedPaintSettings *ups, bool mask)
diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c
index f85a91b66cb..4ad577a7bda 100644
--- a/source/blender/blenkernel/intern/bvhutils.c
+++ b/source/blender/blenkernel/intern/bvhutils.c
@@ -77,288 +77,6 @@ static float sphereray_tri_intersection(const BVHTreeRay *ray, float radius, con
return FLT_MAX;
}
-
-/*
- * Function adapted from David Eberly's distance tools (LGPL)
- * http://www.geometrictools.com/LibFoundation/Distance/Distance.html
- */
-float nearest_point_in_tri_surface_squared(
- const float v0[3], const float v1[3], const float v2[3],
- const float p[3], int *v, int *e, float nearest[3])
-{
- float diff[3];
- float e0[3];
- float e1[3];
- float A00;
- float A01;
- float A11;
- float B0;
- float B1;
- float C;
- float Det;
- float S;
- float T;
- float sqrDist;
- int lv = -1, le = -1;
-
- sub_v3_v3v3(diff, v0, p);
- sub_v3_v3v3(e0, v1, v0);
- sub_v3_v3v3(e1, v2, v0);
-
- A00 = dot_v3v3(e0, e0);
- A01 = dot_v3v3(e0, e1);
- A11 = dot_v3v3(e1, e1);
- B0 = dot_v3v3(diff, e0);
- B1 = dot_v3v3(diff, e1);
- C = dot_v3v3(diff, diff);
- Det = fabsf(A00 * A11 - A01 * A01);
- S = A01 * B1 - A11 * B0;
- T = A01 * B0 - A00 * B1;
-
- if (S + T <= Det) {
- if (S < 0.0f) {
- if (T < 0.0f) { /* Region 4 */
- if (B0 < 0.0f) {
- T = 0.0f;
- if (-B0 >= A00) {
- S = 1.0f;
- sqrDist = A00 + 2.0f * B0 + C;
- lv = 1;
- }
- else {
- if (fabsf(A00) > FLT_EPSILON)
- S = -B0 / A00;
- else
- S = 0.0f;
- sqrDist = B0 * S + C;
- le = 0;
- }
- }
- else {
- S = 0.0f;
- if (B1 >= 0.0f) {
- T = 0.0f;
- sqrDist = C;
- lv = 0;
- }
- else if (-B1 >= A11) {
- T = 1.0f;
- sqrDist = A11 + 2.0f * B1 + C;
- lv = 2;
- }
- else {
- if (fabsf(A11) > FLT_EPSILON)
- T = -B1 / A11;
- else
- T = 0.0f;
- sqrDist = B1 * T + C;
- le = 1;
- }
- }
- }
- else { /* Region 3 */
- S = 0.0f;
- if (B1 >= 0.0f) {
- T = 0.0f;
- sqrDist = C;
- lv = 0;
- }
- else if (-B1 >= A11) {
- T = 1.0f;
- sqrDist = A11 + 2.0f * B1 + C;
- lv = 2;
- }
- else {
- if (fabsf(A11) > FLT_EPSILON)
- T = -B1 / A11;
- else
- T = 0.0;
- sqrDist = B1 * T + C;
- le = 1;
- }
- }
- }
- else if (T < 0.0f) { /* Region 5 */
- T = 0.0f;
- if (B0 >= 0.0f) {
- S = 0.0f;
- sqrDist = C;
- lv = 0;
- }
- else if (-B0 >= A00) {
- S = 1.0f;
- sqrDist = A00 + 2.0f * B0 + C;
- lv = 1;
- }
- else {
- if (fabsf(A00) > FLT_EPSILON)
- S = -B0 / A00;
- else
- S = 0.0f;
- sqrDist = B0 * S + C;
- le = 0;
- }
- }
- else { /* Region 0 */
- /* Minimum at interior lv */
- float invDet;
- if (fabsf(Det) > FLT_EPSILON)
- invDet = 1.0f / Det;
- else
- invDet = 0.0f;
- S *= invDet;
- T *= invDet;
- sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
- T * (A01 * S + A11 * T + 2.0f * B1) + C;
- }
- }
- else {
- float tmp0, tmp1, numer, denom;
-
- if (S < 0.0f) { /* Region 2 */
- tmp0 = A01 + B0;
- tmp1 = A11 + B1;
- if (tmp1 > tmp0) {
- numer = tmp1 - tmp0;
- denom = A00 - 2.0f * A01 + A11;
- if (numer >= denom) {
- S = 1.0f;
- T = 0.0f;
- sqrDist = A00 + 2.0f * B0 + C;
- lv = 1;
- }
- else {
- if (fabsf(denom) > FLT_EPSILON)
- S = numer / denom;
- else
- S = 0.0f;
- T = 1.0f - S;
- sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
- T * (A01 * S + A11 * T + 2.0f * B1) + C;
- le = 2;
- }
- }
- else {
- S = 0.0f;
- if (tmp1 <= 0.0f) {
- T = 1.0f;
- sqrDist = A11 + 2.0f * B1 + C;
- lv = 2;
- }
- else if (B1 >= 0.0f) {
- T = 0.0f;
- sqrDist = C;
- lv = 0;
- }
- else {
- if (fabsf(A11) > FLT_EPSILON)
- T = -B1 / A11;
- else
- T = 0.0f;
- sqrDist = B1 * T + C;
- le = 1;
- }
- }
- }
- else if (T < 0.0f) { /* Region 6 */
- tmp0 = A01 + B1;
- tmp1 = A00 + B0;
- if (tmp1 > tmp0) {
- numer = tmp1 - tmp0;
- denom = A00 - 2.0f * A01 + A11;
- if (numer >= denom) {
- T = 1.0f;
- S = 0.0f;
- sqrDist = A11 + 2.0f * B1 + C;
- lv = 2;
- }
- else {
- if (fabsf(denom) > FLT_EPSILON)
- T = numer / denom;
- else
- T = 0.0f;
- S = 1.0f - T;
- sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
- T * (A01 * S + A11 * T + 2.0f * B1) + C;
- le = 2;
- }
- }
- else {
- T = 0.0f;
- if (tmp1 <= 0.0f) {
- S = 1.0f;
- sqrDist = A00 + 2.0f * B0 + C;
- lv = 1;
- }
- else if (B0 >= 0.0f) {
- S = 0.0f;
- sqrDist = C;
- lv = 0;
- }
- else {
- if (fabsf(A00) > FLT_EPSILON)
- S = -B0 / A00;
- else
- S = 0.0f;
- sqrDist = B0 * S + C;
- le = 0;
- }
- }
- }
- else { /* Region 1 */
- numer = A11 + B1 - A01 - B0;
- if (numer <= 0.0f) {
- S = 0.0f;
- T = 1.0f;
- sqrDist = A11 + 2.0f * B1 + C;
- lv = 2;
- }
- else {
- denom = A00 - 2.0f * A01 + A11;
- if (numer >= denom) {
- S = 1.0f;
- T = 0.0f;
- sqrDist = A00 + 2.0f * B0 + C;
- lv = 1;
- }
- else {
- if (fabsf(denom) > FLT_EPSILON)
- S = numer / denom;
- else
- S = 0.0f;
- T = 1.0f - S;
- sqrDist = S * (A00 * S + A01 * T + 2.0f * B0) +
- T * (A01 * S + A11 * T + 2.0f * B1) + C;
- le = 2;
- }
- }
- }
- }
-
- /* Account for numerical round-off error */
- if (sqrDist < FLT_EPSILON)
- sqrDist = 0.0f;
-
- {
- float w[3], x[3], y[3], z[3];
- copy_v3_v3(w, v0);
- copy_v3_v3(x, e0);
- mul_v3_fl(x, S);
- copy_v3_v3(y, e1);
- mul_v3_fl(y, T);
- add_v3_v3v3(z, w, x);
- add_v3_v3v3(z, z, y);
- //sub_v3_v3v3(d, p, z);
- copy_v3_v3(nearest, z);
- //d = p - ( v0 + S * e0 + T * e1 );
- }
- *v = lv;
- *e = le;
-
- return sqrDist;
-}
-
-
/*
* BVH from meshes callbacks
*/
@@ -380,9 +98,10 @@ static void mesh_faces_nearest_point(void *userdata, int index, const float co[3
do {
float nearest_tmp[3], dist_sq;
- int vertex, edge;
-
- dist_sq = nearest_point_in_tri_surface_squared(t0, t1, t2, co, &vertex, &edge, nearest_tmp);
+
+ closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
if (dist_sq < nearest->dist_sq) {
nearest->index = index;
nearest->dist_sq = dist_sq;
@@ -413,9 +132,10 @@ static void editmesh_faces_nearest_point(void *userdata, int index, const float
{
float nearest_tmp[3], dist_sq;
- int vertex, edge;
- dist_sq = nearest_point_in_tri_surface_squared(t0, t1, t2, co, &vertex, &edge, nearest_tmp);
+ closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
if (dist_sq < nearest->dist_sq) {
nearest->index = index;
nearest->dist_sq = dist_sq;
diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c
index b20ba40c0dd..1402f62291f 100644
--- a/source/blender/blenkernel/intern/camera.c
+++ b/source/blender/blenkernel/intern/camera.c
@@ -201,7 +201,7 @@ void BKE_camera_params_init(CameraParams *params)
/* fallback for non camera objects */
params->clipsta = 0.1f;
- params->clipsta = 100.0f;
+ params->clipend = 100.0f;
}
void BKE_camera_params_from_object(CameraParams *params, Object *ob)
@@ -232,7 +232,7 @@ void BKE_camera_params_from_object(CameraParams *params, Object *ob)
/* lamp object */
Lamp *la = ob->data;
float fac = cosf(la->spotsize * 0.5f);
- float phi = acos(fac);
+ float phi = acosf(fac);
params->lens = 16.0f * fac / sinf(phi);
if (params->lens == 0.0f)
@@ -473,7 +473,7 @@ static void camera_to_frame_view_cb(const float co[3], void *user_data)
unsigned int i;
for (i = 0; i < 4; i++) {
- float nd = dist_squared_to_plane_v3(co, data->plane_tx[i]);
+ float nd = dist_signed_squared_to_plane_v3(co, data->plane_tx[i]);
if (nd < data->dist_vals_sq[i]) {
data->dist_vals_sq[i] = nd;
}
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index 205282c1de7..bfc70c91181 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -34,12 +34,11 @@
* \ingroup bke
*/
-#include "GL/glew.h"
-
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_edgehash.h"
#include "BLI_utildefines.h"
+#include "BLI_stackdefines.h"
#include "BKE_pbvh.h"
#include "BKE_cdderivedmesh.h"
@@ -50,6 +49,7 @@
#include "BKE_editmesh.h"
#include "BKE_curve.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -60,6 +60,7 @@
#include "GPU_buffers.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_glew.h"
#include "GPU_material.h"
#include <string.h>
@@ -551,7 +552,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
MVert *mvert = cddm->mvert;
MFace *mface = cddm->mface;
const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
- short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
+ const short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1;
if (cddm->pbvh && cddm->pbvh_draw) {
@@ -575,11 +576,16 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
new_glmode = mface->v4 ? GL_QUADS : GL_TRIANGLES;
new_matnr = mface->mat_nr + 1;
new_shademodel = (lnors || (mface->flag & ME_SMOOTH)) ? GL_SMOOTH : GL_FLAT;
-
- if (new_glmode != glmode || new_matnr != matnr || new_shademodel != shademodel) {
+
+
+ if ((new_glmode != glmode) || (new_shademodel != shademodel) ||
+ (setMaterial && (new_matnr != matnr)))
+ {
glEnd();
- drawCurrentMat = setMaterial(matnr = new_matnr, NULL);
+ if (setMaterial) {
+ drawCurrentMat = setMaterial(matnr = new_matnr, NULL);
+ }
glShadeModel(shademodel = new_shademodel);
glBegin(glmode = new_glmode);
@@ -597,7 +603,6 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
glNormal3sv((const GLshort *)lnors[0][3]);
glVertex3fv(mvert[mface->v4].co);
}
- lnors++;
}
else if (shademodel == GL_FLAT) {
if (nors) {
@@ -635,7 +640,10 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
}
}
- if (nors) nors += 3;
+ if (nors)
+ nors += 3;
+ if (lnors)
+ lnors++;
}
glEnd();
}
@@ -661,17 +669,18 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
DMSetDrawOptionsTex drawParams,
DMSetDrawOptions drawParamsMapped,
DMCompareDrawOptions compareDrawOptions,
- void *userData)
+ void *userData, DMDrawFlag uvflag)
{
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
MVert *mv = cddm->mvert;
- MFace *mf = DM_get_tessface_data_layer(dm, CD_MFACE);
+ const MFace *mf = DM_get_tessface_data_layer(dm, CD_MFACE);
const float *nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
- short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
+ const short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
MCol *mcol;
int i, orig;
int colType, startFace = 0;
+ bool use_tface = (uvflag & DM_DRAW_USE_ACTIVE_UV) != 0;
/* double lookup */
const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
@@ -710,14 +719,35 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
cdDM_update_normals_from_pbvh(dm);
if (GPU_buffer_legacy(dm)) {
+ int mat_nr_cache = -1;
+ MTFace *tf_base = DM_get_tessface_data_layer(dm, CD_MTFACE);
+ MTFace *tf_stencil_base = NULL;
+ MTFace *tf_stencil = NULL;
+
+ if (uvflag & DM_DRAW_USE_TEXPAINT_UV) {
+ int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
+ tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
+ }
+
DEBUG_VBO("Using legacy code. cdDM_drawFacesTex_common\n");
for (i = 0; i < dm->numTessFaceData; i++, mf++) {
MVert *mvert;
DMDrawOption draw_option;
unsigned char *cp = NULL;
+ if (uvflag & DM_DRAW_USE_TEXPAINT_UV) {
+ if (mf->mat_nr != mat_nr_cache) {
+ tf_base = DM_paint_uvlayer_active_get(dm, mf->mat_nr);
+
+ mat_nr_cache = mf->mat_nr;
+ }
+ }
+
+ tf = tf_base ? tf_base + i : NULL;
+ tf_stencil = tf_stencil_base ? tf_stencil_base + i : NULL;
+
if (drawParams) {
- draw_option = drawParams(tf ? &tf[i] : NULL, (mcol != NULL), mf->mat_nr);
+ draw_option = drawParams(use_tface ? tf : NULL, (mcol != NULL), mf->mat_nr);
}
else {
if (index_mf_to_mpoly) {
@@ -770,21 +800,24 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
}
glBegin(mf->v4 ? GL_QUADS : GL_TRIANGLES);
- if (tf) glTexCoord2fv(tf[i].uv[0]);
+ if (tf) glTexCoord2fv(tf->uv[0]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[0]);
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
mvert = &mv[mf->v1];
if (lnors) glNormal3sv((const GLshort *)lnors[0][0]);
else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no);
glVertex3fv(mvert->co);
- if (tf) glTexCoord2fv(tf[i].uv[1]);
+ if (tf) glTexCoord2fv(tf->uv[1]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[1]);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
mvert = &mv[mf->v2];
if (lnors) glNormal3sv((const GLshort *)lnors[0][1]);
else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no);
glVertex3fv(mvert->co);
- if (tf) glTexCoord2fv(tf[i].uv[2]);
+ if (tf) glTexCoord2fv(tf->uv[2]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[2]);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
mvert = &mv[mf->v3];
if (lnors) glNormal3sv((const GLshort *)lnors[0][2]);
@@ -792,24 +825,30 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
glVertex3fv(mvert->co);
if (mf->v4) {
- if (tf) glTexCoord2fv(tf[i].uv[3]);
+ if (tf) glTexCoord2fv(tf->uv[3]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf->uv[3]);
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
mvert = &mv[mf->v4];
if (lnors) glNormal3sv((const GLshort *)lnors[0][3]);
else if (mf->flag & ME_SMOOTH) glNormal3sv(mvert->no);
glVertex3fv(mvert->co);
}
- if (lnors) lnors++;
glEnd();
}
- if (nors) nors += 3;
+ if (nors)
+ nors += 3;
+ if (lnors)
+ lnors++;
}
}
else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
GPU_vertex_setup(dm);
GPU_normal_setup(dm);
- GPU_uv_setup(dm);
+ if (uvflag & DM_DRAW_USE_TEXPAINT_UV)
+ GPU_texpaint_uv_setup(dm);
+ else
+ GPU_uv_setup(dm);
if (mcol) {
GPU_color_setup(dm, colType);
}
@@ -829,7 +868,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
next_actualFace = dm->drawObject->triangle_to_mface[i + 1];
if (drawParams) {
- draw_option = drawParams(tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr);
+ draw_option = drawParams(use_tface && tf ? &tf[actualFace] : NULL, (mcol != NULL), mf[actualFace].mat_nr);
}
else {
if (index_mf_to_mpoly) {
@@ -885,9 +924,9 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
static void cdDM_drawFacesTex(DerivedMesh *dm,
DMSetDrawOptionsTex setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData)
+ void *userData, DMDrawFlag uvflag)
{
- cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
+ cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, uvflag);
}
static void cdDM_drawMappedFaces(DerivedMesh *dm,
@@ -901,7 +940,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
MFace *mf = cddm->mface;
MCol *mcol;
const float *nors = DM_get_tessface_data_layer(dm, CD_NORMAL);
- short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
+ const short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
int colType, useColors = flag & DM_DRAW_USE_COLORS;
int i, orig;
@@ -973,7 +1012,6 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
glNormal3sv((const GLshort *)lnors[0][3]);
glVertex3fv(mv[mf->v4].co);
}
- lnors++;
}
else if (!drawSmooth) {
if (nors) {
@@ -1024,7 +1062,10 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
glDisable(GL_POLYGON_STIPPLE);
}
- if (nors) nors += 3;
+ if (nors)
+ nors += 3;
+ if (lnors)
+ lnors++;
}
}
else { /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
@@ -1111,13 +1152,13 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm,
static void cdDM_drawMappedFacesTex(DerivedMesh *dm,
DMSetDrawOptions setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData)
+ void *userData, DMDrawFlag flag)
{
- cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
+ cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
}
-static void cddm_draw_attrib_vertex(DMVertexAttribs *attribs, MVert *mvert, int a, int index, int vert,
- short (*lnor)[3], int smoothnormal)
+static void cddm_draw_attrib_vertex(DMVertexAttribs *attribs, const MVert *mvert, int a, int index, int vert,
+ const short (*lnor)[3], const bool smoothnormal)
{
const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
int b;
@@ -1193,11 +1234,11 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
CDDerivedMesh *cddm = (CDDerivedMesh *) dm;
GPUVertexAttribs gattribs;
DMVertexAttribs attribs;
- MVert *mvert = cddm->mvert;
- MFace *mface = cddm->mface;
+ const MVert *mvert = cddm->mvert;
+ const MFace *mface = cddm->mface;
/* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
- float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
- short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
+ const float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
+ const short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
int a, b, matnr, new_matnr;
bool do_draw;
int orig;
@@ -1236,8 +1277,8 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
glBegin(GL_QUADS);
for (a = 0; a < dm->numTessFaceData; a++, mface++) {
- const int smoothnormal = lnors || (mface->flag & ME_SMOOTH);
- short (*ln1)[3] = NULL, (*ln2)[3] = NULL, (*ln3)[3] = NULL, (*ln4)[3] = NULL;
+ const bool smoothnormal = lnors || (mface->flag & ME_SMOOTH);
+ const short (*ln1)[3] = NULL, (*ln2)[3] = NULL, (*ln3)[3] = NULL, (*ln4)[3] = NULL;
new_matnr = mface->mat_nr + 1;
if (new_matnr != matnr) {
@@ -1282,13 +1323,11 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
glNormal3fv(nor);
}
}
-
- if (lnors) {
- ln1 = &lnors[0][0];
- ln2 = &lnors[0][1];
- ln3 = &lnors[0][2];
- ln4 = &lnors[0][3];
- lnors++;
+ else if (lnors) {
+ ln1 = &lnors[a][0];
+ ln2 = &lnors[a][1];
+ ln3 = &lnors[a][2];
+ ln4 = &lnors[a][3];
}
cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v1, 0, ln1, smoothnormal);
@@ -1309,7 +1348,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm,
int start = 0, numfaces = 0 /* , prevdraw = 0 */ /* UNUSED */, curface = 0;
int i;
- MFace *mf = mface;
+ const MFace *mf = mface;
GPUAttrib datatypes[GPU_MAX_ATTRIB]; /* TODO, messing up when switching materials many times - [#21056]*/
memset(&attribs, 0, sizeof(attribs));
@@ -1533,8 +1572,8 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm,
DMVertexAttribs attribs;
MVert *mvert = cddm->mvert;
MFace *mf = cddm->mface;
- float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
- short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
+ const float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
+ const short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
int a, matnr, new_matnr;
int orig;
@@ -1569,8 +1608,8 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm,
glBegin(GL_QUADS);
for (a = 0; a < dm->numTessFaceData; a++, mf++) {
- const int smoothnormal = lnors || (mf->flag & ME_SMOOTH);
- short (*ln1)[3] = NULL, (*ln2)[3] = NULL, (*ln3)[3] = NULL, (*ln4)[3] = NULL;
+ const bool smoothnormal = lnors || (mf->flag & ME_SMOOTH);
+ const short (*ln1)[3] = NULL, (*ln2)[3] = NULL, (*ln3)[3] = NULL, (*ln4)[3] = NULL;
/* material */
new_matnr = mf->mat_nr + 1;
@@ -1609,13 +1648,11 @@ static void cdDM_drawMappedFacesMat(DerivedMesh *dm,
glNormal3fv(nor);
}
}
-
- if (lnors) {
- ln1 = &lnors[0][0];
- ln2 = &lnors[0][1];
- ln3 = &lnors[0][2];
- ln4 = &lnors[0][3];
- lnors++;
+ else if (lnors) {
+ ln1 = &lnors[a][0];
+ ln2 = &lnors[a][1];
+ ln3 = &lnors[a][2];
+ ln4 = &lnors[a][3];
}
/* vertices */
@@ -2530,25 +2567,200 @@ void CDDM_calc_normals_tessface(DerivedMesh *dm)
#if 1
/**
+ * Poly compare with vtargetmap
+ * Function used by #CDDM_merge_verts.
+ * The function compares poly_source after applying vtargetmap, with poly_target.
+ * The two polys are identical if they share the same vertices in the same order, or in reverse order,
+ * but starting position loopstart may be different.
+ * The function is called with direct_reverse=1 for same order (i.e. same normal),
+ * and may be called again with direct_reverse=-1 for reverse order.
+ * \return 1 if polys are identical, 0 if polys are different.
+ */
+static int cddm_poly_compare(MLoop *mloop_array, MPoly *mpoly_source, MPoly *mpoly_target, const int *vtargetmap, const int direct_reverse)
+{
+ int vert_source, first_vert_source, vert_target;
+ int i_loop_source;
+ int i_loop_target, i_loop_target_start, i_loop_target_offset, i_loop_target_adjusted;
+ bool compare_completed = false;
+ bool same_loops = false;
+
+ MLoop *mloop_source, *mloop_target;
+
+ BLI_assert(direct_reverse == 1 || direct_reverse == -1);
+
+ i_loop_source = 0;
+ mloop_source = mloop_array + mpoly_source->loopstart;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ /* Find same vertex within mpoly_target's loops */
+ mloop_target = mloop_array + mpoly_target->loopstart;
+ for (i_loop_target = 0; i_loop_target < mpoly_target->totloop; i_loop_target++, mloop_target++) {
+ if (mloop_target->v == vert_source) {
+ break;
+ }
+ }
+
+ /* If same vertex not found, then polys cannot be equal */
+ if (i_loop_target >= mpoly_target->totloop) {
+ return false;
+ }
+
+ /* Now mloop_source and m_loop_target have one identical vertex */
+ /* mloop_source is at position 0, while m_loop_target has advanced to find identical vertex */
+ /* Go around the loop and check that all vertices match in same order */
+ /* Skipping source loops when consecutive source vertices are mapped to same target vertex */
+
+ i_loop_target_start = i_loop_target;
+ i_loop_target_offset = 0;
+ first_vert_source = vert_source;
+
+ compare_completed = false;
+ same_loops = false;
+
+ while (!compare_completed) {
+
+ vert_target = mloop_target->v;
+
+ /* First advance i_loop_source, until it points to different vertex, after mapping applied */
+ do {
+ i_loop_source++;
+
+ if (i_loop_source == mpoly_source->totloop) {
+ /* End of loops for source, must match end of loop for target. */
+ if (i_loop_target_offset == mpoly_target->totloop - 1) {
+ compare_completed = true;
+ same_loops = true;
+ break; /* Polys are identical */
+ }
+ else {
+ compare_completed = true;
+ same_loops = false;
+ break; /* Polys are different */
+ }
+ }
+
+ mloop_source++;
+ vert_source = mloop_source->v;
+
+ if (vtargetmap[vert_source] != -1) {
+ vert_source = vtargetmap[vert_source];
+ }
+ else {
+ /* All source loop vertices should be mapped */
+ BLI_assert(false);
+ }
+
+ } while (vert_source == vert_target);
+
+ if (compare_completed) {
+ break;
+ }
+
+ /* Now advance i_loop_target as well */
+ i_loop_target_offset++;
+
+ if (i_loop_target_offset == mpoly_target->totloop) {
+ /* End of loops for target only, that means no match */
+ /* except if all remaining source vertices are mapped to first target */
+ for (; i_loop_source < mpoly_source->totloop; i_loop_source++, mloop_source++) {
+ vert_source = vtargetmap[mloop_source->v];
+ if (vert_source != first_vert_source) {
+ compare_completed = true;
+ same_loops = false;
+ break;
+ }
+ }
+ if (!compare_completed) {
+ same_loops = true;
+ }
+ break;
+ }
+
+ /* Adjust i_loop_target for cycling around and for direct/reverse order defined by delta = +1 or -1 */
+ i_loop_target_adjusted = (i_loop_target_start + direct_reverse * i_loop_target_offset) % mpoly_target->totloop;
+ if (i_loop_target_adjusted < 0) {
+ i_loop_target_adjusted += mpoly_target->totloop;
+ }
+ mloop_target = mloop_array + mpoly_target->loopstart + i_loop_target_adjusted;
+ vert_target = mloop_target->v;
+
+ if (vert_target != vert_source) {
+ same_loops = false; /* Polys are different */
+ break;
+ }
+ }
+ return same_loops;
+}
+
+/* Utility stuff for using GHash with polys */
+
+typedef struct PolyKey {
+ int poly_index; /* index of the MPoly within the derived mesh */
+ int totloops; /* number of loops in the poly */
+ unsigned int hash_sum; /* Sum of all vertices indices */
+ unsigned int hash_xor; /* Xor of all vertices indices */
+} PolyKey;
+
+
+static unsigned int poly_gset_hash_fn(const void *key)
+{
+ const PolyKey *pk = key;
+ return pk->hash_sum;
+}
+
+static bool poly_gset_compare_fn(const void *k1, const void *k2)
+{
+ const PolyKey *pk1 = k1;
+ const PolyKey *pk2 = k2;
+ if ((pk1->hash_sum == pk2->hash_sum) &&
+ (pk1->hash_xor == pk2->hash_xor) &&
+ (pk1->totloops == pk2->totloops))
+ {
+ /* Equality - note that this does not mean equality of polys */
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
+/**
* Merge Verts
*
+ * This frees dm, and returns a new one.
+ *
* \param vtargetmap The table that maps vertices to target vertices. a value of -1
* indicates a vertex is a target, and is to be kept.
* This array is aligned with 'dm->numVertData'
*
- * \param tot_vtargetmap The number of non '-1' values in vtargetmap.
- * (not the size )
+ * \param tot_vtargetmap The number of non '-1' values in vtargetmap. (not the size)
*
- * this frees dm, and returns a new one.
+ * \param merge_mode enum with two modes.
+ * - #CDDM_MERGE_VERTS_DUMP_IF_MAPPED
+ * When called by the Mirror Modifier,
+ * In this mode it skips any faces that have all vertices merged (to avoid creating pairs
+ * of faces sharing the same set of vertices)
+ * - #CDDM_MERGE_VERTS_DUMP_IF_EQUAL
+ * When called by the Array Modifier,
+ * In this mode, faces where all vertices are merged are double-checked,
+ * to see whether all target vertices actually make up a poly already.
+ * Indeed it could be that all of a poly's vertices are merged,
+ * but merged to vertices that do not make up a single poly,
+ * in which case the original poly should not be dumped.
+ * Actually this later behavior could apply to the Mirror Modifier as well, but the additional checks are
+ * costly and not necessary in the case of mirror, because each vertex is only merged to its own mirror.
*
- * note, CDDM_recalc_tessellation has to run on the returned DM if you want to access tessfaces.
- *
- * Note: This function is currently only used by the Mirror modifier, so it
- * skips any faces that have all vertices merged (to avoid creating pairs
- * of faces sharing the same set of vertices). If used elsewhere, it may
- * be necessary to make this functionality optional.
+ * \note #CDDM_recalc_tessellation has to run on the returned DM if you want to access tessfaces.
*/
-DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap)
+DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int tot_vtargetmap, const int merge_mode)
{
// #define USE_LOOPS
CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
@@ -2589,16 +2801,19 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
EdgeHash *ehash = BLI_edgehash_new_ex(__func__, totedge);
int i, j, c;
-
- STACK_INIT(oldv);
- STACK_INIT(olde);
- STACK_INIT(oldl);
- STACK_INIT(oldp);
- STACK_INIT(mvert);
- STACK_INIT(medge);
- STACK_INIT(mloop);
- STACK_INIT(mpoly);
+ PolyKey *poly_keys;
+ GSet *poly_gset = NULL;
+
+ STACK_INIT(oldv, totvert_final);
+ STACK_INIT(olde, totedge);
+ STACK_INIT(oldl, totloop);
+ STACK_INIT(oldp, totpoly);
+
+ STACK_INIT(mvert, totvert_final);
+ STACK_INIT(medge, totedge);
+ STACK_INIT(mloop, totloop);
+ STACK_INIT(mpoly, totpoly);
/* fill newl with destination vertex indices */
mv = cddm->mvert;
@@ -2631,10 +2846,9 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
med = cddm->medge;
c = 0;
for (i = 0; i < totedge; i++, med++) {
-
- if (LIKELY(med->v1 != med->v2)) {
- 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;
+ 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);
if (eh_p) {
@@ -2653,13 +2867,49 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
}
}
+ if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* In this mode, we need to determine, whenever a poly' vertices are all mapped */
+ /* if the targets already make up a poly, in which case the new poly is dropped */
+ /* 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);
+ /* Duplicates allowed because our compare function is not pure equality */
+ BLI_gset_flag_set(poly_gset, GHASH_FLAG_ALLOW_DUPES);
+
+ mp = cddm->mpoly;
+ mpgh = poly_keys;
+ for (i = 0; i < totpoly; i++, mp++, mpgh++) {
+ mpgh->poly_index = i;
+ mpgh->totloops = mp->totloop;
+ ml = cddm->mloop + mp->loopstart;
+ mpgh->hash_sum = mpgh->hash_xor = 0;
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ mpgh->hash_sum += ml->v;
+ mpgh->hash_xor ^= ml->v;
+ }
+ BLI_gset_insert(poly_gset, mpgh);
+ }
+
+ if (cddm->pmap) {
+ MEM_freeN(cddm->pmap);
+ MEM_freeN(cddm->pmap_mem);
+ }
+ /* Can we optimise by reusing an old pmap ? How do we know an old pmap is stale ? */
+ /* When called by MOD_array.c, the cddm has just been created, so it has no valid pmap. */
+ BKE_mesh_vert_poly_map_create(&cddm->pmap, &cddm->pmap_mem,
+ cddm->mpoly, cddm->mloop,
+ totvert, totpoly, totloop);
+ } /* done preparing for fast poly compare */
+
+
mp = cddm->mpoly;
for (i = 0; i < totpoly; i++, mp++) {
MPoly *mp_new;
ml = cddm->mloop + mp->loopstart;
- /* skip faces with all vertices merged */
+ /* check faces with all vertices merged */
{
bool all_vertices_merged = true;
@@ -2671,16 +2921,86 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
}
if (UNLIKELY(all_vertices_merged)) {
- continue;
+ if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_MAPPED) {
+ /* In this mode, all vertices merged is enough to dump face */
+ continue;
+ }
+ else if (merge_mode == CDDM_MERGE_VERTS_DUMP_IF_EQUAL) {
+ /* Additional condition for face dump: target vertices must make up an identical face */
+ /* The test has 2 steps: (1) first step is fast ghash lookup, but not failproof */
+ /* (2) second step is thorough but more costly poly compare */
+ int i_poly, v_target, v_prev;
+ bool found = false;
+ PolyKey pkey;
+
+ /* Use poly_gset for fast (although not 100% certain) identification of same poly */
+ /* First, make up a poly_summary structure */
+ ml = cddm->mloop + mp->loopstart;
+ pkey.hash_sum = pkey.hash_xor = 0;
+ pkey.totloops = 0;
+ v_prev = vtargetmap[(ml + mp->totloop -1)->v]; /* since it loops around, the prev of first is the last */
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ v_target = vtargetmap[ml->v]; /* Cannot be -1, they are all mapped */
+ if (v_target == v_prev) {
+ /* consecutive vertices in loop map to the same target: discard */
+ /* but what about last to first ? */
+ continue;
+ }
+ pkey.hash_sum += v_target;
+ pkey.hash_xor ^= v_target;
+ pkey.totloops++;
+ v_prev = v_target;
+ }
+ if (BLI_gset_haskey(poly_gset, &pkey)) {
+
+ /* There might be a poly that matches this one.
+ * We could just leave it there and say there is, and do a "continue".
+ * ... but we are checking whether there is an exact poly match.
+ * It's not so costly in terms of CPU since it's very rare, just a lot of complex code.
+ */
+
+ /* Consider current loop again */
+ ml = cddm->mloop + mp->loopstart;
+ /* Consider the target of the loop's first vert */
+ v_target = vtargetmap[ml->v];
+ /* Now see if v_target belongs to a poly that shares all vertices with source poly,
+ * in same order, or reverse order */
+
+ for (i_poly = 0; i_poly < cddm->pmap[v_target].count; i_poly++) {
+ MPoly *target_poly = cddm->mpoly + *(cddm->pmap[v_target].indices + i_poly);
+
+ if (cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, +1) ||
+ cddm_poly_compare(cddm->mloop, mp, target_poly, vtargetmap, -1))
+ {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ /* Current poly's vertices are mapped to a poly that is strictly identical */
+ /* Current poly is dumped */
+ continue;
+ }
+ }
+ }
}
}
+
+ /* Here either the poly's vertices were not all merged
+ * or they were all merged, but targets do not make up an identical poly,
+ * the poly is retained.
+ */
ml = cddm->mloop + mp->loopstart;
c = 0;
for (j = 0; j < mp->totloop; j++, ml++) {
+ unsigned int v1, v2;
+
med = cddm->medge + ml->e;
- if (LIKELY(med->v1 != med->v2)) {
+ v1 = (vtargetmap[med->v1] != -1) ? vtargetmap[med->v1] : med->v1;
+ v2 = (vtargetmap[med->v2] != -1) ? vtargetmap[med->v2] : med->v2;
+ if (LIKELY(v1 != v2)) {
#ifdef USE_LOOPS
newl[j + mp->loopstart] = STACK_SIZE(mloop);
#endif
@@ -2693,13 +3013,28 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
if (UNLIKELY(c == 0)) {
continue;
}
+ else if (UNLIKELY(c < 3)) {
+ STACK_DISCARD(oldl, c);
+ STACK_DISCARD(mloop, c);
+ continue;
+ }
+
mp_new = STACK_PUSH_RET_PTR(mpoly);
*mp_new = *mp;
mp_new->totloop = c;
+ BLI_assert(mp_new->totloop >= 3);
mp_new->loopstart = STACK_SIZE(mloop) - c;
STACK_PUSH(oldp, i);
+ } /* end of the loop that tests polys */
+
+
+ if (poly_gset) {
+ // printf("hash quality %.6f\n", BLI_gset_calc_quality(poly_gset));
+
+ BLI_gset_free(poly_gset, NULL);
+ MEM_freeN(poly_keys);
}
/*create new cddm*/
@@ -2761,16 +3096,6 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, const int *vtargetmap, const int
MEM_freeN(oldl);
MEM_freeN(oldp);
- STACK_FREE(oldv);
- STACK_FREE(olde);
- STACK_FREE(oldl);
- STACK_FREE(oldp);
-
- STACK_FREE(mvert);
- STACK_FREE(medge);
- STACK_FREE(mloop);
- STACK_FREE(mpoly);
-
BLI_edgehash_free(ehash, NULL);
/*free old derivedmesh*/
@@ -2794,15 +3119,15 @@ void CDDM_calc_edges_tessface(DerivedMesh *dm)
eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_POLYS(numFaces));
for (i = 0; i < numFaces; i++, mf++) {
- BLI_edgeset_reinsert(eh, mf->v1, mf->v2);
- BLI_edgeset_reinsert(eh, mf->v2, mf->v3);
+ BLI_edgeset_add(eh, mf->v1, mf->v2);
+ BLI_edgeset_add(eh, mf->v2, mf->v3);
if (mf->v4) {
- BLI_edgeset_reinsert(eh, mf->v3, mf->v4);
- BLI_edgeset_reinsert(eh, mf->v4, mf->v1);
+ BLI_edgeset_add(eh, mf->v3, mf->v4);
+ BLI_edgeset_add(eh, mf->v4, mf->v1);
}
else {
- BLI_edgeset_reinsert(eh, mf->v3, mf->v1);
+ BLI_edgeset_add(eh, mf->v3, mf->v1);
}
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index f5c7f9e4501..aacf02555d4 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -228,7 +228,7 @@ void bvhtree_update_from_cloth(ClothModifierData *clmd, int moving)
ClothVertex *verts = cloth->verts;
MFace *mfaces;
float co[12], co_moving[12];
- int ret = 0;
+ bool ret = false;
if (!bvhtree)
return;
@@ -1323,14 +1323,14 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
/* insert other near springs in edgeset AFTER bending springs are calculated (for selfcolls) */
for (i = 0; i < numedges; i++) { /* struct springs */
- BLI_edgeset_reinsert(edgeset, medge[i].v1, medge[i].v2);
+ BLI_edgeset_add(edgeset, medge[i].v1, medge[i].v2);
}
for (i = 0; i < numfaces; i++) { /* edge springs */
if (mface[i].v4) {
- BLI_edgeset_reinsert(edgeset, mface[i].v1, mface[i].v3);
+ BLI_edgeset_add(edgeset, mface[i].v1, mface[i].v3);
- BLI_edgeset_reinsert(edgeset, mface[i].v2, mface[i].v4);
+ BLI_edgeset_add(edgeset, mface[i].v2, mface[i].v4);
}
}
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index cedd9eae597..2f600935b1e 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -110,7 +110,7 @@ void bvhtree_update_from_mvert(BVHTree *bvhtree, MFace *faces, int numfaces, MVe
int i;
MFace *mfaces = faces;
float co[12], co_moving[12];
- int ret = 0;
+ bool ret = false;
if ( !bvhtree )
return;
diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c
index c6d07a959d1..a63e06c7cb8 100644
--- a/source/blender/blenkernel/intern/colortools.c
+++ b/source/blender/blenkernel/intern/colortools.c
@@ -577,14 +577,14 @@ static void curvemap_make_table(CurveMap *cuma, const rctf *clipr)
/* store first and last handle for extrapolation, unit length */
cuma->ext_in[0] = bezt[0].vec[0][0] - bezt[0].vec[1][0];
cuma->ext_in[1] = bezt[0].vec[0][1] - bezt[0].vec[1][1];
- range = sqrt(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]);
+ range = sqrtf(cuma->ext_in[0] * cuma->ext_in[0] + cuma->ext_in[1] * cuma->ext_in[1]);
cuma->ext_in[0] /= range;
cuma->ext_in[1] /= range;
a = cuma->totpoint - 1;
cuma->ext_out[0] = bezt[a].vec[1][0] - bezt[a].vec[2][0];
cuma->ext_out[1] = bezt[a].vec[1][1] - bezt[a].vec[2][1];
- range = sqrt(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]);
+ range = sqrtf(cuma->ext_out[0] * cuma->ext_out[0] + cuma->ext_out[1] * cuma->ext_out[1]);
cuma->ext_out[0] /= range;
cuma->ext_out[1] /= range;
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 52cfa92ceaf..8a5d313e3fb 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -185,6 +185,10 @@ void BKE_constraints_clear_evalob(bConstraintOb *cob)
/* calculate delta of constraints evaluation */
invert_m4_m4(imat, cob->startmat);
+ /* XXX This would seem to be in wrong order. However, it does not work in 'right' order - would be nice to
+ * understand why premul is needed here instead of usual postmul?
+ * In any case, we **do not get a delta** here (e.g. startmat & matrix having same location, still gives
+ * a 'delta' with non-null translation component :/ ).*/
mul_m4_m4m4(delta, cob->matrix, imat);
/* copy matrices back to source */
@@ -1158,7 +1162,6 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) {
Curve *cu = ct->tar->data;
float vec[4], dir[3], radius;
- float totmat[4][4] = MAT4_UNITY;
float curvetime;
unit_m4(ct->matrix);
@@ -1206,6 +1209,9 @@ static void followpath_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
}
if (where_on_path(ct->tar, curvetime, vec, dir, (data->followflag & FOLLOWPATH_FOLLOW) ? quat : NULL, &radius, NULL) ) { /* quat_pt is quat or NULL*/
+ float totmat[4][4];
+ unit_m4(totmat);
+
if (data->followflag & FOLLOWPATH_FOLLOW) {
#if 0
float x1, q[4];
@@ -2611,6 +2617,8 @@ static void stretchto_new_data(void *cdata)
data->plane = 0;
data->orglength = 0.0;
data->bulge = 1.0;
+ data->bulge_max = 1.0f;
+ data->bulge_min = 1.0f;
}
static void stretchto_id_looper(bConstraint *con, ConstraintIDFunc func, void *userdata)
@@ -2656,7 +2664,7 @@ static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
if (VALID_CONS_TARGET(ct)) {
float size[3], scale[3], vec[3], xx[3], zz[3], orth[3];
float totmat[3][3];
- float dist;
+ float dist, bulge;
/* store scaling before destroying obmat */
mat4_to_size(size, cob->matrix);
@@ -2674,7 +2682,7 @@ static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
/* vec[2] /= size[2];*/
/* dist = normalize_v3(vec);*/
-
+
dist = len_v3v3(cob->matrix[3], ct->matrix[3]);
/* Only Y constrained object axis scale should be used, to keep same length when scaling it. */
dist /= size[1];
@@ -2682,23 +2690,49 @@ static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
/* data->orglength==0 occurs on first run, and after 'R' button is clicked */
if (data->orglength == 0)
data->orglength = dist;
- if (data->bulge == 0)
- data->bulge = 1.0;
-
+
scale[1] = dist / data->orglength;
+
+ bulge = powf(data->orglength / dist, data->bulge);
+
+ if (bulge > 1.0f) {
+ if (data->flag & STRETCHTOCON_USE_BULGE_MAX) {
+ float bulge_max = max_ff(data->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) / (0.5f * M_PI);
+
+ bulge = interpf(soft, hard, data->bulge_smooth);
+ }
+ }
+ if (bulge < 1.0f) {
+ if (data->flag & STRETCHTOCON_USE_BULGE_MIN) {
+ float bulge_min = CLAMPIS(data->bulge_max, 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) / (0.5f * M_PI);
+
+ bulge = interpf(soft, hard, data->bulge_smooth);
+ }
+ }
+
switch (data->volmode) {
/* volume preserving scaling */
case VOLUME_XZ:
- scale[0] = 1.0f - sqrtf(data->bulge) + sqrtf(data->bulge * (data->orglength / dist));
+ scale[0] = sqrtf(bulge);
scale[2] = scale[0];
break;
case VOLUME_X:
- scale[0] = 1.0f + data->bulge * (data->orglength / dist - 1);
+ scale[0] = bulge;
scale[2] = 1.0;
break;
case VOLUME_Z:
scale[0] = 1.0;
- scale[2] = 1.0f + data->bulge * (data->orglength / dist - 1);
+ scale[2] = bulge;
break;
/* don't care for volume */
case NO_VOLUME:
@@ -3039,11 +3073,12 @@ static void clampto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar
if (VALID_CONS_TARGET(ct) && (ct->tar->type == OB_CURVE)) {
float obmat[4][4], ownLoc[3];
float curveMin[3], curveMax[3];
- float targetMatrix[4][4] = MAT4_UNITY;
+ float targetMatrix[4][4];
copy_m4_m4(obmat, cob->matrix);
copy_v3_v3(ownLoc, obmat[3]);
+ unit_m4(targetMatrix);
INIT_MINMAX(curveMin, curveMax);
/* XXX - don't think this is good calling this here - campbell */
BKE_object_minmax(ct->tar, curveMin, curveMax, true);
@@ -3267,7 +3302,9 @@ static void transform_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
to_max = data->to_max_scale;
for (i = 0; i < 3; i++) {
/* multiply with original scale (so that it can still be scaled) */
- size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
+ /* size[i] *= to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i])); */
+ /* Stay absolute, else it breaks existing rigs... sigh. */
+ size[i] = to_min[i] + (sval[(int)data->map[i]] * (to_max[i] - to_min[i]));
}
break;
case TRANS_ROTATION:
@@ -3370,7 +3407,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
unit_m4(ct->matrix);
if (target != NULL) {
- space_transform_from_matrixs(&transform, cob->matrix, ct->tar->obmat);
+ BLI_space_transform_from_matrices(&transform, cob->matrix, ct->tar->obmat);
switch (scon->shrinkType) {
case MOD_SHRINKWRAP_NEAREST_SURFACE:
@@ -3392,7 +3429,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
break;
}
- space_transform_apply(&transform, co);
+ BLI_space_transform_apply(&transform, co);
BLI_bvhtree_find_nearest(treeData.tree, co, &nearest, treeData.nearest_callback, &treeData);
@@ -3400,7 +3437,7 @@ static void shrinkwrap_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstra
if (dist != 0.0f) {
interp_v3_v3v3(co, co, nearest.co, (dist - scon->dist) / dist); /* linear interpolation */
}
- space_transform_invert(&transform, co);
+ BLI_space_transform_invert(&transform, co);
break;
}
case MOD_SHRINKWRAP_PROJECT:
@@ -3587,7 +3624,7 @@ static void damptrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
cross_v3_v3v3(raxis, obvec, tarvec);
rangle = dot_v3v3(obvec, tarvec);
- rangle = acos(max_ff(-1.0f, min_ff(1.0f, rangle)));
+ rangle = acosf(max_ff(-1.0f, min_ff(1.0f, rangle)));
/* 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
@@ -3904,7 +3941,7 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, framenr, imat);
invert_m4(imat);
- mul_serie_m4(cob->matrix, obmat, mat, imat, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(cob->matrix, obmat, mat, imat);
translate_m4(cob->matrix, track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
}
else {
@@ -3938,19 +3975,31 @@ static void followtrack_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
if (len > FLT_EPSILON) {
CameraParams params;
+ int width, height;
float pos[2], rmat[4][4];
+ BKE_movieclip_get_size(clip, NULL, &width, &height);
+
marker = BKE_tracking_marker_get(track, framenr);
add_v2_v2v2(pos, marker->pos, track->offset);
+ if (data->flag & FOLLOWTRACK_USE_UNDISTORTION) {
+ /* Undistortion need to happen in pixel space. */
+ pos[0] *= width;
+ pos[1] *= height;
+
+ BKE_tracking_undistort_v2(tracking, pos, pos);
+
+ /* Normalize pixel coordinates back. */
+ pos[0] /= width;
+ pos[1] /= height;
+ }
+
/* aspect correction */
if (data->frame_method != FOLLOWTRACK_FRAME_STRETCH) {
- int width, height;
float w_src, h_src, w_dst, h_dst, asp_src, asp_dst;
- BKE_movieclip_get_size(clip, NULL, &width, &height);
-
/* apply clip display aspect */
w_src = width * clip->aspx;
h_src = height * clip->aspy;
@@ -4182,7 +4231,7 @@ static void objectsolver_evaluate(bConstraint *con, bConstraintOb *cob, ListBase
invert_m4_m4(imat, mat);
- mul_serie_m4(cob->matrix, cammat, imat, camimat, parmat, obmat, NULL, NULL, NULL);
+ mul_m4_series(cob->matrix, cammat, imat, camimat, parmat, obmat);
}
}
}
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 89ba2e9d68b..de285f87444 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -48,7 +48,6 @@
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_screen.h"
-#include "BKE_freestyle.h"
#include "RNA_access.h"
@@ -290,7 +289,7 @@ static int ctx_data_get(bContext *C, const char *member, bContextDataResult *res
return done;
/* we check recursion to ensure that we do not get infinite
- * loops requesting data from ourselfs in a context callback */
+ * loops requesting data from ourselves in a context callback */
/* Ok, this looks evil...
* if (ret) done = -(-ret | -done);
@@ -1091,16 +1090,3 @@ int CTX_data_visible_pose_bones(const bContext *C, ListBase *list)
{
return ctx_data_collection_get(C, "visible_pose_bones", list);
}
-
-FreestyleLineStyle *CTX_data_linestyle_from_scene(Scene *scene)
-{
- SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
- FreestyleConfig *config = &actsrl->freestyleConfig;
- FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
-
- if (lineset) {
- return lineset->linestyle;
- }
-
- return NULL;
-}
diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c
index 3fde1cdd710..911bb19a594 100644
--- a/source/blender/blenkernel/intern/crazyspace.c
+++ b/source/blender/blenkernel/intern/crazyspace.c
@@ -40,7 +40,6 @@
#include "BLI_utildefines.h"
#include "BLI_math.h"
-#include "BLI_bitmap.h"
#include "BKE_crazyspace.h"
#include "BKE_DerivedMesh.h"
@@ -49,11 +48,6 @@
#include "BKE_mesh.h"
#include "BKE_editmesh.h"
-typedef struct {
- float (*vertexcos)[3];
- BLI_bitmap *vertex_visit;
-} MappedUserData;
-
BLI_INLINE void tan_calc_quat_v3(
float r_quat[4],
const float co_1[3], const float co_2[3], const float co_3[3])
@@ -88,20 +82,6 @@ static void set_crazy_vertex_quat(
sub_qt_qtqt(r_quat, q2, q1);
}
-static void make_vertexcos__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- MappedUserData *mappedData = (MappedUserData *)userData;
-
- if (BLI_BITMAP_GET(mappedData->vertex_visit, index) == 0) {
- /* we need coord from prototype vertex, not from copies,
- * assume they stored in the beginning of vertex array stored in DM
- * (mirror modifier for eg does this) */
- copy_v3_v3(mappedData->vertexcos[index], co);
- BLI_BITMAP_SET(mappedData->vertex_visit, index);
- }
-}
-
static int modifiers_disable_subsurf_temporary(Object *ob)
{
ModifierData *md;
@@ -124,8 +104,6 @@ float (*BKE_crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3]
DerivedMesh *dm;
float (*vertexcos)[3];
int nverts = me->edit_btmesh->bm->totvert;
- BLI_bitmap *vertex_visit;
- MappedUserData userData;
/* disable subsurf temporal, get mapped cos, and enable it */
if (modifiers_disable_subsurf_temporary(obedit)) {
@@ -134,22 +112,17 @@ float (*BKE_crazyspace_get_mapped_editverts(Scene *scene, Object *obedit))[3]
}
/* now get the cage */
- dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
+ vertexcos = MEM_mallocN(sizeof(*vertexcos) * nverts, "vertexcos map");
- vertexcos = MEM_callocN(sizeof(*vertexcos) * nverts, "vertexcos map");
- vertex_visit = BLI_BITMAP_NEW(nverts, "vertexcos flags");
+ dm = editbmesh_get_derived_cage(scene, obedit, me->edit_btmesh, CD_MASK_BAREMESH);
- userData.vertexcos = vertexcos;
- userData.vertex_visit = vertex_visit;
- dm->foreachMappedVert(dm, make_vertexcos__mapFunc, &userData, DM_FOREACH_NOP);
+ mesh_get_mapped_verts_coords(dm, vertexcos, nverts);
dm->release(dm);
/* set back the flag, no new cage needs to be built, transform does it */
modifiers_disable_subsurf_temporary(obedit);
- MEM_freeN(vertex_visit);
-
return vertexcos;
}
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 14fd44e594a..ca58035d638 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -52,6 +52,7 @@
#include "BKE_animsys.h"
#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
#include "BKE_displist.h"
#include "BKE_font.h"
#include "BKE_global.h"
@@ -642,8 +643,9 @@ void BKE_nurb_test2D(Nurb *nu)
}
}
-/* if use_radius is truth, minmax will take points' radius into account,
- * which will make boundbox closer to bevelled curve.
+/**
+ * if use_radius is truth, minmax will take points' radius into account,
+ * which will make boundbox closer to beveled curve.
*/
void BKE_nurb_minmax(Nurb *nu, bool use_radius, float min[3], float max[3])
{
@@ -717,7 +719,7 @@ void BKE_nurb_bezierPoints_add(Nurb *nu, int number)
BezTriple *bezt;
int i;
- nu->bezt = MEM_recallocN(nu->bp, (nu->pntsu + number) * sizeof(BezTriple));
+ nu->bezt = MEM_recallocN(nu->bezt, (nu->pntsu + number) * sizeof(BezTriple));
for (i = 0, bezt = &nu->bezt[nu->pntsu]; i < number; i++, bezt++) {
bezt->radius = 1.0f;
@@ -1085,12 +1087,6 @@ void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu,
sum = (float *)MEM_callocN(sizeof(float) * len, "makeNurbfaces1");
- len = totu * totv;
- if (len == 0) {
- MEM_freeN(sum);
- return;
- }
-
bp = nu->bp;
i = nu->pntsu * nu->pntsv;
ratcomp = 0;
@@ -1193,6 +1189,8 @@ void BKE_nurb_makeFaces(Nurb *nu, float *coord_array, int rowstride, int resolu,
}
}
+ zero_v3(in);
+
/* one! (1.0) real point now */
fp = sum;
for (j = jsta; j <= jen; j++) {
@@ -1307,6 +1305,8 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float *
}
}
+ zero_v3(coord_fp);
+
/* one! (1.0) real point */
fp = sum;
bp = nu->bp + istart - 1;
@@ -1473,7 +1473,7 @@ float *BKE_curve_surf_make_orco(Object *ob)
}
else {
int size = (nu->pntsu * resolu) * (nu->pntsv * resolv) * 3 * sizeof(float);
- float *_tdata = MEM_callocN(size, "temp data");
+ float *_tdata = MEM_mallocN(size, "temp data");
float *tdata = _tdata;
BKE_nurb_makeFaces(nu, tdata, 0, resolu, resolv);
@@ -1676,7 +1676,7 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
}
else if (cu->ext2 == 0.0f) {
dl = MEM_callocN(sizeof(DispList), "makebevelcurve2");
- dl->verts = MEM_mallocN(2 * 3 * sizeof(float), "makebevelcurve2");
+ dl->verts = MEM_mallocN(2 * sizeof(float[3]), "makebevelcurve2");
BLI_addtail(disp, dl);
dl->type = DL_SEGM;
dl->parts = 1;
@@ -1693,7 +1693,7 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
nr = 4 + 2 * cu->bevresol;
dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
- dl->verts = MEM_mallocN(nr * 3 * sizeof(float), "makebevelcurve p1");
+ dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p1");
BLI_addtail(disp, dl);
dl->type = DL_POLY;
dl->parts = 1;
@@ -1725,7 +1725,7 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
nr = 3 + 2 * cu->bevresol;
dl = MEM_callocN(sizeof(DispList), "makebevelcurve p1");
- dl->verts = MEM_mallocN(nr * 3 * sizeof(float), "makebevelcurve p1");
+ dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p1");
BLI_addtail(disp, dl);
dl->type = DL_SEGM;
dl->parts = 1;
@@ -1751,7 +1751,7 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
nr = 2;
dl = MEM_callocN(sizeof(DispList), "makebevelcurve p2");
- dl->verts = MEM_callocN(nr * 3 * sizeof(float), "makebevelcurve p2");
+ dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p2");
BLI_addtail(disp, dl);
dl->type = DL_SEGM;
dl->parts = 1;
@@ -1783,7 +1783,7 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
nr = 3 + 2 * cu->bevresol;
dl = MEM_callocN(sizeof(DispList), "makebevelcurve p3");
- dl->verts = MEM_mallocN(nr * 3 * sizeof(float), "makebevelcurve p3");
+ dl->verts = MEM_mallocN(nr * sizeof(float[3]), "makebevelcurve p3");
BLI_addtail(disp, dl);
dl->type = DL_SEGM;
dl->flag = DL_FRONT_CURVE;
@@ -1855,7 +1855,7 @@ static bool bevelinside(BevList *bl1, BevList *bl2)
/* take first vertex of possible hole */
- bevp = (BevPoint *)(bl2 + 1);
+ bevp = bl2->bevpoints;
hvec1[0] = bevp->vec[0];
hvec1[1] = bevp->vec[1];
hvec1[2] = 0.0;
@@ -1865,7 +1865,7 @@ static bool bevelinside(BevList *bl1, BevList *bl2)
/* test it with all edges of potential surounding poly */
/* count number of transitions left-right */
- bevp = (BevPoint *)(bl1 + 1);
+ bevp = bl1->bevpoints;
nr = bl1->nr;
prevbevp = bevp + (nr - 1);
@@ -2051,7 +2051,7 @@ static void bevel_list_calc_bisect(BevList *bl)
bool is_cyclic = bl->poly != -1;
if (is_cyclic) {
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
bevp0 = bevp1 - 1;
nr = bl->nr;
@@ -2065,7 +2065,7 @@ static void bevel_list_calc_bisect(BevList *bl)
* of direction for this guys.
*/
- bevp0 = (BevPoint *)(bl + 1);
+ bevp0 = bl->bevpoints;
bevp1 = bevp0 + 1;
bevp2 = bevp1 + 1;
@@ -2086,7 +2086,7 @@ static void bevel_list_flip_tangents(BevList *bl)
BevPoint *bevp2, *bevp1, *bevp0;
int nr;
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
bevp0 = bevp1 - 1;
@@ -2107,7 +2107,7 @@ static void bevel_list_apply_tilt(BevList *bl)
int nr;
float q[4];
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
nr = bl->nr;
@@ -2131,7 +2131,7 @@ static void bevel_list_smooth(BevList *bl, int smooth_iter)
int a;
for (a = 0; a < smooth_iter; a++) {
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
bevp0 = bevp1 - 1;
@@ -2177,7 +2177,7 @@ static void bevel_list_smooth(BevList *bl, int smooth_iter)
static void make_bevel_list_3D_zup(BevList *bl)
{
- BevPoint *bevp = (BevPoint *)(bl + 1);
+ BevPoint *bevp = bl->bevpoints;
int nr = bl->nr;
bevel_list_calc_bisect(bl);
@@ -2212,7 +2212,7 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
bevel_list_calc_bisect(bl);
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
bevp0 = bevp1 - 1;
@@ -2250,7 +2250,7 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
BevPoint *bevp_last;
- bevp_first = (BevPoint *)(bl + 1);
+ bevp_first = bl->bevpoints;
bevp_first += bl->nr - 1;
bevp_last = bevp_first;
bevp_last--;
@@ -2278,7 +2278,7 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
if (angle_normalized_v3v3(bevp_first->dir, cross_tmp) < DEG2RADF(90.0f))
angle = -angle;
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
bevp0 = bevp1 - 1;
@@ -2300,11 +2300,11 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl)
* using it's own direction, which might not correspond
* the twist of neighbor point.
*/
- bevp1 = (BevPoint *)(bl + 1);
+ bevp1 = bl->bevpoints;
bevp0 = bevp1 + 1;
minimum_twist_between_two_points(bevp1, bevp0);
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
bevp0 = bevp1 - 1;
minimum_twist_between_two_points(bevp1, bevp0);
@@ -2322,7 +2322,7 @@ static void make_bevel_list_3D_tangent(BevList *bl)
bevel_list_flip_tangents(bl);
/* correct the tangents */
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
bevp0 = bevp1 - 1;
@@ -2340,7 +2340,7 @@ static void make_bevel_list_3D_tangent(BevList *bl)
/* now for the real twist calc */
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
bevp0 = bevp1 - 1;
@@ -2387,7 +2387,7 @@ static void make_bevel_list_segment_3D(BevList *bl)
{
float q[4];
- BevPoint *bevp2 = (BevPoint *)(bl + 1);
+ BevPoint *bevp2 = bl->bevpoints;
BevPoint *bevp1 = bevp2 + 1;
/* simple quat/dir */
@@ -2406,7 +2406,7 @@ static void make_bevel_list_segment_3D(BevList *bl)
/* only for 2 points */
static void make_bevel_list_segment_2D(BevList *bl)
{
- BevPoint *bevp2 = (BevPoint *)(bl + 1);
+ BevPoint *bevp2 = bl->bevpoints;
BevPoint *bevp1 = bevp2 + 1;
const float x1 = bevp1->vec[0] - bevp2->vec[0];
@@ -2429,13 +2429,13 @@ static void make_bevel_list_2D(BevList *bl)
int nr;
if (bl->poly != -1) {
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
bevp1 = bevp2 + (bl->nr - 1);
bevp0 = bevp1 - 1;
nr = bl->nr;
}
else {
- bevp0 = (BevPoint *)(bl + 1);
+ bevp0 = bl->bevpoints;
bevp1 = bevp0 + 1;
bevp2 = bevp1 + 1;
@@ -2467,16 +2467,16 @@ static void make_bevel_list_2D(BevList *bl)
float angle;
/* first */
- bevp = (BevPoint *)(bl + 1);
- angle = atan2(bevp->dir[0], bevp->dir[1]) - M_PI / 2.0;
+ bevp = bl->bevpoints;
+ angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)(M_PI / 2.0f);
bevp->sina = sinf(angle);
bevp->cosa = cosf(angle);
vec_to_quat(bevp->quat, bevp->dir, 5, 1);
/* last */
- bevp = (BevPoint *)(bl + 1);
+ bevp = bl->bevpoints;
bevp += (bl->nr - 1);
- angle = atan2(bevp->dir[0], bevp->dir[1]) - M_PI / 2.0;
+ angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)(M_PI / 2.0f);
bevp->sina = sinf(angle);
bevp->cosa = cosf(angle);
vec_to_quat(bevp->quat, bevp->dir, 5, 1);
@@ -2489,7 +2489,7 @@ static void bevlist_firstlast_direction_calc_from_bpoint(Nurb *nu, BevList *bl)
BPoint *first_bp = nu->bp, *last_bp = nu->bp + (nu->pntsu - 1);
BevPoint *first_bevp, *last_bevp;
- first_bevp = (BevPoint *)(bl + 1);
+ first_bevp = bl->bevpoints;
last_bevp = first_bevp + (bl->nr - 1);
sub_v3_v3v3(first_bevp->dir, (first_bp + 1)->vec, first_bp->vec);
@@ -2500,29 +2500,53 @@ static void bevlist_firstlast_direction_calc_from_bpoint(Nurb *nu, BevList *bl)
}
}
+void BKE_curve_bevelList_free(ListBase *bev)
+{
+ BevList *bl, *blnext;
+ for (bl = bev->first; bl != NULL; bl = blnext) {
+ blnext = bl->next;
+ if (bl->seglen != NULL) {
+ MEM_freeN(bl->seglen);
+ }
+ if (bl->segbevcount != NULL) {
+ MEM_freeN(bl->segbevcount);
+ }
+ MEM_freeN(bl);
+ }
+ bev->first = bev->last = NULL;
+}
+
void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
{
/*
* - convert all curves to polys, with indication of resol and flags for double-vertices
* - possibly; do a smart vertice removal (in case Nurb)
- * - separate in individual blicks with BoundBox
+ * - separate in individual blocks with BoundBox
* - AutoHole detection
*/
- Curve *cu;
+
+ /* this function needs an object, because of tflag and upflag */
+ Curve *cu = ob->data;
Nurb *nu;
BezTriple *bezt, *prevbezt;
BPoint *bp;
BevList *bl, *blnew, *blnext;
BevPoint *bevp, *bevp2, *bevp1 = NULL, *bevp0;
+ const float treshold = 0.00001f;
float min, inp;
+ float *seglen;
struct BevelSort *sortdata, *sd, *sd1;
- int a, b, nr, poly, resolu = 0, len = 0;
+ int a, b, nr, poly, resolu = 0, len = 0, segcount;
+ int *segbevcount;
bool do_tilt, do_radius, do_weight;
bool is_editmode = false;
ListBase *bev;
- /* this function needs an object, because of tflag and upflag */
- cu = ob->data;
+ /* segbevcount alsp requires seglen. */
+ const bool need_seglen =
+ ELEM(cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) ||
+ ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE);
+
bev = &ob->curve_cache->bev;
@@ -2531,7 +2555,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
/* STEP 1: MAKE POLYS */
- BLI_freelistN(&(ob->curve_cache->bev));
+ BKE_curve_bevelList_free(&ob->curve_cache->bev);
nu = nurbs->first;
if (cu->editnurb && ob->type != OB_FONT) {
is_editmode = 1;
@@ -2561,17 +2585,26 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
else
resolu = nu->resolu;
+ segcount = SEGMENTSU(nu);
+
if (nu->type == CU_POLY) {
len = nu->pntsu;
bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList2");
+ if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
+ bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList2_seglen");
+ bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList2_segbevcount");
+ }
BLI_addtail(bev, bl);
bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
bl->nr = len;
bl->dupe_nr = 0;
bl->charidx = nu->charidx;
- bevp = (BevPoint *)(bl + 1);
+ bevp = bl->bevpoints;
+ bevp->offset = 0;
bp = nu->bp;
+ seglen = bl->seglen;
+ segbevcount = bl->segbevcount;
while (len--) {
copy_v3_v3(bevp->vec, bp->vec);
@@ -2579,8 +2612,19 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
bevp->radius = bp->radius;
bevp->weight = bp->weight;
bevp->split_tag = true;
- bevp++;
bp++;
+ if (seglen != NULL && len != 0) {
+ *seglen = len_v3v3(bevp->vec, bp->vec);
+ bevp++;
+ bevp->offset = *seglen;
+ if (*seglen > treshold) *segbevcount = 1;
+ else *segbevcount = 0;
+ seglen++;
+ segbevcount++;
+ }
+ else {
+ bevp++;
+ }
}
if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
@@ -2589,13 +2633,27 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
}
else if (nu->type == CU_BEZIER) {
/* in case last point is not cyclic */
- len = resolu * (nu->pntsu + (nu->flagu & CU_NURB_CYCLIC) - 1) + 1;
+ len = segcount * resolu + 1;
+
bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelBPoints");
+ if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
+ bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelBPoints_seglen");
+ bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelBPoints_segbevcount");
+ }
BLI_addtail(bev, bl);
bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
bl->charidx = nu->charidx;
- bevp = (BevPoint *)(bl + 1);
+
+ bevp = bl->bevpoints;
+ seglen = bl->seglen;
+ segbevcount = bl->segbevcount;
+
+ bevp->offset = 0;
+ if (seglen != NULL) {
+ *seglen = 0;
+ *segbevcount = 0;
+ }
a = nu->pntsu - 1;
bezt = nu->bezt;
@@ -2611,6 +2669,8 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
sub_v3_v3v3(bevp->dir, prevbezt->vec[2], prevbezt->vec[1]);
normalize_v3(bevp->dir);
+ BLI_assert(segcount >= a);
+
while (a--) {
if (prevbezt->h2 == HD_VECT && bezt->h1 == HD_VECT) {
@@ -2623,6 +2683,14 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
bevp++;
bl->nr++;
bl->dupe_nr = 1;
+ if (seglen != NULL) {
+ *seglen = len_v3v3(prevbezt->vec[1], bezt->vec[1]);
+ bevp->offset = *seglen;
+ seglen++;
+ /* match segbevcount to the cleaned up bevel lists (see STEP 2) */
+ if (bevp->offset > treshold) *segbevcount = 1;
+ segbevcount++;
+ }
}
else {
/* always do all three, to prevent data hanging around */
@@ -2660,8 +2728,28 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
else if (prevbezt->h2 == 0 || prevbezt->h2 == HD_VECT)
bevp->split_tag = true;
}
+
+ /* seglen */
+ if (seglen != NULL) {
+ *seglen = 0;
+ *segbevcount = 0;
+ for (j = 0; j < resolu; j++) {
+ bevp0 = bevp;
+ bevp++;
+ bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
+ /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
+ if (bevp->offset > treshold) {
+ *seglen += bevp->offset;
+ *segbevcount += 1;
+ }
+ }
+ seglen++;
+ segbevcount++;
+ }
+ else {
+ bevp += resolu;
+ }
bl->nr += resolu;
- bevp += resolu;
}
prevbezt = bezt;
bezt++;
@@ -2681,15 +2769,22 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
}
else if (nu->type == CU_NURBS) {
if (nu->pntsv == 1) {
- len = (resolu * SEGMENTSU(nu));
+ len = (resolu * segcount);
bl = MEM_callocN(sizeof(BevList) + len * sizeof(BevPoint), "makeBevelList3");
+ if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) {
+ bl->seglen = MEM_mallocN(segcount * sizeof(float), "makeBevelList3_seglen");
+ bl->segbevcount = MEM_mallocN(segcount * sizeof(int), "makeBevelList3_segbevcount");
+ }
BLI_addtail(bev, bl);
bl->nr = len;
bl->dupe_nr = 0;
bl->poly = (nu->flagu & CU_NURB_CYCLIC) ? 0 : -1;
bl->charidx = nu->charidx;
- bevp = (BevPoint *)(bl + 1);
+
+ bevp = bl->bevpoints;
+ seglen = bl->seglen;
+ segbevcount = bl->segbevcount;
BKE_nurb_makeCurve(nu, &bevp->vec[0],
do_tilt ? &bevp->alfa : NULL,
@@ -2697,6 +2792,31 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
do_weight ? &bevp->weight : NULL,
resolu, sizeof(BevPoint));
+ /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */
+ if (seglen != NULL) {
+ nr = segcount;
+ bevp0 = bevp;
+ bevp++;
+ while (nr) {
+ int j;
+ *seglen = 0;
+ *segbevcount = 0;
+ /* We keep last bevel segment zero-length. */
+ for (j = 0; j < ((nr == 1) ? (resolu - 1) : resolu); j++) {
+ bevp->offset = len_v3v3(bevp0->vec, bevp->vec);
+ if (bevp->offset > treshold) {
+ *seglen += bevp->offset;
+ *segbevcount += 1;
+ }
+ bevp0 = bevp;
+ bevp++;
+ }
+ seglen++;
+ segbevcount++;
+ nr--;
+ }
+ }
+
if ((nu->flagu & CU_NURB_CYCLIC) == 0) {
bevlist_firstlast_direction_calc_from_bpoint(nu, bl);
}
@@ -2712,20 +2832,29 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
bool is_cyclic = bl->poly != -1;
nr = bl->nr;
if (is_cyclic) {
- bevp1 = (BevPoint *)(bl + 1);
+ bevp1 = bl->bevpoints;
bevp0 = bevp1 + (nr - 1);
}
else {
- bevp0 = (BevPoint *)(bl + 1);
+ bevp0 = bl->bevpoints;
+ bevp0->offset = 0;
bevp1 = bevp0 + 1;
}
nr--;
while (nr--) {
- if (fabsf(bevp0->vec[0] - bevp1->vec[0]) < 0.00001f) {
- if (fabsf(bevp0->vec[1] - bevp1->vec[1]) < 0.00001f) {
- if (fabsf(bevp0->vec[2] - bevp1->vec[2]) < 0.00001f) {
- bevp0->dupe_tag = true;
- bl->dupe_nr++;
+ if (seglen != NULL) {
+ if (fabsf(bevp1->offset) < treshold) {
+ bevp0->dupe_tag = true;
+ bl->dupe_nr++;
+ }
+ }
+ else {
+ if (fabsf(bevp0->vec[0] - bevp1->vec[0]) < 0.00001f) {
+ if (fabsf(bevp0->vec[1] - bevp1->vec[1]) < 0.00001f) {
+ if (fabsf(bevp0->vec[2] - bevp1->vec[2]) < 0.00001f) {
+ bevp0->dupe_tag = true;
+ bl->dupe_nr++;
+ }
}
}
}
@@ -2742,11 +2871,13 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */
blnew = MEM_mallocN(sizeof(BevList) + nr * sizeof(BevPoint), "makeBevelList4");
memcpy(blnew, bl, sizeof(BevList));
+ blnew->segbevcount = bl->segbevcount;
+ blnew->seglen = bl->seglen;
blnew->nr = 0;
BLI_remlink(bev, bl);
BLI_insertlinkbefore(bev, blnext, blnew); /* to make sure bevlijst is tuned with nurblist */
- bevp0 = (BevPoint *)(bl + 1);
- bevp1 = (BevPoint *)(blnew + 1);
+ bevp0 = bl->bevpoints;
+ bevp1 = blnew->bevpoints;
nr = bl->nr;
while (nr--) {
if (bevp0->dupe_tag == 0) {
@@ -2782,7 +2913,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
if (bl->poly > 0) {
min = 300000.0;
- bevp = (BevPoint *)(bl + 1);
+ bevp = bl->bevpoints;
nr = bl->nr;
while (nr--) {
if (min > bevp->vec[0]) {
@@ -2794,14 +2925,14 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
sd->bl = bl;
sd->left = min;
- bevp = (BevPoint *)(bl + 1);
+ bevp = bl->bevpoints;
if (bevp1 == bevp)
bevp0 = bevp + (bl->nr - 1);
else
bevp0 = bevp1 - 1;
bevp = bevp + (bl->nr - 1);
if (bevp1 == bevp)
- bevp2 = (BevPoint *)(bl + 1);
+ bevp2 = bl->bevpoints;
else
bevp2 = bevp1 + 1;
@@ -2840,7 +2971,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
for (a = 0; a < poly; a++, sd++) {
if (sd->bl->hole == sd->dir) {
bl = sd->bl;
- bevp1 = (BevPoint *)(bl + 1);
+ bevp1 = bl->bevpoints;
bevp2 = bevp1 + (bl->nr - 1);
nr = bl->nr / 2;
while (nr--) {
@@ -2859,7 +2990,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
/* 2D Curves */
for (bl = bev->first; bl; bl = bl->next) {
if (bl->nr < 2) {
- BevPoint *bevp = (BevPoint *)(bl + 1);
+ BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
else if (bl->nr == 2) { /* 2 pnt, treat separate */
@@ -2874,7 +3005,7 @@ void BKE_curve_bevelList_make(Object *ob, ListBase *nurbs, bool for_render)
/* 3D Curves */
for (bl = bev->first; bl; bl = bl->next) {
if (bl->nr < 2) {
- BevPoint *bevp = (BevPoint *)(bl + 1);
+ BevPoint *bevp = bl->bevpoints;
unit_qt(bevp->quat);
}
else if (bl->nr == 2) { /* 2 pnt, treat separate */
@@ -3072,7 +3203,13 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
madd_v3_v3v3fl(p2_h2, p2, dvec_b, 1.0f / 3.0f);
}
- if (skip_align || (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) {
+ if (skip_align ||
+ /* when one handle is free, alignming makes no sense, see: T35952 */
+ (ELEM(HD_FREE, bezt->h1, bezt->h2)) ||
+ /* also when no handles are aligned, skip this step */
+ (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) &&
+ !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2)))
+ {
/* handles need to be updated during animation and applying stuff like hooks,
* but in such situations it's quite difficult to distinguish in which order
* align handles should be aligned so skip them for now */
@@ -3081,13 +3218,11 @@ static void calchandleNurb_intern(BezTriple *bezt, BezTriple *prev, BezTriple *n
len_a = len_v3v3(p2, p2_h1);
len_b = len_v3v3(p2, p2_h2);
- if (is_fcurve == false) {
- if (len_a == 0.0f)
- len_a = 1.0f;
- if (len_b == 0.0f)
- len_b = 1.0f;
- len_ratio = len_a / len_b;
- }
+
+ if (len_a == 0.0f) len_a = 1.0f;
+ if (len_b == 0.0f) len_b = 1.0f;
+
+ len_ratio = len_a / len_b;
if (bezt->f1 & SELECT) { /* order of calculation */
if (ELEM(bezt->h2, HD_ALIGN, HD_ALIGN_DOUBLESIDE)) { /* aligned */
@@ -3172,6 +3307,31 @@ void BKE_nurb_handles_calc(Nurb *nu) /* first, if needed, set handle flags */
calchandlesNurb_intern(nu, false);
}
+/**
+ * Workaround #BKE_nurb_handles_calc logic
+ * that makes unselected align to the selected handle.
+ */
+static void nurbList_handles_swap_select(Nurb *nu)
+{
+ BezTriple *bezt;
+ int i;
+
+ for (i = nu->pntsu, bezt = nu->bezt; i--; bezt++) {
+ if ((bezt->f1 & SELECT) != (bezt->f3 & SELECT)) {
+ bezt->f1 ^= SELECT;
+ bezt->f3 ^= SELECT;
+ }
+ }
+}
+
+/* internal use only (weak) */
+static void nurb_handles_calc__align_selected(Nurb *nu)
+{
+ nurbList_handles_swap_select(nu);
+ BKE_nurb_handles_calc(nu);
+ nurbList_handles_swap_select(nu);
+}
+
/* similar to BKE_nurb_handle_calc but for curves and
* figures out the previous and next for us */
void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt)
@@ -3369,7 +3529,9 @@ void BKE_nurbList_handles_set(ListBase *editnurb, const char code)
}
bezt++;
}
- BKE_nurb_handles_calc(nu);
+
+ /* like BKE_nurb_handles_calc but moves selected */
+ nurb_handles_calc__align_selected(nu);
}
nu = nu->next;
}
@@ -3413,7 +3575,9 @@ void BKE_nurbList_handles_set(ListBase *editnurb, const char code)
bezt++;
}
- BKE_nurb_handles_calc(nu);
+
+ /* like BKE_nurb_handles_calc but moves selected */
+ nurb_handles_calc__align_selected(nu);
}
}
}
@@ -3829,6 +3993,9 @@ bool BKE_nurb_order_clamp_v(struct Nurb *nu)
return changed;
}
+/**
+ * \note caller must ensure active vertex remains valid.
+ */
bool BKE_nurb_type_convert(Nurb *nu, const short type, const bool use_handles)
{
BezTriple *bezt;
@@ -3980,7 +4147,7 @@ ListBase *BKE_curve_nurbs_get(Curve *cu)
void BKE_curve_nurb_active_set(Curve *cu, Nurb *nu)
{
if (nu == NULL) {
- cu->actnu = -1;
+ cu->actnu = CU_ACT_NONE;
}
else {
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
@@ -4010,13 +4177,18 @@ void BKE_curve_nurb_vert_active_set(Curve *cu, Nurb *nu, void *vert)
if (nu) {
BKE_curve_nurb_active_set(cu, nu);
- if (nu->type == CU_BEZIER) {
- BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu));
- cu->actvert = (BezTriple *)vert - nu->bezt;
+ if (vert) {
+ if (nu->type == CU_BEZIER) {
+ BLI_assert(ARRAY_HAS_ITEM((BezTriple *)vert, nu->bezt, nu->pntsu));
+ cu->actvert = (BezTriple *)vert - nu->bezt;
+ }
+ else {
+ BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv));
+ cu->actvert = (BPoint *)vert - nu->bp;
+ }
}
else {
- BLI_assert(ARRAY_HAS_ITEM((BPoint *)vert, nu->bp, nu->pntsu * nu->pntsv));
- cu->actvert = (BPoint *)vert - nu->bp;
+ cu->actvert = CU_ACT_NONE;
}
}
else {
@@ -4139,7 +4311,50 @@ bool BKE_curve_center_bounds(Curve *cu, float cent[3])
return false;
}
-void BKE_curve_translate(Curve *cu, float offset[3], const bool do_keys)
+
+void BKE_curve_transform_ex(Curve *cu, float mat[4][4], bool do_keys, float unit_scale)
+{
+ Nurb *nu;
+ BPoint *bp;
+ BezTriple *bezt;
+ int i;
+
+ for (nu = cu->nurb.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ i = nu->pntsu;
+ for (bezt = nu->bezt; i--; bezt++) {
+ mul_m4_v3(mat, bezt->vec[0]);
+ mul_m4_v3(mat, bezt->vec[1]);
+ mul_m4_v3(mat, bezt->vec[2]);
+ bezt->radius *= unit_scale;
+ }
+ BKE_nurb_handles_calc(nu);
+ }
+ else {
+ i = nu->pntsu * nu->pntsv;
+ for (bp = nu->bp; i--; bp++)
+ mul_m4_v3(mat, bp->vec);
+ }
+ }
+
+ if (do_keys && cu->key) {
+ KeyBlock *kb;
+ for (kb = cu->key->block.first; kb; kb = kb->next) {
+ float *fp = kb->data;
+ for (i = kb->totelem; i--; fp += 3) {
+ mul_m4_v3(mat, fp);
+ }
+ }
+ }
+}
+
+void BKE_curve_transform(Curve *cu, float mat[4][4], bool do_keys)
+{
+ float unit_scale = mat4_to_scale(mat);
+ BKE_curve_transform_ex(cu, mat, do_keys, unit_scale);
+}
+
+void BKE_curve_translate(Curve *cu, float offset[3], bool do_keys)
{
ListBase *nurb_lb = BKE_curve_nurbs_get(cu);
Nurb *nu;
@@ -4226,10 +4441,49 @@ void BKE_curve_material_index_clear(Curve *cu)
}
}
+int BKE_curve_material_index_validate(Curve *cu)
+{
+ const int curvetype = BKE_curve_type_get(cu);
+ bool is_valid = true;
+
+ if (curvetype == OB_FONT) {
+ CharInfo *info = cu->strinfo;
+ const int max_idx = max_ii(0, cu->totcol); /* OB_FONT use 1 as first mat index, not 0!!! */
+ int i;
+ for (i = cu->len_wchar - 1; i >= 0; i--, info++) {
+ if (info->mat_nr > max_idx) {
+ info->mat_nr = 0;
+ is_valid = false;
+ }
+ }
+ }
+ else {
+ Nurb *nu;
+ const int max_idx = max_ii(0, cu->totcol - 1);
+ 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;
+ }
+ }
+ }
+
+ if (!is_valid) {
+ DAG_id_tag_update(&cu->id, OB_RECALC_DATA);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
void BKE_curve_rect_from_textbox(const struct Curve *cu, const struct TextBox *tb, struct rctf *r_rect)
{
- r_rect->xmin = (cu->xof * cu->fsize) + tb->x;
- r_rect->ymax = (cu->yof * cu->fsize) + tb->y + cu->fsize;
+ r_rect->xmin = cu->xof + tb->x;
+ r_rect->ymax = cu->yof + tb->y + cu->fsize;
r_rect->xmax = r_rect->xmin + tb->w;
r_rect->ymin = r_rect->ymax - tb->h;
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index fd4350123b4..7684c5a3a42 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -129,21 +129,24 @@ typedef struct LayerTypeInfo {
void (*set_default)(void *data, int count);
/** functions necessary for geometry collapse */
- bool (*equal)(void *data1, void *data2);
+ bool (*equal)(const void *data1, const void *data2);
void (*multiply)(void *data, float fac);
void (*initminmax)(void *min, void *max);
- void (*add)(void *data1, void *data2);
- void (*dominmax)(void *data1, void *min, void *max);
- void (*copyvalue)(void *source, void *dest);
+ void (*add)(void *data1, const void *data2);
+ void (*dominmax)(const void *data1, void *min, void *max);
+ void (*copyvalue)(const void *source, void *dest);
/** a function to read data from a cdf file */
int (*read)(CDataFile *cdf, void *data, int count);
/** a function to write data to a cdf file */
- int (*write)(CDataFile *cdf, void *data, int count);
+ int (*write)(CDataFile *cdf, const void *data, int count);
/** a function to determine file size */
- size_t (*filesize)(CDataFile *cdf, void *data, int count);
+ size_t (*filesize)(CDataFile *cdf, const void *data, int count);
+
+ /** a function to determine max allowed number of layers, should be NULL or return -1 if no limit */
+ int (*layers_max)(void);
} LayerTypeInfo;
static void layerCopy_mdeformvert(const void *source, void *dest,
@@ -379,6 +382,11 @@ static void layerDefault_tface(void *data, int count)
tf[i] = default_tf;
}
+static int layerMaxNum_tface(void)
+{
+ return MAX_MTFACE;
+}
+
static void layerCopy_propFloat(const void *source, void *dest,
int count)
{
@@ -552,9 +560,9 @@ static int layerRead_mdisps(CDataFile *cdf, void *data, int count)
return 1;
}
-static int layerWrite_mdisps(CDataFile *cdf, void *data, int count)
+static int layerWrite_mdisps(CDataFile *cdf, const void *data, int count)
{
- MDisps *d = data;
+ const MDisps *d = data;
int i;
for (i = 0; i < count; ++i) {
@@ -567,9 +575,9 @@ static int layerWrite_mdisps(CDataFile *cdf, void *data, int count)
return 1;
}
-static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), void *data, int count)
+static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int count)
{
- MDisps *d = data;
+ const MDisps *d = data;
size_t size = 0;
int i;
@@ -612,9 +620,10 @@ static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size))
}
/* --------- */
-static void layerCopyValue_mloopcol(void *source, void *dest)
+static void layerCopyValue_mloopcol(const void *source, void *dest)
{
- MLoopCol *m1 = source, *m2 = dest;
+ const MLoopCol *m1 = source;
+ MLoopCol *m2 = dest;
m2->r = m1->r;
m2->g = m1->g;
@@ -622,9 +631,9 @@ static void layerCopyValue_mloopcol(void *source, void *dest)
m2->a = m1->a;
}
-static bool layerEqual_mloopcol(void *data1, void *data2)
+static bool layerEqual_mloopcol(const void *data1, const void *data2)
{
- MLoopCol *m1 = data1, *m2 = data2;
+ const MLoopCol *m1 = data1, *m2 = data2;
float r, g, b, a;
r = m1->r - m2->r;
@@ -645,9 +654,10 @@ static void layerMultiply_mloopcol(void *data, float fac)
m->a = (float)m->a * fac;
}
-static void layerAdd_mloopcol(void *data1, void *data2)
+static void layerAdd_mloopcol(void *data1, const void *data2)
{
- MLoopCol *m = data1, *m2 = data2;
+ MLoopCol *m = data1;
+ const MLoopCol *m2 = data2;
m->r += m2->r;
m->g += m2->g;
@@ -655,9 +665,9 @@ static void layerAdd_mloopcol(void *data1, void *data2)
m->a += m2->a;
}
-static void layerDoMinMax_mloopcol(void *data, void *vmin, void *vmax)
+static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax)
{
- MLoopCol *m = data;
+ const MLoopCol *m = data;
MLoopCol *min = vmin, *max = vmax;
if (m->r < min->r) min->r = m->r;
@@ -743,16 +753,22 @@ static void layerInterp_mloopcol(void **sources, const float *weights,
mc->a = (int)col.a;
}
-static void layerCopyValue_mloopuv(void *source, void *dest)
+static int layerMaxNum_mloopcol(void)
{
- MLoopUV *luv1 = source, *luv2 = dest;
+ return MAX_MCOL;
+}
+
+static void layerCopyValue_mloopuv(const void *source, void *dest)
+{
+ const MLoopUV *luv1 = source;
+ MLoopUV *luv2 = dest;
copy_v2_v2(luv2->uv, luv1->uv);
}
-static bool layerEqual_mloopuv(void *data1, void *data2)
+static bool layerEqual_mloopuv(const void *data1, const void *data2)
{
- MLoopUV *luv1 = data1, *luv2 = data2;
+ const MLoopUV *luv1 = data1, *luv2 = data2;
return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
@@ -771,16 +787,18 @@ static void layerInitMinMax_mloopuv(void *vmin, void *vmax)
INIT_MINMAX2(min->uv, max->uv);
}
-static void layerDoMinMax_mloopuv(void *data, void *vmin, void *vmax)
+static void layerDoMinMax_mloopuv(const void *data, void *vmin, void *vmax)
{
- MLoopUV *min = vmin, *max = vmax, *luv = data;
+ const MLoopUV *luv = data;
+ MLoopUV *min = vmin, *max = vmax;
minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
-static void layerAdd_mloopuv(void *data1, void *data2)
+static void layerAdd_mloopuv(void *data1, const void *data2)
{
- MLoopUV *l1 = data1, *l2 = data2;
+ MLoopUV *l1 = data1;
+ const MLoopUV *l2 = data2;
add_v2_v2(l1->uv, l2->uv);
}
@@ -815,16 +833,17 @@ static void layerInterp_mloopuv(void **sources, const float *weights,
}
/* origspace is almost exact copy of mloopuv's, keep in sync */
-static void layerCopyValue_mloop_origspace(void *source, void *dest)
+static void layerCopyValue_mloop_origspace(const void *source, void *dest)
{
- OrigSpaceLoop *luv1 = source, *luv2 = dest;
+ const OrigSpaceLoop *luv1 = source;
+ OrigSpaceLoop *luv2 = dest;
copy_v2_v2(luv2->uv, luv1->uv);
}
-static bool layerEqual_mloop_origspace(void *data1, void *data2)
+static bool layerEqual_mloop_origspace(const void *data1, const void *data2)
{
- OrigSpaceLoop *luv1 = data1, *luv2 = data2;
+ const OrigSpaceLoop *luv1 = data1, *luv2 = data2;
return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f;
}
@@ -843,16 +862,18 @@ static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax)
INIT_MINMAX2(min->uv, max->uv);
}
-static void layerDoMinMax_mloop_origspace(void *data, void *vmin, void *vmax)
+static void layerDoMinMax_mloop_origspace(const void *data, void *vmin, void *vmax)
{
- OrigSpaceLoop *min = vmin, *max = vmax, *luv = data;
+ const OrigSpaceLoop *luv = data;
+ OrigSpaceLoop *min = vmin, *max = vmax;
minmax_v2v2_v2(min->uv, max->uv, luv->uv);
}
-static void layerAdd_mloop_origspace(void *data1, void *data2)
+static void layerAdd_mloop_origspace(void *data1, const void *data2)
{
- OrigSpaceLoop *l1 = data1, *l2 = data2;
+ OrigSpaceLoop *l1 = data1;
+ const OrigSpaceLoop *l2 = data2;
add_v2_v2(l1->uv, l2->uv);
}
@@ -1085,12 +1106,12 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
/* 4: CD_MFACE */
{sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL},
/* 5: CD_MTFACE */
- {sizeof(MTFace), "MTFace", 1, N_("UVMap"), layerCopy_tface, NULL,
- layerInterp_tface, layerSwap_tface, layerDefault_tface},
+ {sizeof(MTFace), "MTFace", 1, N_("UVMap"), layerCopy_tface, NULL, layerInterp_tface, layerSwap_tface,
+ layerDefault_tface, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_tface},
/* 6: CD_MCOL */
/* 4 MCol structs per face */
{sizeof(MCol) * 4, "MCol", 4, N_("Col"), NULL, NULL, layerInterp_mcol,
- layerSwap_mcol, layerDefault_mcol},
+ layerSwap_mcol, layerDefault_mcol, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_mloopcol},
/* 7: CD_ORIGINDEX */
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex},
/* 8: CD_NORMAL */
@@ -1111,15 +1132,16 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(float) * 3, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 15: CD_MTEXPOLY */
/* note, when we expose the UV Map / TexFace split to the user, change this back to face Texture */
- {sizeof(MTexPoly), "MTexPoly", 1, N_("UVMap") /* "Face Texture" */, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(MTexPoly), "MTexPoly", 1, N_("UVMap") /* "Face Texture" */, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, layerMaxNum_tface},
/* 16: CD_MLOOPUV */
{sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap"), NULL, NULL, layerInterp_mloopuv, NULL, NULL,
layerEqual_mloopuv, layerMultiply_mloopuv, layerInitMinMax_mloopuv,
- layerAdd_mloopuv, layerDoMinMax_mloopuv, layerCopyValue_mloopuv},
+ layerAdd_mloopuv, layerDoMinMax_mloopuv, layerCopyValue_mloopuv, NULL, NULL, NULL, layerMaxNum_tface},
/* 17: CD_MLOOPCOL */
{sizeof(MLoopCol), "MLoopCol", 1, N_("Col"), NULL, NULL, layerInterp_mloopcol, NULL,
layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
- layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol},
+ layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol, NULL, NULL, NULL, layerMaxNum_mloopcol},
/* 18: CD_TANGENT */
{sizeof(float) * 4 * 4, "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 19: CD_MDISPS */
@@ -1311,7 +1333,8 @@ bool CustomData_merge(const struct CustomData *source, struct CustomData *dest,
/*const LayerTypeInfo *typeInfo;*/
CustomDataLayer *layer, *newlayer;
void *data;
- int i, type, number = 0, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0, lastflag = 0;
+ int i, type, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0, lastflag = 0;
+ int number = 0, maxnumber = -1;
bool changed = false;
for (i = 0; i < source->totlayer; ++i) {
@@ -1322,6 +1345,7 @@ bool CustomData_merge(const struct CustomData *source, struct CustomData *dest,
if (type != lasttype) {
number = 0;
+ maxnumber = CustomData_layertype_layers_max(type);
lastactive = layer->active;
lastrender = layer->active_rnd;
lastclone = layer->active_clone;
@@ -1334,6 +1358,7 @@ bool CustomData_merge(const struct CustomData *source, struct CustomData *dest,
if (lastflag & CD_FLAG_NOCOPY) continue;
else if (!(mask & CD_TYPE_AS_MASK(type))) continue;
+ else if ((maxnumber != -1) && (number >= maxnumber)) continue;
else if (CustomData_get_layer_named(dest, type, layer->name)) continue;
switch (alloctype) {
@@ -2546,12 +2571,12 @@ void CustomData_bmesh_free_block(CustomData *data, void **block)
/**
* Same as #CustomData_bmesh_free_block but zero the memory rather then freeing.
*/
-void CustomData_bmesh_free_block_data(CustomData *data, void **block)
+void CustomData_bmesh_free_block_data(CustomData *data, void *block)
{
const LayerTypeInfo *typeInfo;
int i;
- if (*block == NULL)
+ if (block == NULL)
return;
for (i = 0; i < data->totlayer; ++i) {
@@ -2560,13 +2585,13 @@ void CustomData_bmesh_free_block_data(CustomData *data, void **block)
if (typeInfo->free) {
int offset = data->layers[i].offset;
- typeInfo->free((char *)*block + offset, 1, typeInfo->size);
+ typeInfo->free((char *)block + offset, 1, typeInfo->size);
}
}
}
if (data->totsize)
- memset(*block, 0, data->totsize);
+ memset(block, 0, data->totsize);
}
static void CustomData_bmesh_alloc_block(CustomData *data, void **block)
@@ -2661,7 +2686,7 @@ void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n)
return (char *)block + data->layers[n].offset;
}
-bool CustomData_layer_has_math(struct CustomData *data, int layer_n)
+bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
@@ -2674,7 +2699,7 @@ bool CustomData_layer_has_math(struct CustomData *data, int layer_n)
return false;
}
-bool CustomData_layer_has_interp(struct CustomData *data, int layer_n)
+bool CustomData_layer_has_interp(const struct CustomData *data, int layer_n)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[layer_n].type);
@@ -2685,7 +2710,7 @@ bool CustomData_layer_has_interp(struct CustomData *data, int layer_n)
return false;
}
-bool CustomData_has_math(struct CustomData *data)
+bool CustomData_has_math(const struct CustomData *data)
{
int i;
@@ -2700,7 +2725,7 @@ bool CustomData_has_math(struct CustomData *data)
}
/* a non bmesh version would have to check layer->data */
-bool CustomData_bmesh_has_free(struct CustomData *data)
+bool CustomData_bmesh_has_free(const struct CustomData *data)
{
const LayerTypeInfo *typeInfo;
int i;
@@ -2716,7 +2741,7 @@ bool CustomData_bmesh_has_free(struct CustomData *data)
return false;
}
-bool CustomData_has_interp(struct CustomData *data)
+bool CustomData_has_interp(const struct CustomData *data)
{
int i;
@@ -2732,7 +2757,7 @@ bool CustomData_has_interp(struct CustomData *data)
/* copies the "value" (e.g. mloopuv uv or mloopcol colors) from one block to
* another, while not overwriting anything else (e.g. flags)*/
-void CustomData_data_copy_value(int type, void *source, void *dest)
+void CustomData_data_copy_value(int type, const void *source, void *dest)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -2744,7 +2769,7 @@ void CustomData_data_copy_value(int type, void *source, void *dest)
memcpy(dest, source, typeInfo->size);
}
-bool CustomData_data_equals(int type, void *data1, void *data2)
+bool CustomData_data_equals(int type, const void *data1, const void *data2)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -2762,7 +2787,7 @@ void CustomData_data_initminmax(int type, void *min, void *max)
}
-void CustomData_data_dominmax(int type, void *data, void *min, void *max)
+void CustomData_data_dominmax(int type, const void *data, void *min, void *max)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -2780,7 +2805,7 @@ void CustomData_data_multiply(int type, void *data, float fac)
}
-void CustomData_data_add(int type, void *data1, void *data2)
+void CustomData_data_add(int type, void *data1, const void *data2)
{
const LayerTypeInfo *typeInfo = layerType_getInfo(type);
@@ -3031,6 +3056,24 @@ bool CustomData_layertype_is_singleton(int type)
return typeInfo->defaultname == NULL;
}
+/**
+ * \return Maximum number of layers of given \a type, -1 means 'no limit'.
+ */
+int CustomData_layertype_layers_max(const int type)
+{
+ const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+
+ /* Same test as for singleton above. */
+ if (typeInfo->defaultname == NULL) {
+ return 1;
+ }
+ else if (typeInfo->layers_max == NULL) {
+ return -1;
+ }
+
+ return typeInfo->layers_max();
+}
+
static bool CustomData_is_property_layer(int type)
{
if ((type == CD_PROP_FLT) || (type == CD_PROP_INT) || (type == CD_PROP_STR))
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index d072088ac8e..528ff2d7b19 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -559,7 +559,7 @@ void defgroup_unique_name(bDeformGroup *dg, Object *ob)
static bool is_char_sep(const char c)
{
- return ELEM4(c, '.', ' ', '-', '_');
+ return ELEM(c, '.', ' ', '-', '_');
}
/* based on BLI_split_dirfile() / os.path.splitext(), "a.b.c" -> ("a.b", ".c") */
@@ -614,6 +614,7 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[
char replace[MAX_VGROUP_NAME] = ""; /* The replacement string */
char number[MAX_VGROUP_NAME] = ""; /* The number extension string */
char *index = NULL;
+ bool is_set = false;
/* always copy the name, since this can be called with an uninitialized string */
BLI_strncpy(name, from_name, MAX_VGROUP_NAME);
@@ -640,6 +641,7 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[
/* first case; separator . - _ with extensions r R l L */
if (is_char_sep(name[len - 2])) {
+ is_set = true;
switch (name[len - 1]) {
case 'l':
prefix[len - 1] = 0;
@@ -657,10 +659,14 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[
prefix[len - 1] = 0;
strcpy(replace, "L");
break;
+ default:
+ is_set = false;
}
}
+
/* case; beginning with r R l L, with separator after it */
- else if (is_char_sep(name[1])) {
+ if (!is_set && is_char_sep(name[1])) {
+ is_set = true;
switch (name[0]) {
case 'l':
strcpy(replace, "r");
@@ -682,40 +688,43 @@ void BKE_deform_flip_side_name(char name[MAX_VGROUP_NAME], const char from_name[
BLI_strncpy(suffix, name + 1, sizeof(suffix));
prefix[0] = 0;
break;
+ default:
+ is_set = false;
}
}
- else if (len > 5) {
+
+ if (!is_set && len > 5) {
/* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
- index = BLI_strcasestr(prefix, "right");
- if (index == prefix || index == prefix + len - 5) {
- if (index[0] == 'r')
+ if (((index = BLI_strcasestr(prefix, "right")) == prefix) ||
+ (index == prefix + len - 5))
+ {
+ is_set = true;
+ if (index[0] == 'r') {
strcpy(replace, "left");
+ }
else {
- if (index[1] == 'I')
- strcpy(replace, "LEFT");
- else
- strcpy(replace, "Left");
+ strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
}
*index = 0;
BLI_strncpy(suffix, index + 5, sizeof(suffix));
}
- else {
- index = BLI_strcasestr(prefix, "left");
- if (index == prefix || index == prefix + len - 4) {
- if (index[0] == 'l')
- strcpy(replace, "right");
- else {
- if (index[1] == 'E')
- strcpy(replace, "RIGHT");
- else
- strcpy(replace, "Right");
- }
- *index = 0;
- BLI_strncpy(suffix, index + 4, sizeof(suffix));
+ else if (((index = BLI_strcasestr(prefix, "left")) == prefix) ||
+ (index == prefix + len - 4))
+ {
+ is_set = true;
+ if (index[0] == 'l') {
+ strcpy(replace, "right");
+ }
+ else {
+ strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
}
+ *index = 0;
+ BLI_strncpy(suffix, index + 4, sizeof(suffix));
}
}
+ (void)is_set; /* quiet warning */
+
BLI_snprintf(name, MAX_VGROUP_NAME, "%s%s%s%s", prefix, replace, suffix, number);
}
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 21579098266..44a0b93fc01 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -59,8 +59,10 @@
#include "DNA_movieclip_types.h"
#include "DNA_mask_types.h"
+#include "BKE_anim.h"
#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_effect.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
@@ -73,12 +75,15 @@
#include "BKE_mball.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_tracking.h"
+#include "GPU_buffers.h"
+
#include "atomic_ops.h"
#include "depsgraph_private.h"
@@ -524,7 +529,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
if (ct->tar->type == OB_MESH)
node3->customdata_mask |= CD_MASK_MDEFORMVERT;
}
- else if (ELEM3(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK))
+ else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK))
dag_add_relation(dag, node3, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, cti->name);
else
dag_add_relation(dag, node3, node, DAG_RL_OB_DATA, cti->name);
@@ -688,6 +693,29 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Curve Taper");
}
if (ob->type == OB_FONT) {
+ /* Really rather dirty hack. needs to support font family to work
+ * reliably on render export.
+ *
+ * This totally mimics behavior of regular verts duplication with
+ * parenting. The only tricky thing here is to get list of objects
+ * used for the custom "font".
+ *
+ * This shouldn't harm so much because this code only runs on DAG
+ * rebuild and this feature is not that commonly used.
+ *
+ * - sergey -
+ */
+ if (cu->family[0] != '\n') {
+ ListBase *duplilist;
+ DupliObject *dob;
+ duplilist = object_duplilist(G.main->eval_ctx, scene, ob);
+ for (dob = duplilist->first; dob; dob = dob->next) {
+ node2 = dag_get_node(dag, dob->ob);
+ dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Object Font");
+ }
+ free_object_duplilist(duplilist);
+ }
+
if (cu->textoncurve) {
node2 = dag_get_node(dag, cu->textoncurve);
/* Text on curve requires path to be evaluated for the target curve. */
@@ -803,7 +831,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
continue;
/* special case for camera tracking -- it doesn't use targets to define relations */
- if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
int depends_on_camera = 0;
if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
@@ -843,7 +871,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Scene *scene, O
if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO))
dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name);
else {
- if (ELEM3(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) {
+ if (ELEM(obt->type, OB_ARMATURE, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) {
dag_add_relation(dag, node2, node, DAG_RL_DATA_OB | DAG_RL_OB_OB, cti->name);
if (obt->type == OB_MESH)
node2->customdata_mask |= CD_MASK_MDEFORMVERT;
@@ -1386,7 +1414,7 @@ static bool check_object_needs_evaluation(Object *object)
if (object->type == OB_MESH) {
return object->derivedFinal == NULL;
}
- else if (ELEM5(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
+ else if (ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
return object->curve_cache == NULL;
}
@@ -1400,7 +1428,7 @@ static bool check_object_tagged_for_update(Object *object)
return true;
}
- if (ELEM6(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
+ if (ELEM(object->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
ID *data_id = object->data;
return (data_id->flag & (LIB_ID_RECALC_DATA | LIB_ID_RECALC)) != 0;
}
@@ -1747,7 +1775,8 @@ static unsigned int flush_layer_node(Scene *sce, DagNode *node, int curtime)
}
/* node was checked to have lasttime != curtime, and is of type ID_OB */
-static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node, int curtime, int reset)
+static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node,
+ int curtime, unsigned int lay, bool reset)
{
DagAdjList *itA;
Object *ob;
@@ -1761,14 +1790,17 @@ static void flush_pointcache_reset(Main *bmain, Scene *scene, DagNode *node, int
if (reset || (ob->recalc & OB_RECALC_ALL)) {
if (BKE_ptcache_object_reset(scene, ob, PTCACHE_RESET_DEPSGRAPH)) {
- ob->recalc |= OB_RECALC_DATA;
- lib_id_recalc_data_tag(bmain, &ob->id);
+ /* Don't tag nodes which are on invisible layer. */
+ if (itA->node->lay & lay) {
+ ob->recalc |= OB_RECALC_DATA;
+ lib_id_recalc_data_tag(bmain, &ob->id);
+ }
}
- flush_pointcache_reset(bmain, scene, itA->node, curtime, 1);
+ flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, true);
}
else
- flush_pointcache_reset(bmain, scene, itA->node, curtime, 0);
+ flush_pointcache_reset(bmain, scene, itA->node, curtime, lay, false);
}
}
}
@@ -1885,10 +1917,12 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho
lib_id_recalc_data_tag(bmain, &ob->id);
}
- flush_pointcache_reset(bmain, sce, itA->node, lasttime, 1);
+ flush_pointcache_reset(bmain, sce, itA->node, lasttime,
+ lay, true);
}
else
- flush_pointcache_reset(bmain, sce, itA->node, lasttime, 0);
+ flush_pointcache_reset(bmain, sce, itA->node, lasttime,
+ lay, false);
}
}
}
@@ -1983,7 +2017,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob)
if (cti) {
/* special case for camera tracking -- it doesn't use targets to define relations */
- if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
ob->recalc |= OB_RECALC_OB;
}
else if (cti->get_constraint_targets) {
@@ -2272,7 +2306,7 @@ static void dag_group_on_visible_update(Group *group)
group->id.flag |= LIB_DOIT;
for (go = group->gobject.first; go; go = go->next) {
- if (ELEM6(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
+ if (ELEM(go->ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
go->ob->recalc |= OB_RECALC_DATA;
go->ob->id.flag |= LIB_DOIT;
lib_id_recalc_tag(G.main, &go->ob->id);
@@ -2319,7 +2353,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
oblay = (node) ? node->lay : ob->lay;
if ((oblay & lay) & ~scene->lay_updated) {
- if (ELEM6(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
ob->recalc |= OB_RECALC_DATA;
lib_id_recalc_tag(bmain, &ob->id);
}
@@ -2472,6 +2506,15 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
BKE_ptcache_object_reset(sce, obt, PTCACHE_RESET_DEPSGRAPH);
}
+ if (ELEM(idtype, ID_MA, ID_TE)) {
+ obt = sce->basact ? sce->basact->object : NULL;
+ if (obt && obt->mode & OB_MODE_TEXTURE_PAINT) {
+ BKE_texpaint_slots_refresh_object(sce, obt);
+ BKE_paint_proj_mesh_data_check(sce, obt, NULL, NULL, NULL, NULL);
+ GPU_drawobject_free(obt->derivedFinal);
+ }
+ }
+
if (idtype == ID_MC) {
MovieClip *clip = (MovieClip *) id;
@@ -2481,7 +2524,7 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
bConstraint *con;
for (con = obt->constraints.first; con; con = con->next) {
bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
- if (ELEM3(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER,
+ if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER,
CONSTRAINT_TYPE_OBJECTSOLVER))
{
obt->recalc |= OB_RECALC_OB;
@@ -2502,6 +2545,23 @@ static void dag_id_flush_update(Main *bmain, Scene *sce, ID *id)
}
}
+ /* Not pretty to iterate all the nodes here, but it's as good as it
+ * could be with the current depsgraph design/
+ */
+ if (idtype == ID_IM) {
+ FOREACH_NODETREE(bmain, ntree, parent_id) {
+ if (ntree->type == NTREE_SHADER) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->id == id) {
+ lib_id_recalc_tag(bmain, &ntree->id);
+ break;
+ }
+ }
+ }
+ } FOREACH_NODETREE_END
+ }
+
if (idtype == ID_MSK) {
if (sce->nodetree) {
bNode *node;
@@ -2742,7 +2802,7 @@ void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
if (ob->type == OB_FONT) {
Curve *cu = ob->data;
- if (ELEM4((struct VFont *)id, cu->vfont, cu->vfontb, cu->vfonti, cu->vfontbi)) {
+ if (ELEM((struct VFont *)id, cu->vfont, cu->vfontb, cu->vfonti, cu->vfontbi)) {
ob->recalc |= (flag & OB_RECALC_ALL);
}
}
@@ -3106,7 +3166,17 @@ short DAG_get_eval_flags_for_object(Scene *scene, void *object)
/* Happens when external render engine exports temporary objects
* which are not in the DAG.
*/
+
/* TODO(sergey): Doublecheck objects with Curve Deform exports all fine. */
+
+ /* TODO(sergey): Weak but currently we can't really access proper DAG from
+ * the modifiers stack. This is because in most cases modifier is to use
+ * the foreground scene, but to access evaluation flags we need to know
+ * active background scene, which we don't know.
+ */
+ if (scene->set) {
+ return DAG_get_eval_flags_for_object(scene->set, object);
+ }
return 0;
}
}
diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c
index 8c21ee15da2..893c69741cd 100644
--- a/source/blender/blenkernel/intern/displist.c
+++ b/source/blender/blenkernel/intern/displist.c
@@ -71,8 +71,6 @@ void BKE_displist_elem_free(DispList *dl)
if (dl->verts) MEM_freeN(dl->verts);
if (dl->nors) MEM_freeN(dl->nors);
if (dl->index) MEM_freeN(dl->index);
- if (dl->col1) MEM_freeN(dl->col1);
- if (dl->col2) MEM_freeN(dl->col2);
if (dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag);
MEM_freeN(dl);
}
@@ -124,7 +122,7 @@ bool BKE_displist_has_faces(ListBase *lb)
DispList *dl;
for (dl = lb->first; dl; dl = dl->next) {
- if (ELEM3(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
+ if (ELEM(dl->type, DL_INDEX3, DL_INDEX4, DL_SURF)) {
return true;
}
}
@@ -145,8 +143,6 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb)
dln->verts = MEM_dupallocN(dl->verts);
dln->nors = MEM_dupallocN(dl->nors);
dln->index = MEM_dupallocN(dl->index);
- dln->col1 = MEM_dupallocN(dl->col1);
- dln->col2 = MEM_dupallocN(dl->col2);
if (dl->bevelSplitFlag)
dln->bevelSplitFlag = MEM_dupallocN(dl->bevelSplitFlag);
@@ -347,7 +343,7 @@ static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase,
dl = MEM_callocN(sizeof(DispList), "makeDispListbez");
/* len+1 because of 'forward_diff_bezier' function */
- dl->verts = MEM_callocN((len + 1) * 3 * sizeof(float), "dlverts");
+ dl->verts = MEM_mallocN((len + 1) * sizeof(float[3]), "dlverts");
BLI_addtail(dispbase, dl);
dl->parts = 1;
dl->nr = len;
@@ -401,7 +397,7 @@ static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase,
len = (resolu * SEGMENTSU(nu));
dl = MEM_callocN(sizeof(DispList), "makeDispListsurf");
- dl->verts = MEM_callocN(len * 3 * sizeof(float), "dlverts");
+ dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
BLI_addtail(dispbase, dl);
dl->parts = 1;
@@ -418,7 +414,7 @@ static void curve_to_displist(Curve *cu, ListBase *nubase, ListBase *dispbase,
else if (nu->type == CU_POLY) {
len = nu->pntsu;
dl = MEM_callocN(sizeof(DispList), "makeDispListpoly");
- dl->verts = MEM_callocN(len * 3 * sizeof(float), "dlverts");
+ dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
BLI_addtail(dispbase, dl);
dl->parts = 1;
dl->nr = len;
@@ -657,8 +653,8 @@ static void curve_to_filledpoly(Curve *cu, ListBase *UNUSED(nurb), ListBase *dis
bevels_to_filledpoly(cu, dispbase);
}
else {
- /* TODO, investigate passing zup instead of NULL */
- BKE_displist_fill(dispbase, dispbase, NULL, false);
+ const float z_up[3] = {0.0f, 0.0f, 1.0f};
+ BKE_displist_fill(dispbase, dispbase, z_up, false);
}
}
@@ -719,21 +715,20 @@ void BKE_displist_make_mball(EvaluationContext *eval_ctx, Scene *scene, Object *
if (!ob || ob->type != OB_MBALL)
return;
- if (ob->curve_cache) {
- BKE_displist_free(&(ob->curve_cache->disp));
- }
- else {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
- }
+ if (ob == BKE_mball_basis_find(scene, ob)) {
+ if (ob->curve_cache) {
+ BKE_displist_free(&(ob->curve_cache->disp));
+ }
+ else {
+ ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
+ }
- if (ob->type == OB_MBALL) {
- if (ob == BKE_mball_basis_find(scene, ob)) {
- BKE_mball_polygonize(eval_ctx, scene, ob, &ob->curve_cache->disp);
- BKE_mball_texspace_calc(ob);
+ BKE_mball_polygonize(eval_ctx, scene, ob, &ob->curve_cache->disp);
+ BKE_mball_texspace_calc(ob);
- object_deform_mball(ob, &ob->curve_cache->disp);
- }
+ object_deform_mball(ob, &ob->curve_cache->disp);
+ /* NOP for MBALLs anyway... */
boundbox_displist_object(ob);
}
}
@@ -771,7 +766,7 @@ static ModifierData *curve_get_tessellate_point(Scene *scene, Object *ob,
if (mti->type == eModifierTypeType_Constructive)
return pretessellatePoint;
- if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
+ if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
pretessellatePoint = md;
/* this modifiers are moving point of tessellation automatically
@@ -1227,7 +1222,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
len = SEGMENTSU(nu) * resolu;
dl = MEM_callocN(sizeof(DispList), "makeDispListsurf");
- dl->verts = MEM_callocN(len * 3 * sizeof(float), "dlverts");
+ dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
BLI_addtail(dispbase, dl);
dl->parts = 1;
@@ -1249,7 +1244,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
len = (nu->pntsu * resolu) * (nu->pntsv * resolv);
dl = MEM_callocN(sizeof(DispList), "makeDispListsurf");
- dl->verts = MEM_callocN(len * 3 * sizeof(float), "dlverts");
+ dl->verts = MEM_mallocN(len * sizeof(float[3]), "dlverts");
BLI_addtail(dispbase, dl);
dl->col = nu->mat_nr;
@@ -1276,6 +1271,7 @@ void BKE_displist_make_surf(Scene *scene, Object *ob, ListBase *dispbase,
}
if (!for_orco) {
+ BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final,
for_render, use_render_resolution);
}
@@ -1344,7 +1340,7 @@ static void fillBevelCap(Nurb *nu, DispList *dlb, float *prev_fp, ListBase *disp
DispList *dl;
dl = MEM_callocN(sizeof(DispList), "makeDispListbev2");
- dl->verts = MEM_mallocN(3 * sizeof(float) * dlb->nr, "dlverts");
+ dl->verts = MEM_mallocN(sizeof(float[3]) * dlb->nr, "dlverts");
memcpy(dl->verts, prev_fp, 3 * sizeof(float) * dlb->nr);
dl->type = DL_POLY;
@@ -1361,47 +1357,85 @@ static void fillBevelCap(Nurb *nu, DispList *dlb, float *prev_fp, ListBase *disp
BLI_addtail(dispbase, dl);
}
+static void calc_bevfac_segment_mapping(BevList *bl, float bevfac, float spline_length, int *r_bev, float *r_blend)
+{
+ float normlen, normsum = 0.0f;
+ float *seglen = bl->seglen;
+ int *segbevcount = bl->segbevcount;
+ int bevcount = 0, nr = bl->nr;
+
+ float bev_fl = bevfac * (bl->nr - 1);
+ *r_bev = (int)bev_fl;
+
+ while (bevcount < nr - 1) {
+ normlen = *seglen / spline_length;
+ if (normsum + normlen > bevfac) {
+ bev_fl = bevcount + (bevfac - normsum) / normlen * *segbevcount;
+ *r_bev = (int) bev_fl;
+ *r_blend = bev_fl - *r_bev;
+ break;
+ }
+ normsum += normlen;
+ bevcount += *segbevcount;
+ segbevcount++;
+ seglen++;
+ }
+}
-static void calc_bevfac_spline_mapping(BevList *bl, float bevfac, float spline_length, const float *bevp_array,
+static void calc_bevfac_spline_mapping(BevList *bl, float bevfac,
+ float spline_length,
int *r_bev, float *r_blend)
{
- float len = 0.0f;
- int i;
- for (i = 0; i < bl->nr; i++) {
- *r_bev = i;
- *r_blend = (bevfac * spline_length - len) / bevp_array[i];
- if (len + bevp_array[i] > bevfac * spline_length) {
+ const float len_target = bevfac * spline_length;
+ BevPoint *bevp = bl->bevpoints;
+ float len_next = 0.0f, len = 0.0f;
+ int i = 0, nr = bl->nr;
+
+ while (nr--) {
+ bevp++;
+ len_next = len + bevp->offset;
+ if (len_next > len_target) {
break;
}
- len += bevp_array[i];
+ len = len_next;
+ i++;
}
+
+ *r_bev = i;
+ *r_blend = (len_target - len) / bevp->offset;
}
-static void calc_bevfac_mapping(Curve *cu, BevList *bl, int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend)
+static void calc_bevfac_mapping_default(BevList *bl,
+ int *r_start, float *r_firstblend,
+ int *r_steps, float *r_lastblend)
{
- BevPoint *bevp, *bevl;
- float l, startf, endf, tmpf = 0.0, sum = 0.0, total_length = 0.0f;
- float *bevp_array = NULL;
- float *segments = NULL;
- int end = 0, i, j, segcount = (int)(bl->nr / cu->resolu);
-
- if ((cu->bevfac1_mapping != CU_BEVFAC_MAP_RESOLU) ||
- (cu->bevfac2_mapping != CU_BEVFAC_MAP_RESOLU))
+ *r_start = 0;
+ *r_steps = bl->nr;
+ *r_firstblend = 1.0f;
+ *r_lastblend = 1.0f;
+}
+
+static void calc_bevfac_mapping(Curve *cu, BevList *bl, Nurb *nu,
+ int *r_start, float *r_firstblend, int *r_steps, float *r_lastblend)
+{
+ float tmpf, total_length = 0.0f;
+ int end = 0, i;
+
+ if ((BKE_nurb_check_valid_u(nu) == false) ||
+ /* not essential, but skips unnecessary calculation */
+ (min_ff(cu->bevfac1, cu->bevfac2) == 0.0f &&
+ max_ff(cu->bevfac1, cu->bevfac2) == 1.0f))
{
- bevp_array = MEM_mallocN(sizeof(*bevp_array) * (bl->nr - 1), "bevp_dists");
- segments = MEM_callocN(sizeof(*segments) * segcount, "bevp_segmentlengths");
- bevp = (BevPoint *)(bl + 1);
- bevp++;
- for (i = 1, j = 0; i < bl->nr; bevp++, i++) {
- sum = 0.0f;
- bevl = bevp - 1;
- bevp_array[i - 1] = len_v3v3(bevp->vec, bevl->vec);
- total_length += bevp_array[i - 1];
- tmpf += bevp_array[i - 1];
- if ((i % cu->resolu) == 0 || (bl->nr - 1) == i) {
- segments[j++] = tmpf;
- tmpf = 0.0f;
- }
+ calc_bevfac_mapping_default(bl, r_start, r_firstblend, r_steps, r_lastblend);
+ return;
+ }
+
+ if (ELEM(cu->bevfac1_mapping,
+ CU_BEVFAC_MAP_SEGMENT,
+ CU_BEVFAC_MAP_SPLINE))
+ {
+ for (i = 0; i < SEGMENTSU(nu); i++) {
+ total_length += bl->seglen[i];
}
}
@@ -1410,36 +1444,23 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, int *r_start, float *r_f
{
const float start_fl = cu->bevfac1 * (bl->nr - 1);
*r_start = (int)start_fl;
-
*r_firstblend = 1.0f - (start_fl - (*r_start));
break;
}
case CU_BEVFAC_MAP_SEGMENT:
{
- const float start_fl = cu->bevfac1 * (bl->nr - 1);
- *r_start = (int)start_fl;
-
- for (i = 0; i < segcount; i++) {
- l = segments[i] / total_length;
- if (sum + l > cu->bevfac1) {
- startf = i * cu->resolu + (cu->bevfac1 - sum) / l * cu->resolu;
- *r_start = (int) startf;
- *r_firstblend = 1.0f - (startf - *r_start);
- break;
- }
- sum += l;
- }
+ calc_bevfac_segment_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend);
+ *r_firstblend = 1.0f - *r_firstblend;
break;
}
case CU_BEVFAC_MAP_SPLINE:
{
- calc_bevfac_spline_mapping(bl, cu->bevfac1, total_length, bevp_array, r_start, r_firstblend);
+ calc_bevfac_spline_mapping(bl, cu->bevfac1, total_length, r_start, r_firstblend);
*r_firstblend = 1.0f - *r_firstblend;
break;
}
}
- sum = 0.0f;
switch (cu->bevfac2_mapping) {
case CU_BEVFAC_MAP_RESOLU:
{
@@ -1452,32 +1473,19 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, int *r_start, float *r_f
}
case CU_BEVFAC_MAP_SEGMENT:
{
- const float end_fl = cu->bevfac2 * (bl->nr - 1);
- end = (int)end_fl;
-
+ calc_bevfac_segment_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend);
*r_steps = end - *r_start + 2;
- for (i = 0; i < segcount; i++) {
- l = segments[i] / total_length;
- if (sum + l > cu->bevfac2) {
- endf = i * cu->resolu + (cu->bevfac2 - sum) / l * cu->resolu;
- end = (int)endf;
- *r_lastblend = (endf - end);
- *r_steps = end - *r_start + 2;
- break;
- }
- sum += l;
- }
break;
}
case CU_BEVFAC_MAP_SPLINE:
{
- calc_bevfac_spline_mapping(bl, cu->bevfac2, total_length, bevp_array, &end, r_lastblend);
+ calc_bevfac_spline_mapping(bl, cu->bevfac2, total_length, &end, r_lastblend);
*r_steps = end - *r_start + 2;
break;
}
}
- if (end < *r_start) {
+ if (end < *r_start || (end == *r_start && *r_lastblend < 1.0f - *r_firstblend )) {
SWAP(int, *r_start, end);
tmpf = *r_lastblend;
*r_lastblend = 1.0f - *r_firstblend;
@@ -1489,13 +1497,6 @@ static void calc_bevfac_mapping(Curve *cu, BevList *bl, int *r_start, float *r_f
*r_steps = bl->nr - *r_start;
*r_lastblend = 1.0f;
}
-
- if (bevp_array) {
- MEM_freeN(bevp_array);
- }
- if (segments) {
- MEM_freeN(segments);
- }
}
static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispbase,
@@ -1505,7 +1506,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
Curve *cu = ob->data;
/* we do allow duplis... this is only displist on curve level */
- if (!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return;
+ if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) return;
if (ob->type == OB_SURF) {
BKE_displist_make_surf(scene, ob, dispbase, r_dm_final, for_render, for_orco, use_render_resolution);
@@ -1514,7 +1515,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
ListBase dlbev;
ListBase nubase = {NULL, NULL};
- BLI_freelistN(&(ob->curve_cache->bev));
+ BKE_curve_bevelList_free(&ob->curve_cache->bev);
/* We only re-evlauate path if evaluation is not happening for orco.
* If the calculation happens for orco, we should never free data which
@@ -1552,15 +1553,15 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
for (; bl && nu; bl = bl->next, nu = nu->next) {
DispList *dl;
float *data;
- BevPoint *bevp;
int a;
if (bl->nr) { /* blank bevel lists can happen */
/* exception handling; curve without bevel or extrude, with width correction */
if (BLI_listbase_is_empty(&dlbev)) {
+ BevPoint *bevp;
dl = MEM_callocN(sizeof(DispList), "makeDispListbev");
- dl->verts = MEM_callocN(3 * sizeof(float) * bl->nr, "dlverts");
+ dl->verts = MEM_mallocN(sizeof(float[3]) * bl->nr, "dlverts");
BLI_addtail(dispbase, dl);
if (bl->poly != -1) dl->type = DL_POLY;
@@ -1578,7 +1579,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
dl->rt = nu->flag & ~CU_2D;
a = dl->nr;
- bevp = (BevPoint *)(bl + 1);
+ bevp = bl->bevpoints;
data = dl->verts;
while (a--) {
data[0] = bevp->vec[0] + widfac * bevp->sina;
@@ -1597,13 +1598,25 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
float firstblend = 0.0f, lastblend = 0.0f;
int i, start, steps;
- calc_bevfac_mapping(cu, bl, &start, &firstblend, &steps, &lastblend);
+ if (nu->flagu & CU_NURB_CYCLIC) {
+ calc_bevfac_mapping_default(bl,
+ &start, &firstblend, &steps, &lastblend);
+ }
+ else {
+ if (fabsf(cu->bevfac2 - cu->bevfac1) < FLT_EPSILON) {
+ continue;
+ }
+
+ calc_bevfac_mapping(cu, bl, nu, &start, &firstblend, &steps, &lastblend);
+ }
for (dlb = dlbev.first; dlb; dlb = dlb->next) {
+ BevPoint *bevp_first, *bevp_last;
+ BevPoint *bevp;
/* for each part of the bevel use a separate displblock */
dl = MEM_callocN(sizeof(DispList), "makeDispListbev1");
- dl->verts = data = MEM_callocN(3 * sizeof(float) * dlb->nr * steps, "dlverts");
+ dl->verts = data = MEM_mallocN(sizeof(float[3]) * dlb->nr * steps, "dlverts");
BLI_addtail(dispbase, dl);
dl->type = DL_SURF;
@@ -1621,11 +1634,13 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
/* CU_2D conflicts with R_NOPUNOFLIP */
dl->rt = nu->flag & ~CU_2D;
- dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->col2) * ((steps + 0x1F) >> 5),
+ dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->bevelSplitFlag) * ((steps + 0x1F) >> 5),
"bevelSplitFlag");
/* for each point of poly make a bevel piece */
- bevp = (BevPoint *)(bl + 1) + start;
+ bevp_first = bl->bevpoints;
+ bevp_last = &bl->bevpoints[bl->nr - 1];
+ bevp = &bl->bevpoints[start];
for (i = start, a = 0; a < steps; i++, bevp++, a++) {
float fac = 1.0;
float *cur_data = data;
@@ -1664,12 +1679,15 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
/* rotate bevel piece and write in data */
- if (a == 0)
+ if ((a == 0) && (bevp != bevp_last)) {
rotateBevelPiece(cu, bevp, bevp + 1, dlb, 1.0f - firstblend, widfac, fac, &data);
- else if (a == steps - 1)
+ }
+ else if ((a == steps - 1) && (bevp != bevp_first) ) {
rotateBevelPiece(cu, bevp, bevp - 1, dlb, 1.0f - lastblend, widfac, fac, &data);
- else
+ }
+ else {
rotateBevelPiece(cu, bevp, NULL, dlb, 0.0f, widfac, fac, &data);
+ }
if (cu->bevobj && (cu->flag & CU_FILL_CAPS) && !(nu->flagu & CU_NURB_CYCLIC)) {
if (a == 1) {
@@ -1712,8 +1730,10 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba
}
}
- if (!for_orco)
+ if (!for_orco) {
+ BKE_nurbList_duplicate(&ob->curve_cache->deformed_nurbs, &nubase);
curve_calc_modifiers_post(scene, ob, &nubase, dispbase, r_dm_final, for_render, use_render_resolution);
+ }
if (cu->flag & CU_DEFORM_FILL && !ob->derivedFinal) {
curve_to_filledpoly(cu, &nubase, dispbase);
@@ -1730,7 +1750,7 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco)
/* The same check for duplis as in do_makeDispListCurveTypes.
* Happens when curve used for constraint/bevel was converted to mesh.
* check there is still needed for render displist and orco displists. */
- if (!ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT))
+ if (!ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT))
return;
BKE_object_free_derived_caches(ob);
@@ -1747,10 +1767,11 @@ void BKE_displist_make_curveTypes(Scene *scene, Object *ob, const bool for_orco)
}
void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase *dispbase,
- DerivedMesh **r_dm_final, const bool for_orco, const bool use_render_resolution)
+ DerivedMesh **r_dm_final, const bool for_orco,
+ const bool use_render_resolution)
{
if (ob->curve_cache == NULL) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
+ ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
do_makeDispListCurveTypes(scene, ob, dispbase, r_dm_final, true, for_orco, use_render_resolution);
@@ -1759,7 +1780,7 @@ void BKE_displist_make_curveTypes_forRender(Scene *scene, Object *ob, ListBase *
void BKE_displist_make_curveTypes_forOrco(struct Scene *scene, struct Object *ob, struct ListBase *dispbase)
{
if (ob->curve_cache == NULL) {
- ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for MBall");
+ ob->curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for Curve");
}
do_makeDispListCurveTypes(scene, ob, dispbase, NULL, 1, 1, 1);
@@ -1814,8 +1835,8 @@ void BKE_displist_minmax(ListBase *dispbase, float min[3], float max[3])
/* this is confusing, there's also min_max_object, appplying the obmat... */
static void boundbox_displist_object(Object *ob)
{
- if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
- /* Curver's BB is already calculated as a part of modifier stack,
+ if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ /* Curve's BB is already calculated as a part of modifier stack,
* here we only calculate object BB based on final display list.
*/
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 11737bccef2..4719013e2f8 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -2942,9 +2942,10 @@ static void mesh_faces_nearest_point_dp(void *userdata, int index, const float c
do {
float nearest_tmp[3], dist_sq;
- int vertex, edge;
-
- dist_sq = nearest_point_in_tri_surface_squared(t0, t1, t2, co, &vertex, &edge, nearest_tmp);
+
+ closest_on_tri_to_point_v3(nearest_tmp, co, t0, t1, t2);
+ dist_sq = len_squared_v3v3(co, nearest_tmp);
+
if (dist_sq < nearest->dist_sq) {
nearest->index = index;
nearest->dist_sq = dist_sq;
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index 99e7282fb79..ce7804d9878 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -41,8 +41,6 @@
* is likely to be a little slow.
*/
-#include "GL/glew.h"
-
#include "BLI_math.h"
#include "BLI_jitter.h"
#include "BLI_bitmap.h"
@@ -58,6 +56,7 @@
#include "MEM_guardedalloc.h"
#include "GPU_extensions.h"
+#include "GPU_glew.h"
extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
@@ -911,7 +910,7 @@ static void emDM_drawFacesTex_common(DerivedMesh *dm,
static void emDM_drawFacesTex(DerivedMesh *dm,
DMSetDrawOptionsTex setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData)
+ void *userData, DMDrawFlag UNUSED(flag))
{
emDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
}
@@ -919,7 +918,7 @@ static void emDM_drawFacesTex(DerivedMesh *dm,
static void emDM_drawMappedFacesTex(DerivedMesh *dm,
DMSetDrawOptions setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData)
+ void *userData, DMDrawFlag UNUSED(flag))
{
emDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
}
@@ -2283,8 +2282,8 @@ static void cage_mapped_verts_callback(void *userData, int index, const float co
{
struct CageUserData *data = userData;
- if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_GET(data->visit_bitmap, index))) {
- BLI_BITMAP_SET(data->visit_bitmap, index);
+ if ((index >= 0 && index < data->totvert) && (!BLI_BITMAP_TEST(data->visit_bitmap, index))) {
+ BLI_BITMAP_ENABLE(data->visit_bitmap, index);
copy_v3_v3(data->cos_cage[index], co);
}
}
diff --git a/source/blender/blenkernel/intern/editmesh_bvh.c b/source/blender/blenkernel/intern/editmesh_bvh.c
index 76ea340ecbd..442ab26ffc8 100644
--- a/source/blender/blenkernel/intern/editmesh_bvh.c
+++ b/source/blender/blenkernel/intern/editmesh_bvh.c
@@ -53,13 +53,17 @@ struct BMBVHTree {
int flag;
};
-BMBVHTree *BKE_bmbvh_new_from_editmesh(BMEditMesh *em, int flag, const float (*cos_cage)[3], const bool cos_cage_free)
+BMBVHTree *BKE_bmbvh_new_from_editmesh(
+ BMEditMesh *em, int flag,
+ const float (*cos_cage)[3], const bool cos_cage_free)
{
return BKE_bmbvh_new(em->bm, em->looptris, em->tottri, flag, cos_cage, cos_cage_free);
}
-BMBVHTree *BKE_bmbvh_new(BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag, const float (*cos_cage)[3],
-const bool cos_cage_free)
+BMBVHTree *BKE_bmbvh_new_ex(
+ BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag,
+ const float (*cos_cage)[3], const bool cos_cage_free,
+ bool (*test_fn)(BMFace *, void *user_data), void *user_data)
{
/* could become argument */
const float epsilon = FLT_EPSILON * 2.0f;
@@ -69,6 +73,10 @@ const bool cos_cage_free)
int i;
int tottri;
+ /* avoid testing every tri */
+ BMFace *f_test, *f_test_prev;
+ bool test_fn_ret;
+
/* BKE_editmesh_tessface_calc() must be called already */
BLI_assert(looptris_tot != 0 || bm->totface == 0);
@@ -83,18 +91,22 @@ const bool cos_cage_free)
bmtree->cos_cage_free = cos_cage_free;
bmtree->flag = flag;
- if (flag & (BMBVH_RESPECT_SELECT)) {
+ if (test_fn) {
+ /* callback must do... */
+ BLI_assert(!(flag & (BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN)));
+
+ f_test_prev = NULL;
+ test_fn_ret = false;
+
tottri = 0;
for (i = 0; i < looptris_tot; i++) {
- if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) {
- tottri++;
+ f_test = looptris[i][0]->f;
+ if (f_test != f_test_prev) {
+ test_fn_ret = test_fn(f_test, user_data);
+ f_test_prev = f_test;
}
- }
- }
- else if (flag & (BMBVH_RESPECT_HIDDEN)) {
- tottri = 0;
- for (i = 0; i < looptris_tot; i++) {
- if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) {
+
+ if (test_fn_ret) {
tottri++;
}
}
@@ -105,17 +117,19 @@ const bool cos_cage_free)
bmtree->tree = BLI_bvhtree_new(tottri, epsilon, 8, 8);
- for (i = 0; i < looptris_tot; i++) {
+ f_test_prev = NULL;
+ test_fn_ret = false;
- if (flag & BMBVH_RESPECT_SELECT) {
+ for (i = 0; i < looptris_tot; i++) {
+ if (test_fn) {
/* note, the arrays wont align now! take care */
- if (!BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_SELECT)) {
- continue;
+ f_test = looptris[i][0]->f;
+ if (f_test != f_test_prev) {
+ test_fn_ret = test_fn(f_test, user_data);
+ f_test_prev = f_test;
}
- }
- else if (flag & BMBVH_RESPECT_HIDDEN) {
- /* note, the arrays wont align now! take care */
- if (BM_elem_flag_test(looptris[i][0]->f, BM_ELEM_HIDDEN)) {
+
+ if (!test_fn_ret) {
continue;
}
}
@@ -139,6 +153,38 @@ const bool cos_cage_free)
return bmtree;
}
+static bool bm_face_is_select(BMFace *f, void *UNUSED(user_data))
+{
+ return (BM_elem_flag_test(f, BM_ELEM_SELECT) != 0);
+}
+
+static bool bm_face_is_not_hidden(BMFace *f, void *UNUSED(user_data))
+{
+ return (BM_elem_flag_test(f, BM_ELEM_HIDDEN) == 0);
+}
+
+BMBVHTree *BKE_bmbvh_new(
+ BMesh *bm, BMLoop *(*looptris)[3], int looptris_tot, int flag,
+ const float (*cos_cage)[3], const bool cos_cage_free)
+{
+ bool (*test_fn)(BMFace *, void *user_data);
+
+ if (flag & BMBVH_RESPECT_SELECT) {
+ test_fn = bm_face_is_select;
+ }
+ else if (flag & BMBVH_RESPECT_HIDDEN) {
+ test_fn = bm_face_is_not_hidden;
+ }
+ else {
+ test_fn = NULL;
+ }
+
+ flag &= ~(BMBVH_RESPECT_SELECT | BMBVH_RESPECT_HIDDEN);
+
+ return BKE_bmbvh_new_ex(bm, looptris, looptris_tot, flag, cos_cage, cos_cage_free, test_fn, NULL);
+}
+
+
void BKE_bmbvh_free(BMBVHTree *bmtree)
{
BLI_bvhtree_free(bmtree->tree);
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index e28152dbc1a..ced9da8d0b1 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -630,8 +630,7 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
}
else {
/* use center of object for distance calculus */
- Object *ob = eff->ob;
- Object obcopy = *ob;
+ const Object *ob = eff->ob;
/* use z-axis as normal*/
normalize_v3_v3(efd->nor, ob->obmat[2]);
@@ -654,8 +653,6 @@ int get_effector_data(EffectorCache *eff, EffectorData *efd, EffectedPoint *poin
if (real_velocity)
copy_v3_v3(efd->vel, eff->velocity);
- *eff->ob = obcopy;
-
efd->size = 0.0f;
ret = 1;
@@ -875,7 +872,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
case PFIELD_HARMONIC:
mul_v3_fl(force, -strength * efd->falloff);
copy_v3_v3(temp, point->vel);
- mul_v3_fl(temp, -damp * 2.0f * (float)sqrt(fabs(strength)) * point->vel_to_sec);
+ mul_v3_fl(temp, -damp * 2.0f * sqrtf(fabsf(strength)) * point->vel_to_sec);
add_v3_v3(force, temp);
break;
case PFIELD_CHARGE:
@@ -935,7 +932,7 @@ static void do_physical_effector(EffectorCache *eff, EffectorData *efd, Effected
if (pd->flag & PFIELD_DO_LOCATION) {
madd_v3_v3fl(total_force, force, 1.0f/point->vel_to_sec);
- if (ELEM3(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) {
+ if (ELEM(pd->forcefield, PFIELD_HARMONIC, PFIELD_DRAG, PFIELD_SMOKEFLOW)==0 && pd->f_flow != 0.0f) {
madd_v3_v3fl(total_force, point->vel, -pd->f_flow * efd->falloff);
}
}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index 65b9d2159df..e90a0891436 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -55,6 +55,7 @@
#include "BKE_action.h"
#include "BKE_armature.h"
#include "BKE_constraint.h"
+#include "BKE_context.h"
#include "BKE_curve.h"
#include "BKE_global.h"
#include "BKE_object.h"
@@ -276,7 +277,7 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix,
int matches = 0;
/* sanity checks */
- if (ELEM4(NULL, dst, src, dataPrefix, dataName))
+ if (ELEM(NULL, dst, src, dataPrefix, dataName))
return 0;
else if ((dataPrefix[0] == 0) || (dataName[0] == 0))
return 0;
@@ -310,19 +311,35 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix,
FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, bAction **action, bool *r_driven)
{
+ return rna_get_fcurve_context_ui(NULL, ptr, prop, rnaindex, action, r_driven);
+}
+
+FCurve *rna_get_fcurve_context_ui(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int rnaindex,
+ bAction **action, bool *r_driven)
+{
FCurve *fcu = NULL;
+ PointerRNA tptr = *ptr;
*r_driven = false;
/* there must be some RNA-pointer + property combon */
- if (prop && ptr->id.data && RNA_property_animateable(ptr, prop)) {
- AnimData *adt = BKE_animdata_from_id(ptr->id.data);
- char *path;
+ if (prop && tptr.id.data && RNA_property_animateable(&tptr, prop)) {
+ AnimData *adt = BKE_animdata_from_id(tptr.id.data);
+ int step = C ? 2 : 1; /* Always 1 in case we have no context (can't check in 'ancestors' of given RNA ptr). */
+ char *path = NULL;
+
+ if (!adt && C) {
+ path = BKE_animdata_driver_path_hack(C, &tptr, prop, NULL);
+ adt = BKE_animdata_from_id(tptr.id.data);
+ step--;
+ }
- if (adt) {
+ while (adt && step--) {
if ((adt->action && adt->action->curves.first) || (adt->drivers.first)) {
/* XXX this function call can become a performance bottleneck */
- path = RNA_path_from_ID_to_property(ptr, prop);
+ if (step) {
+ path = RNA_path_from_ID_to_property(&tptr, prop);
+ }
if (path) {
/* animation takes priority over drivers */
@@ -337,13 +354,25 @@ FCurve *rna_get_fcurve(PointerRNA *ptr, PropertyRNA *prop, int rnaindex, bAction
*r_driven = true;
}
- if (fcu && action)
+ if (fcu && action) {
*action = adt->action;
-
- MEM_freeN(path);
+ break;
+ }
+ else if (step) {
+ char *tpath = BKE_animdata_driver_path_hack(C, &tptr, prop, path);
+ if (tpath && tpath != path) {
+ MEM_freeN(path);
+ path = tpath;
+ adt = BKE_animdata_from_id(tptr.id.data);
+ }
+ else {
+ adt = NULL;
+ }
+ }
}
}
}
+ MEM_SAFE_FREE(path);
}
return fcu;
@@ -469,7 +498,7 @@ static short get_fcurve_end_keyframes(FCurve *fcu, BezTriple **first, BezTriple
}
/* find last selected */
- bezt = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, sizeof(BezTriple), fcu->totvert);
+ bezt = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
for (i = 0; i < fcu->totvert; bezt--, i++) {
if (BEZSELECTED(bezt)) {
*last = bezt;
@@ -481,7 +510,7 @@ static short get_fcurve_end_keyframes(FCurve *fcu, BezTriple **first, BezTriple
else {
/* just full array */
*first = fcu->bezt;
- *last = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, sizeof(BezTriple), fcu->totvert);
+ *last = ARRAY_LAST_ITEM(fcu->bezt, BezTriple, fcu->totvert);
found = true;
}
@@ -522,17 +551,28 @@ bool calc_fcurve_bounds(FCurve *fcu, float *xmin, float *xmax, float *ymin, floa
/* only loop over keyframes to find extents for values if needed */
if (ymin || ymax) {
- BezTriple *bezt;
+ BezTriple *bezt, *prevbezt = NULL;
- for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
- if ((do_sel_only == false) || BEZSELECTED(bezt)) {
+ for (bezt = fcu->bezt, i = 0; i < fcu->totvert; prevbezt = bezt, bezt++, i++) {
+ if ((do_sel_only == false) || BEZSELECTED(bezt)) {
+ /* keyframe itself */
+ yminv = min_ff(yminv, bezt->vec[1][1]);
+ ymaxv = max_ff(ymaxv, bezt->vec[1][1]);
+
if (include_handles) {
- yminv = min_ffff(yminv, bezt->vec[1][1], bezt->vec[0][1], bezt->vec[2][1]);
- ymaxv = max_ffff(ymaxv, bezt->vec[1][1], bezt->vec[0][1], bezt->vec[2][1]);
- }
- else {
- yminv = min_ff(yminv, bezt->vec[1][1]);
- ymaxv = max_ff(ymaxv, bezt->vec[1][1]);
+ /* left handle - only if applicable
+ * NOTE: for the very first keyframe, the left handle actually has no bearings on anything
+ */
+ if (prevbezt && (prevbezt->ipo == BEZT_IPO_BEZ)) {
+ yminv = min_ff(yminv, bezt->vec[0][1]);
+ ymaxv = max_ff(ymaxv, bezt->vec[0][1]);
+ }
+
+ /* right handle - only if applicable */
+ if (bezt->ipo == BEZT_IPO_BEZ) {
+ yminv = min_ff(yminv, bezt->vec[2][1]);
+ ymaxv = max_ff(ymaxv, bezt->vec[2][1]);
+ }
}
foundvert = true;
@@ -2050,8 +2090,14 @@ static float fcurve_eval_keyframes(FCurve *fcu, BezTriple *bezts, float evaltime
/* evaltime occurs somewhere in the middle of the curve */
bool exact = false;
- /* - use binary search to find appropriate keyframes */
- a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.001, &exact);
+ /* Use binary search to find appropriate keyframes...
+ *
+ * The threshold here has the following constraints:
+ * - 0.001 is too coarse -> We get artifacts with 2cm driver movements at 1BU = 1m (see T40332)
+ * - 0.00001 is too fine -> Weird errors, like selecting the wrong keyframe range (see T39207), occur.
+ * This lower bound was established in b888a32eee8147b028464336ad2404d8155c64dd
+ */
+ a = binarysearch_bezt_index_ex(bezts, evaltime, fcu->totvert, 0.0001, &exact);
if (G.debug & G_DEBUG) printf("eval fcurve '%s' - %f => %d/%d, %d\n", fcu->rna_path, evaltime, a, fcu->totvert, exact);
if (exact) {
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index ef861e2844c..8d4bb7ec058 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -312,10 +312,10 @@ static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
bp = (BPoint *)MEM_callocN(4 * sizeof(BPoint), "underline_bp");
- copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f);
- copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f);
- copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f);
- copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymax + yofs), 0.0f, 1.0f);
+ copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymax + yofs), 0.0f, 1.0f);
+ copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f);
+ copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f);
+ copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f);
nu2->bp = bp;
BLI_addtail(nubase, nu2);
@@ -484,26 +484,53 @@ int BKE_vfont_select_get(Object *ob, int *r_start, int *r_end)
{
Curve *cu = ob->data;
EditFont *ef = cu->editfont;
+ int start, end, direction;
if ((ob->type != OB_FONT) || (ef == NULL)) return 0;
+ BLI_assert(ef->len >= 0);
BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1);
- BLI_assert(ef->selend >= 0 && ef->selend <= ef->len + 1);
+ BLI_assert(ef->selend >= 0 && ef->selend <= ef->len);
BLI_assert(ef->pos >= 0 && ef->pos <= ef->len);
- if (ef->selstart == 0) return 0;
+ if (ef->selstart == 0) {
+ return 0;
+ }
+
if (ef->selstart <= ef->selend) {
- *r_start = ef->selstart - 1;
- *r_end = ef->selend - 1;
- return 1;
+ start = ef->selstart - 1;
+ end = ef->selend - 1;
+ direction = 1;
+ }
+ else {
+ start = ef->selend;
+ end = ef->selstart - 2;
+ direction = -1;
+ }
+
+ if (start == end + 1) {
+ return 0;
}
else {
- *r_start = ef->selend;
- *r_end = ef->selstart - 2;
- return -1;
+ BLI_assert(start < end + 1);
+ *r_start = start;
+ *r_end = end;
+ return direction;
}
}
+void BKE_vfont_select_clamp(Object *ob)
+{
+ Curve *cu = ob->data;
+ EditFont *ef = cu->editfont;
+
+ BLI_assert((ob->type == OB_FONT) && ef);
+
+ CLAMP_MAX(ef->pos, ef->len);
+ CLAMP_MAX(ef->selstart, ef->len + 1);
+ CLAMP_MAX(ef->selend, ef->len);
+}
+
static float char_width(Curve *cu, VChar *che, CharInfo *info)
{
/* The character wasn't found, propably ascii = 0, then the width shall be 0 as well */
@@ -518,6 +545,24 @@ static float char_width(Curve *cu, VChar *che, CharInfo *info)
}
}
+static void textbox_scale(TextBox *tb_dst, const TextBox *tb_src, float scale)
+{
+ tb_dst->x = tb_src->x * scale;
+ tb_dst->y = tb_src->y * scale;
+ tb_dst->w = tb_src->w * scale;
+ tb_dst->h = tb_src->h * scale;
+}
+
+/**
+ * Used for storing per-line data for alignment & wrapping.
+ */
+struct TempLineInfo {
+ float x_min; /* left margin */
+ float x_max; /* right margin */
+ int char_nr; /* number of characters */
+ int wspace_nr; /* number of whitespaces of line */
+};
+
bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase,
const wchar_t **r_text, int *r_text_len, bool *r_text_free,
struct CharTrans **r_chartransdata)
@@ -528,18 +573,25 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
VFont *vfont, *oldvfont;
VFontData *vfd = NULL;
CharInfo *info = NULL, *custrinfo;
- TextBox *tb;
+ TextBox tb_scale;
+ bool use_textbox;
VChar *che;
struct CharTrans *chartransdata = NULL, *ct;
- float *f, xof, yof, xtrax, linedist, *linedata, *linedata2, *linedata3, *linedata4;
+ struct TempLineInfo *lineinfo;
+ float *f, xof, yof, xtrax, linedist;
float twidth, maxlen = 0;
int i, slen, j;
int curbox;
int selstart, selend;
- short cnr = 0, lnr = 0, wsnr = 0;
+ int cnr = 0, lnr = 0, wsnr = 0;
const wchar_t *mem;
wchar_t ascii;
bool ok = false;
+ const float xof_scale = cu->xof / cu->fsize;
+ const float yof_scale = cu->yof / cu->fsize;
+
+#define MARGIN_X_MIN (xof_scale + tb_scale.x)
+#define MARGIN_Y_MIN (yof_scale + tb_scale.y)
/* remark: do calculations including the trailing '\0' of a string
* because the cursor can be at that location */
@@ -556,9 +608,6 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
/* The VFont Data can not be found */
if (!vfd) return ok;
-
- if (cu->ulheight == 0.0f)
- cu->ulheight = 0.05f;
if (ef) {
slen = ef->len;
@@ -601,25 +650,26 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase
ct = chartransdata = MEM_callocN((slen + 1) * sizeof(struct CharTrans), "buildtext");
/* We assume the worst case: 1 character per line (is freed at end anyway) */
-
- linedata = MEM_mallocN(sizeof(float) * (slen * 2 + 1), "buildtext2");
- linedata2 = MEM_mallocN(sizeof(float) * (slen * 2 + 1), "buildtext3");
- linedata3 = MEM_callocN(sizeof(float) * (slen * 2 + 1), "buildtext4");
- linedata4 = MEM_callocN(sizeof(float) * (slen * 2 + 1), "buildtext5");
+ lineinfo = MEM_mallocN(sizeof(*lineinfo) * (slen * 2 + 1), "lineinfo");
linedist = cu->linedist;
- xof = cu->xof + (cu->tb[0].x / cu->fsize);
- yof = cu->yof + (cu->tb[0].y / cu->fsize);
+ curbox = 0;
+ textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+ use_textbox = (tb_scale.w != 0.0f);
+
+
+ xof = MARGIN_X_MIN;
+ yof = MARGIN_Y_MIN;
xtrax = 0.5f * cu->spacing - 0.5f;
oldvfont = NULL;
- for (i = 0; i < slen; i++) custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK);
+ for (i = 0; i < slen; i++) {
+ custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK);
+ }
- tb = &(cu->tb[0]);
- curbox = 0;
for (i = 0; i <= slen; i++) {
makebreak:
/* Characters in the list */
@@ -645,6 +695,7 @@ makebreak:
if (!vfd) {
MEM_freeN(chartransdata);
chartransdata = NULL;
+ MEM_freeN(lineinfo);
goto finally;
}
@@ -679,12 +730,12 @@ makebreak:
twidth = char_width(cu, che, info);
/* Calculate positions */
- if ((tb->w != 0.0f) &&
+ if ((tb_scale.w != 0.0f) &&
(ct->dobreak == 0) &&
- (((xof - (tb->x / cu->fsize) + twidth) * cu->fsize) > tb->w + cu->xof * cu->fsize))
+ (((xof - tb_scale.x) + twidth) > xof_scale + tb_scale.w))
{
// fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]);
- for (j = i; j && (mem[j] != '\n') && (mem[j] != '\r') && (chartransdata[j].dobreak == 0); j--) {
+ for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
if (mem[j] == ' ' || mem[j] == '-') {
ct -= (i - (j - 1));
cnr -= (i - (j - 1));
@@ -709,7 +760,7 @@ makebreak:
}
}
- if (ascii == '\n' || ascii == '\r' || ascii == 0 || ct->dobreak) {
+ if (ascii == '\n' || ascii == 0 || ct->dobreak) {
ct->xof = xof;
ct->yof = yof;
ct->linenr = lnr;
@@ -717,30 +768,33 @@ makebreak:
yof -= linedist;
- maxlen = max_ff(maxlen, (xof - tb->x / cu->fsize));
- linedata[lnr] = xof - tb->x / cu->fsize;
- linedata2[lnr] = cnr;
- linedata3[lnr] = tb->w / cu->fsize;
- linedata4[lnr] = wsnr;
-
- if ((tb->h != 0.0f) &&
- ((-(yof - (tb->y / cu->fsize))) > ((tb->h / cu->fsize) - (linedist * cu->fsize)) - cu->yof) &&
- (cu->totbox > (curbox + 1)) )
+ lineinfo[lnr].x_min = (xof - xtrax) - tb_scale.x;
+ lineinfo[lnr].x_max = tb_scale.w;
+ lineinfo[lnr].char_nr = cnr;
+ lineinfo[lnr].wspace_nr = wsnr;
+
+ CLAMP_MIN(maxlen, lineinfo[lnr].x_min);
+
+ if ((tb_scale.h != 0.0f) &&
+ (cu->totbox > (curbox + 1)) &&
+ ((-(yof - tb_scale.y)) > (tb_scale.h - (linedist * cu->fsize)) - yof_scale))
{
maxlen = 0;
- tb++;
curbox++;
- yof = cu->yof + tb->y / cu->fsize;
+
+ textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+
+ yof = MARGIN_Y_MIN;
}
/* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */
#if 0
- if (ascii == '\n' || ascii == '\r')
- xof = cu->xof;
+ if (ascii == '\n')
+ xof = xof_scale;
else
- xof = cu->xof + (tb->x / cu->fsize);
+ xof = MARGIN_X_MIN;
#else
- xof = cu->xof + (tb->x / cu->fsize);
+ xof = MARGIN_X_MIN;
#endif
lnr++;
cnr = 0;
@@ -754,9 +808,9 @@ makebreak:
ct->linenr = lnr;
ct->charnr = cnr++;
- tabfac = (xof - cu->xof + 0.01f);
+ tabfac = (xof - MARGIN_X_MIN + 0.01f);
tabfac = 2.0f * ceilf(tabfac / 2.0f);
- xof = cu->xof + tabfac;
+ xof = MARGIN_X_MIN + tabfac;
}
else {
EditFontSelBox *sb = NULL;
@@ -798,68 +852,88 @@ makebreak:
for (i = 0; i <= slen; i++) {
ascii = mem[i];
ct = &chartransdata[i];
- if (ascii == '\n' || ascii == '\r' || ct->dobreak) cu->lines++;
+ if (ascii == '\n' || ct->dobreak) cu->lines++;
}
- /* linedata is now: width of line
- * linedata2 is now: number of characters
- * linedata3 is now: maxlen of that line
- * linedata4 is now: number of whitespaces of line */
+ /* linedata is now: width of line */
if (cu->spacemode != CU_LEFT) {
ct = chartransdata;
if (cu->spacemode == CU_RIGHT) {
- for (i = 0; i < lnr; i++) linedata[i] = linedata3[i] - linedata[i];
+ struct TempLineInfo *li;
+
+ for (i = 0, li = lineinfo; i < lnr; i++, li++) {
+ li->x_min = (li->x_max - li->x_min) + xof_scale;
+ }
+
for (i = 0; i <= slen; i++) {
- ct->xof += linedata[ct->linenr];
+ ct->xof += lineinfo[ct->linenr].x_min;
ct++;
}
}
else if (cu->spacemode == CU_MIDDLE) {
- for (i = 0; i < lnr; i++) linedata[i] = (linedata3[i] - linedata[i]) / 2;
+ struct TempLineInfo *li;
+
+ for (i = 0, li = lineinfo; i < lnr; i++, li++) {
+ li->x_min = ((li->x_max - li->x_min) + xof_scale) / 2.0f;
+ }
+
for (i = 0; i <= slen; i++) {
- ct->xof += linedata[ct->linenr];
+ ct->xof += lineinfo[ct->linenr].x_min;
ct++;
}
}
- else if ((cu->spacemode == CU_FLUSH) && (cu->tb[0].w != 0.0f)) {
- for (i = 0; i < lnr; i++)
- if (linedata2[i] > 1)
- linedata[i] = (linedata3[i] - linedata[i]) / (linedata2[i] - 1);
+ else if ((cu->spacemode == CU_FLUSH) && use_textbox) {
+ struct TempLineInfo *li;
+
+ for (i = 0, li = lineinfo; i < lnr; i++, li++) {
+ li->x_min = ((li->x_max - li->x_min) + xof_scale);
+
+ if (li->char_nr > 1) {
+ li->x_min /= (float)(li->char_nr - 1);
+ }
+ }
for (i = 0; i <= slen; i++) {
- for (j = i; (!ELEM3(mem[j], '\0', '\n', '\r')) && (chartransdata[j].dobreak == 0) && (j < slen); j++) {
+ for (j = i; (!ELEM(mem[j], '\0', '\n')) && (chartransdata[j].dobreak == 0) && (j < slen); j++) {
/* do nothing */
}
-// if ((mem[j] != '\r') && (mem[j] != '\n') && (mem[j])) {
- ct->xof += ct->charnr * linedata[ct->linenr];
+// if ((mem[j] != '\n') && (mem[j])) {
+ ct->xof += ct->charnr * lineinfo[ct->linenr].x_min;
// }
ct++;
}
}
- else if ((cu->spacemode == CU_JUSTIFY) && (cu->tb[0].w != 0.0f)) {
+ else if ((cu->spacemode == CU_JUSTIFY) && use_textbox) {
float curofs = 0.0f;
for (i = 0; i <= slen; i++) {
- for (j = i; (mem[j]) && (mem[j] != '\n') &&
- (mem[j] != '\r') && (chartransdata[j].dobreak == 0) && (j < slen);
+ for (j = i;
+ (mem[j]) && (mem[j] != '\n') && (chartransdata[j].dobreak == 0) && (j < slen);
j++)
{
/* pass */
}
- if ((mem[j] != '\r') && (mem[j] != '\n') &&
+ if ((mem[j] != '\n') &&
((chartransdata[j].dobreak != 0)))
{
- if (mem[i] == ' ') curofs += (linedata3[ct->linenr] - linedata[ct->linenr]) / linedata4[ct->linenr];
+ if (mem[i] == ' ') {
+ struct TempLineInfo *li;
+
+ li = &lineinfo[ct->linenr];
+ curofs += ((li->x_max - li->x_min) + xof_scale) / (float)li->wspace_nr;
+ }
ct->xof += curofs;
}
- if (mem[i] == '\n' || mem[i] == '\r' || chartransdata[i].dobreak) curofs = 0;
+ if (mem[i] == '\n' || chartransdata[i].dobreak) curofs = 0;
ct++;
}
}
}
-
+
+ MEM_freeN(lineinfo);
+
/* TEXT ON CURVE */
/* Note: Only OB_CURVE objects could have a path */
if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) {
@@ -1031,11 +1105,6 @@ makebreak:
}
- MEM_freeN(linedata);
- MEM_freeN(linedata2);
- MEM_freeN(linedata3);
- MEM_freeN(linedata4);
-
if (mode == FO_SELCHANGE) {
MEM_freeN(chartransdata);
chartransdata = NULL;
@@ -1060,14 +1129,14 @@ makebreak:
info->mat_nr = 0;
}
/* We do not want to see any character for \n or \r */
- if (cha != '\n' && cha != '\r')
+ if (cha != '\n')
buildchar(bmain, cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i);
- if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n') && (cha != '\r')) {
+ if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) {
float ulwidth, uloverlap = 0.0f;
rctf rect;
- if ((i < (slen - 1)) && (mem[i + 1] != '\n') && (mem[i + 1] != '\r') &&
+ if ((i < (slen - 1)) && (mem[i + 1] != '\n') &&
((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) &&
((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0))
{
@@ -1121,6 +1190,9 @@ finally:
}
return ok;
+
+#undef MARGIN_X_MIN
+#undef MARGIN_Y_MIN
}
diff --git a/source/blender/blenkernel/intern/freestyle.c b/source/blender/blenkernel/intern/freestyle.c
index 495e99d61af..4aa1b49ea13 100644
--- a/source/blender/blenkernel/intern/freestyle.c
+++ b/source/blender/blenkernel/intern/freestyle.c
@@ -127,12 +127,13 @@ static FreestyleModuleConfig *alloc_module(void)
return (FreestyleModuleConfig *)MEM_callocN(sizeof(FreestyleModuleConfig), "style module configuration");
}
-void BKE_freestyle_module_add(FreestyleConfig *config)
+FreestyleModuleConfig *BKE_freestyle_module_add(FreestyleConfig *config)
{
FreestyleModuleConfig *module_conf = alloc_module();
BLI_addtail(&config->modules, (void *)module_conf);
module_conf->script = NULL;
module_conf->is_displayed = 1;
+ return module_conf;
}
static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig *module)
@@ -141,21 +142,30 @@ static void copy_module(FreestyleModuleConfig *new_module, FreestyleModuleConfig
new_module->is_displayed = module->is_displayed;
}
-void BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
+bool BKE_freestyle_module_delete(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
{
+ if (BLI_findindex(&config->modules, module_conf) == -1)
+ return false;
BLI_freelinkN(&config->modules, module_conf);
+ return true;
}
-void BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
+bool BKE_freestyle_module_move_up(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
{
+ if (BLI_findindex(&config->modules, module_conf) == -1)
+ return false;
BLI_remlink(&config->modules, module_conf);
BLI_insertlinkbefore(&config->modules, module_conf->prev, module_conf);
+ return true;
}
-void BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
+bool BKE_freestyle_module_move_down(FreestyleConfig *config, FreestyleModuleConfig *module_conf)
{
+ if (BLI_findindex(&config->modules, module_conf) == -1)
+ return false;
BLI_remlink(&config->modules, module_conf);
BLI_insertlinkafter(&config->modules, module_conf->next, module_conf);
+ return true;
}
void BKE_freestyle_lineset_unique_name(FreestyleConfig *config, FreestyleLineSet *lineset)
@@ -177,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_new_linestyle("LineStyle", NULL);
+ lineset->linestyle = BKE_linestyle_new("LineStyle", NULL);
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 c381084cfd2..e226e9d9797 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -506,7 +506,7 @@ void gpencil_layer_setactive(bGPdata *gpd, bGPDlayer *active)
bGPDlayer *gpl;
/* error checking */
- if (ELEM3(NULL, gpd, gpd->layers.first, active))
+ if (ELEM(NULL, gpd, gpd->layers.first, active))
return;
/* loop over layers deactivating all */
diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c
index c987e0b67cb..1b7a03ec80e 100644
--- a/source/blender/blenkernel/intern/idcode.c
+++ b/source/blender/blenkernel/intern/idcode.c
@@ -73,6 +73,8 @@ static IDType idtypes[] = {
{ 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 */
@@ -84,12 +86,11 @@ static IDType idtypes[] = {
{ ID_WO, "World", "worlds", IDTYPE_FLAGS_ISLINKABLE },
{ ID_WM, "WindowManager", "window_managers", 0 },
};
-static int nidtypes = sizeof(idtypes) / sizeof(idtypes[0]);
static IDType *idtype_from_name(const char *str)
{
- int i = nidtypes;
-
+ int i = ARRAY_SIZE(idtypes);
+
while (i--) {
if (STREQ(str, idtypes[i].name)) {
return &idtypes[i];
@@ -100,8 +101,8 @@ static IDType *idtype_from_name(const char *str)
}
static IDType *idtype_from_code(int code)
{
- int i = nidtypes;
-
+ int i = ARRAY_SIZE(idtypes);
+
while (i--)
if (code == idtypes[i].code)
return &idtypes[i];
@@ -182,5 +183,5 @@ const char *BKE_idcode_to_name_plural(int code)
*/
int BKE_idcode_iter_step(int *index)
{
- return (*index < nidtypes) ? idtypes[(*index)++].code : 0;
+ return (*index < ARRAY_SIZE(idtypes)) ? idtypes[(*index)++].code : 0;
}
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index f12a0720692..4dbd15a3774 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -64,7 +64,7 @@ static char idp_size_table[] = {
/** \name IDP Array API
* \{ */
-#define GETPROP(prop, i) (((IDProperty *)(prop)->data.pointer) + (i))
+#define GETPROP(prop, i) &(IDP_IDPArray(prop)[i])
/* --------- property array type -------------*/
@@ -251,7 +251,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen)
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
*/
newsize = newlen;
- newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;\
+ newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize;
if (is_grow == false)
idp_resize_group_array(prop, newlen, prop->data.pointer);
@@ -821,7 +821,7 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
case IDP_INT:
return (IDP_Int(prop1) == IDP_Int(prop2));
case IDP_FLOAT:
-#ifdef DEBUG
+#if !defined(NDEBUG) && defined(WITH_PYTHON)
{
float p1 = IDP_Float(prop1);
float p2 = IDP_Float(prop2);
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 440320e98fe..54f5cb7a68e 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -62,6 +62,7 @@
#include "DNA_meshdata_types.h"
#include "BLI_blenlib.h"
+#include "BLI_math_vector.h"
#include "BLI_threads.h"
#include "BLI_timecode.h" /* for stamp timecode format */
#include "BLI_utildefines.h"
@@ -120,12 +121,12 @@ static unsigned int imagecache_hashhash(const void *key_v)
return key->index;
}
-static int imagecache_hashcmp(const void *a_v, const void *b_v)
+static bool imagecache_hashcmp(const void *a_v, const void *b_v)
{
const ImageCacheKey *a = (ImageCacheKey *) a_v;
const ImageCacheKey *b = (ImageCacheKey *) b_v;
- return a->index - b->index;
+ return (a->index != b->index);
}
static void imagecache_keydata(void *userkey, int *framenr, int *proxy, int *render_flags)
@@ -248,7 +249,7 @@ void BKE_image_de_interlace(Image *ima, int odd)
/* ***************** ALLOC & FREE, DATA MANAGING *************** */
-static void image_free_cahced_frames(Image *image)
+static void image_free_cached_frames(Image *image)
{
if (image->cache) {
IMB_moviecache_free(image->cache);
@@ -256,9 +257,13 @@ static void image_free_cahced_frames(Image *image)
}
}
-static void image_free_buffers(Image *ima)
+/**
+ * Simply free the image data from memory,
+ * on display the image can load again (except for render buffers).
+ */
+void BKE_image_free_buffers(Image *ima)
{
- image_free_cahced_frames(ima);
+ image_free_cached_frames(ima);
if (ima->anim) IMB_free_anim(ima->anim);
ima->anim = NULL;
@@ -278,7 +283,7 @@ void BKE_image_free(Image *ima)
{
int a;
- image_free_buffers(ima);
+ BKE_image_free_buffers(ima);
if (ima->packedfile) {
freePackedFile(ima->packedfile);
ima->packedfile = NULL;
@@ -361,6 +366,7 @@ Image *BKE_image_copy(Main *bmain, Image *ima)
nima->gen_x = ima->gen_x;
nima->gen_y = ima->gen_y;
nima->gen_type = ima->gen_type;
+ copy_v4_v4(nima->gen_color, ima->gen_color);
nima->animspeed = ima->animspeed;
@@ -765,6 +771,7 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
ima->gen_type = gen_type;
ima->gen_flag |= (floatbuf ? IMA_GEN_FLOAT : 0);
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);
@@ -835,8 +842,7 @@ void BKE_image_memorypack(Image *ima)
void BKE_image_tag_time(Image *ima)
{
- if (ima)
- ima->lastused = (int)PIL_check_seconds_timer();
+ ima->lastused = (int)PIL_check_seconds_timer();
}
#if 0
@@ -854,43 +860,6 @@ static void tag_all_images_time()
}
#endif
-void free_old_images(void)
-{
- Image *ima;
- static int lasttime = 0;
- int ctime = (int)PIL_check_seconds_timer();
-
- /*
- * Run garbage collector once for every collecting period of time
- * if textimeout is 0, that's the option to NOT run the collector
- */
- if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime)
- return;
-
- /* of course not! */
- if (G.is_rendering)
- return;
-
- lasttime = ctime;
-
- ima = G.main->image.first;
- while (ima) {
- if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
- /* If it's in GL memory, deallocate and set time tag to current time
- * This gives textures a "second chance" to be used before dying. */
- if (ima->bindcode || ima->repbind) {
- GPU_free_image(ima);
- ima->lastused = ctime;
- }
- /* Otherwise, just kill the buffers */
- else {
- image_free_buffers(ima);
- }
- }
- ima = ima->id.next;
- }
-}
-
static uintptr_t image_mem_size(Image *image)
{
uintptr_t size = 0;
@@ -1291,7 +1260,7 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF
extension = extension_test;
}
#endif
- else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) {
+ else if (ELEM(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) {
if (!BLI_testextensie(string, extension_test = ".png"))
extension = extension_test;
}
@@ -1934,7 +1903,7 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
ibuf->ftype = RADHDR;
}
#endif
- else if (ELEM5(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) {
+ else if (ELEM(imtype, R_IMF_IMTYPE_PNG, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_THEORA, R_IMF_IMTYPE_XVID)) {
ibuf->ftype = PNG;
if (imtype == R_IMF_IMTYPE_PNG) {
@@ -2057,7 +2026,7 @@ int BKE_imbuf_write(ImBuf *ibuf, const char *name, ImageFormatData *imf)
return(ok);
}
-/* same as BKE_imbuf_write() but crappy workaround not to perminantly modify
+/* same as BKE_imbuf_write() but crappy workaround not to permanently modify
* _some_, values in the imbuf */
int BKE_imbuf_write_as(ImBuf *ibuf, const char *name, ImageFormatData *imf,
const bool save_copy)
@@ -2251,7 +2220,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
switch (signal) {
case IMA_SIGNAL_FREE:
- image_free_buffers(ima);
+ BKE_image_free_buffers(ima);
if (iuser)
iuser->ok = 1;
break;
@@ -2283,7 +2252,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
#if 0
/* force reload on first use, but not for multilayer, that makes nodes and buttons in ui drawing fail */
if (ima->type != IMA_TYPE_MULTILAYER)
- image_free_buffers(ima);
+ BKE_image_free_buffers(ima);
#else
/* image buffers for non-sequence multilayer will share buffers with RenderResult,
* however sequence multilayer will own buffers. Such logic makes switching from
@@ -2292,7 +2261,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
* are nicely detecting anyway, but freeing buffers always here makes multilayer
* sequences behave stable
*/
- image_free_buffers(ima);
+ BKE_image_free_buffers(ima);
#endif
ima->ok = 1;
@@ -2311,14 +2280,14 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
if (pf) {
freePackedFile(ima->packedfile);
ima->packedfile = pf;
- image_free_buffers(ima);
+ BKE_image_free_buffers(ima);
}
else {
printf("ERROR: Image not available. Keeping packed image\n");
}
}
else
- image_free_buffers(ima);
+ BKE_image_free_buffers(ima);
if (iuser)
iuser->ok = 1;
@@ -2336,7 +2305,7 @@ void BKE_image_signal(Image *ima, ImageUser *iuser, int signal)
}
break;
case IMA_SIGNAL_COLORMANAGE:
- image_free_buffers(ima);
+ BKE_image_free_buffers(ima);
ima->ok = 1;
@@ -2474,7 +2443,7 @@ static void image_initialize_after_load(Image *ima, ImBuf *ibuf)
else de_interlace_ng(ibuf);
}
/* timer */
- ima->lastused = clock() / CLOCKS_PER_SEC;
+ BKE_image_tag_time(ima);
ima->ok = IMA_OK_LOADED;
@@ -2560,7 +2529,7 @@ static ImBuf *image_load_sequence_multilayer(Image *ima, ImageUser *iuser, int f
* need to ensure there's no image buffers are hanging around
* with dead links after freeing the render result.
*/
- image_free_cahced_frames(ima);
+ image_free_cached_frames(ima);
RE_FreeRenderResult(ima->rr);
ima->rr = NULL;
}
@@ -2656,7 +2625,7 @@ static ImBuf *image_load_image_file(Image *ima, ImageUser *iuser, int cfra)
int assign = 0, flag;
/* always ensure clean ima */
- image_free_buffers(ima);
+ BKE_image_free_buffers(ima);
/* is there a PackedFile with this image ? */
if (ima->packedfile) {
@@ -3030,7 +2999,6 @@ BLI_INLINE bool image_quick_test(Image *ima, ImageUser *iuser)
static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
{
ImBuf *ibuf = NULL;
- float color[] = {0, 0, 0, 1};
int frame = 0, index = 0;
if (lock_r)
@@ -3075,7 +3043,7 @@ static ImBuf *image_acquire_ibuf(Image *ima, ImageUser *iuser, void **lock_r)
if (ima->gen_y == 0) ima->gen_y = 1024;
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,
- color, &ima->colorspace_settings);
+ ima->gen_color, &ima->colorspace_settings);
image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
ima->ok = IMA_OK_LOADED;
}
diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c
index e28fb59cfe6..4cf9d52989f 100644
--- a/source/blender/blenkernel/intern/implicit.c
+++ b/source/blender/blenkernel/intern/implicit.c
@@ -1236,7 +1236,7 @@ DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s,
sub_v3_v3v3(extent, X[s->kl], X[s->ij]);
sub_v3_v3v3(vel, V[s->kl], V[s->ij]);
dot = dot_v3v3(extent, extent);
- length = sqrt(dot);
+ length = sqrtf(dot);
s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
@@ -1432,7 +1432,7 @@ static void hair_velocity_smoothing(ClothModifierData *clmd, lfVector *lF, lfVec
float smoothfac = 2.0f * clmd->sim_parms->velocity_smooth;
float collfac = 2.0f * clmd->sim_parms->collider_friction;
unsigned int v = 0;
- unsigned int i = 0;
+ int i = 0;
int j = 0;
int k = 0;
@@ -1804,6 +1804,7 @@ static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothMo
return 1;
}
+
int implicit_solver(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
{
unsigned int i=0;
@@ -1888,10 +1889,8 @@ int implicit_solver(Object *ob, float frame, ClothModifierData *clmd, ListBase *
//if (do_extra_solve)
// cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
- for (i = 0; i < numverts; i++) {
-
- if (do_extra_solve) {
-
+ if (do_extra_solve) {
+ for (i = 0; i < numverts; i++) {
if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED))
continue;
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 7385322ddeb..51cf26063c7 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -1308,8 +1308,8 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i
* - they were degrees/10
* - we need radians for RNA to do the right thing
*/
- if ( ((icu->blocktype == ID_OB) && ELEM3(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) ||
- ((icu->blocktype == ID_PO) && ELEM3(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z)) )
+ if ( ((icu->blocktype == ID_OB) && ELEM(icu->adrcode, OB_ROT_X, OB_ROT_Y, OB_ROT_Z)) ||
+ ((icu->blocktype == ID_PO) && ELEM(icu->adrcode, AC_EUL_X, AC_EUL_Y, AC_EUL_Z)) )
{
const float fac = (float)M_PI / 18.0f; //10.0f * M_PI/180.0f;
@@ -1341,7 +1341,7 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i
DriverVar *dvar = fcu->driver->variables.first;
DriverTarget *dtar = &dvar->targets[0];
- if (ELEM3(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) {
+ if (ELEM(dtar->transChan, DTAR_TRANSCHAN_ROTX, DTAR_TRANSCHAN_ROTY, DTAR_TRANSCHAN_ROTZ)) {
const float fac = (float)M_PI / 18.0f;
dst->vec[0][0] *= fac;
@@ -1388,7 +1388,7 @@ static void ipo_to_animato(ID *id, Ipo *ipo, char actname[], char constname[], S
IpoCurve *icu;
/* sanity check */
- if (ELEM3(NULL, ipo, anim, drivers))
+ if (ELEM(NULL, ipo, anim, drivers))
return;
if (G.debug & G_DEBUG) printf("ipo_to_animato\n");
diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c
index 0f04c03688c..69b375fba58 100644
--- a/source/blender/blenkernel/intern/key.c
+++ b/source/blender/blenkernel/intern/key.c
@@ -1558,9 +1558,23 @@ KeyBlock *BKE_keyblock_add(Key *key, const char *name)
KeyBlock *BKE_keyblock_add_ctime(Key *key, const char *name, const bool do_force)
{
KeyBlock *kb = BKE_keyblock_add(key, name);
+ const float cpos = key->ctime / 100.0f;
+ /* In case of absolute keys, there is no point in adding more than one key with the same pos.
+ * Hence only set new keybloc pos to current time if none previous one already use it.
+ * Now at least people just adding absolute keys without touching to ctime
+ * won't have to systematically use retiming func (and have ordering issues, too). See T39897.
+ */
+ if (!do_force && (key->type != KEY_RELATIVE)) {
+ KeyBlock *it_kb;
+ for (it_kb = key->block.first; it_kb; it_kb = it_kb->next) {
+ if (it_kb->pos == cpos) {
+ return kb;
+ }
+ }
+ }
if (do_force || (key->type != KEY_RELATIVE)) {
- kb->pos = key->ctime / 100.0f;
+ kb->pos = cpos;
BKE_key_sort(key);
}
@@ -2041,3 +2055,91 @@ void BKE_key_convert_from_offset(Object *ob, KeyBlock *kb, float (*ofs)[3])
}
}
}
+
+/* ==========================================================*/
+
+/** Move shape key from org_index to new_index. Safe, clamps index to valid range, updates reference keys,
+ * the object's active shape index, the 'frame' value in case of absolute keys, etc.
+ * Note indices are expected in real values (not 'fake' shapenr +1 ones).
+ *
+ * \param org_index if < 0, current object's active shape will be used as skey to move.
+ * \return true if something was done, else false.
+ */
+bool BKE_keyblock_move(Object *ob, int org_index, int new_index)
+{
+ Key *key = BKE_key_from_object(ob);
+ KeyBlock *kb;
+ const int act_index = ob->shapenr - 1;
+ const int totkey = key->totkey;
+ int i;
+ bool rev, in_range = false;
+
+ if (org_index < 0) {
+ org_index = act_index;
+ }
+
+ CLAMP(new_index, 0, key->totkey - 1);
+ CLAMP(org_index, 0, key->totkey - 1);
+
+ if (new_index == org_index) {
+ return false;
+ }
+
+ rev = ((new_index - org_index) < 0) ? true : false;
+
+ /* We swap 'org' element with its previous/next neighbor (depending on direction of the move) repeatedly,
+ * until we reach final position.
+ * This allows us to only loop on the list once! */
+ for (kb = (rev ? key->block.last : key->block.first), i = (rev ? totkey - 1 : 0);
+ kb;
+ kb = (rev ? kb->prev : kb->next), rev ? i-- : i++)
+ {
+ if (i == org_index) {
+ in_range = true; /* Start list items swapping... */
+ }
+ else if (i == new_index) {
+ in_range = false; /* End list items swapping. */
+ }
+
+ if (in_range) {
+ KeyBlock *other_kb = rev ? kb->prev : kb->next;
+
+ /* Swap with previous/next list item. */
+ BLI_listbase_swaplinks(&key->block, kb, other_kb);
+
+ /* Swap absolute positions. */
+ SWAP(float, kb->pos, other_kb->pos);
+
+ kb = other_kb;
+ }
+
+ /* Adjust relative indices, this has to be done on the whole list! */
+ if (kb->relative == org_index) {
+ kb->relative = new_index;
+ }
+ else if (kb->relative < org_index && kb->relative >= new_index) {
+ /* remove after, insert before this index */
+ kb->relative++;
+ }
+ else if (kb->relative > org_index && kb->relative <= new_index) {
+ /* remove before, insert after this index */
+ kb->relative--;
+ }
+ }
+
+ /* Need to update active shape number if it's affected, same principle as for relative indices above. */
+ if (org_index == act_index) {
+ ob->shapenr = new_index + 1;
+ }
+ else if (act_index < org_index && act_index >= new_index) {
+ ob->shapenr++;
+ }
+ else if (act_index > org_index && act_index <= new_index) {
+ ob->shapenr--;
+ }
+
+ /* First key is always refkey, matches interface and BKE_key_sort */
+ key->refkey = key->block.first;
+
+ return true;
+}
diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c
index 749e915e5ca..4a413850ec0 100644
--- a/source/blender/blenkernel/intern/lamp.c
+++ b/source/blender/blenkernel/intern/lamp.c
@@ -135,8 +135,7 @@ Lamp *localize_lamp(Lamp *la)
Lamp *lan;
int a;
- lan = BKE_libblock_copy(&la->id);
- BLI_remlink(&G.main->lamp, lan);
+ lan = BKE_libblock_copy_nolib(&la->id, false);
for (a = 0; a < MAX_MTEX; a++) {
if (lan->mtex[a]) {
diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c
index 51fbb86b38e..3f12e3efcc7 100644
--- a/source/blender/blenkernel/intern/lattice.c
+++ b/source/blender/blenkernel/intern/lattice.c
@@ -120,11 +120,11 @@ void BKE_lattice_bitmap_from_flag(Lattice *lt, BLI_bitmap *bitmap, const short f
bp = lt->def;
for (i = 0; i < tot; i++, bp++) {
if ((bp->f1 & flag) && (!respecthide || !bp->hide)) {
- BLI_BITMAP_SET(bitmap, i);
+ BLI_BITMAP_ENABLE(bitmap, i);
}
else {
if (clear) {
- BLI_BITMAP_CLEAR(bitmap, i);
+ BLI_BITMAP_DISABLE(bitmap, i);
}
}
}
@@ -626,16 +626,19 @@ static bool calc_curve_deform(Scene *scene, Object *par, float co[3],
short index;
const bool is_neg_axis = (axis > 2);
- /* to be sure, mostly after file load */
- if (ELEM(NULL, par->curve_cache, par->curve_cache->path)) {
+ /* to be sure, mostly after file load, also cyclic dependencies */
#ifdef CYCLIC_DEPENDENCY_WORKAROUND
+ if (par->curve_cache == NULL) {
BKE_displist_make_curveTypes(scene, par, false);
+ }
#endif
- if (par->curve_cache->path == NULL) {
- return 0; // happens on append and cyclic dependencies...
- }
+
+ if (par->curve_cache->path == NULL) {
+ return 0; /* happens on append, cyclic dependencies
+ * and empty curves
+ */
}
-
+
/* options */
if (is_neg_axis) {
index = axis - 3;
@@ -726,7 +729,8 @@ void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh
Curve *cu;
int a;
CurveDeform cd;
- int use_vgroups;
+ MDeformVert *dvert = NULL;
+ int defgrp_index = -1;
const bool is_neg_axis = (defaxis > 2);
if (cuOb->type != OB_CURVE)
@@ -747,75 +751,63 @@ void curve_deform_verts(Scene *scene, Object *cuOb, Object *target, DerivedMesh
cd.dmax[0] = cd.dmax[1] = cd.dmax[2] = 0.0f;
}
- /* check whether to use vertex groups (only possible if target is a Mesh)
- * we want either a Mesh with no derived data, or derived data with
- * deformverts
+ /* Check whether to use vertex groups (only possible if target is a Mesh or Lattice).
+ * We want either a Mesh/Lattice with no derived data, or derived data with deformverts.
*/
- if (target->type == OB_MESH) {
- /* if there's derived data without deformverts, don't use vgroups */
- if (dm) {
- use_vgroups = (dm->getVertData(dm, 0, CD_MDEFORMVERT) != NULL);
- }
- else {
- Mesh *me = target->data;
- use_vgroups = (me->dvert != NULL);
+ if (vgroup && vgroup[0] && ELEM(target->type, OB_MESH, OB_LATTICE)) {
+ defgrp_index = defgroup_name_index(target, vgroup);
+
+ if (defgrp_index != -1) {
+ /* if there's derived data without deformverts, don't use vgroups */
+ if (dm) {
+ dvert = dm->getVertDataArray(dm, CD_MDEFORMVERT);
+ }
+ else if (target->type == OB_LATTICE) {
+ dvert = ((Lattice *)target->data)->dvert;
+ }
+ else {
+ dvert = ((Mesh *)target->data)->dvert;
+ }
}
}
- else {
- use_vgroups = false;
- }
-
- if (vgroup && vgroup[0] && use_vgroups) {
- Mesh *me = target->data;
- const int defgrp_index = defgroup_name_index(target, vgroup);
- if (defgrp_index != -1 && (me->dvert || dm)) {
- MDeformVert *dvert = me->dvert;
- float vec[3];
- float weight;
-
+ if (dvert) {
+ MDeformVert *dvert_iter;
+ float vec[3];
- if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
- dvert = me->dvert;
- for (a = 0; a < numVerts; a++, dvert++) {
- if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
- weight = defvert_find_weight(dvert, defgrp_index);
-
- if (weight > 0.0f) {
- mul_m4_v3(cd.curvespace, vertexCos[a]);
- copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
- interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
- mul_m4_v3(cd.objectspace, vertexCos[a]);
- }
+ if (cu->flag & CU_DEFORM_BOUNDS_OFF) {
+ for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
+ const float weight = defvert_find_weight(dvert_iter, defgrp_index);
+
+ if (weight > 0.0f) {
+ mul_m4_v3(cd.curvespace, vertexCos[a]);
+ copy_v3_v3(vec, vertexCos[a]);
+ calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
+ interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
+ mul_m4_v3(cd.objectspace, vertexCos[a]);
}
}
- else {
- /* set mesh min/max bounds */
- INIT_MINMAX(cd.dmin, cd.dmax);
-
- for (a = 0; a < numVerts; a++, dvert++) {
- if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
-
- if (defvert_find_weight(dvert, defgrp_index) > 0.0f) {
- mul_m4_v3(cd.curvespace, vertexCos[a]);
- minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
- }
+ }
+ else {
+ /* set mesh min/max bounds */
+ INIT_MINMAX(cd.dmin, cd.dmax);
+
+ for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
+ if (defvert_find_weight(dvert_iter, defgrp_index) > 0.0f) {
+ mul_m4_v3(cd.curvespace, vertexCos[a]);
+ minmax_v3v3_v3(cd.dmin, cd.dmax, vertexCos[a]);
}
-
- dvert = me->dvert;
- for (a = 0; a < numVerts; a++, dvert++) {
- if (dm) dvert = dm->getVertData(dm, a, CD_MDEFORMVERT);
-
- weight = defvert_find_weight(dvert, defgrp_index);
-
- if (weight > 0.0f) {
- /* already in 'cd.curvespace', prev for loop */
- copy_v3_v3(vec, vertexCos[a]);
- calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
- interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
- mul_m4_v3(cd.objectspace, vertexCos[a]);
- }
+ }
+
+ for (a = 0, dvert_iter = dvert; a < numVerts; a++, dvert_iter++) {
+ const float weight = defvert_find_weight(dvert_iter, defgrp_index);
+
+ if (weight > 0.0f) {
+ /* already in 'cd.curvespace', prev for loop */
+ copy_v3_v3(vec, vertexCos[a]);
+ calc_curve_deform(scene, cuOb, vec, defaxis, &cd, NULL);
+ interp_v3_v3v3(vertexCos[a], vertexCos[a], vec, weight);
+ mul_m4_v3(cd.objectspace, vertexCos[a]);
}
}
}
@@ -1163,6 +1155,28 @@ void BKE_lattice_center_bounds(Lattice *lt, float cent[3])
mid_v3_v3v3(cent, min, max);
}
+void BKE_lattice_transform(Lattice *lt, float mat[4][4], bool do_keys)
+{
+ BPoint *bp = lt->def;
+ int i = lt->pntsu * lt->pntsv * lt->pntsw;
+
+ while (i--) {
+ mul_m4_v3(mat, bp->vec);
+ bp++;
+ }
+
+ if (do_keys && lt->key) {
+ KeyBlock *kb;
+
+ for (kb = lt->key->block.first; kb; kb = kb->next) {
+ float *fp = kb->data;
+ for (i = kb->totelem; i--; fp += 3) {
+ mul_m4_v3(mat, fp);
+ }
+ }
+ }
+}
+
void BKE_lattice_translate(Lattice *lt, float offset[3], bool do_keys)
{
int i, numVerts;
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index fe2d1481581..b49eee3ea22 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -71,6 +71,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_threads.h"
#include "BLF_translation.h"
#include "BKE_action.h"
@@ -103,6 +104,7 @@
#include "BKE_mask.h"
#include "BKE_node.h"
#include "BKE_object.h"
+#include "BKE_paint.h"
#include "BKE_particle.h"
#include "BKE_packedFile.h"
#include "BKE_speaker.h"
@@ -381,7 +383,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_copy_linestyle((FreestyleLineStyle *)id);
+ if (!test) *newid = (ID *)BKE_linestyle_copy((FreestyleLineStyle *)id);
return true;
}
@@ -514,6 +516,10 @@ ListBase *which_libbase(Main *mainlib, short type)
return &(mainlib->mask);
case ID_LS:
return &(mainlib->linestyle);
+ case ID_PAL:
+ return &(mainlib->palettes);
+ case ID_PC:
+ return &(mainlib->paintcurves);
}
return NULL;
}
@@ -595,6 +601,8 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[a++] = &(main->text);
lb[a++] = &(main->sound);
lb[a++] = &(main->group);
+ lb[a++] = &(main->palettes);
+ lb[a++] = &(main->paintcurves);
lb[a++] = &(main->brush);
lb[a++] = &(main->script);
lb[a++] = &(main->particle);
@@ -612,6 +620,8 @@ int set_listbasepointers(Main *main, ListBase **lb)
lb[a] = NULL;
+ BLI_assert(a + 1 == MAX_LIBARRAY);
+
return a;
}
@@ -730,6 +740,12 @@ static ID *alloc_libblock_notest(short type)
case ID_LS:
id = MEM_callocN(sizeof(FreestyleLineStyle), "Freestyle Line Style");
break;
+ case ID_PAL:
+ id = MEM_callocN(sizeof(Palette), "Palette");
+ break;
+ case ID_PC:
+ id = MEM_callocN(sizeof(PaintCurve), "Paint Curve");
+ break;
}
return id;
}
@@ -747,12 +763,14 @@ void *BKE_libblock_alloc(Main *bmain, short type, const char *name)
id = alloc_libblock_notest(type);
if (id) {
+ BKE_main_lock(bmain);
BLI_addtail(lb, id);
id->us = 1;
id->icon_id = 0;
*( (short *)id->name) = type;
new_id(lb, id, name);
/* alphabetic insertion: is in new_id */
+ BKE_main_unlock(bmain);
}
DAG_id_type_tag(bmain, type);
return id;
@@ -826,6 +844,7 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action)
id->newid = idn;
idn->flag |= LIB_NEW;
+ idn->us = 1;
BKE_libblock_copy_data(idn, id, do_action);
@@ -881,10 +900,8 @@ static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata
}
}
-void BKE_libblock_free_data(ID *id)
+void BKE_libblock_free_data(Main *bmain, ID *id)
{
- Main *bmain = G.main; /* should eventually be an arg */
-
if (id->properties) {
IDP_FreeProperty(id->properties);
MEM_freeN(id->properties);
@@ -1003,17 +1020,26 @@ void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user)
BKE_mask_free(bmain, (Mask *)id);
break;
case ID_LS:
- BKE_free_linestyle((FreestyleLineStyle *)id);
+ BKE_linestyle_free((FreestyleLineStyle *)id);
+ break;
+ case ID_PAL:
+ BKE_palette_free((Palette *)id);
+ break;
+ case ID_PC:
+ BKE_paint_curve_free((PaintCurve *)id);
break;
}
/* avoid notifying on removed data */
+ BKE_main_lock(bmain);
+
if (free_notifier_reference_cb)
free_notifier_reference_cb(id);
BLI_remlink(lb, id);
- BKE_libblock_free_data(id);
+ BKE_libblock_free_data(bmain, id);
+ BKE_main_unlock(bmain);
MEM_freeN(id);
}
@@ -1043,7 +1069,10 @@ 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 = MEM_callocN(sizeof(EvaluationContext),
+ "EvaluationContext");
+ bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
+ BLI_spin_init((SpinLock *)bmain->lock);
return bmain;
}
@@ -1106,19 +1135,34 @@ void BKE_main_free(Main *mainvar)
}
}
+ BLI_spin_end((SpinLock *)mainvar->lock);
+ MEM_freeN(mainvar->lock);
MEM_freeN(mainvar->eval_ctx);
MEM_freeN(mainvar);
}
-/* ***************** ID ************************ */
+void BKE_main_lock(struct Main *bmain)
+{
+ BLI_spin_lock((SpinLock *) bmain->lock);
+}
+void BKE_main_unlock(struct Main *bmain)
+{
+ BLI_spin_unlock((SpinLock *) bmain->lock);
+}
-ID *BKE_libblock_find_name(const short type, const char *name) /* type: "OB" or "MA" etc */
+/* ***************** ID ************************ */
+ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name)
{
- ListBase *lb = which_libbase(G.main, type);
+ ListBase *lb = which_libbase(bmain, type);
BLI_assert(lb != NULL);
return BLI_findstring(lb, name, offsetof(ID, name) + 2);
}
+ID *BKE_libblock_find_name(const short type, const char *name)
+{
+ return BKE_libblock_find_name_ex(G.main, type, name);
+}
+
void id_sort_by_name(ListBase *lb, ID *id)
{
diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c
index e9bdc3679c1..6d2e2f1ecd4 100644
--- a/source/blender/blenkernel/intern/library_query.c
+++ b/source/blender/blenkernel/intern/library_query.c
@@ -47,10 +47,12 @@
#include "DNA_mask_types.h"
#include "DNA_node_types.h"
#include "DNA_object_force.h"
+#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_screen_types.h"
#include "DNA_speaker_types.h"
#include "DNA_sound_types.h"
+#include "DNA_text_types.h"
#include "DNA_vfont_types.h"
#include "DNA_world_types.h"
@@ -168,6 +170,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_SCE:
{
Scene *scene = (Scene *) id;
+ SceneRenderLayer *srl;
Base *base;
CALLBACK_INVOKE(scene->camera, IDWALK_NOP);
@@ -178,6 +181,31 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
}
CALLBACK_INVOKE(scene->obedit, IDWALK_NOP);
+ for (srl = scene->r.layers.first; srl; srl = srl->next) {
+ FreestyleModuleConfig *fmc;
+ FreestyleLineSet *fls;
+
+ if (srl->mat_override) {
+ CALLBACK_INVOKE(srl->mat_override, IDWALK_NOP);
+ }
+ if (srl->light_override) {
+ CALLBACK_INVOKE(srl->light_override, IDWALK_NOP);
+ }
+ for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) {
+ if (fmc->script) {
+ CALLBACK_INVOKE(fmc->script, IDWALK_NOP);
+ }
+ }
+ for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) {
+ if (fls->group) {
+ CALLBACK_INVOKE(fls->group, IDWALK_NOP);
+ }
+ if (fls->linestyle) {
+ CALLBACK_INVOKE(fls->linestyle, IDWALK_NOP);
+ }
+ }
+ }
+
if (scene->ed) {
Sequence *seq;
SEQP_BEGIN(scene->ed, seq)
@@ -455,12 +483,38 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u
case ID_LS:
{
FreestyleLineStyle *linestyle = (FreestyleLineStyle *) id;
+ LineStyleModifier *m;
for (i = 0; i < MAX_MTEX; i++) {
if (linestyle->mtex[i]) {
library_foreach_mtex(&data, linestyle->mtex[i]);
}
}
CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP);
+
+ for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) {
+ if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleColorModifier_DistanceFromObject *p = (LineStyleColorModifier_DistanceFromObject *)m;
+ if (p->target) {
+ CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ }
+ }
+ }
+ for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) {
+ if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleAlphaModifier_DistanceFromObject *p = (LineStyleAlphaModifier_DistanceFromObject *)m;
+ if (p->target) {
+ CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ }
+ }
+ }
+ for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) {
+ if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) {
+ LineStyleThicknessModifier_DistanceFromObject *p = (LineStyleThicknessModifier_DistanceFromObject *)m;
+ if (p->target) {
+ CALLBACK_INVOKE(p->target, IDWALK_NOP);
+ }
+ }
+ }
break;
}
diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c
index 8028bdbc327..bcdaf9b7af0 100644
--- a/source/blender/blenkernel/intern/linestyle.c
+++ b/source/blender/blenkernel/intern/linestyle.c
@@ -43,6 +43,8 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BKE_context.h"
+#include "BKE_freestyle.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_linestyle.h"
@@ -51,6 +53,8 @@
#include "BKE_colortools.h"
#include "BKE_animsys.h"
+#include "RNA_access.h"
+
static const char *modifier_name[LS_MODIFIER_NUM] = {
NULL,
"Along Stroke",
@@ -89,6 +93,7 @@ static void default_linestyle_settings(FreestyleLineStyle *linestyle)
linestyle->min_length = 0.0f;
linestyle->max_length = 10000.0f;
linestyle->split_length = 100;
+ linestyle->chain_count = 10;
linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
linestyle->integration_type = LS_INTEGRATION_MEAN;
linestyle->texstep = 1.0f;
@@ -99,12 +104,12 @@ static void default_linestyle_settings(FreestyleLineStyle *linestyle)
BLI_listbase_clear(&linestyle->thickness_modifiers);
BLI_listbase_clear(&linestyle->geometry_modifiers);
- BKE_add_linestyle_geometry_modifier(linestyle, LS_MODIFIER_SAMPLING);
+ BKE_linestyle_geometry_modifier_add(linestyle, NULL, LS_MODIFIER_SAMPLING);
linestyle->caps = LS_CAPS_BUTT;
}
-FreestyleLineStyle *BKE_new_linestyle(const char *name, struct Main *main)
+FreestyleLineStyle *BKE_linestyle_new(const char *name, struct Main *main)
{
FreestyleLineStyle *linestyle;
@@ -118,7 +123,7 @@ FreestyleLineStyle *BKE_new_linestyle(const char *name, struct Main *main)
return linestyle;
}
-void BKE_free_linestyle(FreestyleLineStyle *linestyle)
+void BKE_linestyle_free(FreestyleLineStyle *linestyle)
{
LineStyleModifier *m;
@@ -137,33 +142,33 @@ void BKE_free_linestyle(FreestyleLineStyle *linestyle)
BKE_free_animdata(&linestyle->id);
while ((m = (LineStyleModifier *)linestyle->color_modifiers.first))
- BKE_remove_linestyle_color_modifier(linestyle, m);
+ BKE_linestyle_color_modifier_remove(linestyle, m);
while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first))
- BKE_remove_linestyle_alpha_modifier(linestyle, m);
+ BKE_linestyle_alpha_modifier_remove(linestyle, m);
while ((m = (LineStyleModifier *)linestyle->thickness_modifiers.first))
- BKE_remove_linestyle_thickness_modifier(linestyle, m);
+ BKE_linestyle_thickness_modifier_remove(linestyle, m);
while ((m = (LineStyleModifier *)linestyle->geometry_modifiers.first))
- BKE_remove_linestyle_geometry_modifier(linestyle, m);
+ BKE_linestyle_geometry_modifier_remove(linestyle, m);
}
-FreestyleLineStyle *BKE_copy_linestyle(FreestyleLineStyle *linestyle)
+FreestyleLineStyle *BKE_linestyle_copy(FreestyleLineStyle *linestyle)
{
FreestyleLineStyle *new_linestyle;
LineStyleModifier *m;
int a;
- new_linestyle = BKE_new_linestyle(linestyle->id.name + 2, NULL);
- BKE_free_linestyle(new_linestyle);
+ new_linestyle = BKE_linestyle_new(linestyle->id.name + 2, NULL);
+ BKE_linestyle_free(new_linestyle);
for (a = 0; a < MAX_MTEX; a++) {
if (linestyle->mtex[a]) {
- new_linestyle->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_copy_linestyle");
+ new_linestyle->mtex[a] = MEM_mallocN(sizeof(MTex), "BKE_linestyle_copy");
memcpy(new_linestyle->mtex[a], linestyle->mtex[a], sizeof(MTex));
id_us_plus((ID *)new_linestyle->mtex[a]->tex);
}
}
if (linestyle->nodetree) {
- linestyle->nodetree = ntreeCopyTree(linestyle->nodetree);
+ new_linestyle->nodetree = ntreeCopyTree(linestyle->nodetree);
}
new_linestyle->r = linestyle->r;
@@ -182,6 +187,7 @@ FreestyleLineStyle *BKE_copy_linestyle(FreestyleLineStyle *linestyle)
new_linestyle->max_angle = linestyle->max_angle;
new_linestyle->min_length = linestyle->min_length;
new_linestyle->max_length = linestyle->max_length;
+ new_linestyle->chain_count = linestyle->chain_count;
new_linestyle->split_dash1 = linestyle->split_dash1;
new_linestyle->split_gap1 = linestyle->split_gap1;
new_linestyle->split_dash2 = linestyle->split_dash2;
@@ -198,24 +204,39 @@ FreestyleLineStyle *BKE_copy_linestyle(FreestyleLineStyle *linestyle)
new_linestyle->texstep = linestyle->texstep;
new_linestyle->pr_texture = linestyle->pr_texture;
for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next)
- BKE_copy_linestyle_color_modifier(new_linestyle, m);
+ BKE_linestyle_color_modifier_copy(new_linestyle, m);
for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next)
- BKE_copy_linestyle_alpha_modifier(new_linestyle, m);
+ BKE_linestyle_alpha_modifier_copy(new_linestyle, m);
for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next)
- BKE_copy_linestyle_thickness_modifier(new_linestyle, m);
+ BKE_linestyle_thickness_modifier_copy(new_linestyle, m);
for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next)
- BKE_copy_linestyle_geometry_modifier(new_linestyle, m);
+ BKE_linestyle_geometry_modifier_copy(new_linestyle, m);
return new_linestyle;
}
-static LineStyleModifier *new_modifier(int type, size_t size)
+FreestyleLineStyle *BKE_linestyle_active_from_scene(Scene *scene)
+{
+ SceneRenderLayer *actsrl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ FreestyleConfig *config = &actsrl->freestyleConfig;
+ FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(config);
+
+ if (lineset) {
+ return lineset->linestyle;
+ }
+ return NULL;
+}
+
+static LineStyleModifier *new_modifier(const char *name, int type, size_t size)
{
LineStyleModifier *m;
+ if (!name) {
+ name = modifier_name[type];
+ }
m = (LineStyleModifier *)MEM_callocN(size, "line style modifier");
m->type = type;
- BLI_strncpy(m->name, modifier_name[type], sizeof(m->name));
+ BLI_strncpy(m->name, name, sizeof(m->name));
m->influence = 1.0f;
m->flags = LS_MODIFIER_ENABLED | LS_MODIFIER_EXPANDED;
@@ -228,7 +249,7 @@ static void add_to_modifier_list(ListBase *lb, LineStyleModifier *m)
BLI_uniquename(lb, m, modifier_name[m->type], '.', offsetof(LineStyleModifier, name), sizeof(m->name));
}
-static LineStyleModifier *alloc_color_modifier(int type)
+static LineStyleModifier *alloc_color_modifier(const char *name, int type)
{
size_t size;
@@ -249,14 +270,14 @@ static LineStyleModifier *alloc_color_modifier(int type)
return NULL; /* unknown modifier type */
}
- return new_modifier(type, size);
+ return new_modifier(name, type, size);
}
-LineStyleModifier *BKE_add_linestyle_color_modifier(FreestyleLineStyle *linestyle, int type)
+LineStyleModifier *BKE_linestyle_color_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type)
{
LineStyleModifier *m;
- m = alloc_color_modifier(type);
+ m = alloc_color_modifier(name, type);
m->blend = MA_RAMP_BLEND;
switch (type) {
@@ -276,7 +297,7 @@ LineStyleModifier *BKE_add_linestyle_color_modifier(FreestyleLineStyle *linestyl
break;
case LS_MODIFIER_MATERIAL:
((LineStyleColorModifier_Material *)m)->color_ramp = add_colorband(1);
- ((LineStyleColorModifier_Material *)m)->mat_attr = LS_MODIFIER_MATERIAL_DIFF;
+ ((LineStyleColorModifier_Material *)m)->mat_attr = LS_MODIFIER_MATERIAL_LINE;
break;
default:
return NULL; /* unknown modifier type */
@@ -286,11 +307,11 @@ LineStyleModifier *BKE_add_linestyle_color_modifier(FreestyleLineStyle *linestyl
return m;
}
-LineStyleModifier *BKE_copy_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_color_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
LineStyleModifier *new_m;
- new_m = alloc_color_modifier(m->type);
+ new_m = alloc_color_modifier(m->name, m->type);
new_m->influence = m->influence;
new_m->flags = m->flags;
new_m->blend = m->blend;
@@ -341,8 +362,10 @@ LineStyleModifier *BKE_copy_linestyle_color_modifier(FreestyleLineStyle *linesty
return new_m;
}
-void BKE_remove_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+int BKE_linestyle_color_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
+ if (BLI_findindex(&linestyle->color_modifiers, m) == -1)
+ return -1;
switch (m->type) {
case LS_MODIFIER_ALONG_STROKE:
MEM_freeN(((LineStyleColorModifier_AlongStroke *)m)->color_ramp);
@@ -358,9 +381,10 @@ void BKE_remove_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyl
break;
}
BLI_freelinkN(&linestyle->color_modifiers, m);
+ return 0;
}
-static LineStyleModifier *alloc_alpha_modifier(int type)
+static LineStyleModifier *alloc_alpha_modifier(const char *name, int type)
{
size_t size;
@@ -380,14 +404,14 @@ static LineStyleModifier *alloc_alpha_modifier(int type)
default:
return NULL; /* unknown modifier type */
}
- return new_modifier(type, size);
+ return new_modifier(name, type, size);
}
-LineStyleModifier *BKE_add_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, int type)
+LineStyleModifier *BKE_linestyle_alpha_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type)
{
LineStyleModifier *m;
- m = alloc_alpha_modifier(type);
+ m = alloc_alpha_modifier(name, type);
m->blend = LS_VALUE_BLEND;
switch (type) {
@@ -418,7 +442,7 @@ LineStyleModifier *BKE_add_linestyle_alpha_modifier(FreestyleLineStyle *linestyl
{
LineStyleAlphaModifier_Material *p = (LineStyleAlphaModifier_Material *)m;
p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->mat_attr = LS_MODIFIER_MATERIAL_DIFF;
+ p->mat_attr = LS_MODIFIER_MATERIAL_LINE_A;
break;
}
default:
@@ -429,11 +453,11 @@ LineStyleModifier *BKE_add_linestyle_alpha_modifier(FreestyleLineStyle *linestyl
return m;
}
-LineStyleModifier *BKE_copy_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_alpha_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
LineStyleModifier *new_m;
- new_m = alloc_alpha_modifier(m->type);
+ new_m = alloc_alpha_modifier(m->name, m->type);
new_m->influence = m->influence;
new_m->flags = m->flags;
new_m->blend = m->blend;
@@ -487,8 +511,10 @@ LineStyleModifier *BKE_copy_linestyle_alpha_modifier(FreestyleLineStyle *linesty
return new_m;
}
-void BKE_remove_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+int BKE_linestyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
+ if (BLI_findindex(&linestyle->alpha_modifiers, m) == -1)
+ return -1;
switch (m->type) {
case LS_MODIFIER_ALONG_STROKE:
curvemapping_free(((LineStyleAlphaModifier_AlongStroke *)m)->curve);
@@ -504,9 +530,10 @@ void BKE_remove_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyl
break;
}
BLI_freelinkN(&linestyle->alpha_modifiers, m);
+ return 0;
}
-static LineStyleModifier *alloc_thickness_modifier(int type)
+static LineStyleModifier *alloc_thickness_modifier(const char *name, int type)
{
size_t size;
@@ -530,14 +557,14 @@ static LineStyleModifier *alloc_thickness_modifier(int type)
return NULL; /* unknown modifier type */
}
- return new_modifier(type, size);
+ return new_modifier(name, type, size);
}
-LineStyleModifier *BKE_add_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, int type)
+LineStyleModifier *BKE_linestyle_thickness_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type)
{
LineStyleModifier *m;
- m = alloc_thickness_modifier(type);
+ m = alloc_thickness_modifier(name, type);
m->blend = LS_VALUE_BLEND;
switch (type) {
@@ -574,7 +601,7 @@ LineStyleModifier *BKE_add_linestyle_thickness_modifier(FreestyleLineStyle *line
{
LineStyleThicknessModifier_Material *p = (LineStyleThicknessModifier_Material *)m;
p->curve = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
- p->mat_attr = LS_MODIFIER_MATERIAL_DIFF;
+ p->mat_attr = LS_MODIFIER_MATERIAL_LINE;
p->value_min = 0.0f;
p->value_max = 1.0f;
break;
@@ -595,11 +622,11 @@ LineStyleModifier *BKE_add_linestyle_thickness_modifier(FreestyleLineStyle *line
return m;
}
-LineStyleModifier *BKE_copy_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_thickness_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
LineStyleModifier *new_m;
- new_m = alloc_thickness_modifier(m->type);
+ new_m = alloc_thickness_modifier(m->name, m->type);
if (!new_m)
return NULL;
new_m->influence = m->influence;
@@ -672,8 +699,10 @@ LineStyleModifier *BKE_copy_linestyle_thickness_modifier(FreestyleLineStyle *lin
return new_m;
}
-void BKE_remove_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+int BKE_linestyle_thickness_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
+ if (BLI_findindex(&linestyle->thickness_modifiers, m) == -1)
+ return -1;
switch (m->type) {
case LS_MODIFIER_ALONG_STROKE:
curvemapping_free(((LineStyleThicknessModifier_AlongStroke *)m)->curve);
@@ -691,9 +720,10 @@ void BKE_remove_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, Line
break;
}
BLI_freelinkN(&linestyle->thickness_modifiers, m);
+ return 0;
}
-static LineStyleModifier *alloc_geometry_modifier(int type)
+static LineStyleModifier *alloc_geometry_modifier(const char *name, int type)
{
size_t size;
@@ -741,14 +771,14 @@ static LineStyleModifier *alloc_geometry_modifier(int type)
return NULL; /* unknown modifier type */
}
- return new_modifier(type, size);
+ return new_modifier(name, type, size);
}
-LineStyleModifier *BKE_add_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, int type)
+LineStyleModifier *BKE_linestyle_geometry_modifier_add(FreestyleLineStyle *linestyle, const char *name, int type)
{
LineStyleModifier *m;
- m = alloc_geometry_modifier(type);
+ m = alloc_geometry_modifier(name, type);
switch (type) {
case LS_MODIFIER_SAMPLING:
@@ -862,11 +892,11 @@ LineStyleModifier *BKE_add_linestyle_geometry_modifier(FreestyleLineStyle *lines
return m;
}
-LineStyleModifier *BKE_copy_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+LineStyleModifier *BKE_linestyle_geometry_modifier_copy(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
LineStyleModifier *new_m;
- new_m = alloc_geometry_modifier(m->type);
+ new_m = alloc_geometry_modifier(m->name, m->type);
new_m->flags = m->flags;
switch (m->type) {
@@ -996,9 +1026,12 @@ LineStyleModifier *BKE_copy_linestyle_geometry_modifier(FreestyleLineStyle *line
return new_m;
}
-void BKE_remove_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *m)
+int BKE_linestyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, LineStyleModifier *m)
{
+ if (BLI_findindex(&linestyle->geometry_modifiers, m) == -1)
+ return -1;
BLI_freelinkN(&linestyle->geometry_modifiers, m);
+ return 0;
}
static void move_modifier(ListBase *lb, LineStyleModifier *modifier, int direction)
@@ -1010,27 +1043,27 @@ static void move_modifier(ListBase *lb, LineStyleModifier *modifier, int directi
BLI_insertlinkafter(lb, modifier->next, modifier);
}
-void BKE_move_linestyle_color_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+void BKE_linestyle_color_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
move_modifier(&linestyle->color_modifiers, modifier, direction);
}
-void BKE_move_linestyle_alpha_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+void BKE_linestyle_alpha_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
move_modifier(&linestyle->alpha_modifiers, modifier, direction);
}
-void BKE_move_linestyle_thickness_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+void BKE_linestyle_thickness_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
move_modifier(&linestyle->thickness_modifiers, modifier, direction);
}
-void BKE_move_linestyle_geometry_modifier(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
+void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineStyleModifier *modifier, int direction)
{
move_modifier(&linestyle->geometry_modifiers, modifier, direction);
}
-void BKE_list_modifier_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase)
+void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase)
{
LineStyleModifier *m;
ColorBand *color_ramp;
@@ -1061,7 +1094,7 @@ void BKE_list_modifier_color_ramps(FreestyleLineStyle *linestyle, ListBase *list
}
}
-char *BKE_path_from_ID_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand *color_ramp)
+char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand *color_ramp)
{
LineStyleModifier *m;
bool found = false;
@@ -1092,11 +1125,11 @@ char *BKE_path_from_ID_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand *c
return BLI_sprintfN("color_modifiers[\"%s\"].color_ramp", name_esc);
}
}
- printf("BKE_path_from_ID_to_color_ramp: No color ramps correspond to the given pointer.\n");
+ printf("BKE_linestyle_path_to_color_ramp: No color ramps correspond to the given pointer.\n");
return NULL;
}
-void BKE_unlink_linestyle_target_object(FreestyleLineStyle *linestyle, struct Object *ob)
+void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob)
{
LineStyleModifier *m;
@@ -1122,3 +1155,64 @@ void BKE_unlink_linestyle_target_object(FreestyleLineStyle *linestyle, struct Ob
}
}
}
+
+bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes)
+{
+ if (use_shading_nodes) {
+ if (linestyle && linestyle->use_nodes && linestyle->nodetree) {
+ bNode *node;
+
+ for (node = linestyle->nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) {
+ return true;
+ }
+ }
+ }
+ }
+ else {
+ if (linestyle && (linestyle->flag & LS_TEXTURE)) {
+ return (linestyle->mtex[0] != NULL);
+ }
+ }
+ return false;
+}
+
+void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linestyle)
+{
+ bNode *uv_along_stroke, *input_texure, *output_linestyle;
+ bNodeSocket *fromsock, *tosock;
+ bNodeTree *ntree;
+
+ BLI_assert(linestyle->nodetree == NULL);
+
+ ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree");
+
+ linestyle->nodetree = ntree;
+
+ uv_along_stroke = nodeAddStaticNode(C, ntree, SH_NODE_UVALONGSTROKE);
+ uv_along_stroke->locx = 0.0f;
+ uv_along_stroke->locy = 300.0f;
+ uv_along_stroke->custom1 = 0; // use_tips
+
+ input_texure = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
+ input_texure->locx = 200.0f;
+ input_texure->locy = 300.0f;
+
+ output_linestyle = nodeAddStaticNode(C, ntree, SH_NODE_OUTPUT_LINESTYLE);
+ output_linestyle->locx = 400.0f;
+ output_linestyle->locy = 300.0f;
+ output_linestyle->custom1 = MA_RAMP_BLEND;
+ output_linestyle->custom2 = 0; // use_clamp
+
+ nodeSetActive(ntree, input_texure);
+
+ fromsock = BLI_findlink(&uv_along_stroke->outputs, 0); // UV
+ tosock = BLI_findlink(&input_texure->inputs, 0); // UV
+ nodeAddLink(ntree, uv_along_stroke, fromsock, input_texure, tosock);
+
+ fromsock = BLI_findlink(&input_texure->outputs, 0); // Color
+ tosock = BLI_findlink(&output_linestyle->inputs, 0); // Color
+ nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock);
+
+ ntreeUpdateTree(CTX_data_main(C), ntree);
+}
diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c
index 8c1cc4b0279..83ad2f1b2d2 100644
--- a/source/blender/blenkernel/intern/mask.c
+++ b/source/blender/blenkernel/intern/mask.c
@@ -1133,7 +1133,7 @@ void BKE_mask_coord_to_movieclip(MovieClip *clip, MovieClipUser *user, float r_c
BKE_movieclip_get_size_fl(clip, user, frame_size);
BKE_movieclip_get_aspect(clip, &aspx, &aspy);
- frame_size[1] /= (aspy / aspx);
+ frame_size[1] *= (aspy / aspx);
BKE_mask_coord_to_frame(r_co, co, frame_size);
}
@@ -1147,7 +1147,7 @@ void BKE_mask_coord_to_image(Image *image, ImageUser *iuser, float r_co[2], cons
BKE_image_get_size_fl(image, iuser, frame_size);
BKE_image_get_aspect(image, &aspx, &aspy);
- frame_size[1] /= (aspy / aspx);
+ frame_size[1] *= (aspy / aspx);
BKE_mask_coord_to_frame(r_co, co, frame_size);
}
@@ -1212,7 +1212,7 @@ void BKE_mask_point_parent_matrix_get(MaskSplinePoint *point, float ctime, float
}
invert_m3_m3(mask_to_clip_matrix, mask_from_clip_matrix);
- mul_serie_m3(parent_matrix, mask_to_clip_matrix, H, mask_from_clip_matrix, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(parent_matrix, mask_from_clip_matrix, H, mask_to_clip_matrix);
}
}
}
@@ -1821,10 +1821,10 @@ void BKE_mask_layer_shape_unlink(MaskLayer *masklay, MaskLayerShape *masklay_sha
BKE_mask_layer_shape_free(masklay_shape);
}
-static int mask_layer_shape_sort_cb(void *masklay_shape_a_ptr, void *masklay_shape_b_ptr)
+static int mask_layer_shape_sort_cb(const void *masklay_shape_a_ptr, const void *masklay_shape_b_ptr)
{
- MaskLayerShape *masklay_shape_a = (MaskLayerShape *)masklay_shape_a_ptr;
- MaskLayerShape *masklay_shape_b = (MaskLayerShape *)masklay_shape_b_ptr;
+ const MaskLayerShape *masklay_shape_a = masklay_shape_a_ptr;
+ const MaskLayerShape *masklay_shape_b = masklay_shape_b_ptr;
if (masklay_shape_a->frame < masklay_shape_b->frame) return -1;
else if (masklay_shape_a->frame > masklay_shape_b->frame) return 1;
diff --git a/source/blender/blenkernel/intern/mask_rasterize.c b/source/blender/blenkernel/intern/mask_rasterize.c
index 35207595103..4dc8ed21463 100644
--- a/source/blender/blenkernel/intern/mask_rasterize.c
+++ b/source/blender/blenkernel/intern/mask_rasterize.c
@@ -326,7 +326,7 @@ static void maskrasterize_spline_differentiate_point_outset(float (*diff_feather
* are to any of the triangle edges.
*/
static bool layer_bucket_isect_test(
- MaskRasterLayer *layer, unsigned int face_index,
+ const MaskRasterLayer *layer, unsigned int face_index,
const unsigned int bucket_x, const unsigned int bucket_y,
const float bucket_size_x, const float bucket_size_y,
const float bucket_max_rad_squared)
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index de3aea9267f..eeca60f7ef4 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -63,6 +63,7 @@
#include "BKE_main.h"
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_scene.h"
#include "BKE_node.h"
#include "BKE_curve.h"
@@ -111,6 +112,9 @@ void BKE_material_free_ex(Material *ma, bool do_id_user)
MEM_freeN(ma->nodetree);
}
+ if (ma->texpaintslot)
+ MEM_freeN(ma->texpaintslot);
+
if (ma->gpumaterial.first)
GPU_material_free(ma);
}
@@ -269,7 +273,8 @@ Material *localize_material(Material *ma)
if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col);
if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec);
-
+
+ man->texpaintslot = NULL;
man->preview = NULL;
if (ma->nodetree)
@@ -467,7 +472,7 @@ Material ***give_matarar(Object *ob)
me = ob->data;
return &(me->mat);
}
- else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
cu = ob->data;
return &(cu->mat);
}
@@ -488,7 +493,7 @@ short *give_totcolp(Object *ob)
me = ob->data;
return &(me->totcol);
}
- else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
cu = ob->data;
return &(cu->totcol);
}
@@ -780,11 +785,13 @@ void test_object_materials(Main *bmain, ID *id)
return;
}
+ BKE_main_lock(bmain);
for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->data == id) {
BKE_material_resize_object(ob, *totcol, false);
}
}
+ BKE_main_unlock(bmain);
}
void assign_material_id(ID *id, Material *ma, short act)
@@ -1289,7 +1296,7 @@ bool object_remove_material_slot(Object *ob)
}
/* check indices from mesh */
- if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) {
material_data_index_remove_id((ID *)ob->data, actcol - 1);
if (ob->curve_cache) {
BKE_displist_free(&ob->curve_cache->disp);
@@ -1299,6 +1306,124 @@ bool object_remove_material_slot(Object *ob)
return true;
}
+static bool get_mtex_slot_valid_texpaint(struct MTex *mtex)
+{
+ return (mtex && (mtex->texco == TEXCO_UV) &&
+ mtex->tex && (mtex->tex->type == TEX_IMAGE) &&
+ mtex->tex->ima);
+}
+
+void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
+{
+ MTex **mtex;
+ short count = 0;
+ short index = 0, i;
+
+ bool use_nodes = BKE_scene_use_new_shading_nodes(scene);
+ bool is_bi = BKE_scene_uses_blender_internal(scene);
+
+ if (!ma)
+ return;
+
+ if (ma->texpaintslot) {
+ MEM_freeN(ma->texpaintslot);
+ ma->tot_slots = 0;
+ ma->texpaintslot = NULL;
+ }
+
+ if (scene->toolsettings->imapaint.mode == IMAGEPAINT_MODE_IMAGE) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
+ }
+
+ if (use_nodes || ma->use_nodes) {
+ bNode *node, *active_node;
+
+ if (!(ma->nodetree)) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
+ }
+
+ for (node = ma->nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id)
+ count++;
+ }
+
+ if (count == 0) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
+ }
+ ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+
+ active_node = nodeGetActiveTexture(ma->nodetree);
+
+ for (node = ma->nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+ if (active_node == node)
+ ma->paint_active_slot = index;
+ ma->texpaintslot[index++].ima = (Image *)node->id;
+ }
+ }
+ }
+ else if (is_bi) {
+ for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
+ if (get_mtex_slot_valid_texpaint(*mtex)) {
+ count++;
+ }
+ }
+
+ if (count == 0) {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
+ }
+
+ ma->texpaintslot = MEM_callocN(sizeof(*ma->texpaintslot) * count, "texpaint_slots");
+
+ for (mtex = ma->mtex, i = 0; i < MAX_MTEX; i++, mtex++) {
+ if (get_mtex_slot_valid_texpaint(*mtex)) {
+ ma->texpaintslot[index].ima = (*mtex)->tex->ima;
+ ma->texpaintslot[index].uvname = (*mtex)->uvname;
+ ma->texpaintslot[index].index = i;
+
+ index++;
+ }
+ }
+ }
+ else {
+ ma->paint_active_slot = 0;
+ ma->paint_clone_slot = 0;
+ return;
+ }
+
+
+ ma->tot_slots = count;
+
+
+ if (ma->paint_active_slot >= count) {
+ ma->paint_active_slot = count - 1;
+ }
+
+ if (ma->paint_clone_slot >= count) {
+ ma->paint_clone_slot = count - 1;
+ }
+
+ return;
+}
+
+void BKE_texpaint_slots_refresh_object(Scene *scene, struct Object *ob)
+{
+ int i;
+
+ for (i = 1; i < ob->totcol + 1; i++) {
+ Material *ma = give_current_material(ob, i);
+ BKE_texpaint_slot_refresh_cache(scene, ma);
+ }
+}
+
/* r_col = current value, col = new value, (fac == 0) is no change */
void ramp_blend(int type, float r_col[3], const float fac, const float col[3])
@@ -1571,7 +1696,7 @@ void copy_matcopybuf(Material *ma)
matcopybuf.mtex[a] = MEM_dupallocN(mtex);
}
}
- matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, false);
+ matcopybuf.nodetree = ntreeCopyTree_ex(ma->nodetree, G.main, false);
matcopybuf.preview = NULL;
BLI_listbase_clear(&matcopybuf.gpumaterial);
matcopied = 1;
@@ -1624,7 +1749,7 @@ void paste_matcopybuf(Material *ma)
}
}
- ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, false);
+ ma->nodetree = ntreeCopyTree_ex(matcopybuf.nodetree, G.main, false);
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index fc6f9149841..453c6df6e3b 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -491,10 +491,7 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object)
BLI_split_name_num(basisname, &basisnr, active_object->id.name + 2, '.');
- /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */
- if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL))
- return;
-
+ 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 != active_object) {
@@ -537,23 +534,17 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis)
BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
- /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */
- if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL))
- return NULL;
-
+ 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->type == OB_MBALL) && !(base->flag & OB_FROMDUPLI)) {
if (ob != bob) {
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 */
+ /* object ob has to be in same "group" ... it means, that it has to have same base of its name */
if (strcmp(obname, basisname) == 0) {
if (obnr < basisnr) {
- if (!(ob->flag & OB_FROMDUPLI)) {
- basis = ob;
- basisnr = obnr;
- }
+ basis = ob;
+ basisnr = obnr;
}
}
}
@@ -2227,10 +2218,7 @@ static void mball_count(EvaluationContext *eval_ctx, PROCESS *process, Scene *sc
BLI_split_name_num(basisname, &basisnr, basis->id.name + 2, '.');
process->totelem = 0;
- /* XXX recursion check, see scene.c, just too simple code this BKE_scene_base_iter_next() */
- if (F_ERROR == BKE_scene_base_iter_next(eval_ctx, &iter, &sce_iter, 0, NULL, NULL))
- return;
-
+ 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) {
@@ -2280,7 +2268,7 @@ void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob,
mball_count(eval_ctx, &process, scene, ob);
if (process.totelem == 0) return;
- if ((eval_ctx->for_render == false) && (mb->flag == MB_UPDATE_NEVER)) 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;
@@ -2318,7 +2306,7 @@ void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob,
}
/* width is size per polygonize cube */
- if (eval_ctx->for_render) {
+ if (eval_ctx->mode == DAG_EVAL_RENDER) {
width = mb->rendersize;
}
else {
@@ -2361,8 +2349,8 @@ void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob,
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");
+ 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);
@@ -2454,6 +2442,30 @@ bool BKE_mball_center_bounds(MetaBall *mb, float r_cent[3])
return 0;
}
+void BKE_mball_transform(MetaBall *mb, float mat[4][4])
+{
+ MetaElem *me;
+ float quat[4];
+ const float scale = mat4_to_scale(mat);
+ const float scale_sqrt = sqrtf(scale);
+
+ mat4_to_quat(quat, mat);
+
+ for (me = mb->elems.first; me; me = me->next) {
+ mul_m4_v3(mat, &me->x);
+ mul_qt_qtqt(me->quat, quat, me->quat);
+ me->rad *= scale;
+ /* hrmf, probably elems shouldn't be
+ * treating scale differently - campbell */
+ if (!MB_TYPE_SIZE_SQUARED(me->type)) {
+ mul_v3_fl(&me->expx, scale);
+ }
+ else {
+ mul_v3_fl(&me->expx, scale_sqrt);
+ }
+ }
+}
+
void BKE_mball_translate(MetaBall *mb, const float offset[3])
{
MetaElem *ml;
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index f0566a7f473..2e80379522c 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -115,16 +115,16 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
int i, i1 = 0, i2 = 0, tot, j;
for (i = 0; i < c1->totlayer; i++) {
- if (ELEM7(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ if (ELEM(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
{
i1++;
}
}
for (i = 0; i < c2->totlayer; i++) {
- if (ELEM7(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ if (ELEM(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY,
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
{
i2++;
}
@@ -135,16 +135,16 @@ static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2
l1 = c1->layers; l2 = c2->layers;
tot = i1;
- i1 = 0; i2 = 0;
+ i1 = 0; i2 = 0;
for (i = 0; i < tot; i++) {
- while (i1 < c1->totlayer && !ELEM7(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ while (i1 < c1->totlayer && !ELEM(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
{
i1++, l1++;
}
- while (i2 < c2->totlayer && !ELEM7(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
- CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
+ while (i2 < c2->totlayer && !ELEM(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY,
+ CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
{
i2++, l2++;
}
@@ -1531,7 +1531,7 @@ void BKE_mesh_from_nurbs(Object *ob)
}
typedef struct EdgeLink {
- Link *next, *prev;
+ struct EdgeLink *next, *prev;
void *edge;
} EdgeLink;
@@ -1610,13 +1610,11 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
BLI_freelinkN(&edges, edges.last); totedges--;
while (ok) { /* while connected edges are found... */
+ EdgeLink *edl = edges.last;
ok = false;
- i = totedges;
- while (i) {
- EdgeLink *edl;
+ while (edl) {
+ EdgeLink *edl_prev = edl->prev;
- i -= 1;
- edl = BLI_findlink(&edges, i);
med = edl->edge;
if (med->v1 == endVert) {
@@ -1643,6 +1641,8 @@ void BKE_mesh_to_curve_nurblist(DerivedMesh *dm, ListBase *nurblist, const int e
BLI_freelinkN(&edges, edl); totedges--;
ok = true;
}
+
+ edl = edl_prev;
}
}
@@ -1869,6 +1869,27 @@ bool BKE_mesh_minmax(Mesh *me, float r_min[3], float r_max[3])
return (me->totvert != 0);
}
+void BKE_mesh_transform(Mesh *me, float mat[4][4], bool do_keys)
+{
+ int i;
+ MVert *mvert = me->mvert;
+
+ for (i = 0; i < me->totvert; i++, mvert++)
+ mul_m4_v3(mat, mvert->co);
+
+ if (do_keys && me->key) {
+ KeyBlock *kb;
+ for (kb = me->key->block.first; kb; kb = kb->next) {
+ float *fp = kb->data;
+ for (i = kb->totelem; i--; fp += 3) {
+ mul_m4_v3(mat, fp);
+ }
+ }
+ }
+
+ /* don't update normals, caller can do this explicitly */
+}
+
void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys)
{
int i = me->totvert;
@@ -2041,7 +2062,7 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type)
{
int i;
- BLI_assert(ELEM3(type, ME_VSEL, ME_ESEL, ME_FSEL));
+ BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
for (i = 0; i < me->totselect; i++) {
if ((me->mselect[i].index == index) &&
@@ -2059,7 +2080,7 @@ int BKE_mesh_mselect_find(Mesh *me, int index, int type)
*/
int BKE_mesh_mselect_active_get(Mesh *me, int type)
{
- BLI_assert(ELEM3(type, ME_VSEL, ME_ESEL, ME_FSEL));
+ BLI_assert(ELEM(type, ME_VSEL, ME_ESEL, ME_FSEL));
if (me->totselect) {
if (me->mselect[me->totselect - 1].type == type) {
@@ -2148,7 +2169,7 @@ Mesh *BKE_mesh_new_from_object(
* if it didn't the curve did not have any segments or otherwise
* would have generated an empty mesh */
if (tmpobj->type != OB_MESH) {
- BKE_libblock_free_us(G.main, tmpobj);
+ BKE_libblock_free_us(bmain, tmpobj);
return NULL;
}
@@ -2179,7 +2200,7 @@ Mesh *BKE_mesh_new_from_object(
* implemented, this is to be rethinked.
*/
EvaluationContext eval_ctx = {0};
- eval_ctx.for_render = render;
+ eval_ctx.mode = DAG_EVAL_RENDER;
BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 74e380c7d50..4c9e44682c3 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -386,10 +386,12 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
}
else if (e2l[1] == INDEX_UNSET) {
/* Second loop using this edge, time to test its sharpness.
- * An edge is sharp if it is tagged as such, or its face is not smooth, or angle between
- * both its polys' normals is above split_angle value...
+ * An edge is sharp if it is tagged as such, or its face is not smooth,
+ * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the same vertex,
+ * or angle between both its polys' normals is above split_angle value.
*/
if (!(mp->flag & ME_SMOOTH) || (medges[ml_curr->e].flag & ME_SHARP) ||
+ ml_curr->v == mloops[e2l[0]].v ||
(check_angle && dot_v3v3(polynors[loop_to_poly[e2l[0]]], polynors[mp_index]) < split_angle))
{
/* Note: we are sure that loop != 0 here ;) */
@@ -441,8 +443,15 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
copy_v3_v3(*lnors, polynors[mp_index]);
/* No need to mark loop as done here, we won't run into it again anyway! */
}
- /* This loop may have been already computed, in which case its 'to_poly' map is set to -1... */
- else if (loop_to_poly[ml_curr_index] != -1) {
+ /* We *do not need* to check/tag loops as already computed!
+ * Due to the fact a loop only links to one of its two edges, a same fan *will never be walked more than
+ * once!*
+ * Since we consider edges having neighbor polys with inverted (flipped) normals as sharp, we are sure that
+ * no fan will be skipped, even only considering the case (sharp curr_edge, smooth prev_edge), and not the
+ * alternative (smooth curr_edge, sharp prev_edge).
+ * All this due/thanks to link between normals and loop ordering.
+ */
+ else {
/* Gah... We have to fan around current vertex, until we find the other non-smooth edge,
* and accumulate face normals into the vertex!
* Note in case this vertex has only one sharp edges, this is a waste because the normal is the same as
@@ -466,6 +475,10 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
mlfan_vert_index = ml_curr_index;
mpfan_curr_index = mp_index;
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mlfan_vert_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
/* Only need to compute previous edge's vector once, then we can just reuse old current one! */
{
const MEdge *me_prev = &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */
@@ -501,9 +514,6 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
/* We store here a pointer to all loop-normals processed. */
BLI_SMALLSTACK_PUSH(normal, &(r_loopnors[mlfan_vert_index][0]));
- /* And we are done with this loop, mark it as such! */
- loop_to_poly[mlfan_vert_index] = -1;
-
if (IS_EDGE_SHARP(e2lfan_curr)) {
/* Current edge is sharp, we have finished with this fan of faces around this vert! */
break;
@@ -521,6 +531,10 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
*/
mlfan_curr_index = (e2lfan_curr[0] == mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
mpfan_curr_index = loop_to_poly[mlfan_curr_index];
+
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
mlfan_next = &mloops[mlfan_curr_index];
mpfan_next = &mpolys[mpfan_curr_index];
if ((mlfan_curr->v == mlfan_next->v && mlfan_curr->v == mv_pivot_index) ||
@@ -553,6 +567,10 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
copy_v3_v3(nor, lnor);
}
}
+ else {
+ /* We still have to clear the stack! */
+ while (BLI_SMALLSTACK_POP(normal));
+ }
}
ml_prev = ml_curr;
@@ -560,8 +578,6 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
}
}
- BLI_SMALLSTACK_FREE(normal);
-
MEM_freeN(edge_to_loops);
MEM_freeN(loop_to_poly);
@@ -715,7 +731,7 @@ void BKE_mesh_loop_tangents(Mesh *mesh, const char *uvmap, float (*r_looptangent
}
BKE_mesh_loop_tangents_ex(mesh->mvert, mesh->totvert, mesh->mloop, r_looptangents,
- loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
+ loopnors, loopuvs, mesh->totloop, mesh->mpoly, mesh->totpoly, reports);
}
/** \} */
@@ -1007,7 +1023,7 @@ void BKE_mesh_poly_edgebitmap_insert(unsigned int *edge_bitmap, const MPoly *mp,
ml = mloop;
while (i-- != 0) {
- BLI_BITMAP_SET(edge_bitmap, ml->e);
+ BLI_BITMAP_ENABLE(edge_bitmap, ml->e);
ml++;
}
}
@@ -1082,6 +1098,125 @@ bool BKE_mesh_center_centroid(Mesh *me, float cent[3])
/* -------------------------------------------------------------------- */
+/** \name Mesh Volume Calculation
+ * \{ */
+
+static bool mesh_calc_center_centroid_ex(MVert *mverts, int UNUSED(numVerts),
+ MFace *mfaces, int numFaces,
+ float center[3])
+{
+ float totweight;
+ int f;
+
+ zero_v3(center);
+
+ if (numFaces == 0)
+ return false;
+
+ totweight = 0.0f;
+ for (f = 0; f < numFaces; ++f) {
+ MFace *face = &mfaces[f];
+ MVert *v1 = &mverts[face->v1];
+ MVert *v2 = &mverts[face->v2];
+ MVert *v3 = &mverts[face->v3];
+ MVert *v4 = &mverts[face->v4];
+ float area;
+
+ area = area_tri_v3(v1->co, v2->co, v3->co);
+ madd_v3_v3fl(center, v1->co, area);
+ madd_v3_v3fl(center, v2->co, area);
+ madd_v3_v3fl(center, v3->co, area);
+ totweight += area;
+
+ if (face->v4) {
+ area = area_tri_v3(v3->co, v4->co, v1->co);
+ madd_v3_v3fl(center, v3->co, area);
+ madd_v3_v3fl(center, v4->co, area);
+ madd_v3_v3fl(center, v1->co, area);
+ totweight += area;
+ }
+ }
+ if (totweight == 0.0f)
+ return false;
+
+ mul_v3_fl(center, 1.0f / (3.0f * totweight));
+
+ return true;
+}
+
+void BKE_mesh_calc_volume(MVert *mverts, int numVerts,
+ MFace *mfaces, int numFaces,
+ float *r_vol, float *r_com)
+{
+ float center[3];
+ float totvol;
+ int f;
+
+ if (r_vol) *r_vol = 0.0f;
+ if (r_com) zero_v3(r_com);
+
+ if (numFaces == 0)
+ return;
+
+ if (!mesh_calc_center_centroid_ex(mverts, numVerts, mfaces, numFaces, center))
+ return;
+
+ totvol = 0.0f;
+ for (f = 0; f < numFaces; ++f) {
+ MFace *face = &mfaces[f];
+ MVert *v1 = &mverts[face->v1];
+ MVert *v2 = &mverts[face->v2];
+ MVert *v3 = &mverts[face->v3];
+ MVert *v4 = &mverts[face->v4];
+ float vol;
+
+ vol = volume_tetrahedron_signed_v3(center, v1->co, v2->co, v3->co);
+ if (r_vol) {
+ totvol += vol;
+ }
+ if (r_com) {
+ /* averaging factor 1/4 is applied in the end */
+ madd_v3_v3fl(r_com, center, vol); // XXX could extract this
+ madd_v3_v3fl(r_com, v1->co, vol);
+ madd_v3_v3fl(r_com, v2->co, vol);
+ madd_v3_v3fl(r_com, v3->co, vol);
+ }
+
+ if (face->v4) {
+ vol = volume_tetrahedron_signed_v3(center, v3->co, v4->co, v1->co);
+
+ if (r_vol) {
+ totvol += vol;
+ }
+ if (r_com) {
+ /* averaging factor 1/4 is applied in the end */
+ madd_v3_v3fl(r_com, center, vol); // XXX could extract this
+ madd_v3_v3fl(r_com, v3->co, vol);
+ madd_v3_v3fl(r_com, v4->co, vol);
+ madd_v3_v3fl(r_com, v1->co, vol);
+ }
+ }
+ }
+
+ /* Note: Depending on arbitrary centroid position,
+ * totvol can become negative even for a valid mesh.
+ * The true value is always the positive value.
+ */
+ if (r_vol) {
+ *r_vol = fabsf(totvol);
+ }
+ if (r_com) {
+ /* Note: Factor 1/4 is applied once for all vertices here.
+ * This also automatically negates the vector if totvol is negative.
+ */
+ if (totvol != 0.0f)
+ mul_v3_fl(r_com, 0.25f / totvol);
+ }
+}
+
+
+/* -------------------------------------------------------------------- */
+
/** \name NGon Tessellation (NGon/Tessface Conversion)
* \{ */
@@ -1161,9 +1296,9 @@ void BKE_mesh_loops_to_mface_corners(
/**
* Convert all CD layers from loop/poly to tessface data.
*
- * @loopindices is an array of an int[4] per tessface, mapping tessface's verts to loops indices.
+ * \param loopindices is an array of an int[4] per tessface, mapping tessface's verts to loops indices.
*
- * Note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used.
+ * \note when mface is not NULL, mface[face_index].v4 is used to test quads, else, loopindices[face_index][3] is used.
*/
void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData *pdata, MFace *mface,
int *polyindices, unsigned int (*loopindices)[4], const int num_faces)
@@ -1246,7 +1381,7 @@ void BKE_mesh_loops_to_tessdata(CustomData *fdata, CustomData *ldata, CustomData
/**
* Recreate tessellation.
*
- * @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.
*/
@@ -1397,7 +1532,7 @@ int BKE_mesh_recalc_tessellation(CustomData *fdata, CustomData *ldata, CustomDat
mul_v2_m3v3(projverts[j], axis_mat, mvert[ml->v].co);
}
- BLI_polyfill_calc_arena((const float (*)[2])projverts, mp_totloop, tris, arena);
+ BLI_polyfill_calc_arena((const float (*)[2])projverts, mp_totloop, -1, tris, arena);
/* apply fill */
for (j = 0; j < totfilltri; j++) {
@@ -2096,11 +2231,10 @@ void BKE_mesh_calc_relative_deform(
float tvec[3];
- barycentric_transform(
- tvec, vert_cos_dst[v_curr],
- vert_cos_org[v_prev], vert_cos_org[v_curr], vert_cos_org[v_next],
- vert_cos_src[v_prev], vert_cos_src[v_curr], vert_cos_src[v_next]
- );
+ transform_point_by_tri_v3(
+ tvec, vert_cos_dst[v_curr],
+ vert_cos_org[v_prev], vert_cos_org[v_curr], vert_cos_org[v_next],
+ vert_cos_src[v_prev], vert_cos_src[v_curr], vert_cos_src[v_next]);
add_v3_v3(vert_cos_new[v_curr], tvec);
vert_accum[v_curr] += 1;
diff --git a/source/blender/blenkernel/intern/mesh_mapping.c b/source/blender/blenkernel/intern/mesh_mapping.c
index 65c576dd6a0..53d1aae104c 100644
--- a/source/blender/blenkernel/intern/mesh_mapping.c
+++ b/source/blender/blenkernel/intern/mesh_mapping.c
@@ -416,18 +416,22 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge,
while (ps_curr_idx != ps_end_idx) {
const MPoly *mp;
const MLoop *ml;
+ bool sharp_poly;
int j;
poly = poly_stack[ps_curr_idx++];
BLI_assert(poly_groups[poly] == poly_group_id);
mp = &mpoly[poly];
+ sharp_poly = !(mp->flag & ME_SMOOTH);
for (ml = &mloop[mp->loopstart], j = mp->totloop; j--; ml++) {
/* loop over poly users */
const MeshElemMap *map_ele = &edge_poly_map[ml->e];
const int *p = map_ele->indices;
int i = map_ele->count;
- if (!(medge[ml->e].flag & ME_SHARP)) {
+ /* Edge is smooth only if its poly is not sharp, edge is not sharp,
+ * and edge is used by exactly two polygons. */
+ if (!sharp_poly && !(medge[ml->e].flag & ME_SHARP) && i == 2) {
for (; i--; p++) {
/* if we meet other non initialized its a bug */
BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id));
@@ -442,7 +446,7 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge,
/* Find contiguous smooth groups already assigned, these are the values we can't reuse! */
for (; i--; p++) {
int bit = poly_groups[*p];
- if (!ELEM3(bit, 0, poly_group_id, poly_group_id_overflowed) &&
+ if (!ELEM(bit, 0, poly_group_id, poly_group_id_overflowed) &&
!(bit_poly_group_mask & bit))
{
bit_poly_group_mask |= bit;
@@ -482,6 +486,11 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge,
}
}
+ if (use_bitflags) {
+ /* used bits are zero-based. */
+ tot_group++;
+ }
+
if (UNLIKELY(group_id_overflow)) {
int i = totpoly, *gid = poly_groups;
for (; i--; gid++) {
@@ -489,13 +498,15 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge, const int totedge,
*gid = 0;
}
}
+ /* Using 0 as group id adds one more group! */
+ tot_group++;
}
MEM_freeN(edge_poly_map);
MEM_freeN(edge_poly_mem);
MEM_freeN(poly_stack);
- *r_totgroup = tot_group + 1;
+ *r_totgroup = tot_group;
return poly_groups;
}
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 858fe83b43f..f3a9e894eb3 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -164,16 +164,20 @@ static int search_poly_cmp(const void *v1, const void *v2)
{
const SortPoly *sp1 = v1, *sp2 = v2;
const int max_idx = sp1->numverts > sp2->numverts ? sp2->numverts : sp1->numverts;
- int idx = 0;
+ int idx;
/* Reject all invalid polys at end of list! */
if (sp1->invalid || sp2->invalid)
- return sp1->invalid && sp2->invalid ? 0 : sp1->invalid ? 1 : -1;
- /* Else, sort on first non-egal verts (remember verts of valid polys are sorted). */
- while (idx < max_idx && sp1->verts[idx] == sp2->verts[idx])
- idx++;
- return sp1->verts[idx] > sp2->verts[idx] ? 1 : sp1->verts[idx] < sp2->verts[idx] ? -1 :
- sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0;
+ return sp1->invalid ? (sp2->invalid ? 0 : 1) : -1;
+ /* Else, sort on first non-equal verts (remember verts of valid polys are sorted). */
+ for (idx = 0; idx < max_idx; idx++) {
+ const int v1 = sp1->verts[idx];
+ const int v2 = sp2->verts[idx];
+ if (v1 != v2) {
+ return (v1 > v2) ? 1 : -1;
+ }
+ }
+ return sp1->numverts > sp2->numverts ? 1 : sp1->numverts < sp2->numverts ? -1 : 0;
}
static int search_polyloop_cmp(const void *v1, const void *v2)
@@ -255,7 +259,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
do_edge_recalc = do_fixes;
}
- for (i = 1; i < totvert; i++, mv++) {
+ for (i = 0; i < totvert; i++, mv++) {
bool fix_normal = true;
for (j = 0; j < 3; j++) {
@@ -498,8 +502,9 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
PRINT_ERR("\tLoop %u has invalid vert reference (%u)\n", sp->loopstart + j, ml->v);
sp->invalid = true;
}
-
- mverts[ml->v].flag |= ME_VERT_TMP_TAG;
+ else {
+ mverts[ml->v].flag |= ME_VERT_TMP_TAG;
+ }
*v = ml->v;
}
@@ -909,8 +914,6 @@ static bool mesh_validate_customdata(CustomData *data, CustomDataMask mask,
return is_valid;
}
-#undef PRINT
-
/**
* \returns is_valid.
*/
@@ -1052,8 +1055,36 @@ void BKE_mesh_cd_validate(Mesh *me)
}
}
}
-/** \} */
+/**
+ * Check all material indices of polygons are valid, invalid ones are set to 0.
+ * \returns is_valid.
+ */
+int BKE_mesh_validate_material_indices(Mesh *me)
+{
+ MPoly *mp;
+ const int max_idx = max_ii(0, me->totcol - 1);
+ const int totpoly = me->totpoly;
+ int i;
+ bool is_valid = true;
+
+ for (mp = me->mpoly, i = 0; i < totpoly; i++, mp++) {
+ if (mp->mat_nr > max_idx) {
+ mp->mat_nr = 0;
+ is_valid = false;
+ }
+ }
+
+ if (!is_valid) {
+ DAG_id_tag_update(&me->id, OB_RECALC_DATA);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c
index 563831616de..a9e853c873e 100644
--- a/source/blender/blenkernel/intern/modifier.c
+++ b/source/blender/blenkernel/intern/modifier.c
@@ -171,11 +171,14 @@ bool modifier_isPreview(ModifierData *md)
{
ModifierTypeInfo *mti = modifierType_getInfo(md->type);
- if (!(mti->flags & eModifierTypeFlag_UsesPreview))
+ /* Constructive modifiers are highly likely to also modify data like vgroups or vcol! */
+ if (!((mti->flags & eModifierTypeFlag_UsesPreview) || (mti->type == eModifierTypeType_Constructive))) {
return false;
+ }
- if (md->mode & eModifierMode_Realtime)
+ if (md->mode & eModifierMode_Realtime) {
return true;
+ }
return false;
}
@@ -350,6 +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);
+ bool supports_mapping;
md->scene = scene;
@@ -357,16 +361,17 @@ int modifiers_getCageIndex(struct Scene *scene, Object *ob, int *r_lastPossibleC
if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) continue;
if (md->mode & eModifierMode_DisableTemporary) continue;
- if (!modifier_supportsMapping(md))
- break;
-
- if (r_lastPossibleCageIndex) {
+ supports_mapping = modifier_supportsMapping(md);
+ if (r_lastPossibleCageIndex && supports_mapping) {
*r_lastPossibleCageIndex = i;
}
if (!(md->mode & eModifierMode_Realtime)) continue;
if (!(md->mode & eModifierMode_Editmode)) continue;
+ if (!supports_mapping)
+ break;
+
if (md->mode & eModifierMode_OnCage)
cageIndex = i;
}
@@ -409,13 +414,12 @@ bool modifier_isEnabled(struct Scene *scene, ModifierData *md, int required_mode
md->scene = scene;
- if ((md->mode & required_mode) != required_mode) return 0;
- if (mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return 0;
- if (md->mode & eModifierMode_DisableTemporary) return 0;
- if (required_mode & eModifierMode_Editmode)
- if (!(mti->flags & eModifierTypeFlag_SupportsEditmode)) return 0;
+ if ((md->mode & required_mode) != required_mode) return false;
+ if (mti->isDisabled && mti->isDisabled(md, required_mode == eModifierMode_Render)) return false;
+ if (md->mode & eModifierMode_DisableTemporary) return false;
+ if ((required_mode & eModifierMode_Editmode) && !(mti->flags & eModifierTypeFlag_SupportsEditmode)) return false;
- return 1;
+ return true;
}
CDMaskLink *modifiers_calcDataMasks(struct Scene *scene, Object *ob, ModifierData *md,
@@ -709,7 +713,7 @@ const char *modifier_path_relbase(Object *ob)
else {
/* last resort, better then using "" which resolves to the current
* working directory */
- return BLI_temporary_dir();
+ return BLI_temp_dir_session();
}
}
@@ -719,7 +723,7 @@ void modifier_path_init(char *path, int path_maxlen, const char *name)
/* elubie: changed this to default to the same dir as the render output
* to prevent saving to C:\ on Windows */
BLI_join_dirfile(path, path_maxlen,
- G.relbase_valid ? "//" : BLI_temporary_dir(),
+ G.relbase_valid ? "//" : BLI_temp_dir_session(),
name);
}
diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c
index c1726da32ae..645567eea67 100644
--- a/source/blender/blenkernel/intern/modifiers_bmesh.c
+++ b/source/blender/blenkernel/intern/modifiers_bmesh.c
@@ -70,7 +70,7 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
int i, j, totvert, totedge /* , totface */ /* UNUSED */ ;
bool is_init = (bm->totvert == 0) && (bm->totedge == 0) && (bm->totface == 0);
bool is_cddm = (dm->type == DM_TYPE_CDDM); /* duplicate the arrays for non cddm */
- char has_orig_hflag = 0;
+ char has_orig_htype = 0;
int cd_vert_bweight_offset;
int cd_edge_bweight_offset;
@@ -78,9 +78,9 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
if (is_init == false) {
/* check if we have an origflag */
- has_orig_hflag |= CustomData_has_layer(&bm->vdata, CD_ORIGINDEX) ? BM_VERT : 0;
- has_orig_hflag |= CustomData_has_layer(&bm->edata, CD_ORIGINDEX) ? BM_EDGE : 0;
- has_orig_hflag |= CustomData_has_layer(&bm->pdata, CD_ORIGINDEX) ? BM_FACE : 0;
+ has_orig_htype |= CustomData_has_layer(&bm->vdata, CD_ORIGINDEX) ? BM_VERT : 0;
+ has_orig_htype |= CustomData_has_layer(&bm->edata, CD_ORIGINDEX) ? BM_EDGE : 0;
+ has_orig_htype |= CustomData_has_layer(&bm->pdata, CD_ORIGINDEX) ? BM_FACE : 0;
}
/*merge custom data layout*/
@@ -118,7 +118,7 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
/* add bevel weight */
if (cd_vert_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(v, cd_vert_bweight_offset, (float)mv->bweight / 255.0f);
- if (UNLIKELY(has_orig_hflag & BM_VERT)) {
+ if (UNLIKELY(has_orig_htype & BM_VERT)) {
int *orig_index = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_ORIGINDEX);
*orig_index = ORIGINDEX_NONE;
}
@@ -141,7 +141,7 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
if (cd_edge_bweight_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_bweight_offset, (float)me->bweight / 255.0f);
if (cd_edge_crease_offset != -1) BM_ELEM_CD_SET_FLOAT(e, cd_edge_crease_offset, (float)me->crease / 255.0f);
- if (UNLIKELY(has_orig_hflag & BM_EDGE)) {
+ if (UNLIKELY(has_orig_htype & BM_EDGE)) {
int *orig_index = CustomData_bmesh_get(&bm->edata, e->head.data, CD_ORIGINDEX);
*orig_index = ORIGINDEX_NONE;
}
@@ -188,7 +188,7 @@ void DM_to_bmesh_ex(DerivedMesh *dm, BMesh *bm, const bool calc_face_normal)
}
}
- if (UNLIKELY(has_orig_hflag & BM_FACE)) {
+ if (UNLIKELY(has_orig_htype & BM_FACE)) {
int *orig_index = CustomData_bmesh_get(&bm->pdata, f->head.data, CD_ORIGINDEX);
*orig_index = ORIGINDEX_NONE;
}
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index 35bf453c328..e28adb7c0e0 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -406,27 +406,14 @@ static unsigned int moviecache_hashhash(const void *keyv)
return rval;
}
-static int moviecache_hashcmp(const void *av, const void *bv)
+static bool moviecache_hashcmp(const void *av, const void *bv)
{
const MovieClipImBufCacheKey *a = (MovieClipImBufCacheKey *)av;
const MovieClipImBufCacheKey *b = (MovieClipImBufCacheKey *)bv;
- if (a->framenr < b->framenr)
- return -1;
- else if (a->framenr > b->framenr)
- return 1;
-
- if (a->proxy < b->proxy)
- return -1;
- else if (a->proxy > b->proxy)
- return 1;
-
- if (a->render_flag < b->render_flag)
- return -1;
- else if (a->render_flag > b->render_flag)
- return 1;
-
- return 0;
+ return ((a->framenr != b->framenr) ||
+ (a->proxy != b->proxy) ||
+ (a->render_flag != b->render_flag));
}
static void *moviecache_getprioritydata(void *key_v)
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 3d8e35699a9..9f5e049fe24 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -112,7 +112,7 @@ static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden,
/* assumed to be at hi_level (or
* null) */
- BLI_bitmap *prev_hidden)
+ const BLI_bitmap *prev_hidden)
{
BLI_bitmap *subd;
int hi_gridsize = BKE_ccg_gridsize(hi_level);
@@ -126,7 +126,7 @@ static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden,
if (lo_level == hi_level)
return MEM_dupallocN(lo_hidden);
- subd = BLI_BITMAP_NEW(hi_gridsize * hi_gridsize, "MDisps.hidden upsample");
+ subd = BLI_BITMAP_NEW(SQUARE(hi_gridsize), "MDisps.hidden upsample");
factor = BKE_ccg_factor(lo_level, hi_level);
offset = 1 << (hi_level - lo_level - 1);
@@ -134,7 +134,7 @@ static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden,
/* low-res blocks */
for (yl = 0; yl < lo_gridsize; yl++) {
for (xl = 0; xl < lo_gridsize; xl++) {
- int lo_val = BLI_BITMAP_GET(lo_hidden, yl * lo_gridsize + xl);
+ int lo_val = BLI_BITMAP_TEST(lo_hidden, yl * lo_gridsize + xl);
/* high-res blocks */
for (yo = -offset; yo <= offset; yo++) {
@@ -153,13 +153,15 @@ static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden,
/* If prev_hidden is available, copy it to
* subd, except when the equivalent element in
* lo_hidden is different */
- if (lo_val != prev_hidden[hi_ndx])
- BLI_BITMAP_MODIFY(subd, hi_ndx, lo_val);
- else
- BLI_BITMAP_MODIFY(subd, hi_ndx, prev_hidden[hi_ndx]);
+ if (lo_val != prev_hidden[hi_ndx]) {
+ BLI_BITMAP_SET(subd, hi_ndx, lo_val);
+ }
+ else {
+ BLI_BITMAP_SET(subd, hi_ndx, prev_hidden[hi_ndx]);
+ }
}
else {
- BLI_BITMAP_MODIFY(subd, hi_ndx, lo_val);
+ BLI_BITMAP_SET(subd, hi_ndx, lo_val);
}
}
}
@@ -180,17 +182,15 @@ static BLI_bitmap *multires_mdisps_downsample_hidden(BLI_bitmap *old_hidden,
BLI_assert(new_level <= old_level);
factor = BKE_ccg_factor(new_level, old_level);
- new_hidden = BLI_BITMAP_NEW(new_gridsize * new_gridsize,
- "downsample hidden");
-
+ new_hidden = BLI_BITMAP_NEW(SQUARE(new_gridsize), "downsample hidden");
for (y = 0; y < new_gridsize; y++) {
for (x = 0; x < new_gridsize; x++) {
- old_value = BLI_BITMAP_GET(old_hidden,
+ old_value = BLI_BITMAP_TEST(old_hidden,
factor * y * old_gridsize + x * factor);
- BLI_BITMAP_MODIFY(new_hidden, y * new_gridsize + x, old_value);
+ BLI_BITMAP_SET(new_hidden, y * new_gridsize + x, old_value);
}
}
@@ -248,15 +248,15 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level)
MDisps *mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS,
CD_CALLOC, NULL, me->totloop);
int gridsize = BKE_ccg_gridsize(level);
- int gridarea = gridsize * gridsize;
- int i, j, k;
+ int gridarea = SQUARE(gridsize);
+ int i, j;
for (i = 0; i < me->totpoly; i++) {
- int hide = 0;
+ bool hide = false;
for (j = 0; j < me->mpoly[i].totloop; j++) {
if (me->mvert[me->mloop[me->mpoly[i].loopstart + j].v].flag & ME_HIDE) {
- hide = 1;
+ hide = true;
break;
}
}
@@ -270,9 +270,7 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level)
BLI_assert(!md->hidden);
md->hidden = BLI_BITMAP_NEW(gridarea, "MDisps.hidden initialize");
-
- for (k = 0; k < gridarea; k++)
- BLI_BITMAP_SET(md->hidden, k);
+ BLI_BITMAP_SET_ALL(md->hidden, true, gridarea);
}
}
@@ -286,7 +284,7 @@ DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob
DerivedMesh *tdm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
DerivedMesh *dm;
- dm = mti->applyModifier(md, ob, tdm, MOD_APPLY_USECACHE);
+ dm = mti->applyModifier(md, ob, tdm, MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY);
if (dm == tdm) {
dm = CDDM_copy(tdm);
}
@@ -338,12 +336,15 @@ MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_f
return mmd;
}
-static int multires_get_level(Object *ob, MultiresModifierData *mmd, int render)
+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;
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;
}
@@ -433,7 +434,7 @@ int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mm
int numVerts, result;
float (*deformedVerts)[3];
- if (multires_get_level(ob, mmd, 0) == 0)
+ if (multires_get_level(ob, mmd, false, true) == 0)
return 0;
/* Create DerivedMesh for deformation modifier */
@@ -596,7 +597,7 @@ static void multires_grid_paint_mask_downsample(GridPaintMask *gpm, int level)
{
if (level < gpm->level) {
int gridsize = BKE_ccg_gridsize(level);
- float *data = MEM_callocN(sizeof(float) * gridsize * gridsize,
+ float *data = MEM_callocN(sizeof(float) * SQUARE(gridsize),
"multires_grid_paint_mask_downsample");
int x, y;
@@ -682,7 +683,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl)
void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int direction)
{
Mesh *me = BKE_mesh_from_object(ob);
- int lvl = multires_get_level(ob, mmd, 0);
+ int lvl = multires_get_level(ob, mmd, false, true);
int levels = mmd->totlvl - lvl;
MDisps *mdisps;
@@ -1431,7 +1432,9 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm,
CCGDerivedMesh *ccgdm = NULL;
CCGElem **gridData, **subGridData;
CCGKey key;
- int lvl = multires_get_level(ob, mmd, (flags & MULTIRES_USE_RENDER_PARAMS));
+ const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0;
+ const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0;
+ int lvl = multires_get_level(ob, mmd, render, ignore_simplify);
int i, gridSize, numGrids;
if (lvl == 0)
diff --git a/source/blender/blenkernel/intern/navmesh_conversion.c b/source/blender/blenkernel/intern/navmesh_conversion.c
index 64d59b165e1..6c3f4d545d3 100644
--- a/source/blender/blenkernel/intern/navmesh_conversion.c
+++ b/source/blender/blenkernel/intern/navmesh_conversion.c
@@ -305,7 +305,7 @@ struct SortContext {
const int *trisToFacesMap;
};
-static int compareByData(void *ctx, const void *a, const void *b)
+static int compareByData(const void *a, const void *b, void *ctx)
{
return (((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)a]] -
((struct SortContext *)ctx)->recastData[((struct SortContext *)ctx)->trisToFacesMap[*(int *)b]]);
@@ -341,7 +341,7 @@ int buildNavMeshData(const int nverts, const float *verts,
trisMapping[i] = i;
context.recastData = recastData;
context.trisToFacesMap = trisToFacesMap;
- BLI_qsort_r(trisMapping, ntris, sizeof(int), &context, compareByData);
+ BLI_qsort_r(trisMapping, ntris, sizeof(int), compareByData, &context);
/* search first valid triangle - triangle of convex polygon */
validTriStart = -1;
diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c
index 0c244e8a40b..19e45142960 100644
--- a/source/blender/blenkernel/intern/nla.c
+++ b/source/blender/blenkernel/intern/nla.c
@@ -157,8 +157,10 @@ void free_nladata(ListBase *tracks)
/* Copying ------------------------------------------- */
-/* Copy NLA strip
- * < use_same_action: if true, the existing action is used (instead of being duplicated)
+/**
+ * Copy NLA strip
+ *
+ * \param use_same_action When true, the existing action is used (instead of being duplicated)
*/
NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action)
{
@@ -428,7 +430,7 @@ static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short
return (strip->end + (strip->actstart * scale - cframe)) / scale;
}
else { /* if (mode == NLATIME_CONVERT_EVAL) */
- if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) {
+ if (IS_EQF((float)cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
/* this case prevents the motion snapping back to the first frame at the end of the strip
* by catching the case where repeats is a whole number, which means that the end of the strip
* could also be interpreted as the end of the start of a repeat
@@ -451,7 +453,7 @@ static float nlastrip_get_frame_actionclip(NlaStrip *strip, float cframe, short
return strip->actstart + (cframe - strip->start) / scale;
}
else { /* if (mode == NLATIME_CONVERT_EVAL) */
- if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, ((int)strip->repeat))) {
+ if (IS_EQF(cframe, strip->end) && IS_EQF(strip->repeat, floorf(strip->repeat))) {
/* this case prevents the motion snapping back to the first frame at the end of the strip
* by catching the case where repeats is a whole number, which means that the end of the strip
* could also be interpreted as the end of the start of a repeat
@@ -1635,7 +1637,7 @@ bool BKE_nla_tweakmode_enter(AnimData *adt)
}
}
- if (ELEM3(NULL, activeTrack, activeStrip, activeStrip->act)) {
+ if (ELEM(NULL, activeTrack, activeStrip, activeStrip->act)) {
if (G.debug & G_DEBUG) {
printf("NLA tweakmode enter - neither active requirement found\n");
printf("\tactiveTrack = %p, activeStrip = %p\n", (void *)activeTrack, (void *)activeStrip);
@@ -1742,7 +1744,7 @@ static void UNUSED_FUNCTION(BKE_nla_bake) (Scene *scene, ID *UNUSED(id), AnimDat
* 1) Scene and AnimData must be provided
* 2) there must be tracks to merge...
*/
- if (ELEM3(NULL, scene, adt, adt->nla_tracks.first))
+ if (ELEM(NULL, scene, adt, adt->nla_tracks.first))
return;
/* if animdata currently has an action, 'push down' this onto the stack first */
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index ce1e34de0b0..3a7bfb03e07 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -174,7 +174,7 @@ static void node_set_typeinfo(const struct bContext *C, bNodeTree *ntree, bNode
{
/* for nodes saved in older versions storage can get lost, make undefined then */
if (node->flag & NODE_INIT) {
- if (typeinfo->storagename[0] && !node->storage)
+ if (typeinfo && typeinfo->storagename[0] && !node->storage)
typeinfo = NULL;
}
@@ -1205,13 +1205,13 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool do_
return newtree;
}
-bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, const bool do_id_user)
+bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user)
{
- return ntreeCopyTree_internal(ntree, G.main, do_id_user, true, true);
+ return ntreeCopyTree_internal(ntree, bmain, do_id_user, true, true);
}
bNodeTree *ntreeCopyTree(bNodeTree *ntree)
{
- return ntreeCopyTree_ex(ntree, true);
+ return ntreeCopyTree_ex(ntree, G.main, true);
}
/* use when duplicating scenes */
@@ -1777,7 +1777,7 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user)
if (tntree == ntree)
break;
if (tntree == NULL) {
- BKE_libblock_free_data(&ntree->id);
+ BKE_libblock_free_data(G.main, &ntree->id);
}
}
/* same as ntreeFreeTree_ex but always manage users */
@@ -2682,16 +2682,12 @@ static unsigned int node_instance_hash_key(const void *key)
return ((const bNodeInstanceKey *)key)->value;
}
-static int node_instance_hash_key_cmp(const void *a, const void *b)
+static bool node_instance_hash_key_cmp(const void *a, const void *b)
{
unsigned int value_a = ((const bNodeInstanceKey *)a)->value;
unsigned int value_b = ((const bNodeInstanceKey *)b)->value;
- if (value_a == value_b)
- return 0;
- else if (value_a < value_b)
- return -1;
- else
- return 1;
+
+ return (value_a != value_b);
}
bNodeInstanceHash *BKE_node_instance_hash_new(const char *info)
@@ -3406,6 +3402,7 @@ static void registerCompositNodes(void)
register_node_type_cmp_inpaint();
register_node_type_cmp_despeckle();
register_node_type_cmp_defocus();
+ register_node_type_cmp_sunbeams();
register_node_type_cmp_valtorgb();
register_node_type_cmp_rgbtobw();
@@ -3495,6 +3492,8 @@ static void registerShaderNodes(void)
register_node_type_sh_combrgb();
register_node_type_sh_sephsv();
register_node_type_sh_combhsv();
+ register_node_type_sh_sepxyz();
+ register_node_type_sh_combxyz();
register_node_type_sh_hue_sat();
register_node_type_sh_attribute();
@@ -3526,10 +3525,12 @@ static void registerShaderNodes(void)
register_node_type_sh_mix_shader();
register_node_type_sh_add_shader();
register_node_type_sh_uvmap();
+ register_node_type_sh_uvalongstroke();
register_node_type_sh_output_lamp();
register_node_type_sh_output_material();
register_node_type_sh_output_world();
+ register_node_type_sh_output_linestyle();
register_node_type_sh_tex_image();
register_node_type_sh_tex_environment();
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index d99086a626a..53b0e0cf4a1 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -42,6 +42,7 @@
#include "DNA_constraint_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
#include "DNA_lattice_types.h"
#include "DNA_material_types.h"
#include "DNA_meta_types.h"
@@ -180,10 +181,11 @@ void BKE_object_free_curve_cache(Object *ob)
{
if (ob->curve_cache) {
BKE_displist_free(&ob->curve_cache->disp);
- BLI_freelistN(&ob->curve_cache->bev);
+ BKE_curve_bevelList_free(&ob->curve_cache->bev);
if (ob->curve_cache->path) {
free_path(ob->curve_cache->path);
}
+ BKE_nurbList_free(&ob->curve_cache->deformed_nurbs);
MEM_freeN(ob->curve_cache);
ob->curve_cache = NULL;
}
@@ -246,7 +248,7 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
ModifierData *md;
BKE_object_free_modifiers(ob_dst);
- if (!ELEM5(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ if (!ELEM(ob_dst->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
/* only objects listed above can have modifiers and linking them to objects
* which doesn't have modifiers stack is quite silly */
return;
@@ -255,11 +257,11 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
for (md = ob_src->modifiers.first; md; md = md->next) {
ModifierData *nmd = NULL;
- if (ELEM4(md->type,
- eModifierType_Hook,
- eModifierType_Softbody,
- eModifierType_ParticleInstance,
- eModifierType_Collision))
+ if (ELEM(md->type,
+ eModifierType_Hook,
+ eModifierType_Softbody,
+ eModifierType_ParticleInstance,
+ eModifierType_Collision))
{
continue;
}
@@ -296,7 +298,7 @@ void BKE_object_free_derived_caches(Object *ob)
me->bb->flag |= BOUNDBOX_DIRTY;
}
}
- else if (ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
+ else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
Curve *cu = ob->data;
if (cu->bb) {
@@ -320,18 +322,7 @@ void BKE_object_free_derived_caches(Object *ob)
ob->derivedDeform = NULL;
}
- if (ob->curve_cache) {
- BKE_displist_free(&ob->curve_cache->disp);
- BLI_freelistN(&ob->curve_cache->bev);
- if (ob->curve_cache->path) {
- free_path(ob->curve_cache->path);
- ob->curve_cache->path = NULL;
- }
-
- /* Signal for viewport to run DAG workarounds. */
- MEM_freeN(ob->curve_cache);
- ob->curve_cache = NULL;
- }
+ BKE_object_free_curve_cache(ob);
}
/* do not free object itself */
@@ -408,7 +399,7 @@ void BKE_object_free_ex(Object *ob, bool do_id_user)
/* Free runtime curves data. */
if (ob->curve_cache) {
- BLI_freelistN(&ob->curve_cache->bev);
+ BKE_curve_bevelList_free(&ob->curve_cache->bev);
if (ob->curve_cache->path)
free_path(ob->curve_cache->path);
MEM_freeN(ob->curve_cache);
@@ -709,7 +700,7 @@ void BKE_object_unlink(Object *ob)
lineset; lineset = lineset->next)
{
if (lineset->linestyle) {
- BKE_unlink_linestyle_target_object(lineset->linestyle, ob);
+ BKE_linestyle_target_object_unlink(lineset->linestyle, ob);
}
}
}
@@ -873,9 +864,9 @@ bool BKE_object_is_in_wpaint_select_vert(Object *ob)
{
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- return ( (ob->mode & OB_MODE_WEIGHT_PAINT) &&
- (me->edit_btmesh == NULL) &&
- (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX) );
+ return ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
+ (me->edit_btmesh == NULL) &&
+ (ME_EDIT_PAINT_SEL_MODE(me) == SCE_SELECT_VERTEX));
}
return false;
@@ -977,7 +968,7 @@ Object *BKE_object_add_only_object(Main *bmain, int type, const char *name)
ob->empty_drawtype = OB_PLAINAXES;
ob->empty_drawsize = 1.0;
- if (ELEM3(type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ if (ELEM(type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
ob->trackflag = OB_NEGZ;
ob->upflag = OB_POSY;
}
@@ -1066,10 +1057,10 @@ void BKE_object_lod_add(Object *ob)
BLI_addtail(&ob->lodlevels, lod);
}
-static int lod_cmp(void *a, void *b)
+static int lod_cmp(const void *a, const void *b)
{
- LodLevel *loda = (LodLevel *)a;
- LodLevel *lodb = (LodLevel *)b;
+ const LodLevel *loda = a;
+ const LodLevel *lodb = b;
if (loda->distance < lodb->distance) return -1;
return loda->distance > lodb->distance;
@@ -1125,7 +1116,7 @@ static LodLevel *lod_level_select(Object *ob, const float camera_position[3])
}
else {
/* check for lower LoD */
- while (current->next && dist_sq > (current->next->distance * current->next->distance)) {
+ while (current->next && dist_sq > SQUARE(current->next->distance)) {
current = current->next;
}
}
@@ -1479,7 +1470,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches)
defgroup_copy_list(&obn->defbase, &ob->defbase);
BKE_constraints_copy(&obn->constraints, &ob->constraints, true);
- obn->mode = 0;
+ obn->mode = OB_MODE_OBJECT;
obn->sculpt = NULL;
/* increase user numbers */
@@ -1526,6 +1517,18 @@ Object *BKE_object_copy(Object *ob)
return BKE_object_copy_ex(G.main, ob, false);
}
+static void extern_local_object__modifiersForeachIDLink(
+ void *UNUSED(userData), Object *UNUSED(ob),
+ ID **idpoin)
+{
+ if (*idpoin) {
+ /* intentionally omit ID_OB */
+ if (ELEM(GS((*idpoin)->name), ID_IM, ID_TE)) {
+ id_lib_extern(*idpoin);
+ }
+ }
+}
+
static void extern_local_object(Object *ob)
{
ParticleSystem *psys;
@@ -1539,6 +1542,8 @@ static void extern_local_object(Object *ob)
for (psys = ob->particlesystem.first; psys; psys = psys->next)
id_lib_extern((ID *)psys->part);
+
+ modifiers_foreachIDLink(ob, extern_local_object__modifiersForeachIDLink, NULL);
}
void BKE_object_make_local(Object *ob)
@@ -1778,6 +1783,55 @@ void BKE_object_make_proxy(Object *ob, Object *target, Object *gob)
ob->dt = target->dt;
}
+/**
+ * Use with newly created objects to set their size
+ * (used to apply scene-scale).
+ */
+void BKE_object_obdata_size_init(struct Object *ob, const float size)
+{
+ /* apply radius as a scale to types that support it */
+ switch (ob->type) {
+ case OB_EMPTY:
+ {
+ ob->empty_drawsize *= size;
+ break;
+ }
+ case OB_FONT:
+ {
+ Curve *cu = ob->data;
+ cu->fsize *= size;
+ break;
+ }
+ case OB_CAMERA:
+ {
+ Camera *cam = ob->data;
+ cam->drawsize *= size;
+ break;
+ }
+ case OB_LAMP:
+ {
+ Lamp *lamp = ob->data;
+ lamp->dist *= size;
+ lamp->area_size *= size;
+ lamp->area_sizey *= size;
+ lamp->area_sizez *= size;
+ break;
+ }
+ /* Only lattice (not mesh, curve, mball...),
+ * because its got data when newly added */
+ case OB_LATTICE:
+ {
+ struct Lattice *lt = ob->data;
+ float mat[4][4];
+
+ unit_m4(mat);
+ scale_m4_fl(mat, size);
+
+ BKE_lattice_transform(lt, (float (*)[4])mat, false);
+ break;
+ }
+ }
+}
/* *************** CALC ****************** */
@@ -1978,7 +2032,7 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
unit_m4(mat);
cu = par->data;
- if (ELEM3(NULL, par->curve_cache, par->curve_cache->path, par->curve_cache->path->data)) /* only happens on reload file, but violates depsgraph still... fix! */
+ 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! */
BKE_displist_make_curveTypes(scene, par, 0);
if (par->curve_cache->path == NULL) return;
@@ -1994,17 +2048,20 @@ static void ob_parcurve(Scene *scene, Object *ob, Object *par, float mat[4][4])
* we divide the curvetime calculated in the previous step by the length of the path, to get a time
* factor, which then gets clamped to lie within 0.0 - 1.0 range
*/
- if (IS_EQF(cu->pathlen, 0.0f) == 0)
+ if (cu->pathlen) {
ctime = cu->ctime / cu->pathlen;
- else
+ }
+ else {
ctime = cu->ctime;
+ }
CLAMP(ctime, 0.0f, 1.0f);
}
else {
ctime = BKE_scene_frame_get(scene);
- if (IS_EQF(cu->pathlen, 0.0f) == 0)
+ if (cu->pathlen) {
ctime /= cu->pathlen;
+ }
CLAMP(ctime, 0.0f, 1.0f);
}
@@ -2152,8 +2209,18 @@ static void give_parvert(Object *par, int nr, float vec[3])
}
}
else if (ELEM(par->type, OB_CURVE, OB_SURF)) {
- Curve *cu = par->data;
- ListBase *nurb = BKE_curve_nurbs_get(cu);
+ ListBase *nurb;
+
+ /* Unless there's some weird depsgraph failure the cache should exist. */
+ BLI_assert(par->curve_cache != NULL);
+
+ if (par->curve_cache->deformed_nurbs.first != NULL) {
+ nurb = &par->curve_cache->deformed_nurbs;
+ }
+ else {
+ Curve *cu = par->data;
+ nurb = BKE_curve_nurbs_get(cu);
+ }
BKE_nurbList_index_get_co(nurb, nr, vec);
}
@@ -2289,7 +2356,7 @@ static bool where_is_object_parslow(Object *ob, float obmat[4][4], float slowmat
int a;
/* include framerate */
- fac1 = (1.0f / (1.0f + fabsf(ob->sf)) );
+ fac1 = (1.0f / (1.0f + fabsf(ob->sf)));
if (fac1 >= 1.0f) return 0;
fac2 = 1.0f - fac1;
@@ -2466,6 +2533,20 @@ void BKE_boundbox_init_from_minmax(BoundBox *bb, const float min[3], const float
bb->vec[1][2] = bb->vec[2][2] = bb->vec[5][2] = bb->vec[6][2] = max[2];
}
+void BKE_boundbox_calc_center_aabb(const BoundBox *bb, float r_cent[3])
+{
+ r_cent[0] = 0.5f * (bb->vec[0][0] + bb->vec[4][0]);
+ r_cent[1] = 0.5f * (bb->vec[0][1] + bb->vec[2][1]);
+ r_cent[2] = 0.5f * (bb->vec[0][2] + bb->vec[1][2]);
+}
+
+void BKE_boundbox_calc_size_aabb(const BoundBox *bb, float r_size[3])
+{
+ r_size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]);
+ r_size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]);
+ r_size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]);
+}
+
BoundBox *BKE_object_boundbox_get(Object *ob)
{
BoundBox *bb = NULL;
@@ -2473,7 +2554,7 @@ BoundBox *BKE_object_boundbox_get(Object *ob)
if (ob->type == OB_MESH) {
bb = BKE_mesh_boundbox_get(ob);
}
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
bb = BKE_curve_boundbox_get(ob);
}
else if (ob->type == OB_MBALL) {
@@ -2483,7 +2564,7 @@ BoundBox *BKE_object_boundbox_get(Object *ob)
}
/* used to temporally disable/enable boundbox */
-void BKE_object_boundbox_flag(Object *ob, int flag, int set)
+void BKE_object_boundbox_flag(Object *ob, int flag, const bool set)
{
BoundBox *bb = BKE_object_boundbox_get(ob);
if (bb) {
@@ -2907,6 +2988,12 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
{
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 */
}
@@ -2969,7 +3056,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
lamp_drivers_update(scene, ob->data, ctime);
/* particles */
- if (ob->particlesystem.first) {
+ if (ob != scene->obedit && ob->particlesystem.first) {
ParticleSystem *tpsys, *psys;
DerivedMesh *dm;
ob->transflag &= ~OB_DUPLIPARTS;
@@ -2983,7 +3070,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
if (psys_check_enabled(ob, psys)) {
/* check use of dupli objects here */
- if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->for_render) &&
+ 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)))
{
@@ -3003,7 +3090,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx,
psys = psys->next;
}
- if (eval_ctx->for_render && ob->transflag & OB_DUPLIPARTS) {
+ 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 */
@@ -3120,8 +3207,10 @@ int BKE_object_obdata_texspace_get(Object *ob, short **r_texflag, float **r_loc,
* Test a bounding box for ray intersection
* assumes the ray is already local to the boundbox space
*/
-bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], const float ray_normal[3],
- float *r_lambda)
+bool BKE_boundbox_ray_hit_check(
+ const struct BoundBox *bb,
+ const float ray_start[3], const float ray_normal[3],
+ float *r_lambda)
{
const int triangle_indexes[12][3] = {
{0, 1, 2}, {0, 2, 3},
@@ -3153,9 +3242,9 @@ bool BKE_boundbox_ray_hit_check(struct BoundBox *bb, const float ray_start[3], c
return result;
}
-static int pc_cmp(void *a, void *b)
+static int pc_cmp(const void *a, const void *b)
{
- LinkData *ad = a, *bd = b;
+ const LinkData *ad = a, *bd = b;
if (GET_INT_FROM_POINTER(ad->data) > GET_INT_FROM_POINTER(bd->data))
return 1;
else return 0;
@@ -3384,6 +3473,9 @@ int BKE_object_is_deform_modified(Scene *scene, Object *ob)
VirtualModifierData virtualModifierData;
int flag = 0;
+ if (BKE_key_from_object(ob))
+ flag |= eModifierMode_Realtime | eModifierMode_Render;
+
/* cloth */
for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
md && (flag != (eModifierMode_Render | eModifierMode_Realtime));
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 84e626a3104..0d82c6e89a1 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -101,7 +101,7 @@ static void init_context(DupliContext *r_ctx, EvaluationContext *eval_ctx, Scene
r_ctx->eval_ctx = eval_ctx;
r_ctx->scene = scene;
/* don't allow BKE_object_handle_update for viewport during render, can crash */
- r_ctx->do_update = update && !(G.is_rendering && !eval_ctx->for_render);
+ r_ctx->do_update = update && !(G.is_rendering && eval_ctx->mode != DAG_EVAL_RENDER);
r_ctx->animated = false;
r_ctx->group = NULL;
@@ -162,9 +162,6 @@ static DupliObject *make_dupli(const DupliContext *ctx,
dob->type = ctx->gen->type;
dob->animated = animated || ctx->animated; /* object itself or some parent is animated */
- dob->origlay = ob->lay;
- ob->lay = ctx->lay;
-
/* set persistent id, which is an array with a persistent index for each level
* (particle number, vertex number, ..). by comparing this we can find the same
* dupli object between frames, which is needed for motion blur. last level
@@ -250,13 +247,6 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
ob->flag |= OB_DONE; /* doesnt render */
make_child_duplis_cb(ctx, userdata, ob);
-
- /* Set proper layer in case of scene looping,
- * in case of groups the object layer will be
- * changed when it's duplicated due to the
- * group duplication.
- */
- ob->lay = ctx->object->lay;
}
}
}
@@ -268,7 +258,7 @@ static void make_child_duplis(const DupliContext *ctx, void *userdata, MakeChild
/* OB_DUPLIGROUP */
static void make_duplis_group(const DupliContext *ctx)
{
- bool for_render = ctx->eval_ctx->for_render;
+ bool for_render = (ctx->eval_ctx->mode == DAG_EVAL_RENDER);
Object *ob = ctx->object;
Group *group;
GroupObject *go;
@@ -458,7 +448,6 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3],
Object *inst_ob = vdd->inst_ob;
DupliObject *dob;
float obmat[4][4], space_mat[4][4];
- unsigned int origlay;
/* obmat is transform to vertex */
get_duplivert_transform(co, nor_f, nor_s, vdd->use_rotation, inst_ob->trackflag, inst_ob->upflag, obmat);
@@ -472,10 +461,7 @@ static void vertex_dupli__mapFunc(void *userData, int index, const float co[3],
*/
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
- origlay = vdd->inst_ob->lay;
dob = make_dupli(vdd->ctx, vdd->inst_ob, obmat, index, false, false);
- /* restore the original layer so that each dupli will have proper dob->origlay */
- vdd->inst_ob->lay = origlay;
if (vdd->orco)
copy_v3_v3(dob->orco, vdd->orco[index]);
@@ -524,7 +510,7 @@ static void make_duplis_verts(const DupliContext *ctx)
{
Scene *scene = ctx->scene;
Object *parent = ctx->object;
- bool for_render = ctx->eval_ctx->for_render;
+ bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
VertexDupliData vdd;
vdd.ctx = ctx;
@@ -534,7 +520,7 @@ static void make_duplis_verts(const DupliContext *ctx)
{
Mesh *me = parent->data;
BMEditMesh *em = BKE_editmesh_from_object(parent);
- CustomDataMask dm_mask = (for_render ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH);
+ CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO : CD_MASK_BAREMESH);
if (em)
vdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
@@ -542,7 +528,7 @@ static void make_duplis_verts(const DupliContext *ctx)
vdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
vdd.edit_btmesh = me->edit_btmesh;
- if (for_render)
+ if (use_texcoords)
vdd.orco = vdd.dm->getVertDataArray(vdd.dm, CD_ORCO);
else
vdd.orco = NULL;
@@ -724,6 +710,7 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
float (*orco)[3] = fdd->orco;
MLoopUV *mloopuv = fdd->mloopuv;
int a, totface = fdd->totface;
+ bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
float child_imat[4][4];
DupliObject *dob;
@@ -762,19 +749,19 @@ static void make_child_duplis_faces(const DupliContext *ctx, void *userdata, Obj
mul_m4_m4m4(space_mat, obmat, inst_ob->imat);
dob = make_dupli(ctx, inst_ob, obmat, a, false, false);
- if (ctx->eval_ctx->for_render) {
+ if (use_texcoords) {
float w = 1.0f / (float)mp->totloop;
if (orco) {
int j;
- for (j = 0; j < mpoly->totloop; j++) {
+ for (j = 0; j < mp->totloop; j++) {
madd_v3_v3fl(dob->orco, orco[loopstart[j].v], w);
}
}
if (mloopuv) {
int j;
- for (j = 0; j < mpoly->totloop; j++) {
+ for (j = 0; j < mp->totloop; j++) {
madd_v2_v2fl(dob->uv, mloopuv[mp->loopstart + j].uv, w);
}
}
@@ -789,7 +776,7 @@ static void make_duplis_faces(const DupliContext *ctx)
{
Scene *scene = ctx->scene;
Object *parent = ctx->object;
- bool for_render = ctx->eval_ctx->for_render;
+ bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
FaceDupliData fdd;
fdd.use_scale = ((parent->transflag & OB_DUPLIFACES_SCALE) != 0);
@@ -797,14 +784,14 @@ static void make_duplis_faces(const DupliContext *ctx)
/* gather mesh info */
{
BMEditMesh *em = BKE_editmesh_from_object(parent);
- CustomDataMask dm_mask = (for_render ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH);
+ CustomDataMask dm_mask = (use_texcoords ? CD_MASK_BAREMESH | CD_MASK_ORCO | CD_MASK_MLOOPUV : CD_MASK_BAREMESH);
if (em)
fdd.dm = editbmesh_get_derived_cage(scene, parent, em, dm_mask);
else
fdd.dm = mesh_get_derived_final(scene, parent, dm_mask);
- if (for_render) {
+ if (use_texcoords) {
fdd.orco = fdd.dm->getVertDataArray(fdd.dm, CD_ORCO);
fdd.mloopuv = fdd.dm->getLoopDataArray(fdd.dm, CD_MLOOPUV);
}
@@ -834,7 +821,8 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
{
Scene *scene = ctx->scene;
Object *par = ctx->object;
- bool for_render = ctx->eval_ctx->for_render;
+ bool for_render = ctx->eval_ctx->mode == DAG_EVAL_RENDER;
+ bool use_texcoords = ELEM(ctx->eval_ctx->mode, DAG_EVAL_RENDER, DAG_EVAL_PREVIEW);
GroupObject *go;
Object *ob = NULL, **oblist = NULL, obcopy, *obcopylist = NULL;
@@ -1051,7 +1039,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
dob = make_dupli(ctx, go->ob, mat, a, false, false);
dob->particle_system = psys;
- if (for_render)
+ if (use_texcoords)
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
}
}
@@ -1100,7 +1088,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
dob = make_dupli(ctx, ob, mat, a, false, false);
dob->particle_system = psys;
- if (for_render)
+ if (use_texcoords)
psys_get_dupli_texture(psys, part, sim.psmd, pa, cpa, dob->uv, dob->orco);
/* XXX blender internal needs this to be set to dupligroup to render
* groups correctly, but we don't want this hack for cycles */
@@ -1161,7 +1149,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx)
return NULL;
/* Should the dupli's be generated for this object? - Respect restrict flags */
- if (ctx->eval_ctx->for_render ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
+ if (ctx->eval_ctx->mode == DAG_EVAL_RENDER ? (restrictflag & OB_RESTRICT_RENDER) : (restrictflag & OB_RESTRICT_VIEW))
return NULL;
if (transflag & OB_DUPLIPARTS) {
@@ -1215,15 +1203,6 @@ ListBase *object_duplilist(EvaluationContext *eval_ctx, Scene *sce, Object *ob)
void free_object_duplilist(ListBase *lb)
{
- DupliObject *dob;
-
- /* loop in reverse order, if object is instanced multiple times
- * the original layer may not really be original otherwise, proper
- * solution is more complicated */
- for (dob = lb->last; dob; dob = dob->prev) {
- dob->ob->lay = dob->origlay;
- }
-
BLI_freelistN(lb);
MEM_freeN(lb);
}
@@ -1258,10 +1237,11 @@ int count_duplilist(Object *ob)
return 1;
}
-DupliApplyData *duplilist_apply_matrix(ListBase *duplilist)
+DupliApplyData *duplilist_apply(Object *ob, ListBase *duplilist)
{
DupliApplyData *apply_data = NULL;
int num_objects = BLI_countlist(duplilist);
+
if (num_objects > 0) {
DupliObject *dob;
int i;
@@ -1271,14 +1251,19 @@ DupliApplyData *duplilist_apply_matrix(ListBase *duplilist)
"DupliObject apply extra data");
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);
copy_m4_m4(dob->ob->obmat, dob->mat);
+
+ /* copy layers from the main duplicator object */
+ apply_data->extra[i].lay = dob->ob->lay;
+ dob->ob->lay = ob->lay;
}
}
return apply_data;
}
-void duplilist_restore_matrix(ListBase *duplilist, DupliApplyData *apply_data)
+void duplilist_restore(ListBase *duplilist, DupliApplyData *apply_data)
{
DupliObject *dob;
int i;
@@ -1288,6 +1273,8 @@ void duplilist_restore_matrix(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->lay = apply_data->extra[i].lay;
}
}
diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c
index dafe5ca55ff..d186b4299a5 100644
--- a/source/blender/blenkernel/intern/packedFile.c
+++ b/source/blender/blenkernel/intern/packedFile.c
@@ -368,7 +368,7 @@ int writePackedFile(ReportList *reports, const char *filename, PackedFile *pf, i
int checkPackedFile(const char *filename, PackedFile *pf)
{
- struct stat st;
+ BLI_stat_t st;
int ret_val, i, len, file;
char buf[4096];
char name[FILE_MAX];
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index 1b8c4e084cf..d16575d80c8 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -45,8 +45,10 @@
#include "BLI_bitmap.h"
#include "BLI_utildefines.h"
#include "BLI_math_vector.h"
+#include "BLI_listbase.h"
#include "BKE_brush.h"
+#include "BKE_main.h"
#include "BKE_context.h"
#include "BKE_crazyspace.h"
#include "BKE_depsgraph.h"
@@ -269,6 +271,98 @@ void BKE_paint_brush_set(Paint *p, Brush *br)
}
}
+void BKE_paint_curve_free(PaintCurve *pc)
+{
+ if (pc->points) {
+ MEM_freeN(pc->points);
+ pc->points = NULL;
+ pc->tot_points = 0;
+ }
+}
+
+PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name)
+{
+ PaintCurve *pc;
+
+ pc = BKE_libblock_alloc(bmain, ID_PC, name);
+
+ return pc;
+}
+
+Palette *BKE_paint_palette(Paint *p)
+{
+ return p ? p->palette : NULL;
+}
+
+void BKE_paint_palette_set(Paint *p, Palette *palette)
+{
+ if (p) {
+ id_us_min((ID *)p->palette);
+ id_us_plus((ID *)palette);
+ p->palette = palette;
+ }
+}
+
+void BKE_paint_curve_set(Brush *br, PaintCurve *pc)
+{
+ if (br) {
+ id_us_min((ID *)br->paint_curve);
+ id_us_plus((ID *)pc);
+ br->paint_curve = pc;
+ }
+}
+
+/* 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_countlist(&palette->colors);
+ if ((numcolors == palette->active_color + 1) && (numcolors != 1))
+ palette->active_color--;
+
+ BLI_remlink(&palette->colors, color);
+ BLI_addhead(&palette->deleted, color);
+ }
+}
+
+void BKE_palette_cleanup(Palette *palette)
+{
+ BLI_freelistN(&palette->deleted);
+}
+
+
+Palette *BKE_palette_add(Main *bmain, const char *name)
+{
+ Palette *palette;
+
+ palette = BKE_libblock_alloc(bmain, ID_PAL, name);
+
+ /* enable fake user by default */
+ palette->id.flag |= LIB_FAKEUSER;
+
+ return palette;
+}
+
+void BKE_palette_free(Palette *palette)
+{
+ BLI_freelistN(&palette->colors);
+}
+
+PaletteColor *BKE_palette_color_add(Palette *palette)
+{
+ PaletteColor *color = MEM_callocN(sizeof(*color), "Pallete Color");
+ BLI_addtail(&palette->colors, color);
+ palette->active_color = BLI_countlist(&palette->colors) - 1;
+ return color;
+}
+
+
+bool BKE_palette_is_empty(const struct Palette *palette)
+{
+ return BLI_listbase_is_empty(&palette->colors);
+}
+
+
/* are we in vertex paint or weight pain face select mode? */
bool BKE_paint_select_face_test(Object *ob)
{
@@ -318,6 +412,7 @@ void BKE_paint_init(Paint *p, const char col[3])
void BKE_paint_free(Paint *paint)
{
id_us_min((ID *)paint->brush);
+ id_us_min((ID *)paint->palette);
}
/* called when copying scene settings, so even if 'src' and 'tar' are the same
@@ -328,6 +423,7 @@ void BKE_paint_copy(Paint *src, Paint *tar)
{
tar->brush = src->brush;
id_us_plus((ID *)tar->brush);
+ id_us_plus((ID *)tar->palette);
}
/* returns non-zero if any of the face's vertices
@@ -347,10 +443,10 @@ bool paint_is_grid_face_hidden(const unsigned int *grid_hidden,
int gridsize, int x, int y)
{
/* skip face if any of its corners are hidden */
- return (BLI_BITMAP_GET(grid_hidden, y * gridsize + x) ||
- BLI_BITMAP_GET(grid_hidden, y * gridsize + x + 1) ||
- BLI_BITMAP_GET(grid_hidden, (y + 1) * gridsize + x + 1) ||
- BLI_BITMAP_GET(grid_hidden, (y + 1) * gridsize + x));
+ return (BLI_BITMAP_TEST(grid_hidden, y * gridsize + x) ||
+ BLI_BITMAP_TEST(grid_hidden, y * gridsize + x + 1) ||
+ BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x + 1) ||
+ BLI_BITMAP_TEST(grid_hidden, (y + 1) * gridsize + x));
}
/* Return true if all vertices in the face are visible, false otherwise */
@@ -378,7 +474,7 @@ float paint_grid_paint_mask(const GridPaintMask *gpm, unsigned level,
return gpm->data[(y * factor) * gridsize + (x * factor)];
}
-/* threshhold to move before updating the brush rotation */
+/* threshold to move before updating the brush rotation */
#define RAKE_THRESHHOLD 20
void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, const float mouse_pos[2])
@@ -390,7 +486,7 @@ void paint_calculate_rake_rotation(UnifiedPaintSettings *ups, const float mouse_
sub_v2_v2v2(dpos, ups->last_rake, mouse_pos);
if (len_squared_v2(dpos) >= r * r) {
- ups->brush_rotation = atan2(dpos[0], dpos[1]);
+ ups->brush_rotation = atan2f(dpos[0], dpos[1]);
interp_v2_v2v2(ups->last_rake, ups->last_rake,
mouse_pos, u);
@@ -658,14 +754,28 @@ void BKE_sculpt_update_mesh_elements(Scene *scene, Sculpt *sd, Object *ob,
BKE_free_sculptsession_deformMats(ss);
}
- /* if pbvh is deformed, key block is already applied to it */
- if (ss->kb && !BKE_pbvh_isDeformed(ss->pbvh)) {
- float (*vertCos)[3] = BKE_key_convert_to_vertcos(ob, ss->kb);
+ if (ss->kb != NULL && ss->deform_cos == NULL) {
+ ss->deform_cos = BKE_key_convert_to_vertcos(ob, ss->kb);
+ }
- if (vertCos) {
- /* apply shape keys coordinates to PBVH */
- BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
- MEM_freeN(vertCos);
+ /* if pbvh is deformed, key block is already applied to it */
+ if (ss->kb) {
+ bool pbvh_deformd = BKE_pbvh_isDeformed(ss->pbvh);
+ if (!pbvh_deformd || ss->deform_cos == NULL) {
+ float (*vertCos)[3] = BKE_key_convert_to_vertcos(ob, ss->kb);
+
+ if (vertCos) {
+ if (!pbvh_deformd) {
+ /* apply shape keys coordinates to PBVH */
+ BKE_pbvh_apply_vertCos(ss->pbvh, vertCos);
+ }
+ if (ss->deform_cos == NULL) {
+ ss->deform_cos = vertCos;
+ }
+ if (vertCos != ss->deform_cos) {
+ MEM_freeN(vertCos);
+ }
+ }
}
}
}
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index eb657bac312..530573d6e38 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -656,7 +656,7 @@ static float psys_render_projected_area(ParticleSystem *psys, const float center
}
/* screen space radius */
- radius = sqrt(area / (float)M_PI);
+ radius = sqrtf(area / (float)M_PI);
/* make smaller using fallof once over screen edge */
*viewport = 1.0f;
@@ -917,8 +917,8 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
elem->scalemax = (lambda + t < 1.0f) ? 1.0f / lambda : 1.0f / (1.0f - elem->t * elem->t / t);
elem->scalemin = (lambda + t < 1.0f) ? 0.0f : elem->scalemax * (1.0f - elem->t / t);
- elem->scalemin = sqrt(elem->scalemin);
- elem->scalemax = sqrt(elem->scalemax);
+ elem->scalemin = sqrtf(elem->scalemin);
+ elem->scalemax = sqrtf(elem->scalemax);
/* clamp scaling */
scaleclamp = (float)min_ii(elem->totchild, 10);
@@ -939,8 +939,8 @@ int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
}
elem->lambda = lambda;
- elem->scalemin = sqrt(elem->scalemin);
- elem->scalemax = sqrt(elem->scalemax);
+ elem->scalemin = sqrtf(elem->scalemin);
+ elem->scalemax = sqrtf(elem->scalemax);
elem->curchild = 0;
}
@@ -1657,11 +1657,14 @@ int psys_particle_dm_face_lookup(Object *ob, DerivedMesh *dm, int index, const f
index_mp_to_orig = NULL;
}
+ totface = dm->getNumTessFaces(dm);
+ if (!totface) {
+ return DMCACHE_NOTFOUND;
+ }
+
mpoly = dm->getPolyArray(dm);
osface = dm->getTessFaceDataArray(dm, CD_ORIGSPACE);
- totface = dm->getNumTessFaces(dm);
-
if (osface == NULL || index_mf_to_mpoly == NULL) {
/* Assume we don't need osface data */
if (index < totface) {
@@ -1907,7 +1910,7 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
float orco[3], float ornor[3])
{
- if (psmd) {
+ if (psmd && psmd->dm) {
if (psmd->psys->part->distr == PART_DISTR_GRID && psmd->psys->part->from != PART_FROM_VERT) {
if (vec)
copy_v3_v3(vec, fuv);
@@ -1947,10 +1950,10 @@ static void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float
t = time * freq * (float)M_PI;
if (smooth_start) {
- dt = fabs(t);
+ dt = fabsf(t);
/* smooth the beginning of kink */
CLAMP(dt, 0.f, (float)M_PI);
- dt = sin(dt / 2.f);
+ dt = sinf(dt / 2.f);
}
if (type != PART_KINK_RADIAL) {
@@ -2011,12 +2014,12 @@ static void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float
madd_v3_v3fl(result, proj, flat);
}
- madd_v3_v3fl(result, par_vec, -amplitude * (float)sin(t));
+ madd_v3_v3fl(result, par_vec, -amplitude * sinf(t));
break;
}
case PART_KINK_WAVE:
{
- madd_v3_v3fl(result, kink, amplitude * (float)sin(t));
+ madd_v3_v3fl(result, kink, amplitude * sinf(t));
if (flat > 0.f) {
float proj[3];
@@ -2051,22 +2054,22 @@ static void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float
if (inp_y > 0.5f) {
copy_v3_v3(state_co, y_vec);
- mul_v3_fl(y_vec, amplitude * (float)cos(t));
- mul_v3_fl(z_vec, amplitude / 2.f * (float)sin(2.f * t));
+ mul_v3_fl(y_vec, amplitude * cosf(t));
+ mul_v3_fl(z_vec, amplitude / 2.f * sinf(2.f * t));
}
else if (inp_z > 0.0f) {
- mul_v3_v3fl(state_co, z_vec, (float)sin((float)M_PI / 3.f));
+ mul_v3_v3fl(state_co, z_vec, sinf((float)M_PI / 3.f));
madd_v3_v3fl(state_co, y_vec, -0.5f);
- mul_v3_fl(y_vec, -amplitude * (float)cos(t + (float)M_PI / 3.f));
- mul_v3_fl(z_vec, amplitude / 2.f * (float)cos(2.f * t + (float)M_PI / 6.f));
+ mul_v3_fl(y_vec, -amplitude * cosf(t + (float)M_PI / 3.f));
+ mul_v3_fl(z_vec, amplitude / 2.f * cosf(2.f * t + (float)M_PI / 6.f));
}
else {
- mul_v3_v3fl(state_co, z_vec, -(float)sin((float)M_PI / 3.f));
+ mul_v3_v3fl(state_co, z_vec, -sinf((float)M_PI / 3.f));
madd_v3_v3fl(state_co, y_vec, -0.5f);
- mul_v3_fl(y_vec, amplitude * (float)-sin(t + (float)M_PI / 6.f));
- mul_v3_fl(z_vec, amplitude / 2.f * (float)-sin(2.f * t + (float)M_PI / 3.f));
+ mul_v3_fl(y_vec, amplitude * -sinf(t + (float)M_PI / 6.f));
+ mul_v3_fl(z_vec, amplitude / 2.f * -sinf(2.f * t + (float)M_PI / 3.f));
}
mul_v3_fl(state_co, amplitude);
@@ -2268,8 +2271,11 @@ static void do_rough(float *loc, float mat[4][4], float t, float fac, float size
float rough[3];
float rco[3];
- if (thres != 0.0f)
- if ((float)fabs((float)(-1.5f + loc[0] + loc[1] + loc[2])) < 1.5f * thres) return;
+ if (thres != 0.0f) {
+ if (fabsf((float)(-1.5f + loc[0] + loc[1] + loc[2])) < 1.5f * thres) {
+ return;
+ }
+ }
copy_v3_v3(rco, loc);
mul_v3_fl(rco, t);
@@ -2666,6 +2672,9 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
/* get the original coordinates (orco) for texture usage */
cpa_from = part->from;
cpa_num = pa->num;
+ /* XXX hack to avoid messed up particle num and subsequent crash (#40733) */
+ if (cpa_num > ctx->sim.psmd->dm->getNumTessFaces(ctx->sim.psmd->dm))
+ cpa_num = 0;
cpa_fuv = pa->fuv;
psys_particle_on_emitter(ctx->sim.psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, ornor, 0, 0, orco, 0);
@@ -3887,6 +3896,8 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
}
void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTexture *ptex, int event, float cfra)
{
+ Object *ob = sim->ob;
+ Mesh *me = (Mesh *)ob->data;
ParticleSettings *part = sim->psys->part;
MTex **mtexp = part->mtex;
MTex *mtex;
@@ -3926,6 +3937,14 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
/* no break, failed to get uv's, so let's try orco's */
case TEXCO_ORCO:
psys_particle_on_emitter(sim->psmd, sim->psys->part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, co, 0, 0, 0, texvec, 0);
+
+ if (me->bb == NULL || (me->bb->flag & BOUNDBOX_DIRTY)) {
+ BKE_mesh_texspace_calc(me);
+ }
+ sub_v3_v3(texvec, me->loc);
+ if (me->size[0] != 0.0f) texvec[0] /= me->size[0];
+ if (me->size[1] != 0.0f) texvec[1] /= me->size[1];
+ if (me->size[2] != 0.0f) texvec[2] /= me->size[2];
break;
case TEXCO_PARTICLE:
/* texture coordinates in range [-1, 1] */
@@ -4551,8 +4570,8 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa
normalize_v3(nor);
/* make sure that we get a proper side vector */
- if (fabs(dot_v3v3(nor, vec)) > 0.999999) {
- if (fabs(dot_v3v3(nor, xvec)) > 0.999999) {
+ if (fabsf(dot_v3v3(nor, vec)) > 0.999999) {
+ if (fabsf(dot_v3v3(nor, xvec)) > 0.999999) {
nor[0] = 0.0f;
nor[1] = 1.0f;
nor[2] = 0.0f;
@@ -4660,12 +4679,12 @@ void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3]
copy_v3_v3(tvec, xvec);
copy_v3_v3(tvec2, yvec);
- mul_v3_fl(xvec, cos(bb->tilt * (float)M_PI));
- mul_v3_fl(tvec2, sin(bb->tilt * (float)M_PI));
+ mul_v3_fl(xvec, cosf(bb->tilt * (float)M_PI));
+ mul_v3_fl(tvec2, sinf(bb->tilt * (float)M_PI));
add_v3_v3(xvec, tvec2);
- mul_v3_fl(yvec, cos(bb->tilt * (float)M_PI));
- mul_v3_fl(tvec, -sin(bb->tilt * (float)M_PI));
+ mul_v3_fl(yvec, cosf(bb->tilt * (float)M_PI));
+ mul_v3_fl(tvec, -sinf(bb->tilt * (float)M_PI));
add_v3_v3(yvec, tvec);
mul_v3_fl(xvec, bb->size[0]);
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index d213a88f8b1..155299b69c3 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -117,7 +117,7 @@ static int particles_are_dynamic(ParticleSystem *psys)
if (psys->part->type == PART_HAIR)
return psys->flag & PSYS_HAIR_DYNAMICS;
else
- return ELEM3(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID);
+ return ELEM(psys->part->phystype, PART_PHYS_NEWTON, PART_PHYS_BOIDS, PART_PHYS_FLUID);
}
float psys_get_current_display_percentage(ParticleSystem *psys)
@@ -399,7 +399,7 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
}
}
- if (origindex_final != ORIGINDEX_NONE) {
+ if (origindex_final != ORIGINDEX_NONE && origindex_final < totelem) {
if (nodearray[origindex_final]) {
/* prepend */
node->next = nodearray[origindex_final];
@@ -507,7 +507,7 @@ static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
sub_v3_v3v3(delta, max, min);
/* determine major axis */
- axis = (delta[0]>=delta[1]) ? 0 : ((delta[1]>=delta[2]) ? 1 : 2);
+ axis = axis_dominant_v3_single(delta);
d = delta[axis]/(float)res;
@@ -701,7 +701,7 @@ static void init_mv_jit(float *jit, int num, int seed2, float amount)
rad1= (float)(1.0f/sqrtf((float)num));
rad2= (float)(1.0f/((float)num));
- rad3= (float)sqrt((float)num)/((float)num);
+ rad3= (float)sqrtf((float)num)/((float)num);
rng = BLI_rng_new(31415926 + num + seed2);
x= 0;
@@ -1011,7 +1011,7 @@ static void *distribute_threads_exec_cb(void *data)
return 0;
}
-static int distribute_compare_orig_index(void *user_data, const void *p1, const void *p2)
+static int distribute_compare_orig_index(const void *p1, const void *p2, void *user_data)
{
int *orig_index = (int *) user_data;
int index1 = orig_index[*(const int *)p1];
@@ -1079,7 +1079,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
float *element_weight=NULL,*element_sum=NULL,*jitter_offset=NULL, *vweight=NULL;
float cur, maxweight=0.0, tweight, totweight, inv_totweight, co[3], nor[3], orco[3];
- if (ELEM3(NULL, ob, psys, psys->part))
+ if (ELEM(NULL, ob, psys, psys->part))
return 0;
part=psys->part;
@@ -1344,7 +1344,7 @@ static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, D
}
if (orig_index) {
- BLI_qsort_r(particle_element, totpart, sizeof(int), orig_index, distribute_compare_orig_index);
+ BLI_qsort_r(particle_element, totpart, sizeof(int), distribute_compare_orig_index, orig_index);
}
}
@@ -1546,20 +1546,32 @@ static void initialize_particle_texture(ParticleSimulationData *sim, ParticleDat
ParticleSettings *part = psys->part;
ParticleTexture ptex;
- if (part->type != PART_FLUID) {
- psys_get_texture(sim, pa, &ptex, PAMAP_INIT, 0.f);
-
+ psys_get_texture(sim, pa, &ptex, PAMAP_INIT, 0.f);
+
+ switch (part->type) {
+ case PART_EMITTER:
if (ptex.exist < psys_frand(psys, p+125))
pa->flag |= PARS_UNEXIST;
-
- pa->time = (part->type == PART_HAIR) ? 0.f : part->sta + (part->end - part->sta)*ptex.time;
+ pa->time = part->sta + (part->end - part->sta)*ptex.time;
+ break;
+ case PART_HAIR:
+ if (ptex.exist < psys_frand(psys, p+125))
+ pa->flag |= PARS_UNEXIST;
+ pa->time = 0.f;
+ break;
+ case PART_FLUID:
+ break;
}
}
/* set particle parameters that don't change during particle's life */
-void initialize_particle(ParticleData *pa)
+void initialize_particle(ParticleSimulationData *sim, ParticleData *pa)
{
+ ParticleSettings *part = sim->psys->part;
+ float birth_time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart;
+
pa->flag &= ~PARS_UNEXIST;
+ pa->time = part->sta + (part->end - part->sta) * birth_time;
pa->hair_index = 0;
/* we can't reset to -1 anymore since we've figured out correct index in distribute_particles */
@@ -1575,7 +1587,7 @@ static void initialize_all_particles(ParticleSimulationData *sim)
LOOP_PARTICLES {
if ((pa->flag & PARS_UNEXIST)==0)
- initialize_particle(pa);
+ initialize_particle(sim, pa);
if (pa->flag & PARS_UNEXIST)
psys->totunexist++;
@@ -2626,7 +2638,7 @@ static void sph_particle_courant(SPHData *sphdata, SPHRangeData *pfr)
mul_v3_v3fl(sphdata->flow, flow, 1.0f / pfr->tot_neighbors);
}
else {
- sphdata->element_size = MAXFLOAT;
+ sphdata->element_size = FLT_MAX;
copy_v3_v3(sphdata->flow, flow);
}
}
@@ -3141,7 +3153,7 @@ static void basic_rotate(ParticleSettings *part, ParticleData *pa, float dfra, f
extrotfac = 0.0f;
}
- if ((part->flag & PART_ROT_DYN) && ELEM3(part->avemode, PART_AVE_VELOCITY, PART_AVE_HORIZONTAL, PART_AVE_VERTICAL)) {
+ if ((part->flag & PART_ROT_DYN) && ELEM(part->avemode, PART_AVE_VELOCITY, PART_AVE_HORIZONTAL, PART_AVE_VERTICAL)) {
float angle;
float len1 = len_v3(pa->prev_state.vel);
float len2 = len_v3(pa->state.vel);
@@ -4000,6 +4012,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim)
if (!psys->clmd) {
psys->clmd = (ClothModifierData*)modifier_new(eModifierType_Cloth);
psys->clmd->sim_parms->goalspring = 0.0f;
+ psys->clmd->sim_parms->vel_damping = 1.0f;
psys->clmd->sim_parms->flags |= CLOTH_SIMSETTINGS_FLAG_GOAL|CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
psys->clmd->coll_parms->flags &= ~CLOTH_COLLSETTINGS_FLAG_SELF;
}
@@ -4436,7 +4449,7 @@ static void dynamics_step(ParticleSimulationData *sim, float cfra)
* and Monaghan). Note that, unlike double-density relaxation,
* this algorithm is separated into distinct loops. */
-#pragma omp parallel for firstprivate (sphdata) private (pa) schedule(dynamic,5)
+#pragma omp parallel for private (pa) schedule(dynamic,5)
LOOP_DYNAMIC_PARTICLES {
basic_integrate(sim, p, pa->state.time, cfra);
}
@@ -4834,13 +4847,13 @@ void psys_changed_type(Object *ob, ParticleSystem *psys)
psys->flag &= ~PSYS_KEYED;
if (part->type == PART_HAIR) {
- if (ELEM4(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0)
+ if (ELEM(part->ren_as, PART_DRAW_NOT, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR)==0)
part->ren_as = PART_DRAW_PATH;
if (part->distr == PART_DISTR_GRID)
part->distr = PART_DISTR_JIT;
- if (ELEM3(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0)
+ if (ELEM(part->draw_as, PART_DRAW_NOT, PART_DRAW_REND, PART_DRAW_PATH)==0)
part->draw_as = PART_DRAW_REND;
CLAMP(part->path_start, 0.0f, 100.0f);
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index 45de1449027..ff6fae08460 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -50,6 +50,15 @@
#define STACK_FIXED_DEPTH 100
+/* Setting zero so we can catch bugs in OpenMP/PBVH. */
+#ifdef _OPENMP
+# ifdef DEBUG
+# define PBVH_OMP_LIMIT 0
+# else
+# define PBVH_OMP_LIMIT 8
+# endif
+#endif
+
typedef struct PBVHStack {
PBVHNode *node;
int revisiting;
@@ -251,12 +260,12 @@ static int map_insert_vert(PBVH *bvh, GHash *map,
if (value_p == NULL) {
void *value;
- if (BLI_BITMAP_GET(bvh->vert_bitmap, vertex)) {
+ if (BLI_BITMAP_TEST(bvh->vert_bitmap, vertex)) {
value = SET_INT_IN_POINTER(~(*face_verts));
++(*face_verts);
}
else {
- BLI_BITMAP_SET(bvh->vert_bitmap, vertex);
+ BLI_BITMAP_ENABLE(bvh->vert_bitmap, vertex);
value = SET_INT_IN_POINTER(*uniq_verts);
++(*uniq_verts);
}
@@ -410,7 +419,7 @@ static void build_leaf(PBVH *bvh, int node_index, BBC *prim_bbc,
}
/* Return zero if all primitives in the node can be drawn with the
- * same material (including flat/smooth shading), non-zerootherwise */
+ * same material (including flat/smooth shading), non-zero otherwise */
static int leaf_needs_material_split(PBVH *bvh, int offset, int count)
{
int i, prim;
@@ -965,7 +974,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
* can only update vertices marked with ME_VERT_PBVH_UPDATE.
*/
-#pragma omp parallel for private(n) schedule(static)
+#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
@@ -1009,7 +1018,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
}
}
-#pragma omp parallel for private(n) schedule(static)
+#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
@@ -1046,7 +1055,7 @@ void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
int n;
/* update BB, redraw flag */
-#pragma omp parallel for private(n) schedule(static)
+#pragma omp parallel for private(n) schedule(static) if (totnode > PBVH_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHNode *node = nodes[n];
@@ -1329,6 +1338,12 @@ void BKE_pbvh_node_mark_redraw(PBVHNode *node)
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateRedraw;
}
+void BKE_pbvh_node_mark_normals_update(PBVHNode *node)
+{
+ node->flag |= PBVH_UpdateNormals;
+}
+
+
void BKE_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden)
{
BLI_assert(node->flag & PBVH_Leaf);
@@ -1418,7 +1433,7 @@ void BKE_pbvh_node_get_proxies(PBVHNode *node, PBVHProxyNode **proxies, int *pro
typedef struct {
IsectRayAABBData ray;
- int original;
+ bool original;
} RaycastData;
static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
@@ -1434,9 +1449,10 @@ static bool ray_aabb_intersect(PBVHNode *node, void *data_v)
return isect_ray_aabb(&rcd->ray, bb_min, bb_max, &node->tmin);
}
-void BKE_pbvh_raycast(PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data,
- const float ray_start[3], const float ray_normal[3],
- int original)
+void BKE_pbvh_raycast(
+ PBVH *bvh, BKE_pbvh_HitOccludedCallback cb, void *data,
+ const float ray_start[3], const float ray_normal[3],
+ bool original)
{
RaycastData rcd;
@@ -1629,7 +1645,7 @@ void BKE_pbvh_raycast_project_ray_root (PBVH *bvh, bool original, float ray_star
}
-//#include <GL/glew.h>
+//#include "GPU_glew.h"
typedef struct {
DMSetMaterial setMaterial;
diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c
index 83e0d1a4740..01bca44d3b6 100644
--- a/source/blender/blenkernel/intern/pbvh_bmesh.c
+++ b/source/blender/blenkernel/intern/pbvh_bmesh.c
@@ -41,6 +41,13 @@
#include <assert.h>
+// #define USE_VERIFY
+
+#ifdef USE_VERIFY
+static void pbvh_bmesh_verify(PBVH *bvh);
+#endif
+
+
/****************************** Building ******************************/
/* Update node data after splitting */
@@ -71,7 +78,7 @@ static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_ver
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_reinsert(n->bm_other_verts, v, NULL);
+ BLI_gset_add(n->bm_other_verts, v);
}
else {
BLI_gset_insert(n->bm_unique_verts, v);
@@ -274,22 +281,49 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index)
/**********************************************************************/
-static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key, const int cd_node_offset)
+static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele)
{
- int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset);
+ switch (ele->head.htype) {
+ case BM_VERT:
+ return bvh->cd_vert_node_offset;
+ default:
+ BLI_assert(ele->head.htype == BM_FACE);
+ return bvh->cd_face_node_offset;
+ }
- BLI_assert(node_index != DYNTOPO_NODE_NONE);
+}
+
+static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key)
+{
+ const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key);
+ const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset);
+ BLI_assert(node_index != DYNTOPO_NODE_NONE);
BLI_assert(node_index < bvh->totnode);
+ (void)bvh;
+
+ return node_index;
+}
- return &bvh->nodes[node_index];
+static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key)
+{
+ return &bvh->nodes[pbvh_bmesh_node_lookup_index(bvh, key)];
}
-static BMVert *pbvh_bmesh_vert_create(PBVH *bvh, int node_index,
- const float co[3],
- const BMVert *example,
- const int cd_vert_mask_offset,
- const int cd_vert_node_offset)
+/* typecheck */
+#define pbvh_bmesh_node_lookup_index(bvh, key) ( \
+ CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
+ pbvh_bmesh_node_lookup_index(bvh, key))
+#define pbvh_bmesh_node_lookup(bvh, key) ( \
+ CHECK_TYPE_ANY(key, BMFace *, BMVert *), \
+ pbvh_bmesh_node_lookup(bvh, key))
+
+
+static BMVert *pbvh_bmesh_vert_create(
+ PBVH *bvh, int node_index,
+ const float co[3],
+ const BMVert *example,
+ const int cd_vert_mask_offset)
{
BMVert *v = BM_vert_create(bvh->bm, co, example, BM_CREATE_NOP);
PBVHNode *node = &bvh->nodes[node_index];
@@ -297,7 +331,7 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *bvh, int node_index,
BLI_assert((bvh->totnode == 1 || node_index) && node_index <= bvh->totnode);
BLI_gset_insert(node->bm_unique_verts, v);
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, node_index);
+ BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, node_index);
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
@@ -307,9 +341,10 @@ static BMVert *pbvh_bmesh_vert_create(PBVH *bvh, int node_index,
return v;
}
-static BMFace *pbvh_bmesh_face_create(PBVH *bvh, int node_index,
- BMVert *v_tri[3], BMEdge *e_tri[3],
- const BMFace *f_example, const int cd_face_node_offset)
+static BMFace *pbvh_bmesh_face_create(
+ PBVH *bvh, int node_index,
+ BMVert *v_tri[3], BMEdge *e_tri[3],
+ const BMFace *f_example)
{
BMFace *f;
PBVHNode *node = &bvh->nodes[node_index];
@@ -321,7 +356,7 @@ static BMFace *pbvh_bmesh_face_create(PBVH *bvh, int node_index,
f->head.hflag = f_example->head.hflag;
BLI_gset_insert(node->bm_faces, f);
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, node_index);
+ BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, node_index);
/* mark node for update */
node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals;
@@ -334,7 +369,7 @@ static BMFace *pbvh_bmesh_face_create(PBVH *bvh, int node_index,
}
/* Return the number of faces in 'node' that use vertex 'v' */
-static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v, const int cd_face_node_offset)
+static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v)
{
BMIter bm_iter;
BMFace *f;
@@ -343,7 +378,7 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v,
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
PBVHNode *f_node;
- f_node = pbvh_bmesh_node_lookup(bvh, f, cd_face_node_offset);
+ f_node = pbvh_bmesh_node_lookup(bvh, f);
if (f_node == node)
count++;
@@ -353,20 +388,18 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v,
}
/* Return a node that uses vertex 'v' other than its current owner */
-static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v,
- const int cd_vert_node_offset,
- const int cd_face_node_offset)
+static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v)
{
BMIter bm_iter;
BMFace *f;
PBVHNode *current_node;
- current_node = pbvh_bmesh_node_lookup(bvh, v, cd_vert_node_offset);
+ current_node = pbvh_bmesh_node_lookup(bvh, v);
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
PBVHNode *f_node;
- f_node = pbvh_bmesh_node_lookup(bvh, f, cd_face_node_offset);
+ f_node = pbvh_bmesh_node_lookup(bvh, f);
if (f_node != current_node)
return f_node;
@@ -375,12 +408,13 @@ static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v,
return NULL;
}
-static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner,
- BMVert *v, const int cd_vert_node_offset)
+static void pbvh_bmesh_vert_ownership_transfer(
+ PBVH *bvh, PBVHNode *new_owner,
+ BMVert *v)
{
PBVHNode *current_owner;
- current_owner = pbvh_bmesh_node_lookup(bvh, v, cd_vert_node_offset);
+ current_owner = pbvh_bmesh_node_lookup(bvh, v);
/* mark node for update */
current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
@@ -391,7 +425,7 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner,
BLI_gset_remove(current_owner->bm_unique_verts, v, NULL);
/* Set new ownership */
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, new_owner - bvh->nodes);
+ BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, new_owner - bvh->nodes);
BLI_gset_insert(new_owner->bm_unique_verts, v);
BLI_gset_remove(new_owner->bm_other_verts, v, NULL);
BLI_assert(!BLI_gset_haskey(new_owner->bm_other_verts, v));
@@ -400,20 +434,31 @@ static void pbvh_bmesh_vert_ownership_transfer(PBVH *bvh, PBVHNode *new_owner,
new_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
}
-static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v, const int cd_vert_node_offset, const int cd_face_node_offset)
+static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v)
{
PBVHNode *v_node;
BMIter bm_iter;
BMFace *f;
- v_node = pbvh_bmesh_node_lookup(bvh, v, cd_vert_node_offset);
+ /* never match for first time */
+ int f_node_index_prev = DYNTOPO_NODE_NONE;
+
+ v_node = pbvh_bmesh_node_lookup(bvh, v);
BLI_gset_remove(v_node->bm_unique_verts, v, NULL);
- BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
+ BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE);
/* Have to check each neighboring face's node */
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f, cd_face_node_offset);
+ const int f_node_index = pbvh_bmesh_node_lookup_index(bvh, f);
+ PBVHNode *f_node;
+ /* faces often share the same node,
+ * quick check to avoid redundant #BLI_gset_remove calls */
+ if (f_node_index_prev == f_node_index)
+ continue;
+ f_node_index_prev = f_node_index;
+
+ f_node = &bvh->nodes[f_node_index];
f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB;
/* Remove current ownership */
@@ -424,7 +469,7 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v, const int cd_vert_node_
}
}
-static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f, const int cd_vert_node_offset, const int cd_face_node_offset)
+static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f)
{
PBVHNode *f_node;
BMVert *v;
@@ -432,23 +477,23 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f, const int cd_vert_node_
BMLoop *l_iter;
BMLoop *l_first;
- f_node = pbvh_bmesh_node_lookup(bvh, f, cd_face_node_offset);
+ f_node = pbvh_bmesh_node_lookup(bvh, f);
/* Check if any of this face's vertices need to be removed
* from the node */
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, cd_face_node_offset) == 1) {
+ if (pbvh_bmesh_node_vert_use_count(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, cd_vert_node_offset, cd_face_node_offset);
+ new_node = pbvh_bmesh_vert_other_node_find(bvh, v);
BLI_assert(new_node || BM_vert_face_count(v) == 1);
if (new_node) {
- pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v, cd_vert_node_offset);
+ pbvh_bmesh_vert_ownership_transfer(bvh, new_node, v);
}
}
else {
@@ -460,7 +505,7 @@ static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f, const int cd_vert_node_
/* Remove face from node and top level */
BLI_gset_remove(f_node->bm_faces, f, NULL);
- BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
+ BM_ELEM_CD_SET_INT(f, bvh->cd_face_node_offset, DYNTOPO_NODE_NONE);
/* Log removed face */
BM_log_face_removed(bvh->bm_log, f);
@@ -546,7 +591,8 @@ static void edge_queue_insert(EdgeQueueContext *eq_ctx, BMEdge *e,
* should already make the brush move the vertices only 50%, which means
* that topology updates will also happen less frequent, that should be
* enough. */
- if ((check_mask(eq_ctx, e->v1) || check_mask(eq_ctx, e->v2)) &&
+ if (((eq_ctx->cd_vert_mask_offset == -1) ||
+ (check_mask(eq_ctx, e->v1) || check_mask(eq_ctx, e->v2))) &&
!(BM_elem_flag_test_bool(e->v1, BM_ELEM_HIDDEN) ||
BM_elem_flag_test_bool(e->v2, BM_ELEM_HIDDEN)))
{
@@ -706,7 +752,7 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
mid_v3_v3v3(mid, e->v1->co, e->v2->co);
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, eq_ctx->cd_vert_node_offset);
+ v_new = pbvh_bmesh_vert_create(bvh, node_index, mid, e->v1, eq_ctx->cd_vert_mask_offset);
/* update paint mask */
if (eq_ctx->cd_vert_mask_offset != -1) {
@@ -740,14 +786,14 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
v2 = l_adj->next->v;
if (ni != node_index && i == 0)
- pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new, eq_ctx->cd_vert_node_offset);
+ pbvh_bmesh_vert_ownership_transfer(bvh, &bvh->nodes[ni], v_new);
/* Create two new faces */
v_tri[0] = v1;
v_tri[1] = v_new;
v_tri[2] = v_opp;
bm_edges_from_tri(bvh->bm, v_tri, e_tri);
- f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj, eq_ctx->cd_face_node_offset);
+ f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
long_edge_queue_face_add(eq_ctx, f_new);
v_tri[0] = v_new;
@@ -756,11 +802,11 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx, PBVH *bvh,
e_tri[0] = BM_edge_create(bvh->bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE);
e_tri[2] = e_tri[1]; /* switched */
e_tri[1] = BM_edge_create(bvh->bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE);
- f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj, eq_ctx->cd_face_node_offset);
+ f_new = pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f_adj);
long_edge_queue_face_add(eq_ctx, f_new);
/* Delete original */
- pbvh_bmesh_face_remove(bvh, f_adj, eq_ctx->cd_vert_node_offset, eq_ctx->cd_face_node_offset);
+ pbvh_bmesh_face_remove(bvh, f_adj);
BM_face_kill(bvh->bm, f_adj);
/* Ensure new vertex is in the node */
@@ -822,15 +868,16 @@ static bool pbvh_bmesh_subdivide_long_edges(EdgeQueueContext *eq_ctx, PBVH *bvh,
return any_subdivided;
}
-static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e,
- BMVert *v1, BMVert *v2,
- GSet *deleted_verts,
- BLI_Buffer *edge_loops,
- BLI_Buffer *deleted_faces,
- EdgeQueueContext *eq_ctx)
+static void pbvh_bmesh_collapse_edge(
+ PBVH *bvh, BMEdge *e,
+ BMVert *v1, BMVert *v2,
+ GSet *deleted_verts,
+ BLI_Buffer *deleted_faces,
+ EdgeQueueContext *eq_ctx)
{
BMIter bm_iter;
BMFace *f;
+ BMLoop *l_adj;
BMVert *v_del, *v_conn;
int i;
float mask_v1 = BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset);
@@ -845,18 +892,14 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e,
v_conn = v1;
}
- /* Get all faces adjacent to the edge */
- pbvh_bmesh_edge_loops(edge_loops, e);
-
/* Remove the merge vertex from the PBVH */
- pbvh_bmesh_vert_remove(bvh, v_del, eq_ctx->cd_vert_node_offset, eq_ctx->cd_face_node_offset);
+ pbvh_bmesh_vert_remove(bvh, v_del);
/* Remove all faces adjacent to the edge */
- for (i = 0; i < edge_loops->count; i++) {
- BMLoop *l_adj = BLI_buffer_at(edge_loops, BMLoop *, i);
+ while ((l_adj = e->l)) {
BMFace *f_adj = l_adj->f;
- pbvh_bmesh_face_remove(bvh, f_adj, eq_ctx->cd_vert_node_offset, eq_ctx->cd_face_node_offset);
+ pbvh_bmesh_face_remove(bvh, f_adj);
BM_face_kill(bvh->bm, f_adj);
}
@@ -869,7 +912,8 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e,
/* Note: this could be done with BM_vert_splice(), but that
* requires handling other issues like duplicate edges, so doesn't
* really buy anything. */
- deleted_faces->count = 0;
+ BLI_buffer_empty(deleted_faces);
+
BM_ITER_ELEM (f, &bm_iter, v_del, BM_FACES_OF_VERT) {
BMVert *v_tri[3];
BMFace *existing_face;
@@ -895,10 +939,10 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e,
}
else {
BMEdge *e_tri[3];
- n = pbvh_bmesh_node_lookup(bvh, f, eq_ctx->cd_face_node_offset);
+ n = pbvh_bmesh_node_lookup(bvh, f);
ni = n - bvh->nodes;
bm_edges_from_tri(bvh->bm, v_tri, e_tri);
- pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f, eq_ctx->cd_face_node_offset);
+ 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) &&
@@ -931,7 +975,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e,
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], eq_ctx->cd_vert_node_offset, eq_ctx->cd_face_node_offset);
+ pbvh_bmesh_vert_remove(bvh, v_tri[j]);
}
else {
v_tri[j] = NULL;
@@ -939,7 +983,7 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e,
}
/* Remove the face */
- pbvh_bmesh_face_remove(bvh, f_del, eq_ctx->cd_vert_node_offset, eq_ctx->cd_face_node_offset);
+ pbvh_bmesh_face_remove(bvh, f_del);
BM_face_kill(bvh->bm, f_del);
/* Check if any of the face's edges are now unused by any
@@ -972,10 +1016,10 @@ static void pbvh_bmesh_collapse_edge(PBVH *bvh, BMEdge *e,
BM_vert_kill(bvh->bm, v_del);
}
-static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
- PBVH *bvh,
- BLI_Buffer *edge_loops,
- BLI_Buffer *deleted_faces)
+static bool pbvh_bmesh_collapse_short_edges(
+ EdgeQueueContext *eq_ctx,
+ PBVH *bvh,
+ BLI_Buffer *deleted_faces)
{
float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len;
GSet *deleted_verts;
@@ -1019,7 +1063,7 @@ static bool pbvh_bmesh_collapse_short_edges(EdgeQueueContext *eq_ctx,
any_collapsed = true;
pbvh_bmesh_collapse_edge(bvh, e, v1, v2,
- deleted_verts, edge_loops,
+ deleted_verts,
deleted_faces, eq_ctx);
}
@@ -1213,7 +1257,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
const float center[3], float radius)
{
/* 2 is enough for edge faces - manifold edge */
- BLI_buffer_declare_static(BMFace *, edge_loops, BLI_BUFFER_NOP, 2);
+ BLI_buffer_declare_static(BMLoop *, edge_loops, BLI_BUFFER_NOP, 2);
BLI_buffer_declare_static(BMFace *, deleted_faces, BLI_BUFFER_NOP, 32);
const int cd_vert_mask_offset = CustomData_get_offset(&bvh->bm->vdata, CD_PAINT_MASK);
const int cd_vert_node_offset = bvh->cd_vert_node_offset;
@@ -1229,7 +1273,7 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
short_edge_queue_create(&eq_ctx, bvh, center, radius);
modified |= !BLI_heap_is_empty(q.heap);
- pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh, &edge_loops,
+ pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh,
&deleted_faces);
BLI_heap_free(q.heap, NULL);
BLI_mempool_destroy(queue_pool);
@@ -1260,6 +1304,10 @@ bool BKE_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
BLI_buffer_free(&edge_loops);
BLI_buffer_free(&deleted_faces);
+#ifdef USE_VERIFY
+ pbvh_bmesh_verify(bvh);
+#endif
+
return modified;
}
@@ -1381,104 +1429,28 @@ struct GSet *BKE_pbvh_bmesh_node_faces(PBVHNode *node)
#if 0
-void bli_gset_duplicate_key_check(GSet *gs)
-{
- GSetIterator gs_iter1, gs_iter2;
-
- GSET_ITER (gs_iter1, gs) {
- void *key1 = BLI_gsetIterator_getKey(&gs_iter1);
- int dup = -1;
-
- GSET_ITER (gs_iter2, gs) {
- void *key2 = BLI_gsetIterator_getKey(&gs_iter2);
-
- if (key1 == key2) {
- dup++;
- if (dup > 0) {
- BLI_assert(!"duplicate in hash");
- }
- }
- }
- }
-}
-
-void bmesh_print(BMesh *bm)
-{
- BMIter iter, siter;
- BMVert *v;
- BMEdge *e;
- BMFace *f;
- BMLoop *l;
-
- fprintf(stderr, "\nbm=%p, totvert=%d, totedge=%d, "
- "totloop=%d, totface=%d\n",
- bm, bm->totvert, bm->totedge,
- bm->totloop, bm->totface);
-
- fprintf(stderr, "vertices:\n");
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- fprintf(stderr, " %d co=(%.3f %.3f %.3f) oflag=%x\n",
- BM_elem_index_get(v), v->co[0], v->co[1], v->co[2],
- v->oflags[bm->stackdepth - 1].f);
- }
-
- fprintf(stderr, "edges:\n");
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- fprintf(stderr, " %d v1=%d, v2=%d, oflag=%x\n",
- BM_elem_index_get(e),
- BM_elem_index_get(e->v1),
- BM_elem_index_get(e->v2),
- e->oflags[bm->stackdepth - 1].f);
- }
-
- fprintf(stderr, "faces:\n");
- BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
- fprintf(stderr, " %d len=%d, oflag=%x\n",
- BM_elem_index_get(f), f->len,
- f->oflags[bm->stackdepth - 1].f);
-
- fprintf(stderr, " v: ");
- BM_ITER_ELEM(v, &siter, f, BM_VERTS_OF_FACE) {
- fprintf(stderr, "%d ", BM_elem_index_get(v));
- }
- fprintf(stderr, "\n");
-
- fprintf(stderr, " e: ");
- BM_ITER_ELEM(e, &siter, f, BM_EDGES_OF_FACE) {
- fprintf(stderr, "%d ", BM_elem_index_get(e));
- }
- fprintf(stderr, "\n");
-
- fprintf(stderr, " l: ");
- BM_ITER_ELEM(l, &siter, f, BM_LOOPS_OF_FACE) {
- fprintf(stderr, "%d(v=%d, e=%d) ",
- BM_elem_index_get(l),
- BM_elem_index_get(l->v),
- BM_elem_index_get(l->e));
- }
- fprintf(stderr, "\n");
- }
-}
-
-void pbvh_bmesh_print(PBVH *bvh)
+static void pbvh_bmesh_print(PBVH *bvh)
{
- GHashIterator gh_iter;
GSetIterator gs_iter;
int n;
+ BMIter iter;
+ BMFace *f;
+ BMVert *v;
fprintf(stderr, "\npbvh=%p\n", bvh);
fprintf(stderr, "bm_face_to_node:\n");
- GHASH_ITER (gh_iter, bvh->bm_face_to_node) {
+
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
- BM_elem_index_get((BMFace *)BLI_ghashIterator_getKey(&gh_iter)),
- GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter)));
+ BM_elem_index_get(v),
+ pbvh_bmesh_node_lookup_index(bvh, f));
}
fprintf(stderr, "bm_vert_to_node:\n");
- GHASH_ITER (gh_iter, bvh->bm_vert_to_node) {
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) {
fprintf(stderr, " %d -> %d\n",
- BM_elem_index_get((BMVert *)BLI_ghashIterator_getKey(&gh_iter)),
- GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter)));
+ BM_elem_index_get(v),
+ pbvh_bmesh_node_lookup_index(bvh, v));
}
for (n = 0; n < bvh->totnode; n++) {
@@ -1487,9 +1459,9 @@ void pbvh_bmesh_print(PBVH *bvh)
continue;
fprintf(stderr, "node %d\n faces:\n", n);
- GHASH_ITER (gh_iter, node->bm_faces)
+ GSET_ITER (gs_iter, node->bm_faces)
fprintf(stderr, " %d\n",
- BM_elem_index_get((BMFace *)BLI_ghashIterator_getKey(&gh_iter)));
+ BM_elem_index_get((BMFace *)BLI_gsetIterator_getKey(&gs_iter)));
fprintf(stderr, " unique verts:\n");
GSET_ITER (gs_iter, node->bm_unique_verts)
fprintf(stderr, " %d\n",
@@ -1501,7 +1473,7 @@ void pbvh_bmesh_print(PBVH *bvh)
}
}
-void print_flag_factors(int flag)
+static void print_flag_factors(int flag)
{
int i;
printf("flag=0x%x:\n", flag);
@@ -1511,24 +1483,53 @@ void print_flag_factors(int flag)
}
}
}
+#endif
+
-void pbvh_bmesh_verify(PBVH *bvh)
+#ifdef USE_VERIFY
+
+static void pbvh_bmesh_verify(PBVH *bvh)
{
- GHashIterator gh_iter;
GSetIterator gs_iter;
- int i, vert_count = 0;
+ int i;
BMIter iter;
- BMVert *vi;
+ BMFace *f;
+ BMVert *v;
+
+ GSet *faces_all;
+ GSet *verts_all;
+
- /* Check faces */
- BLI_assert(bvh->bm->totface == BLI_ghash_size(bvh->bm_face_to_node));
- GHASH_ITER (gh_iter, bvh->bm_face_to_node) {
+ /* build list of faces & verts to lookup */
+ faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface);
+ verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert);
+
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
+ BLI_gset_insert(faces_all, f);
+ }
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) {
+ BLI_gset_insert(verts_all, v);
+ }
+ }
+
+ /* Check vert/face counts */
+ {
+ int totface = 0, totvert = 0;
+ for (i = 0; i < bvh->totnode; i++) {
+ PBVHNode *n = &bvh->nodes[i];
+ totface += n->bm_faces ? BLI_gset_size(n->bm_faces) : 0;
+ totvert += n->bm_unique_verts ? BLI_gset_size(n->bm_unique_verts) : 0;
+ }
+
+ BLI_assert(totface == BLI_gset_size(faces_all));
+ BLI_assert(totvert == BLI_gset_size(verts_all));
+ }
+
+ BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) {
BMIter bm_iter;
BMVert *v;
- BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
- void *nip = BLI_ghashIterator_getValue(&gh_iter);
- int ni = GET_INT_FROM_POINTER(nip);
- PBVHNode *n = &bvh->nodes[ni];
+ PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f);
/* Check that the face's node is a leaf */
BLI_assert(n->flag & PBVH_Leaf);
@@ -1545,7 +1546,7 @@ void pbvh_bmesh_verify(PBVH *bvh)
BLI_gset_haskey(n->bm_other_verts, v));
/* Check that the vertex has a node owner */
- nv = pbvh_bmesh_node_lookup(bvh, bvh->bm_vert_to_node, v);
+ nv = pbvh_bmesh_node_lookup(bvh, v);
/* Check that the vertex's node knows it owns the vert */
BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v));
@@ -1556,16 +1557,18 @@ void pbvh_bmesh_verify(PBVH *bvh)
}
/* Check verts */
- BLI_assert(bvh->bm->totvert == BLI_ghash_size(bvh->bm_vert_to_node));
- GHASH_ITER (gh_iter, bvh->bm_vert_to_node) {
+ BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) {
BMIter bm_iter;
- BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
- BMFace *f;
- void *nip = BLI_ghashIterator_getValue(&gh_iter);
- int ni = GET_INT_FROM_POINTER(nip);
- PBVHNode *n = &bvh->nodes[ni];
+ PBVHNode *n;
bool found;
+ /* vertex isn't tracked */
+ if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) {
+ continue;
+ }
+
+ n = pbvh_bmesh_node_lookup(bvh, v);
+
/* Check that the vert's node is a leaf */
BLI_assert(n->flag & PBVH_Leaf);
@@ -1578,7 +1581,7 @@ void pbvh_bmesh_verify(PBVH *bvh)
/* Check that the vert's node also contains one of the vert's
* adjacent faces */
BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) {
- if (BLI_ghash_lookup(bvh->bm_face_to_node, f) == nip) {
+ if (pbvh_bmesh_node_lookup(bvh, f) == n) {
found = true;
break;
}
@@ -1589,9 +1592,10 @@ void pbvh_bmesh_verify(PBVH *bvh)
/* total freak stuff, check if node exists somewhere else */
/* Slow */
for (i = 0; i < bvh->totnode; i++) {
- PBVHNode *n = &bvh->nodes[i];
- if (i != ni && n->bm_unique_verts)
- BLI_assert(!BLI_gset_haskey(n->bm_unique_verts, v));
+ PBVHNode *n_other = &bvh->nodes[i];
+ if ((n != n_other) && (n_other->bm_unique_verts)) {
+ BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v));
+ }
}
#endif
@@ -1619,36 +1623,32 @@ void pbvh_bmesh_verify(PBVH *bvh)
for (i = 0; i < bvh->totnode; i++) {
PBVHNode *n = &bvh->nodes[i];
if (n->flag & PBVH_Leaf) {
- /* Check for duplicate entries */
- /* Slow */
-#if 0
- bli_gset_duplicate_key_check(n->bm_faces);
- bli_gset_duplicate_key_check(n->bm_unique_verts);
- bli_gset_duplicate_key_check(n->bm_other_verts);
-#endif
- GHASH_ITER (gh_iter, n->bm_faces) {
- BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
- void *nip = BLI_ghash_lookup(bvh->bm_face_to_node, f);
- BLI_assert(BLI_ghash_haskey(bvh->bm_face_to_node, f));
- BLI_assert(GET_INT_FROM_POINTER(nip) == (n - bvh->nodes));
+ GSET_ITER (gs_iter, n->bm_faces) {
+ BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
+ PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, f);
+ BLI_assert(n == n_other);
+ BLI_assert(BLI_gset_haskey(faces_all, f));
}
GSET_ITER (gs_iter, n->bm_unique_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- void *nip = BLI_ghash_lookup(bvh->bm_vert_to_node, v);
- BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v));
+ PBVHNode *n_other = pbvh_bmesh_node_lookup(bvh, v);
BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v));
- BLI_assert(GET_INT_FROM_POINTER(nip) == (n - bvh->nodes));
+ BLI_assert(n == n_other);
+ BLI_assert(BLI_gset_haskey(verts_all, v));
}
GSET_ITER (gs_iter, n->bm_other_verts) {
BMVert *v = BLI_gsetIterator_getKey(&gs_iter);
- BLI_assert(BLI_ghash_haskey(bvh->bm_vert_to_node, v));
BLI_assert(BM_vert_face_count(v) > 0);
+ BLI_assert(BLI_gset_haskey(verts_all, v));
}
}
}
+
+ BLI_gset_free(faces_all, NULL);
+ BLI_gset_free(verts_all, NULL);
}
#endif
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 17c75341891..b77407cdcb2 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -51,7 +51,6 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_system.h"
-#include BLI_SYSTEM_PID_H
#include "BLF_translation.h"
@@ -86,17 +85,17 @@
#ifdef WITH_LZO
#include "minilzo.h"
-#else
-/* used for non-lzo cases */
-#define LZO_OUT_LEN(size) ((size) + (size) / 16 + 64 + 3)
+#define LZO_HEAP_ALLOC(var,size) \
+ lzo_align_t __LZO_MMODEL var [ ((size) + (sizeof(lzo_align_t) - 1)) / sizeof(lzo_align_t) ]
#endif
+#define LZO_OUT_LEN(size) ((size) + (size) / 16 + 64 + 3)
+
#ifdef WITH_LZMA
#include "LzmaLib.h"
#endif
/* needed for directory lookup */
-/* untitled blend's need getpid for a unique name */
#ifndef WIN32
# include <dirent.h>
#else
@@ -1491,7 +1490,7 @@ static int ptcache_path(PTCacheID *pid, char *filename)
/* use the temp path. this is weak but better then not using point cache at all */
/* temporary directory is assumed to exist and ALWAYS has a trailing slash */
- BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH"%d", BLI_temporary_dir(), abs(getpid()));
+ BLI_snprintf(filename, MAX_PTCACHE_PATH, "%s"PTCACHE_PATH, BLI_temp_dir_session());
return BLI_add_slash(filename); /* new strlen() */
}
diff --git a/source/blender/blenkernel/intern/report.c b/source/blender/blenkernel/intern/report.c
index 90b5d8cf1a1..b2178fe69b3 100644
--- a/source/blender/blenkernel/intern/report.c
+++ b/source/blender/blenkernel/intern/report.c
@@ -284,7 +284,7 @@ Report *BKE_reports_last_displayable(ReportList *reports)
Report *report;
for (report = reports->list.last; report; report = report->prev) {
- if (ELEM3(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO))
+ if (ELEM(report->type, RPT_ERROR, RPT_WARNING, RPT_INFO))
return report;
}
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 8e5b67404ac..3d61b0bdefb 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -57,6 +57,7 @@
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_library.h"
+#include "BKE_mesh.h"
#include "BKE_object.h"
#include "BKE_pointcache.h"
#include "BKE_rigidbody.h"
@@ -287,10 +288,10 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
DM_ensure_tessface(dm);
- mvert = (dm) ? dm->getVertArray(dm) : NULL;
- totvert = (dm) ? dm->getNumVerts(dm) : 0;
- mface = (dm) ? dm->getTessFaceArray(dm) : NULL;
- totface = (dm) ? dm->getNumTessFaces(dm) : 0;
+ mvert = dm->getVertArray(dm);
+ totvert = dm->getNumVerts(dm);
+ mface = dm->getTessFaceArray(dm);
+ totface = dm->getNumTessFaces(dm);
/* sanity checking - potential case when no data will be present */
if ((totvert == 0) || (totface == 0)) {
@@ -344,7 +345,7 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
}
/* cleanup temp data */
- if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
+ if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
dm->release(dm);
}
}
@@ -394,7 +395,7 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
}
mul_v3_fl(size, 0.5f);
- if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) {
+ if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) {
/* take radius as largest x/y dimension, and height as z-dimension */
radius = MAX2(size[0], size[1]);
height = size[2];
@@ -455,8 +456,186 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
/* --------------------- */
-/* Create physics sim representation of object given RigidBody settings
- * < rebuild: even if an instance already exists, replace it
+/* helper function to calculate volume of rigidbody object */
+// TODO: allow a parameter to specify method used to calculate this?
+void BKE_rigidbody_calc_volume(Object *ob, float *r_vol)
+{
+ RigidBodyOb *rbo = ob->rigidbody_object;
+
+ float size[3] = {1.0f, 1.0f, 1.0f};
+ float radius = 1.0f;
+ float height = 1.0f;
+
+ float volume = 0.0f;
+
+ /* if automatically determining dimensions, use the Object's boundbox
+ * - assume that all quadrics are standing upright on local z-axis
+ * - assume even distribution of mass around the Object's pivot
+ * (i.e. Object pivot is centralized in boundbox)
+ * - boundbox gives full width
+ */
+ // XXX: all dimensions are auto-determined now... later can add stored settings for this
+ BKE_object_dimensions_get(ob, size);
+
+ if (ELEM(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) {
+ /* take radius as largest x/y dimension, and height as z-dimension */
+ radius = MAX2(size[0], size[1]) * 0.5f;
+ height = size[2];
+ }
+ else if (rbo->shape == RB_SHAPE_SPHERE) {
+ /* take radius to the the largest dimension to try and encompass everything */
+ radius = max_fff(size[0], size[1], size[2]) * 0.5f;
+ }
+
+ /* calculate volume as appropriate */
+ switch (rbo->shape) {
+ case RB_SHAPE_BOX:
+ volume = size[0] * size[1] * size[2];
+ break;
+
+ case RB_SHAPE_SPHERE:
+ volume = 4.0f / 3.0f * (float)M_PI * radius * radius * radius;
+ break;
+
+ /* for now, assume that capsule is close enough to a cylinder... */
+ case RB_SHAPE_CAPSULE:
+ case RB_SHAPE_CYLINDER:
+ volume = (float)M_PI * radius * radius * height;
+ break;
+
+ case RB_SHAPE_CONE:
+ volume = (float)M_PI / 3.0f * radius * radius * height;
+ break;
+
+ case RB_SHAPE_CONVEXH:
+ case RB_SHAPE_TRIMESH:
+ {
+ if (ob->type == OB_MESH) {
+ DerivedMesh *dm = rigidbody_get_mesh(ob);
+ MVert *mvert;
+ MFace *mface;
+ int totvert, totface;
+
+ /* ensure mesh validity, then grab data */
+ if (dm == NULL)
+ return;
+
+ DM_ensure_tessface(dm);
+
+ mvert = dm->getVertArray(dm);
+ totvert = dm->getNumVerts(dm);
+ mface = dm->getTessFaceArray(dm);
+ totface = dm->getNumTessFaces(dm);
+
+ if (totvert > 0 && totface > 0) {
+ BKE_mesh_calc_volume(mvert, totvert, mface, totface, &volume, NULL);
+ }
+
+ /* cleanup temp data */
+ if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
+ dm->release(dm);
+ }
+ }
+ else {
+ /* rough estimate from boundbox as fallback */
+ /* XXX could implement other types of geometry here (curves, etc.) */
+ volume = size[0] * size[1] * size[2];
+ }
+ break;
+ }
+
+#if 0 // XXX: not defined yet
+ case RB_SHAPE_COMPOUND:
+ volume = 0.0f;
+ break;
+#endif
+ }
+
+ /* return the volume calculated */
+ if (r_vol) *r_vol = volume;
+}
+
+void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_com[3])
+{
+ RigidBodyOb *rbo = ob->rigidbody_object;
+
+ float size[3] = {1.0f, 1.0f, 1.0f};
+ float height = 1.0f;
+
+ zero_v3(r_com);
+
+ /* if automatically determining dimensions, use the Object's boundbox
+ * - assume that all quadrics are standing upright on local z-axis
+ * - assume even distribution of mass around the Object's pivot
+ * (i.e. Object pivot is centralized in boundbox)
+ * - boundbox gives full width
+ */
+ // XXX: all dimensions are auto-determined now... later can add stored settings for this
+ BKE_object_dimensions_get(ob, size);
+
+ /* calculate volume as appropriate */
+ switch (rbo->shape) {
+ case RB_SHAPE_BOX:
+ case RB_SHAPE_SPHERE:
+ case RB_SHAPE_CAPSULE:
+ case RB_SHAPE_CYLINDER:
+ break;
+
+ case RB_SHAPE_CONE:
+ /* take radius as largest x/y dimension, and height as z-dimension */
+ height = size[2];
+ /* cone is geometrically centered on the median,
+ * center of mass is 1/4 up from the base
+ */
+ r_com[2] = -0.25f * height;
+ break;
+
+ case RB_SHAPE_CONVEXH:
+ case RB_SHAPE_TRIMESH:
+ {
+ if (ob->type == OB_MESH) {
+ DerivedMesh *dm = rigidbody_get_mesh(ob);
+ MVert *mvert;
+ MFace *mface;
+ int totvert, totface;
+
+ /* ensure mesh validity, then grab data */
+ if (dm == NULL)
+ return;
+
+ DM_ensure_tessface(dm);
+
+ mvert = dm->getVertArray(dm);
+ totvert = dm->getNumVerts(dm);
+ mface = dm->getTessFaceArray(dm);
+ totface = dm->getNumTessFaces(dm);
+
+ if (totvert > 0 && totface > 0) {
+ BKE_mesh_calc_volume(mvert, totvert, mface, totface, NULL, r_com);
+ }
+
+ /* cleanup temp data */
+ if (ob->rigidbody_object->mesh_source == RBO_MESH_BASE) {
+ dm->release(dm);
+ }
+ }
+ break;
+ }
+
+#if 0 // XXX: not defined yet
+ case RB_SHAPE_COMPOUND:
+ volume = 0.0f;
+ break;
+#endif
+ }
+}
+
+/* --------------------- */
+
+/**
+ * Create physics sim representation of object given RigidBody settings
+ *
+ * \param rebuild Even if an instance already exists, replace it
*/
static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool rebuild)
{
@@ -518,8 +697,10 @@ static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool
/* --------------------- */
-/* Create physics sim representation of constraint given rigid body constraint settings
- * < rebuild: even if an instance already exists, replace it
+/**
+ * Create physics sim representation of constraint given rigid body constraint settings
+ *
+ * \param rebuild Even if an instance already exists, replace it
*/
static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, bool rebuild)
{
@@ -539,7 +720,7 @@ static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, b
return;
}
- if (ELEM4(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) {
+ if (ELEM(NULL, rbc->ob1, rbc->ob1->rigidbody_object, rbc->ob2, rbc->ob2->rigidbody_object)) {
if (rbc->physics_constraint) {
RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
RB_constraint_delete(rbc->physics_constraint);
@@ -895,7 +1076,8 @@ RigidBodyCon *BKE_rigidbody_create_constraint(Scene *scene, Object *ob, short ty
/* Utilities API */
/* Get RigidBody world for the given scene, creating one if needed
- * < scene: Scene to find active Rigid Body world for
+ *
+ * \param scene Scene to find active Rigid Body world for
*/
RigidBodyWorld *BKE_rigidbody_get_world(Scene *scene)
{
@@ -1093,8 +1275,10 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
*/
}
-/* Updates and validates world, bodies and shapes.
- * < rebuild: rebuild entire simulation
+/**
+ * Updates and validates world, bodies and shapes.
+ *
+ * \param rebuild Rebuild entire simulation
*/
static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
{
@@ -1105,6 +1289,26 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
BKE_rigidbody_validate_sim_world(scene, rbw, true);
rigidbody_update_sim_world(scene, rbw);
+ /* XXX TODO For rebuild: remove all constraints first.
+ * Otherwise we can end up deleting objects that are still
+ * referenced by constraints, corrupting bullet's internal list.
+ *
+ * Memory management needs redesign here, this is just a dirty workaround.
+ */
+ if (rebuild && rbw->constraints) {
+ for (go = rbw->constraints->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+ if (ob) {
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+ if (rbc && rbc->physics_constraint) {
+ RB_dworld_remove_constraint(rbw->physics_world, rbc->physics_constraint);
+ RB_constraint_delete(rbc->physics_constraint);
+ rbc->physics_constraint = NULL;
+ }
+ }
+ }
+ }
+
/* update objects */
for (go = rbw->group->gobject.first; go; go = go->next) {
Object *ob = go->ob;
@@ -1150,6 +1354,7 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool
rigidbody_update_sim_ob(scene, rbw, ob, rbo);
}
}
+
/* update constraints */
if (rbw->constraints == NULL) /* no constraints, move on */
return;
@@ -1386,6 +1591,8 @@ struct RigidBodyOb *BKE_rigidbody_copy_object(Object *ob) { return NULL; }
struct RigidBodyCon *BKE_rigidbody_copy_constraint(Object *ob) { return NULL; }
void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc) {}
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild) {}
+void BKE_rigidbody_calc_volume(Object *ob, float *r_vol) { if (r_vol) *r_vol = 0.0f; }
+void BKE_rigidbody_calc_center_of_mass(Object *ob, float r_com[3]) { zero_v3(r_com); }
struct RigidBodyWorld *BKE_rigidbody_create_world(Scene *scene) { return NULL; }
struct RigidBodyWorld *BKE_rigidbody_world_copy(RigidBodyWorld *rbw) { return NULL; }
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw) {}
diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c
index b0b64cac802..4be75344133 100644
--- a/source/blender/blenkernel/intern/sca.c
+++ b/source/blender/blenkernel/intern/sca.c
@@ -391,6 +391,8 @@ void init_actuator(bActuator *act)
bSoundActuator *sa;
bSteeringActuator *sta;
bArmatureActuator *arma;
+ bMouseActuator *ma;
+ bEditObjectActuator *eoa;
if (act->data) MEM_freeN(act->data);
act->data= NULL;
@@ -429,6 +431,9 @@ void init_actuator(bActuator *act)
break;
case ACT_EDIT_OBJECT:
act->data= MEM_callocN(sizeof(bEditObjectActuator), "editobact");
+ eoa = act->data;
+ eoa->upflag= ACT_TRACK_UP_Z;
+ eoa->trackflag= ACT_TRACK_TRAXIS_Y;
break;
case ACT_CONSTRAINT:
act->data= MEM_callocN(sizeof(bConstraintActuator), "cons act");
@@ -477,6 +482,15 @@ void init_actuator(bActuator *act)
sta->flag = ACT_STEERING_AUTOMATICFACING;
sta->facingaxis = 1;
break;
+ case ACT_MOUSE:
+ ma = act->data = MEM_callocN(sizeof( bMouseActuator ), "mouse act");
+ ma->flag = ACT_MOUSE_VISIBLE|ACT_MOUSE_USE_AXIS_X|ACT_MOUSE_USE_AXIS_Y|ACT_MOUSE_RESET_X|ACT_MOUSE_RESET_Y|ACT_MOUSE_LOCAL_Y;
+ ma->sensitivity[0] = ma->sensitivity[1] = 2.f;
+ ma->object_axis[0] = ACT_MOUSE_OBJECT_AXIS_Z;
+ ma->object_axis[1] = ACT_MOUSE_OBJECT_AXIS_X;
+ ma->limit_y[0] = DEG2RADF(-90.0f);
+ ma->limit_y[1] = DEG2RADF(90.0f);
+ break;
default:
; /* this is very severe... I cannot make any memory for this */
/* logic brick... */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 0e95cf1d418..5bfd6e8a120 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -39,6 +39,7 @@
#include "DNA_anim_types.h"
#include "DNA_group_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_rigidbody_types.h"
@@ -46,6 +47,8 @@
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_windowmanager_types.h"
#include "BLI_math.h"
#include "BLI_blenlib.h"
@@ -62,6 +65,7 @@
#include "BKE_action.h"
#include "BKE_colortools.h"
#include "BKE_depsgraph.h"
+#include "BKE_editmesh.h"
#include "BKE_fcurve.h"
#include "BKE_freestyle.h"
#include "BKE_global.h"
@@ -78,6 +82,7 @@
#include "BKE_scene.h"
#include "BKE_sequencer.h"
#include "BKE_sound.h"
+#include "BKE_unit.h"
#include "BKE_world.h"
#include "RE_engine.h"
@@ -86,8 +91,7 @@
#include "IMB_colormanagement.h"
-//XXX #include "BIF_previewrender.h"
-//XXX #include "BIF_editseq.h"
+#include "bmesh.h"
#ifdef WIN32
#else
@@ -253,6 +257,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint);
ts->imapaint.paintcursor = NULL;
+ id_us_plus((ID *)ts->imapaint.stencil);
ts->particle.paintcursor = NULL;
}
@@ -510,7 +515,12 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->r.border.ymin = 0.0f;
sce->r.border.xmax = 1.0f;
sce->r.border.ymax = 1.0f;
+
+ sce->r.preview_start_resolution = 64;
+ sce->r.line_thickness_mode = R_LINE_THICKNESS_ABSOLUTE;
+ sce->r.unit_line_thickness = 1.0f;
+
sce->toolsettings = MEM_callocN(sizeof(struct ToolSettings), "Tool Settings Struct");
sce->toolsettings->doublimit = 0.001;
sce->toolsettings->uvcalc_margin = 0.001f;
@@ -553,6 +563,8 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
sce->toolsettings->proportional_size = 1.0f;
sce->toolsettings->imapaint.paint.flags |= PAINT_SHOW_BRUSH;
+ sce->toolsettings->imapaint.normal_angle = 80;
+ sce->toolsettings->imapaint.seam_bleed = 2;
sce->physics_settings.gravity[0] = 0.0f;
sce->physics_settings.gravity[1] = 0.0f;
@@ -719,14 +731,14 @@ void BKE_scene_set_background(Main *bmain, Scene *scene)
/* called from creator.c */
Scene *BKE_scene_set_name(Main *bmain, const char *name)
{
- Scene *sce = (Scene *)BKE_libblock_find_name(ID_SCE, name);
+ Scene *sce = (Scene *)BKE_libblock_find_name_ex(bmain, ID_SCE, name);
if (sce) {
BKE_scene_set_background(bmain, sce);
- printf("Scene switch: '%s' in file: '%s'\n", name, G.main->name);
+ printf("Scene switch: '%s' in file: '%s'\n", name, bmain->name);
return sce;
}
- printf("Can't find scene: '%s' in file: '%s'\n", name, G.main->name);
+ printf("Can't find scene: '%s' in file: '%s'\n", name, bmain->name);
return NULL;
}
@@ -804,9 +816,7 @@ void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce)
BKE_libblock_free(bmain, sce);
}
-/* used by metaballs
- * doesn't return the original duplicated object, only dupli's
- */
+/* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */
int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
Scene **scene, int val, Base **base, Object **ob)
{
@@ -817,11 +827,12 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
iter->phase = F_START;
iter->dupob = NULL;
iter->duplilist = NULL;
+ iter->dupli_refob = NULL;
}
else {
/* run_again is set when a duplilist has been ended */
while (run_again) {
- run_again = 0;
+ run_again = false;
/* the first base */
if (iter->phase == F_START) {
@@ -879,34 +890,46 @@ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter,
iter->dupob = iter->duplilist->first;
- if (!iter->dupob)
+ if (!iter->dupob) {
free_object_duplilist(iter->duplilist);
+ iter->duplilist = NULL;
+ }
+ iter->dupli_refob = NULL;
}
}
}
/* handle dupli's */
if (iter->dupob) {
-
- copy_m4_m4(iter->omat, iter->dupob->ob->obmat);
- copy_m4_m4(iter->dupob->ob->obmat, iter->dupob->mat);
-
(*base)->flag |= OB_FROMDUPLI;
*ob = iter->dupob->ob;
iter->phase = F_DUPLI;
-
+
+ if (iter->dupli_refob != *ob) {
+ if (iter->dupli_refob) {
+ /* Restore previous object's real matrix. */
+ copy_m4_m4(iter->dupli_refob->obmat, iter->omat);
+ }
+ /* Backup new object's real matrix. */
+ iter->dupli_refob = *ob;
+ copy_m4_m4(iter->omat, iter->dupli_refob->obmat);
+ }
+ copy_m4_m4((*ob)->obmat, iter->dupob->mat);
+
iter->dupob = iter->dupob->next;
}
else if (iter->phase == F_DUPLI) {
iter->phase = F_SCENE;
(*base)->flag &= ~OB_FROMDUPLI;
- for (iter->dupob = iter->duplilist->first; iter->dupob; iter->dupob = iter->dupob->next) {
- copy_m4_m4(iter->dupob->ob->obmat, iter->omat);
+ if (iter->dupli_refob) {
+ /* Restore last object's real matrix. */
+ copy_m4_m4(iter->dupli_refob->obmat, iter->omat);
+ iter->dupli_refob = NULL;
}
free_object_duplilist(iter->duplilist);
iter->duplilist = NULL;
- run_again = 1;
+ run_again = true;
}
}
}
@@ -1118,11 +1141,6 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra)
double intpart;
scene->r.subframe = modf(cfra, &intpart);
scene->r.cfra = (int)intpart;
-
- if (cfra < 0.0) {
- scene->r.cfra -= 1;
- scene->r.subframe = 1.0f + scene->r.subframe;
- }
}
/* drivers support/hacks
@@ -1462,7 +1480,7 @@ static void scene_update_objects(EvaluationContext *eval_ctx, Main *bmain, Scene
bool need_singlethread_pass;
/* Early check for whether we need to invoke all the task-based
- * tihngs (spawn new ppol, traverse dependency graph and so on).
+ * things (spawn new ppol, traverse dependency graph and so on).
*
* Basically if there's no ID datablocks tagged for update which
* corresponds to object->recalc flags (which are checked in
@@ -1541,6 +1559,53 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma
}
+static bool check_rendered_viewport_visible(Main *bmain)
+{
+ wmWindowManager *wm = bmain->wm.first;
+ wmWindow *window;
+ for (window = wm->windows.first; window != NULL; window = window->next) {
+ bScreen *screen = window->screen;
+ ScrArea *area;
+ for (area = screen->areabase.first; area != NULL; area = area->next) {
+ View3D *v3d = area->spacedata.first;
+ if (area->spacetype != SPACE_VIEW3D) {
+ continue;
+ }
+ if (v3d->drawtype == OB_RENDER) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
+{
+ /* This is needed to prepare mesh to be used by the render
+ * engine from the viewport rendering. We do loading here
+ * so all the objects which shares the same mesh datablock
+ * are nicely tagged for update and updated.
+ *
+ * This makes it so viewport render engine doesn't need to
+ * call loading of the edit data for the mesh objects.
+ */
+
+ Object *obedit = scene->obedit;
+ if (obedit) {
+ Mesh *mesh = obedit->data;
+ /* TODO(sergey): Check object recalc flags as well? */
+ if ((obedit->type == OB_MESH) &&
+ (mesh->id.flag & (LIB_ID_RECALC | LIB_ID_RECALC_DATA)))
+ {
+ if (check_rendered_viewport_visible(bmain)) {
+ BMesh *bm = mesh->edit_btmesh->bm;
+ BM_mesh_bm_to_me(bm, mesh, false);
+ DAG_id_tag_update(&mesh->id, 0);
+ }
+ }
+ }
+}
+
void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
{
Scene *sce_iter;
@@ -1552,6 +1617,9 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
DAG_scene_relations_update(bmain, sce_iter);
+ /* flush editing data if needed */
+ prepare_mesh_for_viewport_render(bmain, scene);
+
/* flush recalc flags to dependencies */
DAG_ids_flush_tagged(bmain);
@@ -1599,7 +1667,20 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
BKE_animsys_evaluate_animdata(scene, &material->id, adt, ctime, 0);
}
}
-
+
+ /* Also do the same for node trees. */
+ if (DAG_id_type_tagged(bmain, ID_NT)) {
+ float ctime = BKE_scene_frame_get(scene);
+
+ FOREACH_NODETREE(bmain, ntree, id)
+ {
+ AnimData *adt = BKE_animdata_from_id(&ntree->id);
+ if (adt && (adt->recalc & ADT_RECALC_ANIM))
+ BKE_animsys_evaluate_animdata(scene, &ntree->id, adt, ctime, 0);
+ }
+ FOREACH_NODETREE_END
+ }
+
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST);
DAG_ids_check_recalc(bmain, scene, false);
@@ -1819,6 +1900,12 @@ bool BKE_scene_use_new_shading_nodes(Scene *scene)
return (type && type->flag & RE_USE_SHADING_NODES);
}
+bool BKE_scene_uses_blender_internal(struct Scene *scene)
+{
+ return strcmp("BLENDER_RENDER", scene->r.engine) == 0;
+}
+
+
void BKE_scene_base_flag_to_objects(struct Scene *scene)
{
Base *base = scene->base.first;
@@ -1890,3 +1977,28 @@ int BKE_scene_num_threads(const Scene *scene)
{
return BKE_render_num_threads(&scene->r);
}
+
+/* Apply the needed correction factor to value, based on unit_type (only length-related are affected currently)
+ * and unit->scale_length.
+ */
+double BKE_scene_unit_scale(const UnitSettings *unit, const int unit_type, double value)
+{
+ if (unit->system == USER_UNIT_NONE) {
+ /* Never apply scale_length when not using a unit setting! */
+ return value;
+ }
+
+ switch (unit_type) {
+ case B_UNIT_LENGTH:
+ return value * (double)unit->scale_length;
+ case B_UNIT_AREA:
+ return value * pow(unit->scale_length, 2);
+ case B_UNIT_VOLUME:
+ return value * pow(unit->scale_length, 3);
+ case B_UNIT_MASS:
+ return value * pow(unit->scale_length, 3);
+ case B_UNIT_CAMERA: /* *Do not* use scene's unit scale for camera focal lens! See T42026. */
+ default:
+ return value;
+ }
+}
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index 9d40ee6e667..b2296151cf7 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -425,6 +425,32 @@ ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short
return big;
}
+/**
+ * Utility function to get the active layer to use when adding new objects.
+ */
+unsigned int BKE_screen_view3d_layer_active_ex(const View3D *v3d, const Scene *scene, bool use_localvd)
+{
+ unsigned int lay;
+ if ((v3d == NULL) || (v3d->scenelock && !v3d->localvd)) {
+ lay = scene->layact;
+ }
+ else {
+ lay = v3d->layact;
+ }
+
+ if (use_localvd) {
+ if (v3d && v3d->localvd) {
+ lay |= v3d->lay;
+ }
+ }
+
+ return lay;
+}
+unsigned int BKE_screen_view3d_layer_active(const struct View3D *v3d, const struct Scene *scene)
+{
+ return BKE_screen_view3d_layer_active_ex(v3d, scene, true);
+}
+
void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene)
{
int bit;
diff --git a/source/blender/blenkernel/intern/seqcache.c b/source/blender/blenkernel/intern/seqcache.c
index 97062f728c5..4268b33cb14 100644
--- a/source/blender/blenkernel/intern/seqcache.c
+++ b/source/blender/blenkernel/intern/seqcache.c
@@ -69,58 +69,15 @@ static struct SeqPreprocessCache *preprocess_cache = NULL;
static void preprocessed_cache_destruct(void);
-static int seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
+static bool seq_cmp_render_data(const SeqRenderData *a, const SeqRenderData *b)
{
- if (a->preview_render_size < b->preview_render_size) {
- return -1;
- }
- if (a->preview_render_size > b->preview_render_size) {
- return 1;
- }
-
- if (a->rectx < b->rectx) {
- return -1;
- }
- if (a->rectx > b->rectx) {
- return 1;
- }
-
- if (a->recty < b->recty) {
- return -1;
- }
- if (a->recty > b->recty) {
- return 1;
- }
-
- if (a->bmain < b->bmain) {
- return -1;
- }
- if (a->bmain > b->bmain) {
- return 1;
- }
-
- if (a->scene < b->scene) {
- return -1;
- }
- if (a->scene > b->scene) {
- return 1;
- }
-
- if (a->motion_blur_shutter < b->motion_blur_shutter) {
- return -1;
- }
- if (a->motion_blur_shutter > b->motion_blur_shutter) {
- return 1;
- }
-
- if (a->motion_blur_samples < b->motion_blur_samples) {
- return -1;
- }
- if (a->motion_blur_samples > b->motion_blur_samples) {
- return 1;
- }
-
- return 0;
+ return ((a->preview_render_size != b->preview_render_size) ||
+ (a->rectx != b->rectx) ||
+ (a->recty != b->recty) ||
+ (a->bmain != b->bmain) ||
+ (a->scene != b->scene) ||
+ (a->motion_blur_shutter != b->motion_blur_shutter) ||
+ (a->motion_blur_samples != b->motion_blur_samples));
}
static unsigned int seq_hash_render_data(const SeqRenderData *a)
@@ -148,33 +105,15 @@ static unsigned int seqcache_hashhash(const void *key_)
return rval;
}
-static int seqcache_hashcmp(const void *a_, const void *b_)
+static bool seqcache_hashcmp(const void *a_, const void *b_)
{
const SeqCacheKey *a = (SeqCacheKey *) a_;
const SeqCacheKey *b = (SeqCacheKey *) b_;
- if (a->seq < b->seq) {
- return -1;
- }
- if (a->seq > b->seq) {
- return 1;
- }
-
- if (a->cfra < b->cfra) {
- return -1;
- }
- if (a->cfra > b->cfra) {
- return 1;
- }
-
- if (a->type < b->type) {
- return -1;
- }
- if (a->type > b->type) {
- return 1;
- }
-
- return seq_cmp_render_data(&a->context, &b->context);
+ return ((a->seq != b->seq) ||
+ (a->cfra != b->cfra) ||
+ (a->type != b->type) ||
+ seq_cmp_render_data(&a->context, &b->context));
}
void BKE_sequencer_cache_destruct(void)
diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c
index 7ed9af8b87f..11a6cb7acc3 100644
--- a/source/blender/blenkernel/intern/seqeffects.c
+++ b/source/blender/blenkernel/intern/seqeffects.c
@@ -52,6 +52,11 @@
#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,
const ImBuf *ibuf3, const ImBuf *out, int start_line, unsigned char **rect1,
unsigned char **rect2, unsigned char **rect3, unsigned char **rect_out)
@@ -305,41 +310,45 @@ static void do_alphaover_effect(const SeqRenderData *context, Sequence *UNUSED(s
static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out)
{
- int fac2, mfac, fac, fac4;
+ float fac2, fac, fac4;
int xo;
- unsigned char *rt1, *rt2, *rt;
+ unsigned char *cp1, *cp2, *rt;
+ float tempc[4], rt1[4], rt2[4];
xo = x;
- rt1 = rect1;
- rt2 = rect2;
+ cp1 = rect1;
+ cp2 = rect2;
rt = out;
- fac2 = (int)(256.0f * facf0);
- fac4 = (int)(256.0f * facf1);
+ fac2 = facf0;
+ fac4 = facf1;
while (y--) {
x = xo;
while (x--) {
/* rt = rt1 under rt2 (alpha from rt2) */
+ straight_uchar_to_premul_float(rt1, cp1);
+ straight_uchar_to_premul_float(rt2, cp2);
/* this complex optimization is because the
* 'skybuf' can be crossed in
*/
- if (rt2[3] == 0 && fac2 == 256) *((unsigned int *) rt) = *((unsigned int *) rt1);
- else if (rt2[3] == 255) *((unsigned int *) rt) = *((unsigned int *) rt2);
+ if (rt2[3] <= 0.0f && fac2 >= 1.0f) *((unsigned int *) rt) = *((unsigned int *) cp1);
+ else if (rt2[3] >= 1.0f) *((unsigned int *) rt) = *((unsigned int *) cp2);
else {
- mfac = rt2[3];
- fac = (fac2 * (256 - mfac)) >> 8;
+ fac = (fac2 * (1.0f - rt2[3]));
- if (fac == 0) *((unsigned int *) rt) = *((unsigned int *) rt2);
+ if (fac <= 0) *((unsigned int *) rt) = *((unsigned int *) cp2);
else {
- rt[0] = (fac * rt1[0] + mfac * rt2[0]) >> 8;
- rt[1] = (fac * rt1[1] + mfac * rt2[1]) >> 8;
- rt[2] = (fac * rt1[2] + mfac * rt2[2]) >> 8;
- rt[3] = (fac * rt1[3] + mfac * rt2[3]) >> 8;
+ tempc[0] = (fac * rt1[0] + rt2[0]);
+ tempc[1] = (fac * rt1[1] + rt2[1]);
+ tempc[2] = (fac * rt1[2] + rt2[2]);
+ tempc[3] = (fac * rt1[3] + rt2[3]);
+
+ premul_float_to_straight_uchar(rt, tempc);
}
}
- rt1 += 4; rt2 += 4; rt += 4;
+ cp1 += 4; cp2 += 4; rt += 4;
}
if (y == 0)
@@ -348,28 +357,32 @@ static void do_alphaunder_effect_byte(float facf0, float facf1, int x, int y, un
x = xo;
while (x--) {
- if (rt2[3] == 0 && fac4 == 256) *((unsigned int *) rt) = *((unsigned int *) rt1);
- else if (rt2[3] == 255) *((unsigned int *) rt) = *((unsigned int *) rt2);
- else {
- mfac = rt2[3];
- fac = (fac4 * (256 - mfac)) >> 8;
+ straight_uchar_to_premul_float(rt1, cp1);
+ straight_uchar_to_premul_float(rt2, cp2);
+
+ if (rt2[3] <= 0.0f && fac4 >= 1.0f) *((unsigned int *) rt) = *((unsigned int *) cp1);
+ else if (rt2[3] >= 1.0f) *((unsigned int *) rt) = *((unsigned int *) cp2);
+ else {
+ fac = (fac4 * (1.0f - rt2[3]));
- if (fac == 0) *((unsigned int *)rt) = *((unsigned int *)rt2);
+ if (fac <= 0) *((unsigned int *)rt) = *((unsigned int *)cp2);
else {
- rt[0] = (fac * rt1[0] + mfac * rt2[0]) >> 8;
- rt[1] = (fac * rt1[1] + mfac * rt2[1]) >> 8;
- rt[2] = (fac * rt1[2] + mfac * rt2[2]) >> 8;
- rt[3] = (fac * rt1[3] + mfac * rt2[3]) >> 8;
+ tempc[0] = (fac * rt1[0] + rt2[0]);
+ tempc[1] = (fac * rt1[1] + rt2[1]);
+ tempc[2] = (fac * rt1[2] + rt2[2]);
+ tempc[3] = (fac * rt1[3] + rt2[3]);
+
+ premul_float_to_straight_uchar(rt, tempc);
}
}
- rt1 += 4; rt2 += 4; rt += 4;
+ cp1 += 4; cp2 += 4; rt += 4;
}
}
}
static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out)
{
- float fac2, mfac, fac, fac4;
+ float fac2, fac, fac4;
int xo;
float *rt1, *rt2, *rt;
@@ -396,17 +409,16 @@ static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y,
memcpy(rt, rt2, 4 * sizeof(float));
}
else {
- mfac = rt2[3];
- fac = fac2 * (1.0f - mfac);
+ fac = fac2 * (1.0f - rt2[3]);
if (fac == 0) {
memcpy(rt, rt2, 4 * sizeof(float));
}
else {
- rt[0] = fac * rt1[0] + mfac * rt2[0];
- rt[1] = fac * rt1[1] + mfac * rt2[1];
- rt[2] = fac * rt1[2] + mfac * rt2[2];
- rt[3] = fac * rt1[3] + mfac * rt2[3];
+ rt[0] = fac * rt1[0] + rt2[0];
+ rt[1] = fac * rt1[1] + rt2[1];
+ rt[2] = fac * rt1[2] + rt2[2];
+ rt[3] = fac * rt1[3] + rt2[3];
}
}
rt1 += 4; rt2 += 4; rt += 4;
@@ -425,17 +437,16 @@ static void do_alphaunder_effect_float(float facf0, float facf1, int x, int y,
memcpy(rt, rt2, 4 * sizeof(float));
}
else {
- mfac = rt2[3];
- fac = fac4 * (1.0f - mfac);
+ fac = fac4 * (1.0f - rt2[3]);
if (fac == 0) {
memcpy(rt, rt2, 4 * sizeof(float));
}
else {
- rt[0] = fac * rt1[0] + mfac * rt2[0];
- rt[1] = fac * rt1[1] + mfac * rt2[1];
- rt[2] = fac * rt1[2] + mfac * rt2[2];
- rt[3] = fac * rt1[3] + mfac * rt2[3];
+ rt[0] = fac * rt1[0] + rt2[0];
+ rt[1] = fac * rt1[1] + rt2[1];
+ rt[2] = fac * rt1[2] + rt2[2];
+ rt[3] = fac * rt1[3] + rt2[3];
}
}
rt1 += 4; rt2 += 4; rt += 4;
@@ -1311,7 +1322,7 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
if (angle == 0.0f) {
b1 = posy;
b2 = y;
- hyp = fabs(y - posy);
+ hyp = fabsf(y - posy);
}
else {
b1 = posy - (-angle) * posx;
@@ -1398,7 +1409,7 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
x = x - halfx;
y = y - halfy;
- temp2 = asin(abs(y) / sqrt(x * x + y * y));
+ temp2 = asin(abs(y) / hypot(x, y));
if (x <= 0 && y >= 0) temp2 = (float)M_PI - temp2;
else if (x <= 0 && y <= 0) temp2 += (float)M_PI;
else if (x >= 0 && y <= 0) temp2 = 2.0f * (float)M_PI - temp2;
@@ -1441,7 +1452,7 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
temp1 = xo * (1 - facf0 / 2) - xo * facf0 / 2;
temp2 = yo * (1 - facf0 / 2) - yo * facf0 / 2;
- pointdist = sqrtf(temp1 * temp1 + temp2 * temp2);
+ pointdist = hypot(temp1, temp2);
if (b2 < b1 && b2 < b3) {
if (hwidth < pointdist)
@@ -1498,9 +1509,9 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f
hwidth = width * 0.5f;
temp1 = (halfx - (halfx) * facf0);
- pointdist = sqrtf(temp1 * temp1 + temp1 * temp1);
+ pointdist = hypotf(temp1, temp1);
- temp2 = sqrtf((halfx - x) * (halfx - x) + (halfy - y) * (halfy - y));
+ temp2 = hypotf(halfx - x, halfy - y);
if (temp2 > pointdist) output = in_band(hwidth, fabsf(temp2 - pointdist), 0, 1);
else output = in_band(hwidth, fabsf(temp2 - pointdist), 1, 1);
@@ -1734,8 +1745,8 @@ static void transform_image(int x, int y, ImBuf *ibuf1, ImBuf *out, float scale
yo = y;
/* Rotate */
- s = sin(rotate);
- c = cos(rotate);
+ s = sinf(rotate);
+ c = cosf(rotate);
for (yi = 0; yi < yo; yi++) {
for (xi = 0; xi < xo; xi++) {
@@ -2579,6 +2590,295 @@ static void do_overdrop_effect(const SeqRenderData *context, Sequence *UNUSED(se
}
}
+/*********************** Gaussian Blur *************************/
+
+/* NOTE: This gaussian blur implementation accumulates values in the square
+ * kernel rather that doing X direction and then Y direction because of the
+ * lack of using multiple-staged filters.
+ *
+ * Once we can we'll implement a way to apply filter as multiple stages we
+ * can optimize hell of a lot in here.
+ */
+
+static void init_gaussian_blur_effect(Sequence *seq)
+{
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
+
+ seq->effectdata = MEM_callocN(sizeof(WipeVars), "wipevars");
+}
+
+static int num_inputs_gaussian_blur(void)
+{
+ return 1;
+}
+
+static void free_gaussian_blur_effect(Sequence *seq)
+{
+ if (seq->effectdata)
+ MEM_freeN(seq->effectdata);
+
+ seq->effectdata = NULL;
+}
+
+static void copy_gaussian_blur_effect(Sequence *dst, Sequence *src)
+{
+ dst->effectdata = MEM_dupallocN(src->effectdata);
+}
+
+static int early_out_gaussian_blur(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1))
+{
+ GaussianBlurVars *data = seq->effectdata;
+ if (data->size_x == 0.0f && data->size_y == 0) {
+ return EARLY_USE_INPUT_1;
+ }
+ return EARLY_DO_EFFECT;
+}
+
+/* TODO(sergey): De-duplicate with compositor. */
+static float *make_gaussian_blur_kernel(float rad, int size)
+{
+ float *gausstab, sum, val;
+ float fac;
+ int i, n;
+
+ n = 2 * size + 1;
+
+ gausstab = (float *)MEM_mallocN(sizeof(float) * n, __func__);
+
+ sum = 0.0f;
+ fac = (rad > 0.0f ? 1.0f / rad : 0.0f);
+ for (i = -size; i <= size; i++) {
+ val = RE_filter_value(R_FILTER_GAUSS, (float)i * fac);
+ sum += val;
+ gausstab[i + size] = val;
+ }
+
+ sum = 1.0f / sum;
+ for (i = 0; i < n; i++)
+ gausstab[i] *= sum;
+
+ return gausstab;
+}
+
+static void do_gaussian_blur_effect_byte(Sequence *seq,
+ int start_line,
+ int x, int y,
+ int frame_width, int frame_height,
+ unsigned char *rect,
+ unsigned char *out)
+{
+#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
+ GaussianBlurVars *data = seq->effectdata;
+ const int size_x = (int) (data->size_x + 0.5f),
+ size_y = (int) (data->size_y + 0.5f);
+ int i, j;
+
+ /* Make gaussian weight tabke. */
+ float *gausstab_x, *gausstab_y;
+ gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
+ if (data->size_x == data->size_y) {
+ gausstab_y = gausstab_x;
+ }
+ else {
+ gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
+ }
+
+ for (i = 0; i < y; ++i) {
+ for (j = 0; j < x; ++j) {
+ int out_index = INDEX(j, i);
+ int current_x, current_y;
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.0f;
+ for (current_y = i - size_y;
+ current_y <= i + size_y;
+ ++current_y)
+ {
+ if (current_y < -start_line ||
+ current_y + start_line >= frame_height)
+ {
+ /* Out of bounds. */
+ continue;
+ }
+
+ for (current_x = j - size_x;
+ current_x <= j + size_x;
+ ++current_x)
+ {
+ float weight;
+ int index = INDEX(current_x, current_y + start_line);
+ if (current_x < 0 || current_x >= frame_width) {
+ /* Out of bounds. */
+ continue;
+ }
+ BLI_assert(index >= 0);
+ BLI_assert(index < frame_width * frame_height * 4);
+
+ if (size_x != 0 && size_y != 0) {
+ weight = gausstab_x[current_x - j + size_x] *
+ gausstab_y[current_y - i + size_y];
+ }
+ else if (size_x == 0) {
+ weight = gausstab_y[current_y - i + size_y];
+ }
+ else {
+ weight = gausstab_x[current_x - j + size_x];
+ }
+ accum[0] += rect[index] * weight;
+ accum[1] += rect[index + 1] * weight;
+ accum[2] += rect[index + 2] * weight;
+ accum[3] += rect[index + 3] * weight;
+ accum_weight += weight;
+ }
+ }
+ out[out_index + 0] = accum[0] / accum_weight;
+ out[out_index + 1] = accum[1] / accum_weight;
+ out[out_index + 2] = accum[2] / accum_weight;
+ out[out_index + 3] = accum[3] / accum_weight;
+ }
+ }
+
+ MEM_freeN(gausstab_x);
+ if (gausstab_x != gausstab_y) {
+ MEM_freeN(gausstab_y);
+ }
+#undef INDEX
+}
+
+static void do_gaussian_blur_effect_float(Sequence *seq,
+ int start_line,
+ int x, int y,
+ int frame_width, int frame_height,
+ float *rect,
+ float *out)
+{
+#define INDEX(_x, _y) (((_y) * (x) + (_x)) * 4)
+ GaussianBlurVars *data = seq->effectdata;
+ const int size_x = (int) (data->size_x + 0.5f),
+ size_y = (int) (data->size_y + 0.5f);
+ int i, j;
+
+ /* Make gaussian weight tabke. */
+ float *gausstab_x, *gausstab_y;
+ gausstab_x = make_gaussian_blur_kernel(data->size_x, size_x);
+ if (data->size_x == data->size_y) {
+ gausstab_y = gausstab_x;
+ }
+ else {
+ gausstab_y = make_gaussian_blur_kernel(data->size_y, size_y);
+ }
+
+ for (i = 0; i < y; ++i) {
+ for (j = 0; j < x; ++j) {
+ int out_index = INDEX(j, i);
+ int current_x, current_y;
+ float accum[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float accum_weight = 0.0f;
+ for (current_y = i - size_y;
+ current_y <= i + size_y;
+ ++current_y)
+ {
+ float weight;
+ if (current_y < -start_line ||
+ current_y + start_line >= frame_height)
+ {
+ /* Out of bounds. */
+ continue;
+ }
+
+ for (current_x = j - size_x;
+ current_x <= j + size_x;
+ ++current_x)
+ {
+ int index = INDEX(current_x, current_y + start_line);
+ if (current_x < 0 || current_x >= frame_width) {
+ /* Out of bounds. */
+ continue;
+ }
+
+ if (size_x != 0 && size_y != 0) {
+ weight = gausstab_x[current_x - j + size_x] *
+ gausstab_y[current_y - i + size_y];
+ }
+ else if (size_x == 0) {
+ weight = gausstab_y[current_y - i + size_y];
+ }
+ else {
+ weight = gausstab_x[current_x - j + size_x];
+ }
+ madd_v4_v4fl(accum, &rect[index], weight);
+ accum_weight += weight;
+ }
+ }
+ mul_v4_v4fl(&out[out_index], accum, 1.0f / accum_weight);
+ }
+ }
+
+ MEM_freeN(gausstab_x);
+ if (gausstab_x != gausstab_y) {
+ MEM_freeN(gausstab_y);
+ }
+#undef INDEX
+}
+
+static void do_gaussian_blur_effect(const SeqRenderData *context,
+ Sequence *seq,
+ float UNUSED(cfra),
+ float UNUSED(facf0),
+ float UNUSED(facf1),
+ ImBuf *ibuf1,
+ ImBuf *ibuf2,
+ ImBuf *UNUSED(ibuf3),
+ int start_line,
+ int total_lines,
+ ImBuf *out)
+{
+ if (out->rect_float) {
+ float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_float_buffers(context,
+ ibuf1, ibuf2,
+ NULL,
+ out,
+ start_line,
+ &rect1,
+ &rect2,
+ NULL,
+ &rect_out);
+
+ do_gaussian_blur_effect_float(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ ibuf1->rect_float,
+ rect_out);
+ }
+ else {
+ unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL;
+
+ slice_get_byte_buffers(context,
+ ibuf1, ibuf2,
+ NULL,
+ out,
+ start_line,
+ &rect1,
+ &rect2,
+ NULL,
+ &rect_out);
+
+ do_gaussian_blur_effect_byte(seq,
+ start_line,
+ context->rectx,
+ total_lines,
+ context->rectx,
+ context->recty,
+ (unsigned char *) ibuf1->rect,
+ rect_out);
+ }
+}
+
/*********************** sequence effect factory *************************/
static void init_noop(Sequence *UNUSED(seq))
@@ -2767,6 +3067,15 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type)
rval.early_out = early_out_adjustment;
rval.execute = do_adjustment;
break;
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ rval.multithreaded = true;
+ rval.init = init_gaussian_blur_effect;
+ rval.num_inputs = num_inputs_gaussian_blur;
+ rval.free = free_gaussian_blur_effect;
+ rval.copy = copy_gaussian_blur_effect;
+ rval.early_out = early_out_gaussian_blur;
+ rval.execute_slice = do_gaussian_blur_effect;
+ break;
}
return rval;
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index cf15b235b45..0a22faf3c26 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -257,26 +257,15 @@ Editing *BKE_sequencer_editing_get(Scene *scene, bool alloc)
return scene->ed;
}
-static void seq_free_clipboard_recursive(Sequence *seq_parent)
-{
- Sequence *seq, *nseq;
-
- for (seq = seq_parent->seqbase.first; seq; seq = nseq) {
- nseq = seq->next;
- seq_free_clipboard_recursive(seq);
- }
-
- BKE_sequence_clipboard_pointers_free(seq_parent);
- BKE_sequence_free_ex(NULL, seq_parent, false);
-}
-
void BKE_sequencer_free_clipboard(void)
{
Sequence *seq, *nseq;
+ BKE_sequencer_base_clipboard_pointers_free(&seqbase_clipboard);
+
for (seq = seqbase_clipboard.first; seq; seq = nseq) {
nseq = seq->next;
- seq_free_clipboard_recursive(seq);
+ seq_free_sequence_recurse(NULL, seq);
}
BLI_listbase_clear(&seqbase_clipboard);
}
@@ -373,6 +362,33 @@ void BKE_sequence_clipboard_pointers_restore(Sequence *seq, Main *bmain)
seqclipboard_ptr_restore(bmain, (ID **)&seq->mask);
seqclipboard_ptr_restore(bmain, (ID **)&seq->sound);
}
+
+/* recursive versions of funcions above */
+void BKE_sequencer_base_clipboard_pointers_free(ListBase *seqbase)
+{
+ Sequence *seq;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ BKE_sequence_clipboard_pointers_free(seq);
+ BKE_sequencer_base_clipboard_pointers_free(&seq->seqbase);
+ }
+}
+void BKE_sequencer_base_clipboard_pointers_store(ListBase *seqbase)
+{
+ Sequence *seq;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ BKE_sequence_clipboard_pointers_store(seq);
+ BKE_sequencer_base_clipboard_pointers_store(&seq->seqbase);
+ }
+}
+void BKE_sequencer_base_clipboard_pointers_restore(ListBase *seqbase, Main *bmain)
+{
+ Sequence *seq;
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ BKE_sequence_clipboard_pointers_restore(seq, bmain);
+ BKE_sequencer_base_clipboard_pointers_restore(&seq->seqbase, bmain);
+ }
+}
+
/* end clipboard pointer mess */
@@ -758,7 +774,7 @@ void BKE_sequence_reload_new_file(Scene *scene, Sequence *seq, const bool lock_r
int prev_startdisp = 0, prev_enddisp = 0;
/* note: don't rename the strip, will break animation curves */
- if (ELEM7(seq->type,
+ if (ELEM(seq->type,
SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM,
SEQ_TYPE_SCENE, SEQ_TYPE_META, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) == 0)
{
@@ -994,28 +1010,29 @@ void BKE_sequence_base_unique_name_recursive(ListBase *seqbasep, Sequence *seq)
static const char *give_seqname_by_type(int type)
{
switch (type) {
- case SEQ_TYPE_META: return "Meta";
- case SEQ_TYPE_IMAGE: return "Image";
- case SEQ_TYPE_SCENE: return "Scene";
- case SEQ_TYPE_MOVIE: return "Movie";
- case SEQ_TYPE_MOVIECLIP: return "Clip";
- case SEQ_TYPE_MASK: return "Mask";
- case SEQ_TYPE_SOUND_RAM: return "Audio";
- case SEQ_TYPE_CROSS: return "Cross";
- case SEQ_TYPE_GAMCROSS: return "Gamma Cross";
- case SEQ_TYPE_ADD: return "Add";
- case SEQ_TYPE_SUB: return "Sub";
- case SEQ_TYPE_MUL: return "Mul";
- case SEQ_TYPE_ALPHAOVER: return "Alpha Over";
- case SEQ_TYPE_ALPHAUNDER: return "Alpha Under";
- case SEQ_TYPE_OVERDROP: return "Over Drop";
- case SEQ_TYPE_WIPE: return "Wipe";
- case SEQ_TYPE_GLOW: return "Glow";
- case SEQ_TYPE_TRANSFORM: return "Transform";
- case SEQ_TYPE_COLOR: return "Color";
- case SEQ_TYPE_MULTICAM: return "Multicam";
- case SEQ_TYPE_ADJUSTMENT: return "Adjustment";
- case SEQ_TYPE_SPEED: return "Speed";
+ case SEQ_TYPE_META: return "Meta";
+ case SEQ_TYPE_IMAGE: return "Image";
+ case SEQ_TYPE_SCENE: return "Scene";
+ case SEQ_TYPE_MOVIE: return "Movie";
+ case SEQ_TYPE_MOVIECLIP: return "Clip";
+ case SEQ_TYPE_MASK: return "Mask";
+ case SEQ_TYPE_SOUND_RAM: return "Audio";
+ case SEQ_TYPE_CROSS: return "Cross";
+ case SEQ_TYPE_GAMCROSS: return "Gamma Cross";
+ case SEQ_TYPE_ADD: return "Add";
+ case SEQ_TYPE_SUB: return "Sub";
+ case SEQ_TYPE_MUL: return "Mul";
+ case SEQ_TYPE_ALPHAOVER: return "Alpha Over";
+ case SEQ_TYPE_ALPHAUNDER: return "Alpha Under";
+ case SEQ_TYPE_OVERDROP: return "Over Drop";
+ case SEQ_TYPE_WIPE: return "Wipe";
+ case SEQ_TYPE_GLOW: return "Glow";
+ case SEQ_TYPE_TRANSFORM: return "Transform";
+ case SEQ_TYPE_COLOR: return "Color";
+ case SEQ_TYPE_MULTICAM: return "Multicam";
+ case SEQ_TYPE_ADJUSTMENT: return "Adjustment";
+ case SEQ_TYPE_SPEED: return "Speed";
+ case SEQ_TYPE_GAUSSIAN_BLUR: return "Gaussian Blur";
default:
return NULL;
}
@@ -2224,7 +2241,7 @@ static ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, con
init_data.out = out;
IMB_processor_apply_threaded(out->y, sizeof(RenderEffectThread), &init_data,
- render_effect_execute_init_handle, render_effect_execute_do_thread);
+ render_effect_execute_init_handle, render_effect_execute_do_thread);
return out;
}
@@ -2539,7 +2556,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
}
/* prevent eternal loop */
- do_seq = context->scene->r.scemode & R_DOSEQ;
+ do_seq = scene->r.scemode & R_DOSEQ;
scene->r.scemode &= ~R_DOSEQ;
#ifdef DURIAN_CAMERA_SWITCH
@@ -2808,13 +2825,12 @@ static ImBuf *seq_render_strip(const SeqRenderData *context, Sequence *seq, floa
float nr = give_stripelem_index(seq, cfra);
/* all effects are handled similarly with the exception of speed effect */
int type = (seq->type & SEQ_TYPE_EFFECT && seq->type != SEQ_TYPE_SPEED) ? SEQ_TYPE_EFFECT : seq->type;
- bool is_preprocessed = !ELEM3(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE);
+ bool is_preprocessed = !ELEM(type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SCENE);
ibuf = BKE_sequencer_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
if (ibuf == NULL) {
- if (ibuf == NULL)
- ibuf = copy_from_ibuf_still(context, seq, nr);
+ ibuf = copy_from_ibuf_still(context, seq, nr);
if (ibuf == NULL) {
ibuf = BKE_sequencer_preprocessed_cache_get(context, seq, cfra, SEQ_STRIPELEM_IBUF);
@@ -2876,7 +2892,7 @@ static bool seq_must_swap_input_in_blend_mode(Sequence *seq)
/* bad hack, to fix crazy input ordering of
* those two effects */
- if (ELEM3(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) {
+ if (ELEM(seq->blend_mode, SEQ_TYPE_ALPHAOVER, SEQ_TYPE_ALPHAUNDER, SEQ_TYPE_OVERDROP)) {
swap_input = true;
}
@@ -2961,7 +2977,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
/* Some of the blend modes are unclear how to apply with only single input,
* or some of them will just produce an empty result..
*/
- if (ELEM3(seq->blend_mode, SEQ_BLEND_REPLACE, SEQ_TYPE_CROSS, SEQ_TYPE_ALPHAOVER)) {
+ if (ELEM(seq->blend_mode, SEQ_BLEND_REPLACE, SEQ_TYPE_CROSS, SEQ_TYPE_ALPHAOVER)) {
int early_out;
if (seq->blend_mode == SEQ_BLEND_REPLACE) {
early_out = EARLY_NO_INPUT;
@@ -3028,7 +3044,13 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
break;
case EARLY_DO_EFFECT:
if (i == 0) {
- out = seq_render_strip(context, seq, cfra);
+ ImBuf *ibuf1 = IMB_allocImBuf(context->rectx, context->recty, 32, IB_rect);
+ ImBuf *ibuf2 = seq_render_strip(context, seq, cfra);
+
+ out = seq_render_strip_stack_apply_effect(context, seq, cfra, ibuf1, ibuf2);
+
+ IMB_freeImBuf(ibuf1);
+ IMB_freeImBuf(ibuf2);
}
break;
@@ -3069,13 +3091,12 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, ListBase *seq
ImBuf *BKE_sequencer_give_ibuf(const SeqRenderData *context, float cfra, int chanshown)
{
Editing *ed = BKE_sequencer_editing_get(context->scene, false);
- int count;
ListBase *seqbasep;
if (ed == NULL) return NULL;
- count = BLI_countlist(&ed->metastack);
- if ((chanshown < 0) && (count > 0)) {
+ if ((chanshown < 0) && !BLI_listbase_is_empty(&ed->metastack)) {
+ int count = BLI_countlist(&ed->metastack);
count = max_ii(count + chanshown, 0);
seqbasep = ((MetaStack *)BLI_findlink(&ed->metastack, count))->oldbasep;
}
@@ -3508,16 +3529,28 @@ bool BKE_sequence_single_check(Sequence *seq)
}
/* check if the selected seq's reference unselected seq's */
-bool BKE_sequence_base_isolated_sel_check(ListBase *seqbase)
+bool BKE_sequence_base_isolated_sel_check(ListBase *seqbase, bool one_only)
{
Sequence *seq;
- /* is there more than 1 select */
+ /* is there a valid selection select */
bool ok = false;
+ /* is there one selected already? */
+ bool first = false;
for (seq = seqbase->first; seq; seq = seq->next) {
if (seq->flag & SELECT) {
- ok = true;
- break;
+ if (one_only) {
+ ok = true;
+ break;
+ }
+ else {
+ if (first) {
+ ok = true;
+ break;
+ }
+ else
+ first = true;
+ }
}
}
@@ -3684,7 +3717,7 @@ Sequence *BKE_sequencer_foreground_frame_get(Scene *scene, int frame)
if (seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame)
continue;
/* only use elements you can see - not */
- if (ELEM5(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR)) {
+ if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIE, SEQ_TYPE_COLOR)) {
if (seq->machine > best_machine) {
best_seq = seq;
best_machine = seq->machine;
@@ -4037,19 +4070,31 @@ int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str)
return 1;
}
+/* prefix + [" + escaped_name + "] + \0 */
+#define SEQ_RNAPATH_MAXSTR ((30 + 2 + (SEQ_NAME_MAXSTR * 2) + 2) + 1)
+
+static size_t sequencer_rna_path_prefix(char str[SEQ_RNAPATH_MAXSTR], const char *name)
+{
+ 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);
+}
+
/* XXX - hackish function needed for transforming strips! TODO - have some better solution */
void BKE_sequencer_offset_animdata(Scene *scene, Sequence *seq, int ofs)
{
- char str[SEQ_NAME_MAXSTR + 3];
+ char str[SEQ_RNAPATH_MAXSTR];
+ size_t str_len;
FCurve *fcu;
if (scene->adt == NULL || ofs == 0 || scene->adt->action == NULL)
return;
- BLI_snprintf(str, sizeof(str), "[\"%s\"]", seq->name + 2);
+ str_len = sequencer_rna_path_prefix(str, seq->name + 2);
for (fcu = scene->adt->action->curves.first; fcu; fcu = fcu->next) {
- if (strstr(fcu->rna_path, "sequence_editor.sequences_all[") && strstr(fcu->rna_path, str)) {
+ if (STREQLEN(fcu->rna_path, str, str_len)) {
unsigned int i;
if (fcu->bezt) {
for (i = 0; i < fcu->totvert; i++) {
@@ -4071,7 +4116,8 @@ void BKE_sequencer_offset_animdata(Scene *scene, Sequence *seq, int ofs)
void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char *name_dst)
{
- char str_from[SEQ_NAME_MAXSTR + 3];
+ char str_from[SEQ_RNAPATH_MAXSTR];
+ size_t str_from_len;
FCurve *fcu;
FCurve *fcu_last;
FCurve *fcu_cpy;
@@ -4080,12 +4126,12 @@ void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char
if (scene->adt == NULL || scene->adt->action == NULL)
return;
- BLI_snprintf(str_from, sizeof(str_from), "[\"%s\"]", name_src);
+ str_from_len = sequencer_rna_path_prefix(str_from, name_src);
fcu_last = scene->adt->action->curves.last;
for (fcu = scene->adt->action->curves.first; fcu && fcu->prev != fcu_last; fcu = fcu->next) {
- if (strstr(fcu->rna_path, "sequence_editor.sequences_all[") && strstr(fcu->rna_path, str_from)) {
+ if (STREQLEN(fcu->rna_path, str_from, str_from_len)) {
fcu_cpy = copy_fcurve(fcu);
BLI_addtail(&lb, fcu_cpy);
}
@@ -4101,18 +4147,19 @@ void BKE_sequencer_dupe_animdata(Scene *scene, const char *name_src, const char
/* XXX - hackish function needed to remove all fcurves belonging to a sequencer strip */
static void seq_free_animdata(Scene *scene, Sequence *seq)
{
- char str[SEQ_NAME_MAXSTR + 3];
+ char str[SEQ_RNAPATH_MAXSTR];
+ size_t str_len;
FCurve *fcu;
if (scene->adt == NULL || scene->adt->action == NULL)
return;
- BLI_snprintf(str, sizeof(str), "[\"%s\"]", seq->name + 2);
+ str_len = sequencer_rna_path_prefix(str, seq->name + 2);
fcu = scene->adt->action->curves.first;
while (fcu) {
- if (strstr(fcu->rna_path, "sequence_editor.sequences_all[") && strstr(fcu->rna_path, str)) {
+ if (STREQLEN(fcu->rna_path, str, str_len)) {
FCurve *next_fcu = fcu->next;
BLI_remlink(&scene->adt->action->curves, fcu);
@@ -4126,6 +4173,8 @@ static void seq_free_animdata(Scene *scene, Sequence *seq)
}
}
+#undef SEQ_RNAPATH_MAXSTR
+
Sequence *BKE_sequence_get_by_name(ListBase *seqbase, const char *name, bool recursive)
{
Sequence *iseq = NULL;
@@ -4463,7 +4512,7 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad
int start_frame_back = seq_load->start_frame;
seq_load->channel++;
- BKE_sequencer_add_sound_strip(C, seqbasep, seq_load);
+ seq_load->seq_sound = BKE_sequencer_add_sound_strip(C, seqbasep, seq_load);
seq_load->start_frame = start_frame_back;
seq_load->channel--;
@@ -4583,11 +4632,15 @@ Sequence *BKE_sequence_dupli_recursive(Scene *scene, Scene *scene_to, Sequence *
return seqn;
}
-void BKE_sequence_base_dupli_recursive(Scene *scene, Scene *scene_to, ListBase *nseqbase, ListBase *seqbase, int dupe_flag)
+void BKE_sequence_base_dupli_recursive(
+ Scene *scene, Scene *scene_to, ListBase *nseqbase, ListBase *seqbase,
+ int dupe_flag)
{
Sequence *seq;
Sequence *seqn = NULL;
Sequence *last_seq = BKE_sequencer_active_get(scene);
+ /* always include meta's strips */
+ int dupe_flag_recursive = dupe_flag | SEQ_DUPE_ALL;
for (seq = seqbase->first; seq; seq = seq->next) {
seq->tmp = NULL;
@@ -4600,8 +4653,11 @@ void BKE_sequence_base_dupli_recursive(Scene *scene, Scene *scene_to, ListBase *
}
BLI_addtail(nseqbase, seqn);
- if (seq->type == SEQ_TYPE_META)
- BKE_sequence_base_dupli_recursive(scene, scene_to, &seqn->seqbase, &seq->seqbase, dupe_flag);
+ if (seq->type == SEQ_TYPE_META) {
+ BKE_sequence_base_dupli_recursive(
+ scene, scene_to, &seqn->seqbase, &seq->seqbase,
+ dupe_flag_recursive);
+ }
if (dupe_flag & SEQ_DUPE_CONTEXT) {
if (seq == last_seq) {
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index e2cc7b84f95..d2a4d15a2c6 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -50,6 +50,7 @@
#include "BKE_lattice.h"
#include "BKE_deform.h"
+#include "BKE_mesh.h" /* for OMP limits. */
#include "BKE_subsurf.h"
#include "BKE_editmesh.h"
@@ -65,57 +66,6 @@
/* Util macros */
#define OUT_OF_MEMORY() ((void)printf("Shrinkwrap: Out of memory\n"))
-/* get derived mesh */
-/* TODO is anyfunction that does this? returning the derivedFinal without we caring if its in edit mode or not? */
-DerivedMesh *object_get_derived_final(Object *ob, bool for_render)
-{
- Mesh *me = ob->data;
- BMEditMesh *em = me->edit_btmesh;
-
- if (for_render) {
- /* TODO(sergey): use proper derived render here in the future. */
- return ob->derivedFinal;
- }
-
- if (em) {
- DerivedMesh *dm = em->derivedFinal;
- return dm;
- }
-
- return ob->derivedFinal;
-}
-
-/* Space transform */
-void space_transform_from_matrixs(SpaceTransform *data, float local[4][4], float target[4][4])
-{
- float itarget[4][4];
- invert_m4_m4(itarget, target);
- mul_m4_m4m4(data->local2target, itarget, local);
- invert_m4_m4(data->target2local, data->local2target);
-}
-
-void space_transform_apply(const SpaceTransform *data, float co[3])
-{
- mul_v3_m4v3(co, ((SpaceTransform *)data)->local2target, co);
-}
-
-void space_transform_invert(const SpaceTransform *data, float co[3])
-{
- mul_v3_m4v3(co, ((SpaceTransform *)data)->target2local, co);
-}
-
-static void space_transform_apply_normal(const SpaceTransform *data, float no[3])
-{
- mul_mat3_m4_v3(((SpaceTransform *)data)->local2target, no);
- normalize_v3(no); /* TODO: could we just determine de scale value from the matrix? */
-}
-
-static void space_transform_invert_normal(const SpaceTransform *data, float no[3])
-{
- mul_mat3_m4_v3(((SpaceTransform *)data)->target2local, no);
- normalize_v3(no); /* TODO: could we just determine de scale value from the matrix? */
-}
-
/*
* Shrinkwrap to the nearest vertex
*
@@ -135,12 +85,12 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
OUT_OF_MEMORY();
return;
}
-
+
/* Setup nearest */
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
#ifndef __APPLE__
-#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static)
+#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(treeData, calc) schedule(static) if(calc->numVerts > BKE_MESH_OMP_LIMIT)
#endif
for (i = 0; i < calc->numVerts; ++i) {
float *co = calc->vertexCos[i];
@@ -158,7 +108,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
else {
copy_v3_v3(tmp_co, co);
}
- space_transform_apply(&calc->local2target, tmp_co);
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
/* Use local proximity heuristics (to reduce the nearest search)
*
@@ -184,7 +134,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
/* Convert the coordinates back to mesh coordinates */
copy_v3_v3(tmp_co, nearest.co);
- space_transform_invert(&calc->local2target, tmp_co);
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
}
@@ -223,11 +173,11 @@ bool BKE_shrinkwrap_project_normal(
/* Apply space transform (TODO readjust dist) */
if (transf) {
copy_v3_v3(tmp_co, vert);
- space_transform_apply(transf, tmp_co);
+ BLI_space_transform_apply(transf, tmp_co);
co = tmp_co;
copy_v3_v3(tmp_no, dir);
- space_transform_apply_normal(transf, tmp_no);
+ BLI_space_transform_apply_normal(transf, tmp_no);
no = tmp_no;
#ifdef USE_DIST_CORRECT
@@ -246,7 +196,7 @@ bool BKE_shrinkwrap_project_normal(
if (hit_tmp.index != -1) {
/* invert the normal first so face culling works on rotated objects */
if (transf) {
- space_transform_invert_normal(transf, hit_tmp.no);
+ BLI_space_transform_invert_normal(transf, hit_tmp.no);
}
if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) {
@@ -261,7 +211,7 @@ bool BKE_shrinkwrap_project_normal(
if (transf) {
/* Inverting space transform (TODO make coeherent with the initial dist readjust) */
- space_transform_invert(transf, hit_tmp.co);
+ BLI_space_transform_invert(transf, hit_tmp.co);
#ifdef USE_DIST_CORRECT
hit_tmp.dist = len_v3v3(vert, hit_tmp.co);
#endif
@@ -326,7 +276,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
auxMesh = object_get_derived_final(calc->smd->auxTarget, for_render);
if (!auxMesh)
return;
- SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget);
+ BLI_SPACE_TRANSFORM_SETUP(&local2aux, calc->ob, calc->smd->auxTarget);
}
/* After sucessufuly build the trees, start projection vertexs */
@@ -335,7 +285,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for
{
#ifndef __APPLE__
-#pragma omp parallel for private(i, hit) schedule(static)
+#pragma omp parallel for private(i, hit) schedule(static) if (calc->numVerts > BKE_MESH_OMP_LIMIT)
#endif
for (i = 0; i < calc->numVerts; ++i) {
float *co = calc->vertexCos[i];
@@ -445,7 +395,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
/* Find the nearest vertex */
#ifndef __APPLE__
-#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static)
+#pragma omp parallel for default(none) private(i) firstprivate(nearest) shared(calc, treeData) schedule(static) if(calc->numVerts > BKE_MESH_OMP_LIMIT)
#endif
for (i = 0; i < calc->numVerts; ++i) {
float *co = calc->vertexCos[i];
@@ -460,7 +410,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
else {
copy_v3_v3(tmp_co, co);
}
- space_transform_apply(&calc->local2target, tmp_co);
+ BLI_space_transform_apply(&calc->local2target, tmp_co);
/* Use local proximity heuristics (to reduce the nearest search)
*
@@ -494,7 +444,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
}
/* Convert the coordinates back to mesh coordinates */
- space_transform_invert(&calc->local2target, tmp_co);
+ BLI_space_transform_invert(&calc->local2target, tmp_co);
interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */
}
}
@@ -537,7 +487,7 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd, Object *ob, DerivedM
/* TODO there might be several "bugs" on non-uniform scales matrixs
* because it will no longer be nearest surface, not sphere projection
* because space has been deformed */
- SPACE_TRANSFORM_SETUP(&calc.local2target, ob, smd->target);
+ BLI_SPACE_TRANSFORM_SETUP(&calc.local2target, ob, smd->target);
/* TODO: smd->keepDist is in global units.. must change to local */
calc.keepDist = smd->keepDist;
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index c0cc2cd119c..50e0054b125 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -33,8 +33,6 @@
/* Part of the code copied from elbeem fluid library, copyright by Nils Thuerey */
-#include <GL/glew.h>
-
#include "MEM_guardedalloc.h"
#include <float.h>
@@ -84,6 +82,8 @@
#include "RE_shader_ext.h"
+#include "GPU_glew.h"
+
/* UNUSED so far, may be enabled later */
/* #define USE_SMOKE_COLLISION_DM */
@@ -211,7 +211,7 @@ void smoke_reallocate_highres_fluid(SmokeDomainSettings *sds, float dx, int res[
/* smoke_turbulence_init uses non-threadsafe functions from fftw3 lib (like fftw_plan & co). */
BLI_lock_thread(LOCK_FFTW);
- sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BLI_temporary_dir(), use_fire, use_colors);
+ sds->wt = smoke_turbulence_init(res, sds->amplify + 1, sds->noise, BLI_temp_dir_session(), use_fire, use_colors);
if (sds->flags & MOD_SMOKE_USE_MANTA){
smoke_mantaflow_write_scene_file(sds->smd);
}
@@ -1579,8 +1579,7 @@ static void sample_derivedmesh(
static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, SmokeFlowSettings *sfs, EmissionMap *em, float dt)
{
clock_t start = clock();
- if (!sfs->dm) return;
- {
+ if (sfs->dm) {
DerivedMesh *dm;
int defgrp_index = sfs->vgroup_density - 1;
MDeformVert *dvert = NULL;
@@ -1711,10 +1710,16 @@ static void emit_from_derivedmesh(Object *flow_ob, SmokeDomainSettings *sds, Smo
free_bvhtree_from_mesh(&treeData);
/* restore original mverts */
CustomData_set_layer(&dm->vertData, CD_MVERT, mvert_orig);
- if (mvert)
+
+ if (mvert) {
MEM_freeN(mvert);
+ }
+ if (vert_vel) {
+ MEM_freeN(vert_vel);
+ }
- if (vert_vel) MEM_freeN(vert_vel);
+ dm->needsFree = 1;
+ dm->release(dm);
}
clock_t end = clock();
float seconds = (float)(end - start) / CLOCKS_PER_SEC;
diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c
index 9c411142566..13575560669 100644
--- a/source/blender/blenkernel/intern/softbody.c
+++ b/source/blender/blenkernel/intern/softbody.c
@@ -2160,7 +2160,7 @@ static void sb_spring_force(Object *ob, int bpi, BodySpring *bs, float iks, floa
// dfdx_spring(ia, ia, op, dir, bs->len, distance, -mpos);
/* depending on my vel */
// dfdv_goal(ia, ia, mvel); // well that ignores geometie
- if (bp2->goal < SOFTGOALSNAP) { /* ommit this bp when it snaps */
+ if (bp2->goal < SOFTGOALSNAP) { /* omit this bp when it snaps */
/* depending on other pos */
// dfdx_spring(ia, ic, op, dir, bs->len, distance, mpos);
/* depending on other vel */
@@ -2257,7 +2257,7 @@ static int _softbody_calc_forces_slice_in_a_thread(Scene *scene, Object *ob, flo
}
/* naive ball self collision done */
- if (_final_goal(ob, bp) < SOFTGOALSNAP) { /* ommit this bp when it snaps */
+ if (_final_goal(ob, bp) < SOFTGOALSNAP) { /* omit this bp when it snaps */
float auxvect[3];
float velgoal[3];
@@ -2652,7 +2652,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa
}
/* naive ball self collision done */
- if (_final_goal(ob, bp) < SOFTGOALSNAP) { /* ommit this bp when it snaps */
+ if (_final_goal(ob, bp) < SOFTGOALSNAP) { /* omit this bp when it snaps */
float auxvect[3];
float velgoal[3];
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 6ba843c8a8f..da6ead06d98 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -727,7 +727,7 @@ void sound_update_scene(Main *bmain, struct Scene *scene)
if (AUD_removeSet(scene->speaker_handles, strip->speaker_handle)) {
if (speaker->sound) {
- AUD_moveSequence(strip->speaker_handle, (double)strip->start / FPS, -1, 0);
+ AUD_moveSequence(strip->speaker_handle, (double)strip->start / FPS, FLT_MAX, 0);
}
else {
AUD_removeSequence(scene->sound_scene, strip->speaker_handle);
@@ -738,7 +738,7 @@ void sound_update_scene(Main *bmain, struct Scene *scene)
if (speaker->sound) {
strip->speaker_handle = AUD_addSequence(scene->sound_scene,
speaker->sound->playback_handle,
- (double)strip->start / FPS, -1, 0);
+ (double)strip->start / FPS, FLT_MAX, 0);
AUD_setRelativeSequence(strip->speaker_handle, 0);
}
}
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index a9eba54128a..f03e2eaff4a 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -41,6 +41,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
@@ -71,10 +72,9 @@
# include "BLI_array.h"
#endif
-#include "GL/glew.h"
-
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_glew.h"
#include "GPU_material.h"
#include "CCGSubSurf.h"
@@ -360,7 +360,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm,
MVert *mv0 = mvert + (ml[j_next].v);
MVert *mv1 = mvert + (ml[j].v);
- if (BLI_edgeset_reinsert(eset, v0, v1)) {
+ if (BLI_edgeset_add(eset, v0, v1)) {
CCGEdge *e, *orige = ccgSubSurf_getFaceEdge(origf, j_next);
CCGEdgeHDL ehdl = SET_INT_IN_POINTER(mp->loopstart + j_next);
float crease;
@@ -1077,7 +1077,7 @@ void subsurf_copy_grid_hidden(DerivedMesh *dm, const MPoly *mpoly,
vndx = getFaceIndex(ss, f, j, x, y, edgeSize, gridSize);
offset = (y * factor) * hidden_gridsize + (x * factor);
- if (BLI_BITMAP_GET(md->hidden, offset))
+ if (BLI_BITMAP_TEST(md->hidden, offset))
mvert[vndx].flag |= ME_HIDE;
}
}
@@ -1457,6 +1457,7 @@ static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3])
edgeMap2[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))] = e;
}
+ ccgEdgeIterator_free(ei);
totface = ccgSubSurf_getNumFaces(ss);
faceMap2 = MEM_mallocN(totface * sizeof(*faceMap2), "facemap");
@@ -2290,18 +2291,23 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
DMSetDrawOptionsTex drawParams,
DMSetDrawOptions drawParamsMapped,
DMCompareDrawOptions compareDrawOptions,
- void *userData)
+ void *userData, DMDrawFlag flag)
{
CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm;
CCGSubSurf *ss = ccgdm->ss;
CCGKey key;
MCol *mcol = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
+ MTFace *tf_stencil_base = NULL;
+ MTFace *tf_stencil = NULL;
+ MTFace *tf_base;
short (*lnors)[4][3] = dm->getTessFaceDataArray(dm, CD_TESSLOOPNORMAL);
DMFlagMat *faceFlags = ccgdm->faceFlags;
DMDrawOption draw_option;
int i, totface, gridSize = ccgSubSurf_getGridSize(ss);
int gridFaces = gridSize - 1;
+ int gridOffset = 0;
+ int mat_nr_cache = -1;
(void) compareDrawOptions;
@@ -2315,6 +2321,12 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
mcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL);
totface = ccgSubSurf_getNumFaces(ss);
+
+ if (flag & DM_DRAW_USE_TEXPAINT_UV) {
+ int stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
+ tf_stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
+ }
+
for (i = 0; i < totface; i++) {
CCGFace *f = ccgdm->faceMap[i].face;
int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
@@ -2333,6 +2345,19 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
mat_nr = 0;
}
+ /* texture painting, handle the correct uv layer here */
+ if (flag & DM_DRAW_USE_TEXPAINT_UV) {
+ if (mat_nr != mat_nr_cache) {
+ tf_base = DM_paint_uvlayer_active_get(dm, mat_nr);
+
+ mat_nr_cache = mat_nr;
+ }
+
+ tf = tf_base ? tf_base + gridOffset : NULL;
+ tf_stencil = tf_stencil_base ? tf_stencil_base + gridOffset : NULL;
+ gridOffset += gridFaces * gridFaces * numVerts;
+ }
+
if (drawParams)
draw_option = drawParams(tf, (mcol != NULL), mat_nr);
else if (index != ORIGINDEX_NONE)
@@ -2373,26 +2398,31 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
float *d_co = CCG_grid_elem_co(&key, faceGridData, x, y + 1);
if (tf) glTexCoord2fv(tf->uv[1]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[1]);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
glNormal3sv(ln[0][1]);
glVertex3fv(d_co);
if (tf) glTexCoord2fv(tf->uv[2]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[2]);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
glNormal3sv(ln[0][2]);
glVertex3fv(c_co);
if (tf) glTexCoord2fv(tf->uv[3]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[3]);
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
glNormal3sv(ln[0][3]);
glVertex3fv(b_co);
if (tf) glTexCoord2fv(tf->uv[0]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[0]);
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
glNormal3sv(ln[0][0]);
glVertex3fv(a_co);
if (tf) tf++;
+ if (tf_stencil) tf_stencil++;
if (cp) cp += 16;
ln++;
}
@@ -2408,17 +2438,20 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
b = CCG_grid_elem(&key, faceGridData, x, y + 1);
if (tf) glTexCoord2fv(tf->uv[0]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[0]);
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
glNormal3fv(CCG_elem_no(&key, a));
glVertex3fv(CCG_elem_co(&key, a));
if (tf) glTexCoord2fv(tf->uv[1]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[1]);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
glNormal3fv(CCG_elem_no(&key, b));
glVertex3fv(CCG_elem_co(&key, b));
if (x != gridFaces - 1) {
if (tf) tf++;
+ if (tf_stencil) tf_stencil++;
if (cp) cp += 16;
}
}
@@ -2427,16 +2460,19 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
b = CCG_grid_elem(&key, faceGridData, x, y + 1);
if (tf) glTexCoord2fv(tf->uv[3]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[3]);
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
glNormal3fv(CCG_elem_no(&key, a));
glVertex3fv(CCG_elem_co(&key, a));
if (tf) glTexCoord2fv(tf->uv[2]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[2]);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
glNormal3fv(CCG_elem_no(&key, b));
glVertex3fv(CCG_elem_co(&key, b));
if (tf) tf++;
+ if (tf_stencil) tf_stencil++;
if (cp) cp += 16;
glEnd();
@@ -2455,22 +2491,27 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
ccgDM_glNormalFast(a_co, b_co, c_co, d_co);
if (tf) glTexCoord2fv(tf->uv[1]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[1]);
if (cp) glColor3ub(cp[7], cp[6], cp[5]);
glVertex3fv(d_co);
if (tf) glTexCoord2fv(tf->uv[2]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[2]);
if (cp) glColor3ub(cp[11], cp[10], cp[9]);
glVertex3fv(c_co);
if (tf) glTexCoord2fv(tf->uv[3]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[3]);
if (cp) glColor3ub(cp[15], cp[14], cp[13]);
glVertex3fv(b_co);
if (tf) glTexCoord2fv(tf->uv[0]);
+ if (tf_stencil) glMultiTexCoord2fv(GL_TEXTURE2, tf_stencil->uv[0]);
if (cp) glColor3ub(cp[3], cp[2], cp[1]);
glVertex3fv(a_co);
if (tf) tf++;
+ if (tf_stencil) tf_stencil++;
if (cp) cp += 16;
}
}
@@ -2483,17 +2524,17 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
static void ccgDM_drawFacesTex(DerivedMesh *dm,
DMSetDrawOptionsTex setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData)
+ void *userData, DMDrawFlag flag)
{
- ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
+ ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData, flag);
}
static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
DMSetDrawOptions setDrawOptions,
DMCompareDrawOptions compareDrawOptions,
- void *userData)
+ void *userData, DMDrawFlag flag)
{
- ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
+ ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData, flag);
}
static void ccgDM_drawUVEdges(DerivedMesh *dm)
@@ -3542,6 +3583,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->edgeMap[GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e))].edge = e;
}
+ ccgEdgeIterator_free(ei);
totface = ccgSubSurf_getNumFaces(ss);
ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap");
@@ -3780,8 +3822,9 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
}
if (has_edge_cd) {
+ BLI_assert(edgeIdx >= 0 && edgeIdx < dm->getNumEdges(dm));
for (i = 0; i < numFinalEdges; ++i) {
- CustomData_copy_data(&dm->edgeData, &ccgdm->dm.edgeData, mapIndex, edgeNum + i, 1);
+ CustomData_copy_data(&dm->edgeData, &ccgdm->dm.edgeData, edgeIdx, edgeNum + i, 1);
}
}
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index b6d7e8922c4..8a272cd9d81 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -267,16 +267,79 @@ static void cleanup_textline(TextLine *tl)
tl->len += txt_extended_ascii_as_utf8(&tl->line);
}
+/**
+ * used for load and reload (unlike txt_insert_buf)
+ * assumes all fields are empty
+ */
+static void text_from_buf(Text *text, const unsigned char *buffer, const int len)
+{
+ int i, llen;
+
+ BLI_assert(BLI_listbase_is_empty(&text->lines));
+
+ text->nlines = 0;
+ llen = 0;
+ for (i = 0; i < len; i++) {
+ if (buffer[i] == '\n') {
+ TextLine *tmp;
+
+ tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
+ tmp->format = NULL;
+
+ if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
+ tmp->line[llen] = 0;
+ tmp->len = llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&text->lines, tmp);
+ text->nlines++;
+
+ llen = 0;
+ continue;
+ }
+ llen++;
+ }
+
+ /* create new line in cases:
+ * - rest of line (if last line in file hasn't got \n terminator).
+ * in this case content of such line would be used to fill text line buffer
+ * - file is empty. in this case new line is needed to start editing from.
+ * - last characted in buffer is \n. in this case new line is needed to
+ * deal with newline at end of file. (see [#28087]) (sergey) */
+ if (llen != 0 || text->nlines == 0 || buffer[len - 1] == '\n') {
+ TextLine *tmp;
+
+ tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
+ tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
+ tmp->format = NULL;
+
+ if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
+
+ tmp->line[llen] = 0;
+ tmp->len = llen;
+
+ cleanup_textline(tmp);
+
+ BLI_addtail(&text->lines, tmp);
+ text->nlines++;
+ }
+
+ text->curl = text->sell = text->lines.first;
+ text->curc = text->selc = 0;
+}
+
int BKE_text_reload(Text *text)
{
FILE *fp;
- int i, llen, len;
+ int len;
unsigned char *buffer;
TextLine *tmp;
char str[FILE_MAX];
- struct stat st;
+ BLI_stat_t st;
- if (!text || !text->name) return 0;
+ if (!text->name) return 0;
BLI_strncpy(str, text->name, FILE_MAX);
BLI_path_abs(str, G.main->name);
@@ -299,13 +362,12 @@ int BKE_text_reload(Text *text)
/* clear undo buffer */
MEM_freeN(text->undo_buf);
init_undo_text(text);
-
+
fseek(fp, 0L, SEEK_END);
len = ftell(fp);
fseek(fp, 0L, SEEK_SET);
- text->undo_pos = -1;
-
+
buffer = MEM_mallocN(len, "text_buffer");
// under windows fread can return less then len bytes because
// of CR stripping
@@ -313,51 +375,11 @@ int BKE_text_reload(Text *text)
fclose(fp);
- stat(str, &st);
+ BLI_stat(str, &st);
text->mtime = st.st_mtime;
-
- text->nlines = 0;
- llen = 0;
- for (i = 0; i < len; i++) {
- if (buffer[i] == '\n') {
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
- tmp->format = NULL;
-
- if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
- tmp->line[llen] = 0;
- tmp->len = llen;
-
- cleanup_textline(tmp);
-
- BLI_addtail(&text->lines, tmp);
- text->nlines++;
-
- llen = 0;
- continue;
- }
- llen++;
- }
- if (llen != 0 || text->nlines == 0) {
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
- tmp->format = NULL;
-
- if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
+ text_from_buf(text, buffer, len);
- tmp->line[llen] = 0;
- tmp->len = llen;
-
- cleanup_textline(tmp);
-
- BLI_addtail(&text->lines, tmp);
- text->nlines++;
- }
-
- text->curl = text->sell = text->lines.first;
- text->curc = text->selc = 0;
-
MEM_freeN(buffer);
return 1;
}
@@ -365,12 +387,11 @@ int BKE_text_reload(Text *text)
Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const bool is_internal)
{
FILE *fp;
- int i, llen, len;
+ int len;
unsigned char *buffer;
- TextLine *tmp;
Text *ta;
char str[FILE_MAX];
- struct stat st;
+ BLI_stat_t st;
BLI_strncpy(str, file, FILE_MAX);
if (relpath) /* can be NULL (bg mode) */
@@ -388,10 +409,6 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
if ((U.flag & USER_TXT_TABSTOSPACES_DISABLE) == 0)
ta->flags = TXT_TABSTOSPACES;
- fseek(fp, 0L, SEEK_END);
- len = ftell(fp);
- fseek(fp, 0L, SEEK_SET);
-
if (is_internal == false) {
ta->name = MEM_mallocN(strlen(file) + 1, "text_name");
strcpy(ta->name, file);
@@ -400,7 +417,12 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
ta->flags |= TXT_ISMEM | TXT_ISDIRTY;
}
+ /* 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 then len bytes because
@@ -409,56 +431,10 @@ Text *BKE_text_load_ex(Main *bmain, const char *file, const char *relpath, const
fclose(fp);
- stat(str, &st);
+ BLI_stat(str, &st);
ta->mtime = st.st_mtime;
- ta->nlines = 0;
- llen = 0;
- for (i = 0; i < len; i++) {
- if (buffer[i] == '\n') {
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
- tmp->format = NULL;
-
- if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
- tmp->line[llen] = 0;
- tmp->len = llen;
-
- cleanup_textline(tmp);
-
- BLI_addtail(&ta->lines, tmp);
- ta->nlines++;
-
- llen = 0;
- continue;
- }
- llen++;
- }
-
- /* create new line in cases:
- * - rest of line (if last line in file hasn't got \n terminator).
- * in this case content of such line would be used to fill text line buffer
- * - file is empty. in this case new line is needed to start editing from.
- * - last characted in buffer is \n. in this case new line is needed to
- * deal with newline at end of file. (see [#28087]) (sergey) */
- if (llen != 0 || ta->nlines == 0 || buffer[len - 1] == '\n') {
- tmp = (TextLine *) MEM_mallocN(sizeof(TextLine), "textline");
- tmp->line = (char *) MEM_mallocN(llen + 1, "textline_string");
- tmp->format = NULL;
-
- if (llen) memcpy(tmp->line, &buffer[i - llen], llen);
-
- tmp->line[llen] = 0;
- tmp->len = llen;
-
- cleanup_textline(tmp);
-
- BLI_addtail(&ta->lines, tmp);
- ta->nlines++;
- }
-
- ta->curl = ta->sell = ta->lines.first;
- ta->curc = ta->selc = 0;
+ text_from_buf(ta, buffer, len);
MEM_freeN(buffer);
@@ -667,11 +643,11 @@ void BKE_text_write(Text *text, const char *str) /* called directly from rna */
int BKE_text_file_modified_check(Text *text)
{
- struct stat st;
+ BLI_stat_t st;
int result;
char file[FILE_MAX];
- if (!text || !text->name)
+ if (!text->name)
return 0;
BLI_strncpy(file, text->name, FILE_MAX);
@@ -696,11 +672,11 @@ int BKE_text_file_modified_check(Text *text)
void BKE_text_file_modified_ignore(Text *text)
{
- struct stat st;
+ BLI_stat_t st;
int result;
char file[FILE_MAX];
- if (!text || !text->name) return;
+ if (!text->name) return;
BLI_strncpy(file, text->name, FILE_MAX);
BLI_path_abs(file, G.main->name);
@@ -766,9 +742,7 @@ static TextLine *txt_new_linen(const char *str, int n)
void txt_clean_text(Text *text)
{
TextLine **top, **bot;
-
- if (!text) return;
-
+
if (!text->lines.first) {
if (text->lines.last) text->lines.first = text->lines.last;
else text->lines.first = text->lines.last = txt_new_line(NULL);
@@ -907,8 +881,7 @@ void txt_move_up(Text *text, const bool sel)
{
TextLine **linep;
int *charp;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
if (!*linep) return;
@@ -930,8 +903,7 @@ void txt_move_down(Text *text, const bool sel)
{
TextLine **linep;
int *charp;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
if (!*linep) return;
@@ -953,8 +925,7 @@ void txt_move_left(Text *text, const bool sel)
TextLine **linep;
int *charp;
int tabsize = 0, i = 0;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
if (!*linep) return;
@@ -998,8 +969,7 @@ void txt_move_right(Text *text, const bool sel)
TextLine **linep;
int *charp, i;
bool do_tab = false;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
if (!*linep) return;
@@ -1040,8 +1010,7 @@ void txt_jump_left(Text *text, const bool sel, const bool use_init_step)
{
TextLine **linep;
int *charp;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else { txt_pop_first(text); txt_curs_cur(text, &linep, &charp); }
if (!*linep) return;
@@ -1057,8 +1026,7 @@ void txt_jump_right(Text *text, const bool sel, const bool use_init_step)
{
TextLine **linep;
int *charp;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else { txt_pop_last(text); txt_curs_cur(text, &linep, &charp); }
if (!*linep) return;
@@ -1074,8 +1042,7 @@ void txt_move_bol(Text *text, const bool sel)
{
TextLine **linep;
int *charp;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else txt_curs_cur(text, &linep, &charp);
if (!*linep) return;
@@ -1089,8 +1056,7 @@ void txt_move_eol(Text *text, const bool sel)
{
TextLine **linep;
int *charp;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else txt_curs_cur(text, &linep, &charp);
if (!*linep) return;
@@ -1104,8 +1070,7 @@ void txt_move_bof(Text *text, const bool sel)
{
TextLine **linep;
int *charp;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else txt_curs_cur(text, &linep, &charp);
if (!*linep) return;
@@ -1120,8 +1085,7 @@ void txt_move_eof(Text *text, const bool sel)
{
TextLine **linep;
int *charp;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else txt_curs_cur(text, &linep, &charp);
if (!*linep) return;
@@ -1143,8 +1107,7 @@ void txt_move_to(Text *text, unsigned int line, unsigned int ch, const bool sel)
TextLine **linep;
int *charp;
unsigned int i;
-
- if (!text) return;
+
if (sel) txt_curs_sel(text, &linep, &charp);
else txt_curs_cur(text, &linep, &charp);
if (!*linep) return;
@@ -1181,7 +1144,6 @@ static void txt_curs_swap(Text *text)
static void txt_pop_first(Text *text)
{
-
if (txt_get_span(text->curl, text->sell) < 0 ||
(text->curl == text->sell && text->curc > text->selc))
{
@@ -1210,7 +1172,6 @@ void txt_pop_sel(Text *text)
void txt_order_cursors(Text *text, const bool reverse)
{
- if (!text) return;
if (!text->curl) return;
if (!text->sell) return;
@@ -1240,8 +1201,7 @@ static void txt_delete_sel(Text *text)
{
TextLine *tmpl;
char *buf;
-
- if (!text) return;
+
if (!text->curl) return;
if (!text->sell) return;
@@ -1277,8 +1237,6 @@ static void txt_delete_sel(Text *text)
void txt_sel_all(Text *text)
{
- if (!text) return;
-
text->curl = text->lines.first;
text->curc = 0;
@@ -1286,9 +1244,21 @@ void txt_sel_all(Text *text)
text->selc = text->sell->len;
}
+/**
+ * Reverse of #txt_pop_sel
+ * Clears the selection and ensures the cursor is located
+ * at the selection (where the cursor is visually while editing).
+ */
+void txt_sel_clear(Text *text)
+{
+ if (text->sell) {
+ text->curl = text->sell;
+ text->curc = text->selc;
+ }
+}
+
void txt_sel_line(Text *text)
{
- if (!text) return;
if (!text->curl) return;
text->curc = 0;
@@ -1306,8 +1276,7 @@ char *txt_to_buf(Text *text)
TextLine *tmp, *linef, *linel;
int charf, charl;
char *buf;
-
- if (!text) return NULL;
+
if (!text->curl) return NULL;
if (!text->sell) return NULL;
if (!text->lines.first) return NULL;
@@ -1369,7 +1338,7 @@ int txt_find_string(Text *text, const char *findstr, int wrap, int match_case)
TextLine *tl, *startl;
const char *s = NULL;
- if (!text || !text->curl || !text->sell) return 0;
+ if (!text->curl || !text->sell) return 0;
txt_order_cursors(text, false);
@@ -1409,8 +1378,7 @@ char *txt_sel_to_buf(Text *text)
int length = 0;
TextLine *tmp, *linef, *linel;
int charf, charl;
-
- if (!text) return NULL;
+
if (!text->curl) return NULL;
if (!text->sell) return NULL;
@@ -1491,7 +1459,6 @@ void txt_insert_buf(Text *text, const char *in_buffer)
TextLine *add;
char *buffer;
- if (!text) return;
if (!in_buffer) return;
txt_delete_sel(text);
@@ -2373,8 +2340,7 @@ void txt_split_curline(Text *text)
{
TextLine *ins;
char *left, *right;
-
- if (!text) return;
+
if (!text->curl) return;
txt_delete_sel(text);
@@ -2416,7 +2382,6 @@ void txt_split_curline(Text *text)
static void txt_delete_line(Text *text, TextLine *line)
{
- if (!text) return;
if (!text->curl) return;
BLI_remlink(&text->lines, line);
@@ -2433,8 +2398,6 @@ static void txt_delete_line(Text *text, TextLine *line)
static void txt_combine_lines(Text *text, TextLine *linea, TextLine *lineb)
{
char *tmp, *s;
-
- if (!text) return;
if (!linea || !lineb) return;
@@ -2458,7 +2421,7 @@ void txt_duplicate_line(Text *text)
{
TextLine *textline;
- if (!text || !text->curl) return;
+ if (!text->curl) return;
if (text->curl == text->sell) {
textline = txt_new_line(text->curl->line);
@@ -2474,8 +2437,7 @@ void txt_duplicate_line(Text *text)
void txt_delete_char(Text *text)
{
unsigned int c = '\n';
-
- if (!text) return;
+
if (!text->curl) return;
if (txt_has_sel(text)) { /* deleting a selection */
@@ -2518,7 +2480,6 @@ void txt_backspace_char(Text *text)
{
unsigned int c = '\n';
- if (!text) return;
if (!text->curl) return;
if (txt_has_sel(text)) { /* deleting a selection */
@@ -2582,8 +2543,7 @@ static bool txt_add_char_intern(Text *text, unsigned int add, bool replace_tabs)
{
char *tmp, ch[BLI_UTF8_MAX];
size_t add_len;
-
- if (!text) return 0;
+
if (!text->curl) return 0;
if (add == '\n') {
@@ -2642,8 +2602,7 @@ bool txt_replace_char(Text *text, unsigned int add)
unsigned int del;
size_t del_size = 0, add_size;
char ch[BLI_UTF8_MAX];
-
- if (!text) return 0;
+
if (!text->curl) return 0;
/* If text is selected or we're at the end of the line just use txt_add_char */
@@ -2697,7 +2656,7 @@ void txt_indent(Text *text)
/* hardcoded: TXT_TABSIZE = 4 spaces: */
int spaceslen = TXT_TABSIZE;
- if (ELEM3(NULL, text, text->curl, text->sell)) {
+ if (ELEM(NULL, text->curl, text->sell)) {
return;
}
@@ -2764,7 +2723,7 @@ void txt_unindent(Text *text)
/* hardcoded: TXT_TABSIZE = 4 spaces: */
int spaceslen = TXT_TABSIZE;
- if (ELEM3(NULL, text, text->curl, text->sell)) {
+ if (ELEM(NULL, text->curl, text->sell)) {
return;
}
@@ -2817,8 +2776,7 @@ void txt_comment(Text *text)
int len, num;
char *tmp;
char add = '#';
-
- if (!text) return;
+
if (!text->curl) return;
if (!text->sell) return; // Need to change this need to check if only one line is selected to more than one
@@ -2865,8 +2823,7 @@ void txt_uncomment(Text *text)
{
int num = 0;
char remove = '#';
-
- if (!text) return;
+
if (!text->curl) return;
if (!text->sell) return;
@@ -2912,7 +2869,7 @@ void txt_move_lines(struct Text *text, const int direction)
BLI_assert(ELEM(direction, TXT_MOVE_LINE_UP, TXT_MOVE_LINE_DOWN));
- if (!text || !text->curl || !text->sell) return;
+ if (!text->curl || !text->sell) return;
txt_order_cursors(text, false);
@@ -2945,6 +2902,7 @@ int txt_setcurr_tab_spaces(Text *text, int space)
const char *comm = "#";
const char indent = (text->flags & TXT_TABSTOSPACES) ? ' ' : '\t';
static const char *back_words[] = {"return", "break", "continue", "pass", "yield", NULL};
+
if (!text->curl) return 0;
while (text->curl->line[i] == indent) {
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index 4fff50153ef..b1981a3a804 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -41,6 +41,7 @@
#include "BLI_math.h"
#include "BLI_kdopbvh.h"
#include "BLI_utildefines.h"
+#include "BLI_math_color.h"
#include "DNA_key_types.h"
#include "DNA_object_types.h"
@@ -145,12 +146,12 @@ void init_tex_mapping(TexMapping *texmap)
if (texmap->type == TEXMAP_TYPE_TEXTURE) {
/* to transform a texture, the inverse transform needs
* to be applied to the texture coordinate */
- mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0);
+ mul_m4_series(texmap->mat, tmat, rmat, smat);
invert_m4(texmap->mat);
}
else if (texmap->type == TEXMAP_TYPE_POINT) {
/* forward transform */
- mul_serie_m4(texmap->mat, tmat, rmat, smat, 0, 0, 0, 0, 0);
+ mul_m4_series(texmap->mat, tmat, rmat, smat);
}
else if (texmap->type == TEXMAP_TYPE_VECTOR) {
/* no translation for vectors */
@@ -237,7 +238,7 @@ void init_colorband(ColorBand *coba, bool rangetype)
}
coba->tot = 2;
-
+ coba->color_mode = COLBAND_BLEND_RGB;
}
ColorBand *add_colorband(bool rangetype)
@@ -252,106 +253,209 @@ ColorBand *add_colorband(bool rangetype)
/* ------------------------------------------------------------------------- */
+static float colorband_hue_interp(
+ const int ipotype_hue,
+ const float mfac, const float fac,
+ float h1, float h2)
+{
+ float h_interp;
+ int mode = 0;
+
+#define HUE_INTERP(h_a, h_b) ((mfac * (h_a)) + (fac * (h_b)))
+#define HUE_MOD(h) (((h) < 1.0f) ? (h) : (h) - 1.0f)
+
+ h1 = HUE_MOD(h1);
+ h2 = HUE_MOD(h2);
+
+ BLI_assert(h1 >= 0.0f && h1 < 1.0f);
+ BLI_assert(h2 >= 0.0f && h2 < 1.0f);
+
+ switch (ipotype_hue) {
+ case COLBAND_HUE_NEAR:
+ {
+ if ((h1 < h2) && (h2 - h1) > +0.5f) mode = 1;
+ else if ((h1 > h2) && (h2 - h1) < -0.5f) mode = 2;
+ else mode = 0;
+ break;
+ }
+ case COLBAND_HUE_FAR:
+ {
+ if ((h1 < h2) && (h2 - h1) < +0.5f) mode = 1;
+ else if ((h1 > h2) && (h2 - h1) > -0.5f) mode = 2;
+ else mode = 0;
+ break;
+ }
+ case COLBAND_HUE_CCW:
+ {
+ if (h1 > h2) mode = 2;
+ else mode = 0;
+ break;
+ }
+ case COLBAND_HUE_CW:
+ {
+ if (h1 < h2) mode = 1;
+ else mode = 0;
+ break;
+ }
+ }
+
+ switch (mode) {
+ case 0:
+ h_interp = HUE_INTERP(h1, h2);
+ break;
+ case 1:
+ h_interp = HUE_INTERP(h1 + 1.0f, h2);
+ h_interp = HUE_MOD(h_interp);
+ break;
+ case 2:
+ h_interp = HUE_INTERP(h1, h2 + 1.0f);
+ h_interp = HUE_MOD(h_interp);
+ break;
+ }
+
+ BLI_assert(h_interp >= 0.0f && h_interp < 1.0f);
+
+#undef HUE_INTERP
+#undef HUE_MOD
+
+ return h_interp;
+}
+
bool do_colorband(const ColorBand *coba, float in, float out[4])
{
const CBData *cbd1, *cbd2, *cbd0, *cbd3;
- float fac, mfac, t[4];
+ float fac;
+ int ipotype;
int a;
if (coba == NULL || coba->tot == 0) return 0;
cbd1 = coba->data;
+
+ ipotype = (coba->color_mode == COLBAND_BLEND_RGB) ? coba->ipotype : COLBAND_INTERP_LINEAR;
+
if (coba->tot == 1) {
out[0] = cbd1->r;
out[1] = cbd1->g;
out[2] = cbd1->b;
out[3] = cbd1->a;
}
+ else if ((in <= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) {
+ out[0] = cbd1->r;
+ out[1] = cbd1->g;
+ out[2] = cbd1->b;
+ out[3] = cbd1->a;
+ }
else {
- if (in <= cbd1->pos && coba->ipotype < 2) {
+ CBData left, right;
+
+ /* we're looking for first pos > in */
+ for (a = 0; a < coba->tot; a++, cbd1++) if (cbd1->pos > in) break;
+
+ if (a == coba->tot) {
+ cbd2 = cbd1 - 1;
+ right = *cbd2;
+ right.pos = 1.0f;
+ cbd1 = &right;
+ }
+ else if (a == 0) {
+ left = *cbd1;
+ left.pos = 0.0f;
+ cbd2 = &left;
+ }
+ else {
+ cbd2 = cbd1 - 1;
+ }
+
+ if ((in >= cbd1->pos) && ELEM(ipotype, COLBAND_INTERP_LINEAR, COLBAND_INTERP_EASE)) {
out[0] = cbd1->r;
out[1] = cbd1->g;
out[2] = cbd1->b;
out[3] = cbd1->a;
}
else {
- CBData left, right;
-
- /* we're looking for first pos > in */
- for (a = 0; a < coba->tot; a++, cbd1++) if (cbd1->pos > in) break;
-
- if (a == coba->tot) {
- cbd2 = cbd1 - 1;
- right = *cbd2;
- right.pos = 1.0f;
- cbd1 = &right;
- }
- else if (a == 0) {
- left = *cbd1;
- left.pos = 0.0f;
- cbd2 = &left;
+
+ if (cbd2->pos != cbd1->pos) {
+ fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos);
}
else {
- cbd2 = cbd1 - 1;
+ /* was setting to 0.0 in 2.56 & previous, but this
+ * is incorrect for the last element, see [#26732] */
+ fac = (a != coba->tot) ? 0.0f : 1.0f;
}
-
- if (in >= cbd1->pos && coba->ipotype < 2) {
- out[0] = cbd1->r;
- out[1] = cbd1->g;
- out[2] = cbd1->b;
- out[3] = cbd1->a;
+
+ if (ipotype == COLBAND_INTERP_CONSTANT) {
+ /* constant */
+ out[0] = cbd2->r;
+ out[1] = cbd2->g;
+ out[2] = cbd2->b;
+ out[3] = cbd2->a;
}
- else {
-
- if (cbd2->pos != cbd1->pos)
- fac = (in - cbd1->pos) / (cbd2->pos - cbd1->pos);
+ else if (ipotype >= COLBAND_INTERP_B_SPLINE) {
+ /* ipo from right to left: 3 2 1 0 */
+ float t[4];
+
+ if (a >= coba->tot - 1) cbd0 = cbd1;
+ else cbd0 = cbd1 + 1;
+ if (a < 2) cbd3 = cbd2;
+ else cbd3 = cbd2 - 1;
+
+ CLAMP(fac, 0.0f, 1.0f);
+
+ if (ipotype == COLBAND_INTERP_CARDINAL) {
+ key_curve_position_weights(fac, t, KEY_CARDINAL);
+ }
else {
- /* was setting to 0.0 in 2.56 & previous, but this
- * is incorrect for the last element, see [#26732] */
- fac = (a != coba->tot) ? 0.0f : 1.0f;
+ key_curve_position_weights(fac, t, KEY_BSPLINE);
}
-
- if (coba->ipotype == 4) {
- /* constant */
- out[0] = cbd2->r;
- out[1] = cbd2->g;
- out[2] = cbd2->b;
- out[3] = cbd2->a;
- return 1;
+
+ out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r;
+ out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g;
+ out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b;
+ out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a;
+ CLAMP(out[0], 0.0f, 1.0f);
+ CLAMP(out[1], 0.0f, 1.0f);
+ CLAMP(out[2], 0.0f, 1.0f);
+ CLAMP(out[3], 0.0f, 1.0f);
+ }
+ else {
+ float mfac;
+
+ if (ipotype == COLBAND_INTERP_EASE) {
+ mfac = fac * fac;
+ fac = 3.0f * mfac - 2.0f * mfac * fac;
}
-
- if (coba->ipotype >= 2) {
- /* ipo from right to left: 3 2 1 0 */
-
- if (a >= coba->tot - 1) cbd0 = cbd1;
- else cbd0 = cbd1 + 1;
- if (a < 2) cbd3 = cbd2;
- else cbd3 = cbd2 - 1;
-
- CLAMP(fac, 0.0f, 1.0f);
-
- if (coba->ipotype == 3)
- key_curve_position_weights(fac, t, KEY_CARDINAL);
- else
- key_curve_position_weights(fac, t, KEY_BSPLINE);
-
- out[0] = t[3] * cbd3->r + t[2] * cbd2->r + t[1] * cbd1->r + t[0] * cbd0->r;
- out[1] = t[3] * cbd3->g + t[2] * cbd2->g + t[1] * cbd1->g + t[0] * cbd0->g;
- out[2] = t[3] * cbd3->b + t[2] * cbd2->b + t[1] * cbd1->b + t[0] * cbd0->b;
- out[3] = t[3] * cbd3->a + t[2] * cbd2->a + t[1] * cbd1->a + t[0] * cbd0->a;
- CLAMP(out[0], 0.0f, 1.0f);
- CLAMP(out[1], 0.0f, 1.0f);
- CLAMP(out[2], 0.0f, 1.0f);
- CLAMP(out[3], 0.0f, 1.0f);
+
+ mfac = 1.0f - fac;
+
+ if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSV)) {
+ float col1[3], col2[3];
+
+ rgb_to_hsv_v(&cbd1->r, col1);
+ rgb_to_hsv_v(&cbd2->r, col2);
+
+ out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
+ out[1] = mfac * col1[1] + fac * col2[1];
+ out[2] = mfac * col1[2] + fac * col2[2];
+ out[3] = mfac * cbd1->a + fac * cbd2->a;
+
+ hsv_to_rgb_v(out, out);
+ }
+ else if (UNLIKELY(coba->color_mode == COLBAND_BLEND_HSL)) {
+ float col1[3], col2[3];
+
+ rgb_to_hsl_v(&cbd1->r, col1);
+ rgb_to_hsl_v(&cbd2->r, col2);
+
+ out[0] = colorband_hue_interp(coba->ipotype_hue, mfac, fac, col1[0], col2[0]);
+ out[1] = mfac * col1[1] + fac * col2[1];
+ out[2] = mfac * col1[2] + fac * col2[2];
+ out[3] = mfac * cbd1->a + fac * cbd2->a;
+
+ hsl_to_rgb_v(out, out);
}
else {
-
- if (coba->ipotype == 1) { /* EASE */
- mfac = fac * fac;
- fac = 3.0f * mfac - 2.0f * mfac * fac;
- }
- mfac = 1.0f - fac;
-
+ /* COLBAND_BLEND_RGB */
out[0] = mfac * cbd1->r + fac * cbd2->r;
out[1] = mfac * cbd1->g + fac * cbd2->g;
out[2] = mfac * cbd1->b + fac * cbd2->b;
@@ -408,19 +512,18 @@ CBData *colorband_element_add(struct ColorBand *coba, float position)
if (coba->tot == MAXCOLORBAND) {
return NULL;
}
- else if (coba->tot > 0) {
+ else {
CBData *xnew;
- float col[4];
-
- do_colorband(coba, position, col);
xnew = &coba->data[coba->tot];
xnew->pos = position;
- xnew->r = col[0];
- xnew->g = col[1];
- xnew->b = col[2];
- xnew->a = col[3];
+ if (coba->tot != 0) {
+ do_colorband(coba, position, &xnew->r);
+ }
+ else {
+ zero_v4(&xnew->r);
+ }
}
coba->tot++;
@@ -474,7 +577,8 @@ void BKE_texture_free(Tex *tex)
void default_tex(Tex *tex)
{
- tex->type = TEX_CLOUDS;
+ tex->type = TEX_IMAGE;
+ tex->ima = NULL;
tex->stype = 0;
tex->flag = TEX_CHECKER_ODD;
tex->imaflag = TEX_INTERPOL | TEX_MIPMAP | TEX_USEALPHA;
@@ -592,7 +696,7 @@ Tex *add_texture(Main *bmain, const char *name)
void default_mtex(MTex *mtex)
{
- mtex->texco = TEXCO_ORCO;
+ mtex->texco = TEXCO_UV;
mtex->mapto = MAP_COL;
mtex->object = NULL;
mtex->projx = PROJ_X;
@@ -705,6 +809,10 @@ MTex *add_mtex_id(ID *id, int slot)
MEM_freeN(mtex_ar[slot]);
mtex_ar[slot] = NULL;
}
+ else if (GS(id->name) == ID_MA) {
+ /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
+ ((Material *)id)->septex &= ~(1 << slot);
+ }
mtex_ar[slot] = add_mtex();
@@ -743,8 +851,7 @@ Tex *localize_texture(Tex *tex)
{
Tex *texn;
- texn = BKE_libblock_copy(&tex->id);
- BLI_remlink(&G.main->tex, texn);
+ texn = BKE_libblock_copy_nolib(&tex->id, false);
/* image texture: BKE_texture_free also doesn't decrease */
@@ -1174,8 +1281,11 @@ void set_current_material_texture(Material *ma, Tex *newtex)
id_us_min(&tex->id);
if (newtex) {
- if (!ma->mtex[act])
+ if (!ma->mtex[act]) {
ma->mtex[act] = add_mtex();
+ /* Reset this slot's ON/OFF toggle, for materials, when slot was empty. */
+ ma->septex &= ~(1 << act);
+ }
ma->mtex[act]->tex = newtex;
id_us_plus(&newtex->id);
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index 22005892535..40d9dc0d7e0 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -371,6 +371,9 @@ void BKE_tracking_clipboard_paste_tracks(MovieTracking *tracking, MovieTrackingO
while (track) {
MovieTrackingTrack *new_track = BKE_tracking_track_duplicate(track);
+ if (track->prev == NULL) {
+ tracking->act_track = new_track;
+ }
BLI_addtail(tracksbase, new_track);
BKE_tracking_track_unique_name(tracksbase, new_track);
@@ -1789,13 +1792,19 @@ ImBuf *BKE_tracking_distortion_exec(MovieDistortion *distortion, MovieTracking *
if (ibuf->rect_float) {
if (undistort) {
libmv_cameraIntrinsicsUndistortFloat(distortion->intrinsics,
- ibuf->rect_float, resibuf->rect_float,
- ibuf->x, ibuf->y, overscan, ibuf->channels);
+ ibuf->rect_float,
+ ibuf->x, ibuf->y,
+ overscan,
+ ibuf->channels,
+ resibuf->rect_float);
}
else {
libmv_cameraIntrinsicsDistortFloat(distortion->intrinsics,
- ibuf->rect_float, resibuf->rect_float,
- ibuf->x, ibuf->y, overscan, ibuf->channels);
+ ibuf->rect_float,
+ ibuf->x, ibuf->y,
+ overscan,
+ ibuf->channels,
+ resibuf->rect_float);
}
if (ibuf->rect)
@@ -1804,13 +1813,19 @@ ImBuf *BKE_tracking_distortion_exec(MovieDistortion *distortion, MovieTracking *
else {
if (undistort) {
libmv_cameraIntrinsicsUndistortByte(distortion->intrinsics,
- (unsigned char *)ibuf->rect, (unsigned char *)resibuf->rect,
- ibuf->x, ibuf->y, overscan, ibuf->channels);
+ (unsigned char *)ibuf->rect,
+ ibuf->x, ibuf->y,
+ overscan,
+ ibuf->channels,
+ (unsigned char *)resibuf->rect);
}
else {
libmv_cameraIntrinsicsDistortByte(distortion->intrinsics,
- (unsigned char *)ibuf->rect, (unsigned char *)resibuf->rect,
- ibuf->x, ibuf->y, overscan, ibuf->channels);
+ (unsigned char *)ibuf->rect,
+ ibuf->x, ibuf->y,
+ overscan,
+ ibuf->channels,
+ (unsigned char *)resibuf->rect);
}
}
@@ -1891,11 +1906,21 @@ ImBuf *BKE_tracking_distort_frame(MovieTracking *tracking, ImBuf *ibuf, int cali
calibration_height, overscan, false);
}
-void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, rcti *rect, float delta[2])
+void BKE_tracking_max_distortion_delta_across_bound(MovieTracking *tracking, rcti *rect,
+ bool undistort, float delta[2])
{
int a;
float pos[2], warped_pos[2];
const int coord_delta = 5;
+ void (*apply_distortion) (MovieTracking *tracking,
+ const float pos[2], float out[2]);
+
+ if (undistort) {
+ apply_distortion = BKE_tracking_undistort_v2;
+ }
+ else {
+ apply_distortion = BKE_tracking_distort_v2;
+ }
delta[0] = delta[1] = -FLT_MAX;
@@ -1907,7 +1932,7 @@ void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, r
pos[0] = a;
pos[1] = rect->ymin;
- BKE_tracking_undistort_v2(tracking, pos, warped_pos);
+ apply_distortion(tracking, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -1916,7 +1941,7 @@ void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, r
pos[0] = a;
pos[1] = rect->ymax;
- BKE_tracking_undistort_v2(tracking, pos, warped_pos);
+ apply_distortion(tracking, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -1933,7 +1958,7 @@ void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, r
pos[0] = rect->xmin;
pos[1] = a;
- BKE_tracking_undistort_v2(tracking, pos, warped_pos);
+ apply_distortion(tracking, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -1942,7 +1967,7 @@ void BKE_tracking_max_undistortion_delta_across_bound(MovieTracking *tracking, r
pos[0] = rect->xmax;
pos[1] = a;
- BKE_tracking_undistort_v2(tracking, pos, warped_pos);
+ apply_distortion(tracking, pos, warped_pos);
delta[0] = max_ff(delta[0], fabsf(pos[0] - warped_pos[0]));
delta[1] = max_ff(delta[1], fabsf(pos[1] - warped_pos[1]));
@@ -2007,14 +2032,14 @@ ImBuf *BKE_tracking_sample_pattern(int frame_width, int frame_height, ImBuf *sea
}
if (search_ibuf->rect_float) {
- libmv_samplePlanarPatch(search_ibuf->rect_float,
- search_ibuf->x, search_ibuf->y, 4,
- src_pixel_x, src_pixel_y,
- num_samples_x, num_samples_y,
- mask,
- pattern_ibuf->rect_float,
- &warped_position_x,
- &warped_position_y);
+ libmv_samplePlanarPatchFloat(search_ibuf->rect_float,
+ search_ibuf->x, search_ibuf->y, 4,
+ src_pixel_x, src_pixel_y,
+ num_samples_x, num_samples_y,
+ mask,
+ pattern_ibuf->rect_float,
+ &warped_position_x,
+ &warped_position_y);
}
else {
libmv_samplePlanarPatchByte((unsigned char *) search_ibuf->rect,
@@ -2175,10 +2200,10 @@ void BKE_tracking_disable_channels(ImBuf *ibuf, bool disable_red, bool disable_g
/* ** Channels sort comparators ** */
-static int channels_alpha_sort(void *a, void *b)
+static int channels_alpha_sort(const void *a, const void *b)
{
- MovieTrackingDopesheetChannel *channel_a = a;
- MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
if (BLI_strcasecmp(channel_a->track->name, channel_b->track->name) > 0)
return 1;
@@ -2186,10 +2211,10 @@ static int channels_alpha_sort(void *a, void *b)
return 0;
}
-static int channels_total_track_sort(void *a, void *b)
+static int channels_total_track_sort(const void *a, const void *b)
{
- MovieTrackingDopesheetChannel *channel_a = a;
- MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
if (channel_a->total_frames > channel_b->total_frames)
return 1;
@@ -2197,10 +2222,10 @@ static int channels_total_track_sort(void *a, void *b)
return 0;
}
-static int channels_longest_segment_sort(void *a, void *b)
+static int channels_longest_segment_sort(const void *a, const void *b)
{
- MovieTrackingDopesheetChannel *channel_a = a;
- MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
if (channel_a->max_segment > channel_b->max_segment)
return 1;
@@ -2208,10 +2233,10 @@ static int channels_longest_segment_sort(void *a, void *b)
return 0;
}
-static int channels_average_error_sort(void *a, void *b)
+static int channels_average_error_sort(const void *a, const void *b)
{
- MovieTrackingDopesheetChannel *channel_a = a;
- MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
if (channel_a->track->error > channel_b->track->error)
return 1;
@@ -2219,7 +2244,7 @@ static int channels_average_error_sort(void *a, void *b)
return 0;
}
-static int channels_alpha_inverse_sort(void *a, void *b)
+static int channels_alpha_inverse_sort(const void *a, const void *b)
{
if (channels_alpha_sort(a, b))
return 0;
@@ -2227,7 +2252,7 @@ static int channels_alpha_inverse_sort(void *a, void *b)
return 1;
}
-static int channels_total_track_inverse_sort(void *a, void *b)
+static int channels_total_track_inverse_sort(const void *a, const void *b)
{
if (channels_total_track_sort(a, b))
return 0;
@@ -2235,7 +2260,7 @@ static int channels_total_track_inverse_sort(void *a, void *b)
return 1;
}
-static int channels_longest_segment_inverse_sort(void *a, void *b)
+static int channels_longest_segment_inverse_sort(const void *a, const void *b)
{
if (channels_longest_segment_sort(a, b))
return 0;
@@ -2243,10 +2268,10 @@ static int channels_longest_segment_inverse_sort(void *a, void *b)
return 1;
}
-static int channels_average_error_inverse_sort(void *a, void *b)
+static int channels_average_error_inverse_sort(const void *a, const void *b)
{
- MovieTrackingDopesheetChannel *channel_a = a;
- MovieTrackingDopesheetChannel *channel_b = b;
+ const MovieTrackingDopesheetChannel *channel_a = a;
+ const MovieTrackingDopesheetChannel *channel_b = b;
if (channel_a->track->error < channel_b->track->error)
return 1;
diff --git a/source/blender/blenkernel/intern/tracking_region_tracker.c b/source/blender/blenkernel/intern/tracking_region_tracker.c
index 76b7ad5d982..c41106f37cb 100644
--- a/source/blender/blenkernel/intern/tracking_region_tracker.c
+++ b/source/blender/blenkernel/intern/tracking_region_tracker.c
@@ -501,7 +501,7 @@ static void tracking_scale_marker_search(const MovieTrackingMarker *old_marker,
static void tracking_insert_new_marker(MovieTrackingContext *context, MovieTrackingTrack *track,
const MovieTrackingMarker *old_marker, int curfra, bool tracked,
int frame_width, int frame_height,
- double dst_pixel_x[5], double dst_pixel_y[5])
+ const double dst_pixel_x[5], const double dst_pixel_y[5])
{
MovieTrackingMarker new_marker;
int frame_delta = context->backwards ? -1 : 1;
@@ -725,6 +725,35 @@ void BKE_tracking_context_finish(MovieTrackingContext *context)
}
}
+static bool refine_marker_reference_frame_get(MovieTrackingTrack *track,
+ MovieTrackingMarker *marker,
+ bool backwards,
+ int *reference_framenr)
+{
+ const MovieTrackingMarker *first_marker = track->markers;
+ const MovieTrackingMarker *last_marker = track->markers + track->markersnr - 1;
+ MovieTrackingMarker *reference = backwards ? marker + 1 : marker - 1;
+
+ while (reference >= first_marker &&
+ reference <= last_marker &&
+ (reference->flag & MARKER_DISABLED) != 0)
+ {
+ if (backwards)
+ reference++;
+ else
+ reference--;
+ }
+
+ if (reference < first_marker ||
+ reference > last_marker)
+ {
+ return false;
+ }
+
+ *reference_framenr = reference->framenr;
+ return (reference->flag & MARKER_DISABLED) == 0;
+}
+
/* Refine marker's position using previously known keyframe.
* Direction of searching for a keyframe depends on backwards flag,
* which means if backwards is false, previous keyframe will be as
@@ -748,14 +777,15 @@ void BKE_tracking_refine_marker(MovieClip *clip, MovieTrackingTrack *track, Movi
BKE_movieclip_get_size(clip, &user, &frame_width, &frame_height);
- /* Get an image buffer for reference frame, also gets reference marker.
- *
- * Usually tracking_context_get_reference_ibuf will return current frame
- * if marker is keyframed, which is correct for normal tracking. But here
- * we'll want to have next/previous frame in such cases. So let's use small
- * magic with original frame number used to get reference frame for.
- */
- reference_framenr = backwards ? marker->framenr + 1 : marker->framenr - 1;
+ /* Get an image buffer for reference frame, also gets reference marker. */
+ if (!refine_marker_reference_frame_get(track,
+ marker,
+ backwards,
+ &reference_framenr))
+ {
+ return;
+ }
+
reference_ibuf = tracking_context_get_reference_ibuf(clip, &user, clip_flag, track, reference_framenr,
backwards, &reference_marker);
if (reference_ibuf == NULL) {
diff --git a/source/blender/blenkernel/intern/tracking_stabilize.c b/source/blender/blenkernel/intern/tracking_stabilize.c
index 8cdb547612c..eb224020977 100644
--- a/source/blender/blenkernel/intern/tracking_stabilize.c
+++ b/source/blender/blenkernel/intern/tracking_stabilize.c
@@ -82,7 +82,7 @@ static bool stabilization_median_point_get(MovieTracking *tracking, int framenr,
* NOTE: frame number should be in clip space, not scene space
*/
static void stabilization_calculate_data(MovieTracking *tracking, int framenr, int width, int height,
- float firstmedian[2], float median[2],
+ const float firstmedian[2], const float median[2],
float translation[2], float *scale, float *angle)
{
MovieTrackingStabilization *stab = &tracking->stabilization;
@@ -155,7 +155,7 @@ static float stabilization_calculate_autoscale_factor(MovieTracking *tracking, i
}
/* For every frame we calculate scale factor needed to eliminate black
- * aread and choose largest scale factor as final one.
+ * area and choose largest scale factor as final one.
*/
for (cfra = sfra; cfra <= efra; cfra++) {
float median[2];
@@ -439,6 +439,6 @@ void BKE_tracking_stabilization_data_to_mat4(int width, int height, float aspect
rotate_m4(rotation_mat, 'Z', angle); /* rotation matrix */
/* compose transformation matrix */
- mul_serie_m4(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat,
- scale_mat, inv_center_mat, NULL);
+ mul_m4_series(mat, translation_mat, center_mat, aspect_mat, rotation_mat, inv_aspect_mat,
+ scale_mat, inv_center_mat);
}
diff --git a/source/blender/blenkernel/intern/tracking_util.c b/source/blender/blenkernel/intern/tracking_util.c
index 4ebe8494101..0a8293630c7 100644
--- a/source/blender/blenkernel/intern/tracking_util.c
+++ b/source/blender/blenkernel/intern/tracking_util.c
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/blenkernel/tracking_util.c
+/** \file blender/blenkernel/intern/tracking_util.c
* \ingroup bke
*
* This file contains implementation of function which are used
diff --git a/source/blender/blenkernel/intern/treehash.c b/source/blender/blenkernel/intern/treehash.c
index fb55e3d2137..866502c4ae1 100644
--- a/source/blender/blenkernel/intern/treehash.c
+++ b/source/blender/blenkernel/intern/treehash.c
@@ -59,7 +59,7 @@ static TseGroup *tse_group_create(void)
static void tse_group_add(TseGroup *tse_group, TreeStoreElem *elem)
{
- if (tse_group->size == tse_group->allocated) {
+ if (UNLIKELY(tse_group->size == tse_group->allocated)) {
tse_group->allocated *= 2;
tse_group->elems = MEM_reallocN(tse_group->elems, sizeof(TreeStoreElem *) * tse_group->allocated);
}
@@ -91,7 +91,7 @@ static unsigned int tse_hash(const void *ptr)
return hash.u_int;
}
-static int tse_cmp(const void *a, const void *b)
+static bool tse_cmp(const void *a, const void *b)
{
const TreeStoreElem *tse_a = a;
const TreeStoreElem *tse_b = b;
diff --git a/source/blender/blenkernel/intern/unit.c b/source/blender/blenkernel/intern/unit.c
index de6424f3145..5a2c77b5619 100644
--- a/source/blender/blenkernel/intern/unit.c
+++ b/source/blender/blenkernel/intern/unit.c
@@ -41,6 +41,8 @@
# include "BLI_winstuff.h"
#endif
+/* no BKE or DNA includes! */
+
#define TEMP_STR_SIZE 256
#define SEP_CHR '#'
@@ -349,7 +351,7 @@ static void unit_dual_convert(double value, bUnitCollection *usys, bUnitDef **un
static size_t unit_as_string(char *str, int len_max, double value, int prec, bUnitCollection *usys,
/* non exposed options */
- bUnitDef *unit, char pad)
+ const bUnitDef *unit, char pad)
{
double value_conv;
size_t len, i;
@@ -456,7 +458,7 @@ size_t bUnit_AsString(char *str, int len_max, double value, int prec, int system
return unit_as_string(str, len_max, value, prec, usys, NULL, pad ? ' ' : '\0');
}
-BLI_INLINE int isalpha_or_utf8(const int ch)
+BLI_INLINE bool isalpha_or_utf8(const int ch)
{
return (ch >= 128 || isalpha(ch));
}
@@ -493,11 +495,11 @@ static const char *unit_find_str(const char *str, const char *substr)
*
* "1m1cm+2mm" - Original value
* "1*1#1*0.01#+2*0.001#" - Replace numbers
- * "1*1,1*0.01 +2*0.001 " - Add comma's if ( - + * / % ^ < > ) not found in between
+ * "1*1+1*0.01 +2*0.001 " - Add add signs if ( + - * / | & ~ < > ^ ! = % ) not found in between
*
*/
-/* not too strict, (- = * /) are most common */
+/* not too strict, (+ - * /) are most common */
static bool ch_is_op(char op)
{
switch (op) {
@@ -514,9 +516,11 @@ static bool ch_is_op(char op)
case '!':
case '=':
case '%':
- return 1;
+ return true;
+ break;
default:
- return 0;
+ return false;
+ break;
}
}
@@ -536,7 +540,7 @@ static int unit_scale_str(char *str, int len_max, char *str_tmp, double scale_pr
len_name = strlen(replace_str);
len_move = (len - (found_ofs + len_name)) + 1; /* 1+ to copy the string terminator */
- len_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "*%g"SEP_STR, unit->scalar / scale_pref); /* # removed later */
+ len_num = BLI_snprintf(str_tmp, TEMP_STR_SIZE, "*%.9g"SEP_STR, unit->scalar / scale_pref); /* # removed later */
if (len_num > len_max)
len_num = len_max;
@@ -579,14 +583,42 @@ static int unit_replace(char *str, int len_max, char *str_tmp, double scale_pref
return ofs;
}
-static int unit_find(const char *str, bUnitDef *unit)
+static bool unit_find(const char *str, bUnitDef *unit)
{
- if (unit_find_str(str, unit->name_short)) return 1;
- if (unit_find_str(str, unit->name_plural)) return 1;
- if (unit_find_str(str, unit->name_alt)) return 1;
- if (unit_find_str(str, unit->name)) return 1;
+ if (unit_find_str(str, unit->name_short)) return true;
+ if (unit_find_str(str, unit->name_plural)) return true;
+ if (unit_find_str(str, unit->name_alt)) return true;
+ if (unit_find_str(str, unit->name)) return true;
- return 0;
+ return false;
+}
+
+static bUnitDef *unit_detect_from_str(bUnitCollection *usys, const char *str, const char *str_prev)
+{
+ /* Try to find a default unit from current or previous string.
+ * This allows us to handle cases like 2 + 2mm, people would expect to get 4mm, not 2.002m!
+ * Note this does not handle corner cases like 2 + 2cm + 1 + 2.5mm... We can't support everything. */
+ bUnitDef *unit = NULL;
+
+ /* see which units the new value has */
+ for (unit = usys->units; unit->name; unit++) {
+ if (unit_find(str, unit))
+ break;
+ }
+ /* Else, try to infer the default unit from the previous string. */
+ if (str_prev && (unit == NULL || unit->name == NULL)) {
+ /* see which units the original value had */
+ for (unit = usys->units; unit->name; unit++) {
+ if (unit_find(str_prev, unit))
+ break;
+ }
+ }
+ /* Else, fall back to default unit. */
+ if (unit == NULL || unit->name == NULL) {
+ unit = unit_default(usys);
+ }
+
+ return unit;
}
/* make a copy of the string that replaces the units with numbers
@@ -597,37 +629,58 @@ static int unit_find(const char *str, bUnitDef *unit)
* 10.1km -> 10.1*1000.0
* ...will be resolved by python.
*
- * values will be split by a comma's
- * 5'2" -> 5'0.0254, 2*0.3048
+ * values will be split by an add sign
+ * 5'2" -> 5*0.3048 + 2*0.0254
*
* str_prev is optional, when valid it is used to get a base unit when none is set.
*
* return true of a change was made.
*/
-int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
+bool bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double scale_pref, int system, int type)
{
bUnitCollection *usys = unit_get_system(system, type);
- bUnitDef *unit;
+ bUnitDef *unit = NULL, *default_unit;
+ double scale_pref_base = scale_pref;
char str_tmp[TEMP_STR_SIZE];
- int changed = 0;
+ bool changed = false;
if (usys == NULL || usys->units[0].name == NULL) {
- return 0;
+ return changed;
}
/* make lowercase */
BLI_ascii_strtolower(str, len_max);
+ /* Try to find a default unit from current or previous string. */
+ default_unit = unit_detect_from_str(usys, str, str_prev);
+
+ /* We apply the default unit to the whole expression (default unit is now the reference '1.0' one). */
+ scale_pref_base *= default_unit->scalar;
+
+ /* Apply the default unit on the whole expression, this allows to handle nasty cases like '2+2in'. */
+ if (BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)*%.9g", str, default_unit->scalar) < sizeof(str_tmp)) {
+ strncpy(str, str_tmp, len_max);
+ }
+ else {
+ /* BLI_snprintf would not fit into str_tmp, cant do much in this case
+ * check for this because otherwise bUnit_ReplaceString could call its self forever */
+ return changed;
+ }
+
for (unit = usys->units; unit->name; unit++) {
/* in case there are multiple instances */
- while (unit_replace(str, len_max, str_tmp, scale_pref, unit))
+ while (unit_replace(str, len_max, str_tmp, scale_pref_base, unit))
changed = true;
}
unit = NULL;
{
/* try other unit systems now, so we can evaluate imperial when metric is set for eg. */
+ /* Note that checking other systems at that point means we do not support their units as 'default' one.
+ * In other words, when in metrics, typing '2+2in' will give 2 meters 2 inches, not 4 inches.
+ * I do think this is the desired behavior!
+ */
bUnitCollection *usys_iter;
int system_iter;
@@ -638,7 +691,7 @@ int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sca
for (unit = usys_iter->units; unit->name; unit++) {
int ofs = 0;
/* in case there are multiple instances */
- while ((ofs = unit_replace(str + ofs, len_max - ofs, str_tmp, scale_pref, unit)))
+ while ((ofs = unit_replace(str + ofs, len_max - ofs, str_tmp, scale_pref_base, unit)))
changed = true;
}
}
@@ -647,35 +700,9 @@ int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sca
}
unit = NULL;
- if (changed == 0) {
- /* no units given so infer a unit from the previous string or default */
- if (str_prev) {
- /* see which units the original value had */
- for (unit = usys->units; unit->name; unit++) {
- if (unit_find(str_prev, unit))
- break;
- }
- }
-
- if (unit == NULL || unit->name == NULL)
- unit = unit_default(usys);
-
- /* add the unit prefix and re-run, use brackets in case there was an expression given */
- if (BLI_snprintf(str_tmp, sizeof(str_tmp), "(%s)%s", str, unit->name) < sizeof(str_tmp)) {
- strncpy(str, str_tmp, len_max);
- return bUnit_ReplaceString(str, len_max, NULL, scale_pref, system, type);
- }
- else {
- /* BLI_snprintf would not fit into str_tmp, cant do much in this case
- * check for this because otherwise bUnit_ReplaceString could call its self forever */
- return 0;
- }
-
- }
-
- /* replace # with commas when there is no operator between it and the next number
+ /* replace # with add sign when there is no operator between it and the next number
*
- * "1*1# 3*100# * 3" -> "1 *1, 3 *100 * 3"
+ * "1*1# 3*100# * 3" -> "1*1+ 3*100 * 3"
*
* */
{
@@ -683,25 +710,19 @@ int bUnit_ReplaceString(char *str, int len_max, const char *str_prev, double sca
const char *ch = str;
while ((str_found = strchr(str_found, SEP_CHR))) {
+ bool op_found = false;
- int op_found = 0;
- /* any operators after this?*/
+ /* any operators after this? */
for (ch = str_found + 1; *ch != '\0'; ch++) {
-
if (*ch == ' ' || *ch == '\t') {
- /* do nothing */
- }
- else if (ch_is_op(*ch) || *ch == ',') { /* found an op, no need to insert a ',' */
- op_found = 1;
- break;
- }
- else { /* found a non-op character */
- op_found = 0;
- break;
+ continue;
}
+ op_found = (ch_is_op(*ch) || ELEM(*ch, ',', ')'));
+ break;
}
- *str_found++ = op_found ? ' ' : ',';
+ /* If found an op, comma or closing parenthesis, no need to insert a '+', else we need it. */
+ *str_found++ = op_found ? ' ' : '+';
}
}
@@ -771,7 +792,7 @@ double bUnit_BaseScalar(int system, int type)
}
/* external access */
-int bUnit_IsValid(int system, int type)
+bool bUnit_IsValid(int system, int type)
{
return !(system < 0 || system > UNIT_SYSTEM_TOT || type < 0 || type > B_UNIT_TYPE_TOT);
}
diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c
index 5065c3ae04f..8e3c92314e6 100644
--- a/source/blender/blenkernel/intern/world.c
+++ b/source/blender/blenkernel/intern/world.c
@@ -142,8 +142,7 @@ World *localize_world(World *wrld)
World *wrldn;
int a;
- wrldn = BKE_libblock_copy(&wrld->id);
- BLI_remlink(&G.main->world, wrldn);
+ wrldn = BKE_libblock_copy_nolib(&wrld->id, false);
for (a = 0; a < MAX_MTEX; a++) {
if (wrld->mtex[a]) {
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index a9f040b8650..aef44993912 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -110,7 +110,7 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
}
#endif
#ifdef WITH_FFMPEG
- if (ELEM4(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) {
+ if (ELEM(imtype, R_IMF_IMTYPE_FFMPEG, R_IMF_IMTYPE_H264, R_IMF_IMTYPE_XVID, R_IMF_IMTYPE_THEORA)) {
mh.start_movie = BKE_ffmpeg_start;
mh.append_movie = BKE_ffmpeg_append;
mh.end_movie = BKE_ffmpeg_end;
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index dbceba288c7..739db7b7bdb 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -30,13 +30,6 @@
#include <string.h>
#include <stdio.h>
-#if defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
-/* This does not seem necessary or present on MSVC 8, but may be needed in earlier versions? */
-#if _MSC_VER < 1400
-#include <stdint.h>
-#endif
-#endif
-
#include <stdlib.h>
#include <libavformat/avformat.h>
@@ -105,6 +98,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);
/* Delete a picture buffer */
@@ -422,6 +416,11 @@ static AVFrame *generate_video_frame(uint8_t *pixels, ReportList *reports)
current_frame->data, current_frame->linesize);
delete_picture(rgb_frame);
}
+
+ current_frame->format = PIX_FMT_BGR32;
+ current_frame->width = width;
+ current_frame->height = height;
+
return current_frame;
}
@@ -488,6 +487,19 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char
void *iter;
IDProperty *curr;
+ /* TODO(sergey): This is actually rather stupid, because changing
+ * codec settings in render panel would also set expert options.
+ *
+ * But we need ti here in order to get rid of deprecated settings
+ * when opening old files in new blender.
+ *
+ * For as long we don't allow editing properties in the interface
+ * it's all good. bug if we allow editing them, we'll need to
+ * repace it with some smarter code which would port settings
+ * from deprecated to new one.
+ */
+ ffmpeg_set_expert_options(rd);
+
if (!rd->ffcodecdata.properties) {
return;
}
@@ -684,12 +696,12 @@ static AVStream *alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
}
if (codec->sample_fmts) {
- /* check if the prefered sample format for this codec is supported.
+ /* check if the preferred sample format for this codec is supported.
* this is because, depending on the version of libav, and with the whole ffmpeg/libav fork situation,
* you have various implementations around. float samples in particular are not always supported.
*/
const enum AVSampleFormat *p = codec->sample_fmts;
- for (; *p!=-1; p++) {
+ for (; *p != -1; p++) {
if (*p == st->codec->sample_fmt)
break;
}
diff --git a/source/blender/blenlib/BLI_array.h b/source/blender/blenlib/BLI_array.h
index 4110c85c2a5..db33c5cec8b 100644
--- a/source/blender/blenlib/BLI_array.h
+++ b/source/blender/blenlib/BLI_array.h
@@ -75,36 +75,39 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
* switching to dynamic heap allocation */
#define BLI_array_staticdeclare(arr, maxstatic) \
int _##arr##_count = 0; \
- char _##arr##_static[maxstatic * sizeof(arr)]
+ char _##arr##_static[maxstatic * sizeof(*(arr))]
/* this returns the logical size of the array, not including buffering. */
-#define BLI_array_count(arr) _##arr##_count
+#define BLI_array_count(arr) ((void)0, _##arr##_count)
/* Grow the array by a fixed number of items.
*
* Allow for a large 'num' value when the new size is more than double
* to allocate the exact sized array. */
-#define BLI_array_grow_items(arr, num) (( \
+#define BLI_array_reserve(arr, num) (void)( \
(((void *)(arr) == NULL) && \
((void *)(_##arr##_static) != NULL) && \
/* don't add _##arr##_count below because it must be zero */ \
- (_bli_array_totalsize_static(arr) >= _##arr##_count + num)) ? \
+ (_bli_array_totalsize_static(arr) >= _##arr##_count + (num))) ? \
/* we have an empty array and a static var big enough */ \
(void)(arr = (void *)_##arr##_static) \
: \
/* use existing static array or allocate */ \
- (LIKELY(_bli_array_totalsize(arr) >= _##arr##_count + num) ? \
+ (LIKELY(_bli_array_totalsize(arr) >= _##arr##_count + (num)) ? \
(void)0 /* do nothing */ : \
_bli_array_grow_func((void **)&(arr), _##arr##_static, \
sizeof(*(arr)), _##arr##_count, num, \
- "BLI_array." #arr), \
- (void)0) /* msvc2008 needs this */ \
- ), \
- /* increment the array count, all conditions above are accounted for. */ \
- (_##arr##_count += num))
+ "BLI_array." #arr)) \
+ )
+
/* returns length of array */
-#define BLI_array_grow_one(arr) BLI_array_grow_items(arr, 1)
+
+#define BLI_array_grow_items(arr, num) \
+ (BLI_array_reserve(arr, num), (_##arr##_count += num))
+
+#define BLI_array_grow_one(arr) \
+ BLI_array_grow_items(arr, 1)
/* appends an item to the array. */
@@ -121,9 +124,9 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
(&arr[_##arr##_count - 1]) \
)
-#define BLI_array_reserve(arr, num) \
- BLI_array_grow_items(arr, num), (void)(_##arr##_count -= (num))
-
+/* appends (grows) & returns a pointer to the uninitialized memory */
+#define BLI_array_append_ret(arr) \
+ (BLI_array_reserve(arr, 1), &arr[(_##arr##_count++)])
#define BLI_array_free(arr) \
if (arr && (char *)arr != _##arr##_static) { \
@@ -144,7 +147,7 @@ void _bli_array_grow_func(void **arr_p, const void *arr_static,
/* set the count of the array, doesn't actually increase the allocated array
* size. don't use this unless you know what you're doing. */
-#define BLI_array_length_set(arr, count) \
+#define BLI_array_count_set(arr, count) \
{ _##arr##_count = (count); }(void)0
/* only to prevent unused warnings */
@@ -182,5 +185,8 @@ 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)
+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)
#endif /* __BLI_ARRAY_H__ */
diff --git a/source/blender/blenlib/BLI_bitmap.h b/source/blender/blenlib/BLI_bitmap.h
index cf10fe53a5d..594bf89b667 100644
--- a/source/blender/blenlib/BLI_bitmap.h
+++ b/source/blender/blenlib/BLI_bitmap.h
@@ -37,17 +37,17 @@ typedef unsigned int BLI_bitmap;
/* internal use */
/* 2^5 = 32 (bits) */
-#define BLI_BITMAP_POWER 5
+#define _BITMAP_POWER 5
/* 0b11111 */
-#define BLI_BITMAP_MASK 31
+#define _BITMAP_MASK 31
/* number of blocks needed to hold '_tot' bits */
-#define BLI_BITMAP_NUM_BLOCKS(_tot) \
- (((_tot) >> BLI_BITMAP_POWER) + 1)
+#define _BITMAP_NUM_BLOCKS(_tot) \
+ (((_tot) >> _BITMAP_POWER) + 1)
/* size (in bytes) used to hold '_tot' bits */
#define BLI_BITMAP_SIZE(_tot) \
- (BLI_BITMAP_NUM_BLOCKS(_tot) * sizeof(unsigned int))
+ (_BITMAP_NUM_BLOCKS(_tot) * sizeof(BLI_bitmap))
/* allocate memory for a bitmap with '_tot' bits; free
* with MEM_freeN() */
@@ -55,35 +55,57 @@ typedef unsigned int BLI_bitmap;
((BLI_bitmap *)MEM_callocN(BLI_BITMAP_SIZE(_tot), \
_alloc_string))
+/* allocate a bitmap on the stack */
+#define BLI_BITMAP_NEW_ALLOCA(_tot) \
+ ((BLI_bitmap *)memset(alloca(BLI_BITMAP_SIZE(_tot)), 0, BLI_BITMAP_SIZE(_tot)))
+
/* get the value of a single bit at '_index' */
-#define BLI_BITMAP_GET(_bitmap, _index) \
- ((_bitmap)[(_index) >> BLI_BITMAP_POWER] & \
- (1u << ((_index) & BLI_BITMAP_MASK)))
+#define BLI_BITMAP_TEST(_bitmap, _index) \
+ (CHECK_TYPE_INLINE(_bitmap, BLI_bitmap *), \
+ ((_bitmap)[(_index) >> _BITMAP_POWER] & \
+ (1u << ((_index) & _BITMAP_MASK))))
-#define BLI_BITMAP_GET_BOOL(_bitmap, _index) \
- (BLI_BITMAP_GET(_bitmap, _index) != 0)
+#define BLI_BITMAP_TEST_BOOL(_bitmap, _index) \
+ (CHECK_TYPE_INLINE(_bitmap, BLI_bitmap *), \
+ (BLI_BITMAP_TEST(_bitmap, _index) != 0))
/* set the value of a single bit at '_index' */
-#define BLI_BITMAP_SET(_bitmap, _index) \
- ((_bitmap)[(_index) >> BLI_BITMAP_POWER] |= \
- (1u << ((_index) & BLI_BITMAP_MASK)))
+#define BLI_BITMAP_ENABLE(_bitmap, _index) \
+ (CHECK_TYPE_INLINE(_bitmap, BLI_bitmap *), \
+ ((_bitmap)[(_index) >> _BITMAP_POWER] |= \
+ (1u << ((_index) & _BITMAP_MASK))))
/* clear the value of a single bit at '_index' */
-#define BLI_BITMAP_CLEAR(_bitmap, _index) \
- ((_bitmap)[(_index) >> BLI_BITMAP_POWER] &= \
- ~(1u << ((_index) & BLI_BITMAP_MASK)))
+#define BLI_BITMAP_DISABLE(_bitmap, _index) \
+ (CHECK_TYPE_INLINE(_bitmap, BLI_bitmap *), \
+ ((_bitmap)[(_index) >> _BITMAP_POWER] &= \
+ ~(1u << ((_index) & _BITMAP_MASK))))
/* set or clear the value of a single bit at '_index' */
-#define BLI_BITMAP_MODIFY(_bitmap, _index, _set) \
- do { \
+#define BLI_BITMAP_SET(_bitmap, _index, _set) \
+ { \
+ CHECK_TYPE(_bitmap, BLI_bitmap *); \
+ if (_set) \
+ BLI_BITMAP_ENABLE(_bitmap, _index); \
+ else \
+ BLI_BITMAP_DISABLE(_bitmap, _index); \
+ } (void)0
+
+/* set or clear the value of the whole bitmap (needs size info) */
+#define BLI_BITMAP_SET_ALL(_bitmap, _set, _tot) \
+ { \
+ CHECK_TYPE(_bitmap, BLI_bitmap *); \
if (_set) \
- BLI_BITMAP_SET(_bitmap, _index); \
+ memset(_bitmap, UCHAR_MAX, BLI_BITMAP_SIZE(_tot)); \
else \
- BLI_BITMAP_CLEAR(_bitmap, _index); \
- } while (0)
+ memset(_bitmap, 0, BLI_BITMAP_SIZE(_tot)); \
+ } (void)0
/* resize bitmap to have space for '_tot' bits */
#define BLI_BITMAP_RESIZE(_bitmap, _tot) \
- (_bitmap) = MEM_reallocN(_bitmap, BLI_BITMAP_SIZE(_tot))
+ { \
+ CHECK_TYPE(_bitmap, BLI_bitmap *); \
+ (_bitmap) = MEM_reallocN(_bitmap, BLI_BITMAP_SIZE(_tot)); \
+ } (void)0
#endif
diff --git a/source/blender/blenlib/BLI_buffer.h b/source/blender/blenlib/BLI_buffer.h
index 9c4b4b00b24..700abcad9bd 100644
--- a/source/blender/blenlib/BLI_buffer.h
+++ b/source/blender/blenlib/BLI_buffer.h
@@ -88,13 +88,15 @@ enum {
#define BLI_buffer_resize_data(buffer_, type_, new_count_) ( \
(BLI_buffer_resize(buffer_, new_count_), new_count_ ? BLI_buffer_array(buffer_, type_) : NULL))
-
-
#define BLI_buffer_append(buffer_, type_, val_) ( \
BLI_buffer_resize(buffer_, (buffer_)->count + 1), \
(BLI_buffer_at(buffer_, type_, (buffer_)->count - 1) = val_) \
)
+#define BLI_buffer_empty(buffer_) { \
+ (buffer_)->count = 0; \
+} (void)0
+
/* Never decreases the amount of memory allocated */
void BLI_buffer_resize(BLI_Buffer *buffer, int new_count);
diff --git a/source/blender/blenlib/BLI_callbacks.h b/source/blender/blenlib/BLI_callbacks.h
index 8d5ea91c422..2f963cfac51 100644
--- a/source/blender/blenlib/BLI_callbacks.h
+++ b/source/blender/blenlib/BLI_callbacks.h
@@ -29,12 +29,20 @@ struct bContext;
struct Main;
struct ID;
+/**
+ * Common suffix uses:
+ * - ``_PRE/_POST``:
+ * For handling discrete non-interactive events.
+ * - ``_INIT/_COMPLETE/_CANCEL``:
+ * For handling jobs (which may in turn cause other handlers to be called).
+ */
typedef enum {
BLI_CB_EVT_FRAME_CHANGE_PRE,
BLI_CB_EVT_FRAME_CHANGE_POST,
BLI_CB_EVT_RENDER_PRE,
BLI_CB_EVT_RENDER_POST,
BLI_CB_EVT_RENDER_STATS,
+ BLI_CB_EVT_RENDER_INIT,
BLI_CB_EVT_RENDER_COMPLETE,
BLI_CB_EVT_RENDER_CANCEL,
BLI_CB_EVT_LOAD_PRE,
@@ -45,6 +53,7 @@ typedef enum {
BLI_CB_EVT_SCENE_UPDATE_POST,
BLI_CB_EVT_GAME_PRE,
BLI_CB_EVT_GAME_POST,
+ BLI_CB_EVT_VERSION_UPDATE,
BLI_CB_EVT_TOT
} eCbEvent;
diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h
index 60a7d8dbd02..10c0752c9a7 100644
--- a/source/blender/blenlib/BLI_compiler_compat.h
+++ b/source/blender/blenlib/BLI_compiler_compat.h
@@ -32,4 +32,9 @@
# define alloca _alloca
#endif
+/* alloca is defined here for MinGW32 */
+#ifdef __MINGW32__
+# include <malloc.h>
+#endif
+
#endif /* __BLI_COMPILER_COMPAT_H__ */
diff --git a/source/blender/blenlib/BLI_compiler_typecheck.h b/source/blender/blenlib/BLI_compiler_typecheck.h
new file mode 100644
index 00000000000..551569b066d
--- /dev/null
+++ b/source/blender/blenlib/BLI_compiler_typecheck.h
@@ -0,0 +1,379 @@
+/*
+ * ***** 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_COMPILER_TYPECHECK_H__
+#define __BLI_COMPILER_TYPECHECK_H__
+
+/** \file BLI_compiler_typecheck.h
+ * \ingroup bli
+ *
+ * Type checking macros (often used to ensure valid use of macro args).
+ * These depend on compiler extensions and c11 in some cases.
+ */
+
+/* Causes warning:
+ * incompatible types when assigning to type 'Foo' from type 'Bar'
+ * ... the compiler optimizes away the temp var */
+#ifdef __GNUC__
+#define CHECK_TYPE(var, type) { \
+ typeof(var) *__tmp; \
+ __tmp = (type *)NULL; \
+ (void)__tmp; \
+} (void)0
+
+#define CHECK_TYPE_PAIR(var_a, var_b) { \
+ typeof(var_a) *__tmp; \
+ __tmp = (typeof(var_b) *)NULL; \
+ (void)__tmp; \
+} (void)0
+
+#define CHECK_TYPE_PAIR_INLINE(var_a, var_b) ((void)({ \
+ typeof(var_a) *__tmp; \
+ __tmp = (typeof(var_b) *)NULL; \
+ (void)__tmp; \
+}))
+
+#else
+# define CHECK_TYPE(var, type)
+# define CHECK_TYPE_PAIR(var_a, var_b)
+# define CHECK_TYPE_PAIR_INLINE(var_a, var_b) (void)0
+#endif
+
+/* can be used in simple macros */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# define CHECK_TYPE_INLINE(val, type) \
+ (void)((void)(((type)0) != (0 ? (val) : ((type)0))), \
+ _Generic((val), type: 0, const type: 0))
+#else
+# define CHECK_TYPE_INLINE(val, type) \
+ ((void)(((type)0) != (0 ? (val) : ((type)0))))
+#endif
+
+#define CHECK_TYPE_NONCONST(var) { \
+ void *non_const = 0 ? (var) : NULL; \
+ (void)non_const; \
+} (void)0
+
+/**
+ * CHECK_TYPE_ANY: handy macro, eg:
+ * ``CHECK_TYPE_ANY(var, Foo *, Bar *, Baz *)``
+ *
+ * excuse ridiculously long generated args.
+ * <pre>
+ * 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_CHECK_TYPE_ANY%d(v, %s) \\" % (i + 2, ", ".join(args)))
+ * print(" ((void)_Generic((v), %s))" % (": 0, ".join(args) + ": 0"))
+ * </pre>
+ */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+
+#define _VA_CHECK_TYPE_ANY2(v, a0) \
+ ((void)_Generic((v), a0: 0))
+#define _VA_CHECK_TYPE_ANY3(v, a0, b0) \
+ ((void)_Generic((v), a0: 0, b0: 0))
+#define _VA_CHECK_TYPE_ANY4(v, a0, b0, c0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0))
+#define _VA_CHECK_TYPE_ANY5(v, a0, b0, c0, d0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0))
+#define _VA_CHECK_TYPE_ANY6(v, a0, b0, c0, d0, e0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0))
+#define _VA_CHECK_TYPE_ANY7(v, a0, b0, c0, d0, e0, f0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0))
+#define _VA_CHECK_TYPE_ANY8(v, a0, b0, c0, d0, e0, f0, g0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0))
+#define _VA_CHECK_TYPE_ANY9(v, a0, b0, c0, d0, e0, f0, g0, h0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0))
+#define _VA_CHECK_TYPE_ANY10(v, a0, b0, c0, d0, e0, f0, g0, h0, i0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0))
+#define _VA_CHECK_TYPE_ANY11(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0))
+#define _VA_CHECK_TYPE_ANY12(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0))
+#define _VA_CHECK_TYPE_ANY13(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0))
+#define _VA_CHECK_TYPE_ANY14(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0))
+#define _VA_CHECK_TYPE_ANY15(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0))
+#define _VA_CHECK_TYPE_ANY16(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0))
+#define _VA_CHECK_TYPE_ANY17(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0))
+#define _VA_CHECK_TYPE_ANY18(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0))
+#define _VA_CHECK_TYPE_ANY19(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0))
+#define _VA_CHECK_TYPE_ANY20(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0))
+#define _VA_CHECK_TYPE_ANY21(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0))
+#define _VA_CHECK_TYPE_ANY22(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0))
+#define _VA_CHECK_TYPE_ANY23(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, \
+ v0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0))
+#define _VA_CHECK_TYPE_ANY24(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, \
+ v0, w0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0))
+#define _VA_CHECK_TYPE_ANY25(v, a0, b0, c0, d0, e0, f0, g0, h0, i0, j0, k0, l0, m0, n0, o0, p0, q0, r0, s0, t0, u0, \
+ v0, w0, x0) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0))
+#define _VA_CHECK_TYPE_ANY26(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0))
+#define _VA_CHECK_TYPE_ANY27(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0))
+#define _VA_CHECK_TYPE_ANY28(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0))
+#define _VA_CHECK_TYPE_ANY29(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0))
+#define _VA_CHECK_TYPE_ANY30(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0))
+#define _VA_CHECK_TYPE_ANY31(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0))
+#define _VA_CHECK_TYPE_ANY32(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0))
+#define _VA_CHECK_TYPE_ANY33(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0))
+#define _VA_CHECK_TYPE_ANY34(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0))
+#define _VA_CHECK_TYPE_ANY35(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0))
+#define _VA_CHECK_TYPE_ANY36(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0))
+#define _VA_CHECK_TYPE_ANY37(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0))
+#define _VA_CHECK_TYPE_ANY38(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0))
+#define _VA_CHECK_TYPE_ANY39(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0))
+#define _VA_CHECK_TYPE_ANY40(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0))
+#define _VA_CHECK_TYPE_ANY41(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0))
+#define _VA_CHECK_TYPE_ANY42(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0))
+#define _VA_CHECK_TYPE_ANY43(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0))
+#define _VA_CHECK_TYPE_ANY44(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0))
+#define _VA_CHECK_TYPE_ANY45(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0))
+#define _VA_CHECK_TYPE_ANY46(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0))
+#define _VA_CHECK_TYPE_ANY47(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0))
+#define _VA_CHECK_TYPE_ANY48(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0))
+#define _VA_CHECK_TYPE_ANY49(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0))
+#define _VA_CHECK_TYPE_ANY50(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0))
+#define _VA_CHECK_TYPE_ANY51(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0))
+#define _VA_CHECK_TYPE_ANY52(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0))
+#define _VA_CHECK_TYPE_ANY53(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0))
+#define _VA_CHECK_TYPE_ANY54(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0))
+#define _VA_CHECK_TYPE_ANY55(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0))
+#define _VA_CHECK_TYPE_ANY56(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0, c2: 0))
+#define _VA_CHECK_TYPE_ANY57(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0, c2: 0, d2: 0))
+#define _VA_CHECK_TYPE_ANY58(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0, c2: 0, d2: 0, e2: 0))
+#define _VA_CHECK_TYPE_ANY59(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0))
+#define _VA_CHECK_TYPE_ANY60(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0))
+#define _VA_CHECK_TYPE_ANY61(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0))
+#define _VA_CHECK_TYPE_ANY62(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0, i2: 0))
+#define _VA_CHECK_TYPE_ANY63(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0, i2: 0, \
+ j2: 0))
+#define _VA_CHECK_TYPE_ANY64(v, 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) \
+ ((void)_Generic((v), a0: 0, b0: 0, c0: 0, d0: 0, e0: 0, f0: 0, g0: 0, h0: 0, i0: 0, j0: 0, k0: 0, l0: 0, m0: 0, \
+ n0: 0, o0: 0, p0: 0, q0: 0, r0: 0, s0: 0, t0: 0, u0: 0, v0: 0, w0: 0, x0: 0, y0: 0, z0: 0, a1: 0, b1: 0, c1: 0, \
+ d1: 0, e1: 0, f1: 0, g1: 0, h1: 0, i1: 0, j1: 0, k1: 0, l1: 0, m1: 0, n1: 0, o1: 0, p1: 0, q1: 0, r1: 0, s1: 0, \
+ t1: 0, u1: 0, v1: 0, w1: 0, x1: 0, y1: 0, z1: 0, a2: 0, b2: 0, c2: 0, d2: 0, e2: 0, f2: 0, g2: 0, h2: 0, i2: 0, \
+ j2: 0, k2: 0))
+# define CHECK_TYPE_ANY(...) VA_NARGS_CALL_OVERLOAD(_VA_CHECK_TYPE_ANY, __VA_ARGS__)
+#else
+# define CHECK_TYPE_ANY(...) (void)0
+#endif
+
+#endif /* __BLI_COMPILER_TYPECHECK_H__ */
diff --git a/source/blender/blenlib/BLI_dial.h b/source/blender/blenlib/BLI_dial.h
new file mode 100644
index 00000000000..c8b57e803d2
--- /dev/null
+++ b/source/blender/blenlib/BLI_dial.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_DIAL_H__
+#define __BLI_DIAL_H__
+
+/** \file BLI_dial.h
+ * \ingroup bli
+ *
+ * \note dials act similar to old rotation based phones and output an angle.
+ *
+ * They just are initialized with the center of the dial and a threshold value as input.
+ *
+ * When the distance of the current position of the dial from the center
+ * exceeds the threshold, this position is used to calculate the initial direction.
+ * After that, the angle from the initial direction is calculated based on
+ * current and previous directions of the digit, and returned to the user.
+ *
+ * Usage examples:
+ * \code
+ * float start_position[2] = {0.0f, 0.0f};
+ * float current_position[2];
+ * float threshold = 0.5f;
+ * float angle;
+ * Dial *dial;
+ *
+ * dial = BLI_dial_initialize(start_position, threshold);
+ *
+ * angle = BLI_dial_angle(dial, curent_position);
+ *
+ * MEM_freeN(dial);
+ *
+ * \endcode
+ */
+
+typedef struct Dial Dial;
+
+Dial *BLI_dial_initialize(float start_position[2], float threshold);
+
+float BLI_dial_angle(Dial *dial, float current_position[2]);
+
+#endif /* __BLI_DIAL_H__ */
diff --git a/source/blender/blenlib/BLI_dynstr.h b/source/blender/blenlib/BLI_dynstr.h
index 61bdf23cec1..7aa1c30e449 100644
--- a/source/blender/blenlib/BLI_dynstr.h
+++ b/source/blender/blenlib/BLI_dynstr.h
@@ -47,73 +47,17 @@ struct DynStr;
/** The abstract DynStr type */
typedef struct DynStr DynStr;
-/**
- * Create a new DynStr.
- *
- * \return Pointer to a new DynStr.
- */
-DynStr *BLI_dynstr_new(void);
+DynStr *BLI_dynstr_new(void) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
+void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr) ATTR_NONNULL();
+void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len) ATTR_NONNULL();
-/**
- * Append a c-string to a DynStr.
- *
- * \param ds The DynStr to append to.
- * \param cstr The c-string to append.
- */
-void BLI_dynstr_append(DynStr *ds, const char *cstr);
+void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...) ATTR_PRINTF_FORMAT(2, 3) ATTR_NONNULL(1, 2);
+void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args) ATTR_PRINTF_FORMAT(2, 0) ATTR_NONNULL(1, 2);
-/**
- * Append a length clamped c-string to a DynStr.
- *
- * \param ds The DynStr to append to.
- * \param cstr The c-string to append.
- * \param len The maximum length of the c-string to copy.
- */
-void BLI_dynstr_nappend(DynStr *ds, const char *cstr, int len);
-
-/**
- * Append a c-string to a DynStr, but with formatting like printf.
- *
- * \param ds The DynStr to append to.
- * \param format The printf format string to use.
- */
-void BLI_dynstr_appendf(DynStr *ds, const char *format, ...) ATTR_PRINTF_FORMAT(2, 3);
-void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args) ATTR_PRINTF_FORMAT(2, 0);
-
-/**
- * Find the length of a DynStr.
- *
- * \param ds The DynStr of interest.
- * \return The length of \a ds.
- */
-int BLI_dynstr_get_len(DynStr *ds);
-
-/**
- * Get a DynStr's contents as a c-string.
- * <i> The returned c-string should be freed
- * using MEM_freeN. </i>
- *
- * \param ds The DynStr of interest.
- * \return The contents of \a ds as a c-string.
- */
-char *BLI_dynstr_get_cstring(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>
- *
- * \param ds The DynStr of interest.
- * \param str The string to fill.
- */
-void BLI_dynstr_get_cstring_ex(DynStr *ds, char *str);
-
-/**
- * Free the DynStr
- *
- * \param ds The DynStr to free.
- */
-void BLI_dynstr_free(DynStr *ds);
+int BLI_dynstr_get_len(DynStr *ds) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+char *BLI_dynstr_get_cstring(DynStr *ds) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-#endif
+void BLI_dynstr_get_cstring_ex(DynStr *__restrict ds, char *__restrict str) ATTR_NONNULL();
+void BLI_dynstr_free(DynStr *ds) ATTR_NONNULL();
+#endif /* __BLI_DYNSTR_H__ */
diff --git a/source/blender/blenlib/BLI_edgehash.h b/source/blender/blenlib/BLI_edgehash.h
index 8e74ce3a9e3..a0455489d24 100644
--- a/source/blender/blenlib/BLI_edgehash.h
+++ b/source/blender/blenlib/BLI_edgehash.h
@@ -102,10 +102,12 @@ EdgeSet *BLI_edgeset_new_ex(const char *info,
const unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
EdgeSet *BLI_edgeset_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
int BLI_edgeset_size(EdgeSet *es) ATTR_WARN_UNUSED_RESULT;
-bool BLI_edgeset_reinsert(EdgeSet *es, unsigned int v0, unsigned int v1);
+bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1);
void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1);
bool BLI_edgeset_haskey(EdgeSet *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
void BLI_edgeset_free(EdgeSet *es);
+void BLI_edgeset_flag_set(EdgeSet *es, unsigned int flag);
+void BLI_edgeset_flag_clear(EdgeSet *es, unsigned int flag);
/* rely on inline api for now */
BLI_INLINE EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *gs) { return (EdgeSetIterator *)BLI_edgehashIterator_new((EdgeHash *)gs); }
@@ -114,5 +116,9 @@ BLI_INLINE void BLI_edgesetIterator_getKey(EdgeSetIterator *esi, unsigned int *r
BLI_INLINE void BLI_edgesetIterator_step(EdgeSetIterator *esi) { BLI_edgehashIterator_step((EdgeHashIterator *)esi); }
BLI_INLINE bool BLI_edgesetIterator_isDone(EdgeSetIterator *esi) { return BLI_edgehashIterator_isDone((EdgeHashIterator *)esi); }
+#ifdef DEBUG
+double BLI_edgehash_calc_quality(EdgeHash *eh);
+double BLI_edgeset_calc_quality(EdgeSet *es);
+#endif
#endif /* __BLI_EDGEHASH_H__ */
diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h
index 7c10e50acc4..4f451a6c741 100644
--- a/source/blender/blenlib/BLI_fileops.h
+++ b/source/blender/blenlib/BLI_fileops.h
@@ -59,7 +59,24 @@ int BLI_rename(const char *from, const char *to);
int BLI_delete(const char *path, bool dir, bool recursive);
int BLI_move(const char *path, const char *to);
int BLI_create_symlink(const char *path, const char *to);
-int BLI_stat(const char *path, struct stat *buffer);
+
+/* keep in sync with the definition of struct direntry in BLI_fileops_types.h */
+#ifdef WIN32
+# if defined(_MSC_VER) || defined(__MINGW64__)
+typedef struct _stat64 BLI_stat_t;
+# elif defined(__MINGW32__)
+typedef struct _stati64 BLI_stat_t;
+# else
+typedef struct _stat BLI_stat_t;
+# endif
+#else
+typedef struct stat BLI_stat_t;
+#endif
+
+int BLI_stat(const char *path, BLI_stat_t *buffer);
+#ifdef WIN32
+int BLI_wstat(const wchar_t *path, BLI_stat_t *buffer);
+#endif
/* Directories */
@@ -84,7 +101,9 @@ int BLI_access(const char *filename, int mode);
bool BLI_file_is_writable(const char *file);
bool BLI_file_touch(const char *file);
+#if 0 /* UNUSED */
int BLI_file_gzip(const char *from, const char *to);
+#endif
char *BLI_file_ungzip_to_mem(const char *from_file, int *r_size);
size_t BLI_file_descriptor_size(int file);
diff --git a/source/blender/blenlib/BLI_fileops_types.h b/source/blender/blenlib/BLI_fileops_types.h
index a7372c01e52..0e6eab687ad 100644
--- a/source/blender/blenlib/BLI_fileops_types.h
+++ b/source/blender/blenlib/BLI_fileops_types.h
@@ -45,12 +45,16 @@ struct direntry {
mode_t type;
char *relname;
char *path;
-#if (defined(WIN32) || defined(WIN64)) && !defined(__MINGW32__) && (_MSC_VER >= 1500)
+#ifdef WIN32 /* keep in sync with the definition of BLI_stat_t in BLI_fileops.h */
+# if defined(_MSC_VER) || defined(__MINGW64__)
struct _stat64 s;
-#elif defined(__MINGW32__)
+# elif defined(__MINGW32__)
struct _stati64 s;
+# else
+ struct _stat s;
+# endif
#else
- struct stat s;
+ struct stat s;
#endif
unsigned int flags;
char size[16];
diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h
index 2aa79d6da8d..af2605894e3 100644
--- a/source/blender/blenlib/BLI_ghash.h
+++ b/source/blender/blenlib/BLI_ghash.h
@@ -41,7 +41,7 @@ extern "C" {
#endif
typedef unsigned int (*GHashHashFP) (const void *key);
-typedef int (*GHashCmpFP) (const void *a, const void *b);
+typedef bool (*GHashCmpFP) (const void *a, const void *b);
typedef void (*GHashKeyFreeFP) (void *key);
typedef void (*GHashValFreeFP) (void *val);
@@ -120,17 +120,17 @@ BLI_INLINE bool BLI_ghashIterator_done(GHashIterator *ghi) { return !ghi
* \{ */
unsigned int BLI_ghashutil_ptrhash(const void *key);
-int BLI_ghashutil_ptrcmp(const void *a, const void *b);
+bool BLI_ghashutil_ptrcmp(const void *a, const void *b);
unsigned int BLI_ghashutil_strhash_n(const char *key, size_t n);
#define BLI_ghashutil_strhash(key) ( \
CHECK_TYPE_INLINE(key, char *), \
BLI_ghashutil_strhash_p(key))
unsigned int BLI_ghashutil_strhash_p(const void *key);
-int BLI_ghashutil_strcmp(const void *a, const void *b);
+bool BLI_ghashutil_strcmp(const void *a, const void *b);
#define BLI_ghashutil_inthash(key) ( \
- CHECK_TYPE_INLINE(key, int), \
+ CHECK_TYPE_INLINE(&(key), int *), \
BLI_ghashutil_uinthash((unsigned int)key))
unsigned int BLI_ghashutil_uinthash(unsigned int key);
#define BLI_ghashutil_inthash_v4(key) ( \
@@ -139,8 +139,11 @@ unsigned int BLI_ghashutil_uinthash(unsigned int key);
unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4]);
#define BLI_ghashutil_inthash_v4_p \
((GSetHashFP)BLI_ghashutil_uinthash_v4)
+bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b);
+#define BLI_ghashutil_inthash_v4_cmp \
+ BLI_ghashutil_uinthash_v4_cmp
unsigned int BLI_ghashutil_inthash_p(const void *ptr);
-int BLI_ghashutil_intcmp(const void *a, const void *b);
+bool BLI_ghashutil_intcmp(const void *a, const void *b);
/** \} */
@@ -164,7 +167,7 @@ typedef struct GHashPair {
GHashPair *BLI_ghashutil_pairalloc(const void *first, const void *second);
unsigned int BLI_ghashutil_pairhash(const void *ptr);
-int BLI_ghashutil_paircmp(const void *a, const void *b);
+bool BLI_ghashutil_paircmp(const void *a, const void *b);
void BLI_ghashutil_pairfree(void *ptr);
@@ -189,8 +192,11 @@ GSet *BLI_gset_new_ex(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info,
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;
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);
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);
@@ -223,6 +229,11 @@ BLI_INLINE bool BLI_gsetIterator_done(GSetIterator *gsi) { return BLI_ghashItera
BLI_gsetIterator_done(&gs_iter_) == false; \
BLI_gsetIterator_step(&gs_iter_), i_++)
+#ifdef DEBUG
+double BLI_ghash_calc_quality(GHash *gh);
+double BLI_gset_calc_quality(GSet *gs);
+#endif
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_gsqueue.h b/source/blender/blenlib/BLI_gsqueue.h
index e002545d189..4600d6f6325 100644
--- a/source/blender/blenlib/BLI_gsqueue.h
+++ b/source/blender/blenlib/BLI_gsqueue.h
@@ -30,20 +30,17 @@
/** \file BLI_gsqueue.h
* \ingroup bli
- * \brief A generic structure queue (a queue for fixed length
- * (generally small) structures.
*/
typedef struct _GSQueue GSQueue;
-GSQueue *BLI_gsqueue_new(int elem_size);
+GSQueue *BLI_gsqueue_new(size_t elem_size);
bool BLI_gsqueue_is_empty(GSQueue *gq);
int BLI_gsqueue_size(GSQueue *gq);
-void BLI_gsqueue_peek(GSQueue *gq, void *item_r);
-void BLI_gsqueue_pop(GSQueue *gq, void *item_r);
-void BLI_gsqueue_push(GSQueue *gq, void *item);
-void BLI_gsqueue_pushback(GSQueue *gq, void *item);
+void BLI_gsqueue_peek(GSQueue *gq, void *r_item);
+void BLI_gsqueue_pop(GSQueue *gq, void *r_item);
+void BLI_gsqueue_push(GSQueue *gq, const void *item);
+void BLI_gsqueue_pushback(GSQueue *gq, const void *item);
void BLI_gsqueue_free(GSQueue *gq);
#endif /* __BLI_GSQUEUE_H__ */
-
diff --git a/source/blender/blenlib/BLI_heap.h b/source/blender/blenlib/BLI_heap.h
index 8a157f5e8db..ac9edfd46a2 100644
--- a/source/blender/blenlib/BLI_heap.h
+++ b/source/blender/blenlib/BLI_heap.h
@@ -35,31 +35,31 @@ typedef void (*HeapFreeFP)(void *ptr);
/* Creates a new heap. BLI_memarena is used for allocating nodes. Removed nodes
* are recycled, so memory usage will not shrink. */
-Heap *BLI_heap_new_ex(unsigned int tot_reserve);
-Heap *BLI_heap_new(void);
-void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp);
+Heap *BLI_heap_new_ex(unsigned int tot_reserve) ATTR_WARN_UNUSED_RESULT;
+Heap *BLI_heap_new(void) ATTR_WARN_UNUSED_RESULT;
+void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) ATTR_NONNULL(1);
/* Insert heap node with a value (often a 'cost') and pointer into the heap,
* duplicate values are allowed. */
-HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr);
+HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) ATTR_NONNULL(1);
/* Remove a heap node. */
-void BLI_heap_remove(Heap *heap, HeapNode *node);
+void BLI_heap_remove(Heap *heap, HeapNode *node) ATTR_NONNULL(1, 2);
/* Return 0 if the heap is empty, 1 otherwise. */
-bool BLI_heap_is_empty(Heap *heap);
+bool BLI_heap_is_empty(Heap *heap) ATTR_NONNULL(1);
/* Return the size of the heap. */
-unsigned int BLI_heap_size(Heap *heap);
+unsigned int BLI_heap_size(Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* Return the top node of the heap. This is the node with the lowest value. */
-HeapNode *BLI_heap_top(Heap *heap);
+HeapNode *BLI_heap_top(Heap *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* Pop the top node off the heap and return it's pointer. */
-void *BLI_heap_popmin(Heap *heap);
+void *BLI_heap_popmin(Heap *heap) ATTR_NONNULL(1);
/* Return the value or pointer of a heap node. */
-float BLI_heap_node_value(HeapNode *heap);
-void *BLI_heap_node_ptr(HeapNode *heap);
+float BLI_heap_node_value(HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void *BLI_heap_node_ptr(HeapNode *heap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
#endif /* __BLI_HEAP_H__ */
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 7b00fd90bf6..49d072ddfdc 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -89,11 +89,11 @@ void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoin
void BLI_bvhtree_balance(BVHTree *tree);
/* update: first update points/nodes, then call update_tree to refit the bounding volumes */
-int BLI_bvhtree_update_node(BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints);
+bool BLI_bvhtree_update_node(BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints);
void BLI_bvhtree_update_tree(BVHTree *tree);
/* collision/overlap: check two trees if they overlap, alloc's *overlap with length of the int return value */
-BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int *result);
+BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int *r_overlap_tot);
float BLI_bvhtree_getepsilon(const BVHTree *tree);
diff --git a/source/blender/blenlib/BLI_linklist_stack.h b/source/blender/blenlib/BLI_linklist_stack.h
index 5f4f98c5a4f..17d40e068b3 100644
--- a/source/blender/blenlib/BLI_linklist_stack.h
+++ b/source/blender/blenlib/BLI_linklist_stack.h
@@ -69,14 +69,14 @@
BLI_linklist_prepend_pool(&(var), ptr, _##var##_pool))
#define BLI_LINKSTACK_POP(var) \
(var ? (typeof(_##var##_type))BLI_linklist_pop_pool(&(var), _##var##_pool) : NULL)
-#define BLI_LINKSTACK_POP_ELSE(var, r) \
+#define BLI_LINKSTACK_POP_DEFAULT(var, r) \
(var ? (typeof(_##var##_type))BLI_linklist_pop_pool(&(var), _##var##_pool) : r)
#else /* non gcc */
#define BLI_LINKSTACK_PUSH(var, ptr) ( \
BLI_linklist_prepend_pool(&(var), ptr, _##var##_pool))
#define BLI_LINKSTACK_POP(var) \
(var ? BLI_linklist_pop_pool(&(var), _##var##_pool) : NULL)
-#define BLI_LINKSTACK_POP_ELSE(var, r) \
+#define BLI_LINKSTACK_POP_DEFAULT(var, r) \
(var ? BLI_linklist_pop_pool(&(var), _##var##_pool) : r)
#endif /* gcc check */
@@ -116,6 +116,9 @@
# define _BLI_SMALLSTACK_CAST(var)
#endif
+#define _BLI_SMALLSTACK_FAKEUSER(var) \
+ (void)(&(_##var##_type))
+
#define BLI_SMALLSTACK_DECLARE(var, type) \
LinkNode *_##var##_stack = NULL, *_##var##_free = NULL, *_##var##_temp = NULL; \
type _##var##_type
@@ -133,11 +136,14 @@
_##var##_temp->next = _##var##_stack; \
_##var##_temp->link = data; \
_##var##_stack = _##var##_temp; \
+ _BLI_SMALLSTACK_FAKEUSER(var); \
} (void)0
/* internal use, no null check */
#define _BLI_SMALLSTACK_DEL_EX(var_src, var_dst) \
- (void)((_##var_src##_temp = _##var_src##_stack->next), \
+ (void)(_BLI_SMALLSTACK_FAKEUSER(var_src), \
+ _BLI_SMALLSTACK_FAKEUSER(var_dst), \
+ (_##var_src##_temp = _##var_src##_stack->next), \
(_##var_src##_stack->next = _##var_dst##_free), \
(_##var_dst##_free = _##var_src##_stack), \
(_##var_src##_stack = _##var_src##_temp)) \
@@ -160,7 +166,7 @@
_##var##_stack->link : NULL))
#define BLI_SMALLSTACK_IS_EMPTY(var) \
- (_BLI_SMALLSTACK_CAST(var) (_##var##_stack != NULL))
+ ((_BLI_SMALLSTACK_CAST(var) _##var##_stack) == NULL)
/* loop over stack members last-added-first */
#define BLI_SMALLSTACK_ITER_BEGIN(var, item) \
@@ -180,10 +186,6 @@
SWAP(LinkNode *, _##var_a##_free, _##var_b##_free); \
} (void)0
-#define BLI_SMALLSTACK_FREE(var) { \
- (void)&(_##var##_type); \
-} (void)0
-
/** \} */
#endif /* __BLI_LINKLIST_STACK_H__ */
diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h
index 028892e8f66..3f03c4e3845 100644
--- a/source/blender/blenlib/BLI_listbase.h
+++ b/source/blender/blenlib/BLI_listbase.h
@@ -67,17 +67,19 @@ void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1);
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink) ATTR_NONNULL(1);
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1);
-void BLI_sortlist(struct ListBase *listbase, int (*cmp)(void *, void *)) ATTR_NONNULL(1, 2);
-void BLI_sortlist_r(ListBase *listbase, void *thunk, int (*cmp)(void *, void *, void *)) ATTR_NONNULL(1, 3);
+void BLI_sortlist(struct ListBase *listbase, int (*cmp)(const void *, const void *)) ATTR_NONNULL(1, 2);
+void BLI_sortlist_r(ListBase *listbase, void *thunk, int (*cmp)(void *, const void *, const void *)) ATTR_NONNULL(1, 3);
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
int BLI_countlist(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
+void BLI_listbase_swaplinks(struct ListBase *listbase, void *vlinka, void *vlinkb) ATTR_NONNULL(1, 2);
+
void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2);
-void BLI_reverselist(struct ListBase *lb) ATTR_NONNULL(1);
-void BLI_rotatelist_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
-void BLI_rotatelist_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
+void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1);
+void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
+void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
/**
* Utility functions to avoid first/last references inline all over.
@@ -95,27 +97,27 @@ struct LinkData *BLI_genericNodeN(void *data);
*
* \code{.c}
*
- * LISTBASE_CIRCULAR_FORWARD_BEGIN (listbase, item, item_init) {
+ * BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (listbase, item, item_init) {
* ...operate on marker...
* }
- * LISTBASE_CIRCULAR_FORWARD_END (listbase, item, item_init);
+ * BLI_LISTBASE_CIRCULAR_FORWARD_END (listbase, item, item_init);
*
* \endcode
*/
-#define LISTBASE_CIRCULAR_FORWARD_BEGIN(lb, lb_iter, lb_init) \
+#define BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN(lb, lb_iter, lb_init) \
if ((lb)->first && (lb_init || (lb_init = (lb)->first))) { \
lb_iter = lb_init; \
do {
-#define LISTBASE_CIRCULAR_FORWARD_END(lb, lb_iter, lb_init) \
+#define BLI_LISTBASE_CIRCULAR_FORWARD_END(lb, lb_iter, lb_init) \
} while ((lb_iter = (lb_iter)->next ? (lb_iter)->next : (lb)->first), \
(lb_iter != lb_init)); \
}
-#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init) \
+#define BLI_LISTBASE_CIRCULAR_BACKWARD_BEGIN(lb, lb_iter, lb_init) \
if ((lb)->last && (lb_init || (lb_init = (lb)->last))) { \
lb_iter = lb_init; \
do {
-#define LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init) \
+#define BLI_LISTBASE_CIRCULAR_BACKWARD_END(lb, lb_iter, lb_init) \
} while ((lb_iter = (lb_iter)->prev ? (lb_iter)->prev : (lb)->last), \
(lb_iter != lb_init)); \
}
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 5bd8490db6e..07de074e717 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -75,11 +75,6 @@
#define M_LN10 2.30258509299404568402
#endif
-/* non-standard defines, used in some places */
-#ifndef MAXFLOAT
-#define MAXFLOAT ((float)3.40282347e+38)
-#endif
-
#if defined(__GNUC__)
# define NAN_FLT __builtin_nanf("")
#else
@@ -88,8 +83,8 @@ static const int NAN_INT = 0x7FC00000;
# define NAN_FLT (*((float *)(&NAN_INT)))
#endif
-/* do not redefine functions from C99 or POSIX.1-2001 */
-#if !(defined(_ISOC99_SOURCE) || (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L))
+/* 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))
#ifndef sqrtf
#define sqrtf(a) ((float)sqrt(a))
@@ -143,46 +138,14 @@ static const int NAN_INT = 0x7FC00000;
#define copysignf(a, b) ((float)copysign(a, b))
#endif
-#endif /* C99 or POSIX.1-2001 */
+#endif /* C99, POSIX.1-2001 or MSVC12 (partial C99) */
#ifdef WIN32
# if defined(_MSC_VER)
-# if (_MSC_VER < 1800) && !defined(isnan)
-# define isnan(n) _isnan(n)
-# endif
# define finite(n) _finite(n)
-# if (_MSC_VER < 1800) && !defined(hypot)
-# define hypot(a, b) _hypot(a, b)
-# endif
# endif
#endif
-/* Causes warning:
- * incompatible types when assigning to type 'Foo' from type 'Bar'
- * ... the compiler optimizes away the temp var */
-#ifndef CHECK_TYPE
-#ifdef __GNUC__
-#define CHECK_TYPE(var, type) { \
- __typeof(var) *__tmp; \
- __tmp = (type *)NULL; \
- (void)__tmp; \
-} (void)0
-#else
-#define CHECK_TYPE(var, type)
-#endif
-#endif
-
-#ifndef SWAP
-# define SWAP(type, a, b) { \
- type sw_ap; \
- CHECK_TYPE(a, type); \
- CHECK_TYPE(b, type); \
- sw_ap = (a); \
- (a) = (b); \
- (b) = sw_ap; \
-} (void)0
-#endif
-
#if BLI_MATH_DO_INLINE
#include "intern/math_base_inline.c"
#endif
@@ -241,11 +204,6 @@ 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);
-#if defined(_MSC_VER) && (_MSC_VER < 1800)
-extern double copysign(double x, double y);
-extern double round(double x);
-#endif
-
double double_round(double x, int ndigits);
#ifdef BLI_MATH_GCC_WARN_PRAGMA
@@ -255,7 +213,7 @@ double double_round(double x, int ndigits);
/* asserts, some math functions expect normalized inputs
* check the vector is unit length, or zero length (which can't be helped in some cases).
*/
-#ifdef DEBUG
+#ifndef NDEBUG
/* note: 0.0001 is too small becaues normals may be converted from short's: see [#34322] */
# define BLI_ASSERT_UNIT_EPSILON 0.0002f
# define BLI_ASSERT_UNIT_V3(v) { \
diff --git a/source/blender/blenlib/BLI_math_color_blend.h b/source/blender/blenlib/BLI_math_color_blend.h
index d7e9bf50eae..d966676e19e 100644
--- a/source/blender/blenlib/BLI_math_color_blend.h
+++ b/source/blender/blenlib/BLI_math_color_blend.h
@@ -49,6 +49,24 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char
MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4]);
+
+MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4]);
+
MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float t);
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4]);
@@ -59,6 +77,24 @@ MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const
MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const float src2[4]);
MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], const float src2[4]);
MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], const float src2[4]);
+
+MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[4]);
+MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[4]);
+
MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t);
#if BLI_MATH_DO_INLINE
diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h
index f4bcc810846..ba32b29becc 100644
--- a/source/blender/blenlib/BLI_math_geom.h
+++ b/source/blender/blenlib/BLI_math_geom.h
@@ -72,6 +72,7 @@ MINLINE float plane_point_side_v3(const float plane[4], const float co[3]);
/********************************* Volume **********************************/
float volume_tetrahedron_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
+float volume_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
bool is_quad_convex_v2(const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
@@ -85,8 +86,11 @@ float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const
float dist_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2]);
void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]);
-float dist_squared_to_plane_v3(const float p[3], const float plane[4]);
-float dist_to_plane_v3(const float p[3], const float plane[4]);
+float dist_signed_squared_to_plane_v3(const float p[3], const float plane[4]);
+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]);
+
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]);
@@ -126,9 +130,14 @@ int isect_line_sphere_v2(const float l1[2], const float l2[2], const float sp[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]);
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_v3(const float v1[3], const float v2[3],
- const float v3[3], const float v4[3],
- float i1[3], float i2[3]);
+int isect_line_line_epsilon_v3(
+ const float v1[3], const float v2[3],
+ const float v3[3], const float v4[3], float i1[3], float i2[3],
+ const float epsilon);
+int isect_line_line_v3(
+ const float v1[3], const float v2[3],
+ const float v3[3], const float v4[3],
+ float i1[3], float i2[3]);
bool isect_line_line_strict_v3(const float v1[3], const float v2[3],
const float v3[3], const float v4[3],
float vi[3], float *r_lambda);
@@ -168,6 +177,8 @@ int isect_point_tri_v2(const float pt[2], const float v1[2], const float v2[2],
bool isect_point_tri_v2_cw(const float pt[2], const float v1[2], const float v2[2], const float v3[2]);
int isect_point_tri_v2_int(const int x1, const int y1, const int x2, const int y2, const int a, const int b);
bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3]);
+bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3],
+ float r_vi[3]);
/* axis-aligned bounding box */
bool isect_aabb_aabb_v3(const float min1[3], const float max1[3], const float min2[3], const float max2[3]);
@@ -209,9 +220,14 @@ void interp_cubic_v3(float x[3], float v[3],
int interp_sparse_array(float *array, const int list_size, const float invalid);
-void barycentric_transform(float pt_tar[3], float const pt_src[3],
- const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3],
- const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3]);
+void transform_point_by_tri_v3(
+ float pt_tar[3], float const pt_src[3],
+ const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3],
+ const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3]);
+void transform_point_by_seg_v3(
+ float p_dst[3], const float p_src[3],
+ const float l_dst_p1[3], const float l_dst_p2[3],
+ const float l_src_p1[3], const float l_src_p2[3]);
void barycentric_weights_v2(const float v1[2], const float v2[2], const float v3[2],
const float co[2], float w[3]);
@@ -259,17 +275,22 @@ void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const f
/********************************** Normals **********************************/
-void accumulate_vertex_normals(float n1[3], float n2[3], float n3[3],
- float n4[3], const float f_no[3], const float co1[3], const float co2[3],
- const float co3[3], const float co4[3]);
+void accumulate_vertex_normals(
+ float n1[3], float n2[3], float n3[3], float n4[3],
+ const float f_no[3],
+ const float co1[3], const float co2[3], const float co3[3], const float co4[3]);
-void accumulate_vertex_normals_poly(float **vertnos, const float polyno[3],
- const float **vertcos, float vdiffs[][3], const int nverts);
+void accumulate_vertex_normals_poly(
+ float **vertnos, const float polyno[3],
+ const float **vertcos, float vdiffs[][3], const int nverts);
/********************************* Tangents **********************************/
-void tangent_from_uv(float uv1[2], float uv2[2], float uv3[2],
- float co1[3], float co2[3], float co3[3], float n[3], float tang[3]);
+void tangent_from_uv(
+ const float uv1[2], const float uv2[2], const float uv3[2],
+ const float co1[3], const float co2[3], const float co3[3],
+ const float n[3],
+ float r_tang[3]);
/******************************** Vector Clouds ******************************/
diff --git a/source/blender/blenlib/BLI_math_interp.h b/source/blender/blenlib/BLI_math_interp.h
index 43ef64214ad..d2ec7b80d86 100644
--- a/source/blender/blenlib/BLI_math_interp.h
+++ b/source/blender/blenlib/BLI_math_interp.h
@@ -45,4 +45,24 @@ void BLI_bilinear_interpolation_fl(const float *buffer, float *output, int width
void BLI_bilinear_interpolation_char(const unsigned char *buffer, unsigned char *output, int width, int height,
int components, float u, float v);
+#define EWA_MAXIDX 255
+extern const float EWA_WTS[EWA_MAXIDX + 1];
+
+typedef void (*ewa_filter_read_pixel_cb) (void *userdata, int x, int y, float result[4]);
+
+void BLI_ewa_imp2radangle(float A, float B, float C, float F, float *a, float *b, float *th, float *ecc);
+
+/* TODO(sergey): Consider making this function inlined, so the pixel read callback
+ * could also be inlined in order to avoid per-pixel function calls.
+ */
+void BLI_ewa_filter(const int width, const int height,
+ const bool intpol,
+ const bool use_alpha,
+ const float uv[2],
+ const float du[2],
+ const float dv[2],
+ ewa_filter_read_pixel_cb read_pixel_cb,
+ void *customdata,
+ float result[4]);
+
#endif /* __BLI_MATH_INTERP_H__ */
diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h
index 7cfc8948baa..732f4b66f38 100644
--- a/source/blender/blenlib/BLI_math_matrix.h
+++ b/source/blender/blenlib/BLI_math_matrix.h
@@ -34,27 +34,19 @@
extern "C" {
#endif
-/********************************* Init **************************************/
-
-#define MAT4_UNITY { \
- { 1.0, 0.0, 0.0, 0.0}, \
- { 0.0, 1.0, 0.0, 0.0}, \
- { 0.0, 0.0, 1.0, 0.0}, \
- { 0.0, 0.0, 0.0, 1.0} \
-}
+#include "BLI_compiler_attrs.h"
-#define MAT3_UNITY { \
- { 1.0, 0.0, 0.0}, \
- { 0.0, 1.0, 0.0}, \
- { 0.0, 0.0, 1.0} \
-}
+/********************************* Init **************************************/
+void zero_m2(float R[2][2]);
void zero_m3(float R[3][3]);
void zero_m4(float R[4][4]);
+void unit_m2(float R[2][2]);
void unit_m3(float R[3][3]);
void unit_m4(float R[4][4]);
+void copy_m2_m2(float R[2][2], float A[2][2]);
void copy_m3_m3(float R[3][3], float A[3][3]);
void copy_m4_m4(float R[4][4], float A[4][4]);
void copy_m3_m4(float R[3][3], float A[4][4]);
@@ -80,12 +72,33 @@ void mul_m4_m4m3(float R[4][4], float A[4][4], float B[3][3]);
void mul_m4_m4m4(float R[4][4], float A[4][4], float B[4][4]);
void mul_m3_m3m4(float R[3][3], float A[4][4], float B[3][3]);
-void mul_serie_m3(float R[3][3],
- float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3],
- float M5[3][3], float M6[3][3], float M7[3][3], float M8[3][3]);
-void mul_serie_m4(float R[4][4],
- float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4],
- float M5[4][4], float M6[4][4], float M7[4][4], float M8[4][4]);
+/* mul_m3_series */
+void _va_mul_m3_series_3(float R[3][3], float M1[3][3], float M2[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_4(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_5(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_6(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3],
+ float M5[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_7(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3],
+ float M5[3][3], float M6[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_8(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3],
+ float M5[3][3], float M6[3][3], float M7[3][3]) ATTR_NONNULL();
+void _va_mul_m3_series_9(float R[3][3], float M1[3][3], float M2[3][3], float M3[3][3], float M4[3][3],
+ float M5[3][3], float M6[3][3], float M7[3][3], float M8[3][3]) ATTR_NONNULL();
+/* mul_m4_series */
+void _va_mul_m4_series_3(float R[4][4], float M1[4][4], float M2[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_4(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_5(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_6(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4],
+ float M5[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_7(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4],
+ float M5[4][4], float M6[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_8(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4],
+ float M5[4][4], float M6[4][4], float M7[4][4]) ATTR_NONNULL();
+void _va_mul_m4_series_9(float R[4][4], float M1[4][4], float M2[4][4], float M3[4][4], float M4[4][4],
+ float M5[4][4], float M6[4][4], float M7[4][4], float M8[4][4]) ATTR_NONNULL();
+
+#define mul_m3_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m3_series_, __VA_ARGS__)
+#define mul_m4_series(...) VA_NARGS_CALL_OVERLOAD(_va_mul_m4_series_, __VA_ARGS__)
void mul_m4_v3(float M[4][4], float r[3]);
void mul_v3_m4v3(float r[3], float M[4][4], const float v[3]);
@@ -96,6 +109,7 @@ void mul_mat3_m4_v3(float M[4][4], float r[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]);
+void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3]);
void mul_v2_project_m4_v3(float r[2], float M[4][4], const float vec[3]);
void mul_m3_v2(float m[3][3], float r[2]);
@@ -111,6 +125,9 @@ void mul_m3_fl(float R[3][3], float f);
void mul_m4_fl(float R[4][4], float f);
void mul_mat3_m4_fl(float R[4][4], float f);
+void negate_m3(float R[4][4]);
+void negate_m4(float R[4][4]);
+
bool invert_m3_ex(float m[3][3], const float epsilon);
bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon);
@@ -145,6 +162,7 @@ bool is_orthonormal_m3(float mat[3][3]);
bool is_orthonormal_m4(float mat[4][4]);
bool is_uniform_scaled_m3(float mat[3][3]);
+bool is_uniform_scaled_m4(float m[4][4]);
void adjoint_m2_m2(float R[2][2], float A[2][2]);
void adjoint_m3_m3(float R[3][3], float A[3][3]);
@@ -210,6 +228,22 @@ bool is_negative_m4(float mat[4][4]);
bool is_zero_m3(float mat[3][3]);
bool is_zero_m4(float mat[4][4]);
+/* SpaceTransform helper */
+typedef struct SpaceTransform {
+ float local2target[4][4];
+ float target2local[4][4];
+
+} SpaceTransform;
+
+void BLI_space_transform_from_matrices(struct SpaceTransform *data, float local[4][4], float target[4][4]);
+void BLI_space_transform_apply(const struct SpaceTransform *data, float co[3]);
+void BLI_space_transform_invert(const struct SpaceTransform *data, float co[3]);
+void BLI_space_transform_apply_normal(const struct SpaceTransform *data, float no[3]);
+void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float no[3]);
+
+#define BLI_SPACE_TRANSFORM_SETUP(data, local, target) \
+ BLI_space_transform_from_matrices((data), (local)->obmat, (target)->obmat)
+
/*********************************** Other ***********************************/
void print_m3(const char *str, float M[3][3]);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index f816ad53d15..6885a5aa351 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -65,6 +65,7 @@ MINLINE void swap_v4_v4(float a[4], float b[4]);
MINLINE void copy_v2_v2_char(char r[2], const char a[2]);
MINLINE void copy_v3_v3_char(char r[3], const char a[3]);
MINLINE void copy_v4_v4_char(char r[4], const char a[4]);
+
/* short */
MINLINE void copy_v2_v2_short(short r[2], const short a[2]);
MINLINE void copy_v3_v3_short(short r[3], const short a[3]);
@@ -231,6 +232,7 @@ MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_R
MINLINE bool compare_v2v2(const float a[2], const float b[2], const float limit) ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_len_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT;
+MINLINE bool compare_len_squared_v3v3(const float a[3], const float b[3], const float limit) ATTR_WARN_UNUSED_RESULT;
MINLINE bool compare_v4v4(const float a[4], const float b[4], const float limit) ATTR_WARN_UNUSED_RESULT;
MINLINE bool equals_v4v4(const float a[4], const float b[4]) ATTR_WARN_UNUSED_RESULT;
@@ -251,6 +253,7 @@ float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WA
float cos_v3v3v3(const float p1[3], const float p2[3], const float p3[3]) ATTR_WARN_UNUSED_RESULT;
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT;
float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
+float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3]) ATTR_WARN_UNUSED_RESULT;
void angle_tri_v3(float angles[3], const float v1[3], const float v2[3], const float v3[3]);
void angle_quad_v3(float angles[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
void angle_poly_v3(float *angles, const float *verts[3], int len);
@@ -263,7 +266,7 @@ 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]);
void ortho_v3_v3(float p[3], const float v[3]);
-void ortho_v2_v2(float p[3], const float v[3]);
+void ortho_v2_v2(float p[2], const float v[2]);
void bisect_v3_v3v3v3(float r[3], const float a[3], const float b[3], const float c[3]);
void rotate_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle);
void rotate_normalized_v3_v3v3fl(float v[3], const float p[3], const float axis[3], const float angle);
diff --git a/source/blender/blenlib/BLI_md5.h b/source/blender/blenlib/BLI_md5.h
index 8ce479b1801..6a760f53e45 100644
--- a/source/blender/blenlib/BLI_md5.h
+++ b/source/blender/blenlib/BLI_md5.h
@@ -41,5 +41,7 @@ void *md5_buffer(const char *buffer, size_t len, void *resblock);
int md5_stream(FILE *stream, void *resblock);
+char *md5_to_hexdigest(void *resblock, char r_hex_digest[33]);
+
#endif
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index 3e98e2ceeae..3d82480d050 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -97,6 +97,7 @@ void BLI_join_dirfile(char *__restrict string, const size_t maxlen,
const char *__restrict dir, const char *__restrict file) ATTR_NONNULL();
const char *BLI_path_basename(const char *path) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
+#if 0
typedef enum bli_rebase_state {
BLI_REBASE_NO_SRCDIR = 0,
BLI_REBASE_OK = 1,
@@ -104,11 +105,13 @@ typedef enum bli_rebase_state {
} bli_rebase_state;
int BLI_rebase_path(char *abs, size_t abs_len, char *rel, size_t rel_len, const char *base_dir, const char *src_dir, const char *dest_dir);
+#endif
const char *BLI_last_slash(const char *string) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT;
int BLI_add_slash(char *string) ATTR_NONNULL();
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();
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;
@@ -126,9 +129,6 @@ int BLI_stringdec(const char *string, char *head, char *start, unsigned short *n
void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic);
int BLI_split_name_num(char *left, int *nr, const char *name, const char delim);
-/* make sure path separators conform to system one */
-void BLI_clean(char *path) ATTR_NONNULL();
-
/**
* dir can be any input, like from buttons, and this function
* converts it to a regular full path.
@@ -189,12 +189,14 @@ void BLI_char_switch(char *string, char from, char to) ATTR_NONNULL();
void BLI_init_program_path(const char *argv0);
/* Initialize path to temporary directory.
* NOTE: On Window userdir will be set to the temporary directory! */
-void BLI_init_temporary_dir(char *userdir);
+void BLI_temp_dir_init(char *userdir);
const char *BLI_program_path(void);
const char *BLI_program_dir(void);
-const char *BLI_temporary_dir(void);
+const char *BLI_temp_dir_session(void);
+const char *BLI_temp_dir_base(void);
void BLI_system_temporary_dir(char *dir);
+void BLI_temp_dir_session_purge(void);
#ifdef WITH_ICONV
void BLI_string_to_utf8(char *original, char *utf_8, const char *code);
diff --git a/source/blender/blenlib/BLI_polyfill2d.h b/source/blender/blenlib/BLI_polyfill2d.h
index d434e1b82b9..5c5cea8f67d 100644
--- a/source/blender/blenlib/BLI_polyfill2d.h
+++ b/source/blender/blenlib/BLI_polyfill2d.h
@@ -23,17 +23,10 @@
struct MemArena;
-void BLI_polyfill_calc_ex(
- const float (*coords)[2],
- const unsigned int count,
- unsigned int (*r_tris)[3],
-
- /* avoid allocating each time */
- unsigned int *r_indices, signed char *r_coords_sign);
-
void BLI_polyfill_calc_arena(
const float (*coords)[2],
const unsigned int coords_tot,
+ const int coords_sign,
unsigned int (*r_tris)[3],
struct MemArena *arena);
@@ -41,6 +34,7 @@ void BLI_polyfill_calc_arena(
void BLI_polyfill_calc(
const float (*coords)[2],
const unsigned int coords_tot,
+ const int coords_sign,
unsigned int (*r_tris)[3]);
#endif /* __BLI_POLYFILL2D_H__ */
diff --git a/source/blender/blenlib/BLI_rand.h b/source/blender/blenlib/BLI_rand.h
index 045cadbcc6f..879af446469 100644
--- a/source/blender/blenlib/BLI_rand.h
+++ b/source/blender/blenlib/BLI_rand.h
@@ -40,34 +40,38 @@
struct RNG;
typedef struct RNG RNG;
+struct RNG_THREAD_ARRAY;
+typedef struct RNG_THREAD_ARRAY RNG_THREAD_ARRAY;
+
struct RNG *BLI_rng_new(unsigned int seed);
struct RNG *BLI_rng_new_srandom(unsigned int seed);
-void BLI_rng_free(struct RNG *rng);
+void BLI_rng_free(struct RNG *rng) ATTR_NONNULL(1);
-void BLI_rng_seed(struct RNG *rng, unsigned int seed);
-void BLI_rng_srandom(struct RNG *rng, unsigned int seed);
-int BLI_rng_get_int(struct RNG *rng);
-unsigned int BLI_rng_get_uint(struct RNG *rng);
-double BLI_rng_get_double(struct RNG *rng);
-float BLI_rng_get_float(struct RNG *rng);
-void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]);
-void BLI_rng_shuffle_array(struct RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_tot);
+void BLI_rng_seed(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
+void BLI_rng_srandom(struct RNG *rng, unsigned int seed) ATTR_NONNULL(1);
+int BLI_rng_get_int(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+unsigned int BLI_rng_get_uint(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+double BLI_rng_get_double(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+float BLI_rng_get_float(struct RNG *rng) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+void BLI_rng_get_float_unit_v2(struct RNG *rng, float v[2]) ATTR_NONNULL(1, 2);
+void BLI_rng_get_float_unit_v3(struct RNG *rng, float v[3]) ATTR_NONNULL(1, 2);
+void BLI_rng_shuffle_array(struct RNG *rng, void *data, unsigned int elem_size_i, unsigned int elem_tot) ATTR_NONNULL(1, 2);
/** Note that skipping is as slow as generating n numbers! */
-void BLI_rng_skip(struct RNG *rng, int n);
+void BLI_rng_skip(struct RNG *rng, int n) ATTR_NONNULL(1);
/** Seed for the random number generator, using noise.c hash[] */
void BLI_srandom(unsigned int seed);
/** Return a pseudo-random number N where 0<=N<(2^31) */
-int BLI_rand(void);
+int BLI_rand(void) ATTR_WARN_UNUSED_RESULT;
/** Return a pseudo-random number N where 0.0f<=N<1.0f */
-float BLI_frand(void);
+float BLI_frand(void) ATTR_WARN_UNUSED_RESULT;
void BLI_frand_unit_v3(float v[3]);
/** Return a pseudo-random (hash) float from an integer value */
-float BLI_hash_frand(unsigned int seed);
+float BLI_hash_frand(unsigned int seed) ATTR_WARN_UNUSED_RESULT;
/** Shuffle an array randomly using the given seed.
* contents. This routine does not use nor modify
@@ -82,10 +86,15 @@ void BLI_thread_srandom(int thread, unsigned int seed);
/** Return a pseudo-random number N where 0<=N<(2^31) */
/** Allows up to BLENDER_MAX_THREADS threads to address */
-int BLI_thread_rand(int thread);
+int BLI_thread_rand(int thread) ATTR_WARN_UNUSED_RESULT;
/** Return a pseudo-random number N where 0.0f<=N<1.0f */
/** Allows up to BLENDER_MAX_THREADS threads to address */
-float BLI_thread_frand(int thread);
+float BLI_thread_frand(int thread) ATTR_WARN_UNUSED_RESULT;
+
+/** array versions for thread safe random generation */
+RNG_THREAD_ARRAY *BLI_rng_threaded_new(void);
+void BLI_rng_threaded_free(struct RNG_THREAD_ARRAY *rngarr) ATTR_NONNULL(1);
+int BLI_rng_thread_rand(RNG_THREAD_ARRAY *rngarr, int thread) ATTR_WARN_UNUSED_RESULT;
#endif /* __BLI_RAND_H__ */
diff --git a/source/blender/blenlib/BLI_smallhash.h b/source/blender/blenlib/BLI_smallhash.h
index b2fec6f870c..b80044bccff 100644
--- a/source/blender/blenlib/BLI_smallhash.h
+++ b/source/blender/blenlib/BLI_smallhash.h
@@ -70,4 +70,8 @@ void *BLI_smallhash_iternext(SmallHashIter *iter, uintptr_t *key) ATTR_NONNUL
void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT;
/* void BLI_smallhash_print(SmallHash *sh); */ /* UNUSED */
+#ifdef DEBUG
+double BLI_smallhash_calc_quality(SmallHash *sh);
+#endif
+
#endif /* __BLI_SMALLHASH_H__ */
diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h
index 4df17d98a4b..cb6b87bda38 100644
--- a/source/blender/blenlib/BLI_sort.h
+++ b/source/blender/blenlib/BLI_sort.h
@@ -33,10 +33,17 @@
* \ingroup bli
*/
+#include <stdlib.h>
+
+/* glibc 2.8+ */
+#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8))
+# define BLI_qsort_r qsort_r
+#endif
+
/* Quick sort reentrant */
-typedef int (*BLI_sort_cmp_t)(void *ctx, const void *a, const void *b);
+typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx);
-void BLI_qsort_r(void *a, size_t n, size_t es, void *thunk, BLI_sort_cmp_t cmp)
+void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
#ifdef __GNUC__
__attribute__((nonnull(1, 5)))
#endif
diff --git a/source/blender/blenlib/BLI_stack.h b/source/blender/blenlib/BLI_stack.h
index 564ff513490..a8c4478c450 100644
--- a/source/blender/blenlib/BLI_stack.h
+++ b/source/blender/blenlib/BLI_stack.h
@@ -28,27 +28,29 @@
* \ingroup bli
*/
+#include "BLI_compiler_attrs.h"
+
typedef struct BLI_Stack BLI_Stack;
-/* Create a new homogeneous stack with elements of 'elem_size' bytes */
-BLI_Stack *BLI_stack_new(int elem_size, const char *description);
+BLI_Stack *BLI_stack_new_ex(
+ const size_t elem_size, const char *description,
+ const size_t chunk_size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BLI_Stack *BLI_stack_new(
+ const size_t elem_size, const char *description) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* Free the stack's data and the stack itself */
-void BLI_stack_free(BLI_Stack *stack);
+void BLI_stack_free(BLI_Stack *stack) ATTR_NONNULL();
-/* Copies the source value onto the stack (note that it copies
- * elem_size bytes from 'src', the pointer itself is not stored) */
-void BLI_stack_push(BLI_Stack *stack, void *src);
+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();
-/* Retrieves and removes the top element from the stack. The value is
- * copies to 'dst', which must be at least elem_size bytes.
- *
- * Does not reduce amount of allocated memory.
- *
- * If stack is empty, 'dst' will not be modified. */
-void BLI_stack_pop(BLI_Stack *stack, void *dst);
+void BLI_stack_pop_n(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();
+
+size_t BLI_stack_count(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-/* Returns true if the stack is empty, false otherwise */
-int BLI_stack_empty(const BLI_Stack *stack);
+bool BLI_stack_is_empty(const BLI_Stack *stack) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-#endif
+#endif /* __BLI_STACK_H__ */
diff --git a/source/blender/blenlib/BLI_stackdefines.h b/source/blender/blenlib/BLI_stackdefines.h
new file mode 100644
index 00000000000..864a7704aa9
--- /dev/null
+++ b/source/blender/blenlib/BLI_stackdefines.h
@@ -0,0 +1,88 @@
+/*
+ * ***** 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_STACKDEFINES_H__
+#define __BLI_STACKDEFINES_H__
+
+/** \file BLI_stackdefines.h
+ * \ingroup bli
+ *
+ * Macro's for a simple array based stack
+ * \note Caller handles alloc & free).
+ */
+
+/* only validate array-bounds in debug mode */
+#ifdef DEBUG
+# define STACK_DECLARE(stack) unsigned int _##stack##_index, _##stack##_totalloc
+# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)((_##stack##_totalloc) = tot))
+# define _STACK_SIZETEST(stack, off) (BLI_assert((_##stack##_index) + off <= _##stack##_totalloc))
+# define _STACK_SWAP_TOTALLOC(stack_a, stack_b) SWAP(unsigned int, _##stack_a##_totalloc, _##stack_b##_totalloc)
+#else
+# define STACK_DECLARE(stack) unsigned int _##stack##_index
+# define STACK_INIT(stack, tot) ((void)stack, (void)((_##stack##_index) = 0), (void)(0 ? tot : 0))
+# 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_SIZE(stack) ((void)stack, (_##stack##_index))
+/** add item to stack */
+#define STACK_PUSH(stack, val) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++] = val))
+#define STACK_PUSH_RET(stack) ((void)stack, _STACK_SIZETEST(stack, 1), ((stack)[(_##stack##_index)++]))
+#define STACK_PUSH_RET_PTR(stack) ((void)stack, _STACK_SIZETEST(stack, 1), &((stack)[(_##stack##_index)++]))
+/** take last item from stack */
+#define STACK_POP(stack) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : NULL)
+#define STACK_POP_PTR(stack) ((_##stack##_index) ? &((stack)[--(_##stack##_index)]) : NULL)
+#define STACK_POP_DEFAULT(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : r)
+/** look at last item (assumes non-empty stack) */
+#define STACK_PEEK(stack) (BLI_assert(_##stack##_index), ((stack)[_##stack##_index - 1]))
+#define STACK_PEEK_PTR(stack) (BLI_assert(_##stack##_index), &((stack)[_##stack##_index - 1]))
+/** remove any item from the stack, take care, re-orders */
+#define STACK_REMOVE(stack, i) \
+ { \
+ const unsigned int _i = i; \
+ _STACK_BOUNDSTEST(stack, _i); \
+ if (--_##stack##_index != _i) { \
+ stack[_i] = stack[_##stack##_index]; \
+ } \
+ } (void)0
+#define STACK_DISCARD(stack, n) \
+ { \
+ const unsigned int _n = n; \
+ BLI_assert(_##stack##_index >= _n); \
+ (void)stack; \
+ _##stack##_index -= _n; \
+ } (void)0
+#ifdef __GNUC__
+#define STACK_SWAP(stack_a, stack_b) { \
+ SWAP(typeof(stack_a), stack_a, stack_b); \
+ SWAP(unsigned int, _##stack_a##_index, _##stack_b##_index); \
+ _STACK_SWAP_TOTALLOC(stack_a, stack_b); \
+ } (void)0
+#else
+#define STACK_SWAP(stack_a, stack_b) { \
+ SWAP(void *, stack_a, stack_b); \
+ SWAP(unsigned int, _##stack_a##_index, _##stack_b##_index); \
+ _STACK_SWAP_TOTALLOC(stack_a, stack_b); \
+ } (void)0
+#endif
+
+#endif /* __BLI_STACKDEFINES_H__ */
diff --git a/source/blender/blenlib/BLI_strict_flags.h b/source/blender/blenlib/BLI_strict_flags.h
index 1d595ff3bf3..964ee06469d 100644
--- a/source/blender/blenlib/BLI_strict_flags.h
+++ b/source/blender/blenlib/BLI_strict_flags.h
@@ -28,13 +28,15 @@
*/
#ifdef __GNUC__
-# pragma GCC diagnostic error "-Wsign-conversion"
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 /* gcc4.6+ only */
# pragma GCC diagnostic error "-Wsign-compare"
# pragma GCC diagnostic error "-Wconversion"
# endif
-# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 /* gcc4.8+ only (behavior changed to ignore globals)*/
+# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 408
+ /* gcc4.8+ only (behavior changed to ignore globals)*/
# pragma GCC diagnostic error "-Wshadow"
+ /* older gcc changed behavior with ternary */
+# pragma GCC diagnostic error "-Wsign-conversion"
# endif
/* pedantic gives too many issues, developers can define this for own use */
# ifdef WARN_PEDANTIC
diff --git a/source/blender/blenlib/BLI_string.h b/source/blender/blenlib/BLI_string.h
index b995f2565e1..b249bc720c6 100644
--- a/source/blender/blenlib/BLI_string.h
+++ b/source/blender/blenlib/BLI_string.h
@@ -56,14 +56,16 @@ 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() ATTR_PRINTF_FORMAT(3, 4);
+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_vsnprintf(char *__restrict dst, 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() ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
+char *BLI_sprintfN(const char *__restrict format, ...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1, 2);
size_t BLI_strescape(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL();
+size_t BLI_str_format_int_grouped(char dst[16], int num) ATTR_NONNULL();
+
int BLI_strcaseeq(const char *a, const char *b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
char *BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
int BLI_strcasecmp(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
@@ -76,6 +78,13 @@ void BLI_ascii_strtolower(char *str, const size_t len) ATTR_NONNULL();
void BLI_ascii_strtoupper(char *str, const size_t len) ATTR_NONNULL();
int BLI_str_rstrip_float_zero(char *str, const char pad) ATTR_NONNULL();
+int BLI_str_index_in_array_n(const char *__restrict str, const char **__restrict str_array, const int str_array_len) ATTR_NONNULL();
+int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array) 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();
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_string_utf8.h b/source/blender/blenlib/BLI_string_utf8.h
index 4aef2318683..89754be25ba 100644
--- a/source/blender/blenlib/BLI_string_utf8.h
+++ b/source/blender/blenlib/BLI_string_utf8.h
@@ -66,6 +66,10 @@ 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();
+
#define BLI_UTF8_MAX 6 /* mem */
#define BLI_UTF8_WIDTH_MAX 2 /* columns */
#define BLI_UTF8_ERR ((unsigned int)-1)
diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h
index b0a8adeef22..c9cf33f2f69 100644
--- a/source/blender/blenlib/BLI_sys_types.h
+++ b/source/blender/blenlib/BLI_sys_types.h
@@ -47,127 +47,7 @@
extern "C" {
#endif
-/* MSVC 2010 and 2012 (>=1600) have stdint.h so we should use this for consistency */
-#if defined(_WIN32) && defined(_MSC_VER) && _MSC_VER <= 1500
-
-/* The __intXX are built-in types of the visual compiler! So we don't
- * need to include anything else here. */
-
-
-typedef signed __int8 int8_t;
-typedef signed __int16 int16_t;
-typedef signed __int32 int32_t;
-typedef signed __int64 int64_t;
-
-typedef unsigned __int8 uint8_t;
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-
-// 7.18.2 Limits of specified-width integer types
-
-#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
-
-// 7.18.2.1 Limits of exact-width integer types
-#define INT8_MIN ((int8_t)_I8_MIN)
-#define INT8_MAX _I8_MAX
-#define INT16_MIN ((int16_t)_I16_MIN)
-#define INT16_MAX _I16_MAX
-#define INT32_MIN ((int32_t)_I32_MIN)
-#define INT32_MAX _I32_MAX
-#define INT64_MIN ((int64_t)_I64_MIN)
-#define INT64_MAX _I64_MAX
-#define UINT8_MAX _UI8_MAX
-#define UINT16_MAX _UI16_MAX
-#define UINT32_MAX _UI32_MAX
-#define UINT64_MAX _UI64_MAX
-
-// 7.18.2.2 Limits of minimum-width integer types
-#define INT_LEAST8_MIN INT8_MIN
-#define INT_LEAST8_MAX INT8_MAX
-#define INT_LEAST16_MIN INT16_MIN
-#define INT_LEAST16_MAX INT16_MAX
-#define INT_LEAST32_MIN INT32_MIN
-#define INT_LEAST32_MAX INT32_MAX
-#define INT_LEAST64_MIN INT64_MIN
-#define INT_LEAST64_MAX INT64_MAX
-#define UINT_LEAST8_MAX UINT8_MAX
-#define UINT_LEAST16_MAX UINT16_MAX
-#define UINT_LEAST32_MAX UINT32_MAX
-#define UINT_LEAST64_MAX UINT64_MAX
-
-// 7.18.2.3 Limits of fastest minimum-width integer types
-#define INT_FAST8_MIN INT8_MIN
-#define INT_FAST8_MAX INT8_MAX
-#define INT_FAST16_MIN INT16_MIN
-#define INT_FAST16_MAX INT16_MAX
-#define INT_FAST32_MIN INT32_MIN
-#define INT_FAST32_MAX INT32_MAX
-#define INT_FAST64_MIN INT64_MIN
-#define INT_FAST64_MAX INT64_MAX
-#define UINT_FAST8_MAX UINT8_MAX
-#define UINT_FAST16_MAX UINT16_MAX
-#define UINT_FAST32_MAX UINT32_MAX
-#define UINT_FAST64_MAX UINT64_MAX
-
-// 7.18.2.4 Limits of integer types capable of holding object pointers
-#ifdef _WIN64 // [
-# define INTPTR_MIN INT64_MIN
-# define INTPTR_MAX INT64_MAX
-# define UINTPTR_MAX UINT64_MAX
-#else // _WIN64 ][
-# define INTPTR_MIN INT32_MIN
-# define INTPTR_MAX INT32_MAX
-# define UINTPTR_MAX UINT32_MAX
-#endif // _WIN64 ]
-
-// 7.18.2.5 Limits of greatest-width integer types
-#define INTMAX_MIN INT64_MIN
-#define INTMAX_MAX INT64_MAX
-#define UINTMAX_MAX UINT64_MAX
-
-// 7.18.3 Limits of other integer types
-
-#ifdef _WIN64 // [
-# define PTRDIFF_MIN _I64_MIN
-# define PTRDIFF_MAX _I64_MAX
-#else // _WIN64 ][
-# define PTRDIFF_MIN _I32_MIN
-# define PTRDIFF_MAX _I32_MAX
-#endif // _WIN64 ]
-
-#define SIG_ATOMIC_MIN INT_MIN
-#define SIG_ATOMIC_MAX INT_MAX
-
-#ifndef SIZE_MAX // [
-# ifdef _WIN64 // [
-# define SIZE_MAX _UI64_MAX
-# else // _WIN64 ][
-# define SIZE_MAX _UI32_MAX
-# endif // _WIN64 ]
-#endif // SIZE_MAX ]
-
-#endif // __STDC_LIMIT_MACROS ]
-
-#ifndef _INTPTR_T_DEFINED
-#ifdef _WIN64
-typedef __int64 intptr_t;
-#else
-typedef long intptr_t;
-#endif
-#define _INTPTR_T_DEFINED
-#endif
-
-#ifndef _UINTPTR_T_DEFINED
-#ifdef _WIN64
-typedef unsigned __int64 uintptr_t;
-#else
-typedef unsigned long uintptr_t;
-#endif
-#define _UINTPTR_T_DEFINED
-#endif
-
-#elif defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__)
+#if defined(__linux__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD_kernel__) || defined(__GNU__)
/* Linux-i386, Linux-Alpha, Linux-ppc */
#include <stdint.h>
@@ -186,7 +66,7 @@ typedef uint64_t u_int64_t;
#include <inttypes.h>
/* MinGW and MSVC >= 2010 */
-#elif defined(FREE_WINDOWS) || (defined(_MSC_VER) && _MSC_VER >= 1600)
+#elif defined(FREE_WINDOWS) || defined(_MSC_VER)
#include <stdint.h>
#else
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index c9cbaf997fb..8c22a25fe14 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -100,6 +100,18 @@ ThreadMutex *BLI_task_pool_user_mutex(TaskPool *pool);
/* number of tasks done, for stats, don't use this to make decisions */
size_t BLI_task_pool_tasks_done(TaskPool *pool);
+/* Parallel for routines */
+typedef void (*TaskParallelRangeFunc)(void *userdata, int iter);
+void BLI_task_parallel_range_ex(
+ int start, int stop,
+ void *userdata,
+ TaskParallelRangeFunc func,
+ const int range_threshold);
+void BLI_task_parallel_range(
+ int start, int stop,
+ void *userdata,
+ TaskParallelRangeFunc func);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h
index 1c9e75d950a..74291ca305e 100644
--- a/source/blender/blenlib/BLI_threads.h
+++ b/source/blender/blenlib/BLI_threads.h
@@ -74,8 +74,6 @@ void BLI_end_threaded_malloc(void);
int BLI_system_thread_count(void); /* gets the number of threads the system can make use of */
void BLI_system_num_threads_override_set(int num);
int BLI_system_num_threads_override_get(void);
-
-int BLI_system_thread_count_omp(void);
/* Global Mutex Locks
*
diff --git a/source/blender/blenlib/BLI_utildefines.h b/source/blender/blenlib/BLI_utildefines.h
index f70befddc4d..736578361b3 100644
--- a/source/blender/blenlib/BLI_utildefines.h
+++ b/source/blender/blenlib/BLI_utildefines.h
@@ -40,6 +40,29 @@
#include <stdio.h>
#endif
+
+/* varargs macros (keep first so others can use) */
+/* --- internal helpers --- */
+#define _VA_NARGS_GLUE(x, y) x y
+#define _VA_NARGS_RETURN_COUNT(\
+ _1_, _2_, _3_, _4_, _5_, _6_, _7_, _8_, _9_, _10_, _11_, _12_, _13_, _14_, _15_, _16_, \
+ _17_, _18_, _19_, _20_, _21_, _22_, _23_, _24_, _25_, _26_, _27_, _28_, _29_, _30_, _31_, _32_, \
+ _33_, _34_, _35_, _36_, _37_, _38_, _39_, _40_, _41_, _42_, _43_, _44_, _45_, _46_, _47_, _48_, \
+ _49_, _50_, _51_, _52_, _53_, _54_, _55_, _56_, _57_, _58_, _59_, _60_, _61_, _62_, _63_, _64_, \
+ count, ...) count
+#define _VA_NARGS_EXPAND(args) _VA_NARGS_RETURN_COUNT args
+#define _VA_NARGS_COUNT_MAX32(...) _VA_NARGS_EXPAND((__VA_ARGS__, \
+ 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, \
+ 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
+ 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
+#define _VA_NARGS_OVERLOAD_MACRO2(name, count) name##count
+#define _VA_NARGS_OVERLOAD_MACRO1(name, count) _VA_NARGS_OVERLOAD_MACRO2(name, count)
+#define _VA_NARGS_OVERLOAD_MACRO(name, count) _VA_NARGS_OVERLOAD_MACRO1(name, count)
+/* --- expose for re-use --- */
+#define VA_NARGS_CALL_OVERLOAD(name, ...) \
+ _VA_NARGS_GLUE(_VA_NARGS_OVERLOAD_MACRO(name, _VA_NARGS_COUNT_MAX32(__VA_ARGS__)), (__VA_ARGS__))
+
/* useful for finding bad use of min/max */
#if 0
/* gcc only */
@@ -48,6 +71,9 @@
# define MAX2(x, y) (_TYPECHECK(x, y), (((x) > (y) ? (x) : (y))))
#endif
+/* include after _VA_NARGS macro */
+#include "BLI_compiler_typecheck.h"
+
/* min/max */
#if defined(__GNUC__) || defined(__clang__)
@@ -132,29 +158,6 @@
/* some math and copy defines */
-/* Causes warning:
- * incompatible types when assigning to type 'Foo' from type 'Bar'
- * ... the compiler optimizes away the temp var */
-#ifdef __GNUC__
-#define CHECK_TYPE(var, type) { \
- __typeof(var) *__tmp; \
- __tmp = (type *)NULL; \
- (void)__tmp; \
-} (void)0
-
-#define CHECK_TYPE_PAIR(var_a, var_b) { \
- __typeof(var_a) *__tmp; \
- __tmp = (__typeof(var_b) *)NULL; \
- (void)__tmp; \
-} (void)0
-#else
-# define CHECK_TYPE(var, type)
-# define CHECK_TYPE_PAIR(var_a, var_b)
-#endif
-
-/* can be used in simple macros */
-#define CHECK_TYPE_INLINE(val, type) \
- ((void)(((type)0) != (val)))
#define SWAP(type, a, b) { \
type sw_ap; \
@@ -174,17 +177,42 @@
(b) = (tval); \
} (void)0
-/* ELEM#(a, ...): is the first arg equal any of the others */
-#define ELEM(a, b, c) ((a) == (b) || (a) == (c))
-#define ELEM3(a, b, c, d) (ELEM(a, b, c) || (a) == (d) )
-#define ELEM4(a, b, c, d, e) (ELEM(a, b, c) || ELEM(a, d, e) )
-#define ELEM5(a, b, c, d, e, f) (ELEM(a, b, c) || ELEM3(a, d, e, f) )
-#define ELEM6(a, b, c, d, e, f, g) (ELEM(a, b, c) || ELEM4(a, d, e, f, g) )
-#define ELEM7(a, b, c, d, e, f, g, h) (ELEM3(a, b, c, d) || ELEM4(a, e, f, g, h) )
-#define ELEM8(a, b, c, d, e, f, g, h, i) (ELEM4(a, b, c, d, e) || ELEM4(a, f, g, h, i) )
-#define ELEM9(a, b, c, d, e, f, g, h, i, j) (ELEM4(a, b, c, d, e) || ELEM5(a, f, g, h, i, j) )
-#define ELEM10(a, b, c, d, e, f, g, h, i, j, k) (ELEM4(a, b, c, d, e) || ELEM6(a, f, g, h, i, j, k) )
-#define ELEM11(a, b, c, d, e, f, g, h, i, j, k, l) (ELEM4(a, b, c, d, e) || ELEM7(a, f, g, h, i, j, k, l) )
+/* ELEM#(v, ...): is the first arg equal any others? */
+/* internal helpers*/
+#define _VA_ELEM3(v, a, b) \
+ (((v) == (a)) || ((v) == (b)))
+#define _VA_ELEM4(v, a, b, c) \
+ (_VA_ELEM3(v, a, b) || ((v) == (c)))
+#define _VA_ELEM5(v, a, b, c, d) \
+ (_VA_ELEM4(v, a, b, c) || ((v) == (d)))
+#define _VA_ELEM6(v, a, b, c, d, e) \
+ (_VA_ELEM5(v, a, b, c, d) || ((v) == (e)))
+#define _VA_ELEM7(v, a, b, c, d, e, f) \
+ (_VA_ELEM6(v, a, b, c, d, e) || ((v) == (f)))
+#define _VA_ELEM8(v, a, b, c, d, e, f, g) \
+ (_VA_ELEM7(v, a, b, c, d, e, f) || ((v) == (g)))
+#define _VA_ELEM9(v, a, b, c, d, e, f, g, h) \
+ (_VA_ELEM8(v, a, b, c, d, e, f, g) || ((v) == (h)))
+#define _VA_ELEM10(v, a, b, c, d, e, f, g, h, i) \
+ (_VA_ELEM9(v, a, b, c, d, e, f, g, h) || ((v) == (i)))
+#define _VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) \
+ (_VA_ELEM10(v, a, b, c, d, e, f, g, h, i) || ((v) == (j)))
+#define _VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) \
+ (_VA_ELEM11(v, a, b, c, d, e, f, g, h, i, j) || ((v) == (k)))
+#define _VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) \
+ (_VA_ELEM12(v, a, b, c, d, e, f, g, h, i, j, k) || ((v) == (l)))
+#define _VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) \
+ (_VA_ELEM13(v, a, b, c, d, e, f, g, h, i, j, k, l) || ((v) == (m)))
+#define _VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) \
+ (_VA_ELEM14(v, a, b, c, d, e, f, g, h, i, j, k, l, m) || ((v) == (n)))
+#define _VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) \
+ (_VA_ELEM15(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n) || ((v) == (o)))
+#define _VA_ELEM17(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p) \
+ (_VA_ELEM16(v, a, b, c, d, e, f, g, h, i, j, k, l, m, n, o) || ((v) == (p)))
+
+/* reusable ELEM macro */
+#define ELEM(...) VA_NARGS_CALL_OVERLOAD(_VA_ELEM, __VA_ARGS__)
+
/* shift around elements */
#define SHIFT3(type, a, b, c) { \
@@ -281,10 +309,14 @@
#define ABS(a) ({ \
typeof(a) a_ = (a); \
((a_) < 0 ? (-(a_)) : (a_)); })
+#define SQUARE(a) ({ \
+ typeof(a) a_ = (a); \
+ ((a_) * (a_)); })
#else
#define ABS(a) ((a) < 0 ? (-(a)) : (a))
+#define SQUARE(a) ((a) * (a))
#endif
@@ -305,54 +337,32 @@
#define IS_EQ(a, b) ( \
CHECK_TYPE_INLINE(a, double), CHECK_TYPE_INLINE(b, double), \
- ((fabs((double)(a) - (b)) >= (double) FLT_EPSILON) ? false : true))
+ ((fabs((double)((a) - (b))) >= (double) FLT_EPSILON) ? false : true))
#define IS_EQF(a, b) ( \
CHECK_TYPE_INLINE(a, float), CHECK_TYPE_INLINE(b, float), \
- ((fabsf((float)(a) - (b)) >= (float) FLT_EPSILON) ? false : true))
+ ((fabsf((float)((a) - (b))) >= (float) FLT_EPSILON) ? false : true))
#define IS_EQT(a, b, c) ((a > b) ? (((a - b) <= c) ? 1 : 0) : ((((b - a) <= c) ? 1 : 0)))
#define IN_RANGE(a, b, c) ((b < c) ? ((b < a && a < c) ? 1 : 0) : ((c < a && a < b) ? 1 : 0))
#define IN_RANGE_INCL(a, b, c) ((b < c) ? ((b <= a && a <= c) ? 1 : 0) : ((c <= a && a <= b) ? 1 : 0))
/* unpack vector for args */
-#define UNPACK2(a) ((a)[0]), ((a)[1])
-#define UNPACK3(a) ((a)[0]), ((a)[1]), ((a)[2])
-#define UNPACK4(a) ((a)[0]), ((a)[1]), ((a)[2]), ((a)[3])
-/* op may be '&' or '*' */
-#define UNPACK2OP(op, a) op((a)[0]), op((a)[1])
-#define UNPACK3OP(op, a) op((a)[0]), op((a)[1]), op((a)[2])
-#define UNPACK4OP(op, a) op((a)[0]), op((a)[1]), op((a)[2]), op((a)[3])
-
-/* simple stack */
-#define STACK_DECLARE(stack) unsigned int _##stack##_index
-#define STACK_INIT(stack) ((void)stack, (void)((_##stack##_index) = 0))
-#define STACK_SIZE(stack) ((void)stack, (_##stack##_index))
-#define STACK_PUSH(stack, val) (void)((stack)[(_##stack##_index)++] = val)
-#define STACK_PUSH_RET(stack) ((void)stack, ((stack)[(_##stack##_index)++]))
-#define STACK_PUSH_RET_PTR(stack) ((void)stack, &((stack)[(_##stack##_index)++]))
-#define STACK_POP(stack) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : NULL)
-#define STACK_POP_PTR(stack) ((_##stack##_index) ? &((stack)[--(_##stack##_index)]) : NULL)
-#define STACK_POP_ELSE(stack, r) ((_##stack##_index) ? ((stack)[--(_##stack##_index)]) : r)
-#define STACK_FREE(stack) ((void)stack)
-#ifdef __GNUC__
-#define STACK_SWAP(stack_a, stack_b) { \
- SWAP(typeof(stack_a), stack_a, stack_b); \
- SWAP(unsigned int, _##stack_a##_index, _##stack_b##_index); \
- } (void)0
-#else
-#define STACK_SWAP(stack_a, stack_b) { \
- SWAP(void *, stack_a, stack_b); \
- SWAP(unsigned int, _##stack_a##_index, _##stack_b##_index); \
- } (void)0
-#endif
+#define UNPACK2(a) ((a)[0]), ((a)[1])
+#define UNPACK3(a) UNPACK2(a), ((a)[2])
+#define UNPACK4(a) UNPACK3(a), ((a)[3])
+/* pre may be '&', '*' or func, post may be '->member' */
+#define UNPACK2_EX(pre, a, post) (pre((a)[0])post), (pre((a)[1])post)
+#define UNPACK3_EX(pre, a, post) UNPACK2_EX(pre, a, post), (pre((a)[2])post)
+#define UNPACK4_EX(pre, a, post) UNPACK3_EX(pre, a, post), (pre((a)[3])post)
/* array helpers */
-#define ARRAY_LAST_ITEM(arr_start, arr_dtype, elem_size, tot) \
- (arr_dtype *)((char *)arr_start + (elem_size * (tot - 1)))
+#define ARRAY_LAST_ITEM(arr_start, arr_dtype, tot) \
+ (arr_dtype *)((char *)arr_start + (sizeof(*((arr_dtype *)NULL)) * (size_t)(tot - 1)))
-#define ARRAY_HAS_ITEM(arr_item, arr_start, tot) \
- ((unsigned int)((arr_item) - (arr_start)) < (unsigned int)(tot))
+#define ARRAY_HAS_ITEM(arr_item, arr_start, tot) ( \
+ CHECK_TYPE_PAIR_INLINE(arr_start, arr_item), \
+ ((unsigned int)((arr_item) - (arr_start)) < (unsigned int)(tot)))
#define ARRAY_DELETE(arr, index, tot_delete, tot) { \
BLI_assert(index + tot_delete <= tot); \
@@ -361,13 +371,36 @@
(((tot) - (index)) - (tot_delete)) * sizeof(*(arr))); \
} (void)0
+/* assuming a static array */
+#if defined(__GNUC__) && !defined(__cplusplus)
+# define ARRAY_SIZE(arr) \
+ ((sizeof(struct {int isnt_array : ((void *)&(arr) == &(arr)[0]);}) * 0) + \
+ (sizeof(arr) / sizeof(*(arr))))
+#else
+# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(*(arr)))
+#endif
+
+/* Like offsetof(typeof(), member), for non-gcc compilers */
+#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 */
+#define MEMCPY_STRUCT_OFS(struct_dst, struct_src, member) { \
+ CHECK_TYPE_NONCONST(struct_dst); \
+ ((void)(struct_dst == struct_src), \
+ memcpy((char *)(struct_dst) + OFFSETOF_STRUCT(struct_dst, member), \
+ (char *)(struct_src) + OFFSETOF_STRUCT(struct_dst, member), \
+ sizeof(*(struct_dst)) - OFFSETOF_STRUCT(struct_dst, 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))
-#define GET_INT_FROM_POINTER(i) ((int)(intptr_t)(i))
+#define GET_INT_FROM_POINTER(i) ((void)0, ((int)(intptr_t)(i)))
#define SET_UINT_IN_POINTER(i) ((void *)(uintptr_t)(i))
-#define GET_UINT_FROM_POINTER(i) ((unsigned int)(uintptr_t)(i))
+#define GET_UINT_FROM_POINTER(i) ((void)0, ((unsigned int)(uintptr_t)(i)))
/* Macro to convert a value to string in the preprocessor
diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h
index f615e5a9300..f40359ec3dc 100644
--- a/source/blender/blenlib/BLI_winstuff.h
+++ b/source/blender/blenlib/BLI_winstuff.h
@@ -125,10 +125,6 @@ typedef long ssize_t;
# endif
#endif
-
-#ifdef FREE_WINDOWS
-#include <dirent.h>
-#else
struct dirent {
int d_ino;
int d_off;
@@ -151,7 +147,6 @@ typedef struct _DIR {
DIR *opendir(const char *path);
struct dirent *readdir(DIR *dp);
int closedir(DIR *dp);
-#endif
void RegisterBlendExtension(void);
void get_default_root(char *root);
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 9e360741b23..9efa20da13e 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -42,6 +42,7 @@ set(INC_SYS
set(SRC
intern/BLI_args.c
intern/BLI_array.c
+ intern/BLI_dial.c
intern/BLI_dynstr.c
intern/BLI_ghash.c
intern/BLI_heap.c
@@ -117,7 +118,9 @@ set(SRC
BLI_callbacks.h
BLI_compiler_attrs.h
BLI_compiler_compat.h
+ BLI_compiler_typecheck.h
BLI_convexhull2d.h
+ BLI_dial.h
BLI_dlrbTree.h
BLI_dynlib.h
BLI_dynstr.h
@@ -164,6 +167,7 @@ set(SRC
BLI_sort.h
BLI_sort_utils.h
BLI_stack.h
+ BLI_stackdefines.h
BLI_strict_flags.h
BLI_string.h
BLI_string_cursor_utf8.h
diff --git a/source/blender/blenlib/intern/BLI_args.c b/source/blender/blenlib/intern/BLI_args.c
index 8bd35f651b7..49a3c466727 100644
--- a/source/blender/blenlib/intern/BLI_args.c
+++ b/source/blender/blenlib/intern/BLI_args.c
@@ -91,15 +91,17 @@ static unsigned int keyhash(const void *ptr)
return case_strhash(k->arg); /* ^ BLI_ghashutil_inthash((void *)k->pass); */
}
-static int keycmp(const void *a, const void *b)
+static bool keycmp(const void *a, const void *b)
{
const bAKey *ka = a;
const bAKey *kb = b;
if (ka->pass == kb->pass || ka->pass == -1 || kb->pass == -1) { /* -1 is wildcard for pass */
- if (ka->case_str == 1 || kb->case_str == 1)
- return BLI_strcasecmp(ka->arg, kb->arg);
- else
- return strcmp(ka->arg, kb->arg);
+ if (ka->case_str == 1 || kb->case_str == 1) {
+ return (BLI_strcasecmp(ka->arg, kb->arg) != 0);
+ }
+ else {
+ return (strcmp(ka->arg, kb->arg) != 0);
+ }
}
else {
return BLI_ghashutil_intcmp((const void *)ka->pass, (const void *)kb->pass);
diff --git a/source/blender/blenlib/intern/BLI_array.c b/source/blender/blenlib/intern/BLI_array.c
index 21d7a5a6d10..da2eef8ab6a 100644
--- a/source/blender/blenlib/intern/BLI_array.c
+++ b/source/blender/blenlib/intern/BLI_array.c
@@ -137,3 +137,18 @@ void _bli_array_wrap(void *arr_v, unsigned int arr_len, size_t arr_stride, int d
BLI_assert(0);
}
}
+
+/**
+ * \note Not efficient, use for error checks/asserts.
+ */
+int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p)
+{
+ const char *arr_step = (const char *)arr;
+ unsigned int i;
+ for (i = 0; i < arr_len; i++, arr_step += arr_stride) {
+ if (memcmp(arr_step, p, arr_stride) == 0) {
+ return (int)i;
+ }
+ }
+ return -1;
+}
diff --git a/source/blender/blenlib/intern/BLI_dial.c b/source/blender/blenlib/intern/BLI_dial.c
new file mode 100644
index 00000000000..cfbb52847fd
--- /dev/null
+++ b/source/blender/blenlib/intern/BLI_dial.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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "BLI_dial.h"
+#include "BLI_math.h"
+
+#include "MEM_guardedalloc.h"
+
+struct Dial {
+ /* center of the dial */
+ float center[2];
+
+ /* threshold of the dial. Distance of current position has to be greater
+ * than the threshold to be used in any calculations */
+ float threshold_squared;
+
+ /* the direction of the first dial position exceeding the threshold. This
+ * is later used as the basis against which rotation angle is calculated */
+ float initial_direction[2];
+
+ /* cache the last angle to detect rotations bigger than -/+ PI */
+ float last_angle;
+
+ /* number of full rotations */
+ int rotations;
+
+ /* has initial_direction been initialized */
+ bool initialized;
+};
+
+
+Dial *BLI_dial_initialize(float start_position[2], float threshold)
+{
+ Dial *dial = MEM_callocN(sizeof(Dial), "dial");
+
+ copy_v2_v2(dial->center, start_position);
+ dial->threshold_squared = threshold * threshold;
+
+ return dial;
+}
+
+float BLI_dial_angle(Dial *dial, float current_position[2])
+{
+ float current_direction[2];
+
+ sub_v2_v2v2(current_direction, current_position, dial->center);
+
+ /* only update when we have enough precision, by having the mouse adequately away from center */
+ if (len_squared_v2(current_direction) > dial->threshold_squared) {
+ float angle;
+ float cosval, sinval;
+
+ normalize_v2(current_direction);
+
+ if (!dial->initialized) {
+ copy_v2_v2(dial->initial_direction, current_direction);
+ dial->initialized = true;
+ }
+
+ /* calculate mouse angle between initial and final mouse position */
+ cosval = dot_v2v2(current_direction, dial->initial_direction);
+ sinval = cross_v2v2(current_direction, dial->initial_direction);
+
+ /* clamp to avoid nans in acos */
+ angle = atan2f(sinval, cosval);
+
+ /* change of sign, we passed the 180 degree threshold. This means we need to add a turn.
+ * to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2 */
+ if ((angle * dial->last_angle < 0.0f) &&
+ (fabsf(dial->last_angle) > (float)M_PI_2))
+ {
+ if (dial->last_angle < 0.0f)
+ dial->rotations--;
+ else
+ dial->rotations++;
+ }
+ dial->last_angle = angle;
+
+ return angle + 2.0f * (float)M_PI * dial->rotations;
+ }
+
+ return dial->last_angle;
+}
diff --git a/source/blender/blenlib/intern/BLI_dynstr.c b/source/blender/blenlib/intern/BLI_dynstr.c
index 4c712a2f237..8617132e988 100644
--- a/source/blender/blenlib/intern/BLI_dynstr.c
+++ b/source/blender/blenlib/intern/BLI_dynstr.c
@@ -34,6 +34,7 @@
#include <string.h>
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "BLI_dynstr.h"
@@ -67,6 +68,11 @@ struct DynStr {
/***/
+/**
+ * Create a new DynStr.
+ *
+ * \return Pointer to a new DynStr.
+ */
DynStr *BLI_dynstr_new(void)
{
DynStr *ds = MEM_mallocN(sizeof(*ds), "DynStr");
@@ -76,7 +82,13 @@ DynStr *BLI_dynstr_new(void)
return ds;
}
-void BLI_dynstr_append(DynStr *ds, const char *cstr)
+/**
+ * Append a c-string to a DynStr.
+ *
+ * \param ds The DynStr to append to.
+ * \param cstr The c-string to append.
+ */
+void BLI_dynstr_append(DynStr *__restrict ds, const char *cstr)
{
DynStrElem *dse = malloc(sizeof(*dse));
int cstrlen = strlen(cstr);
@@ -93,7 +105,14 @@ void BLI_dynstr_append(DynStr *ds, const char *cstr)
ds->curlen += cstrlen;
}
-void BLI_dynstr_nappend(DynStr *ds, const char *cstr, int len)
+/**
+ * Append a length clamped c-string to a DynStr.
+ *
+ * \param ds The DynStr to append to.
+ * \param cstr The c-string to append.
+ * \param len The maximum length of the c-string to copy.
+ */
+void BLI_dynstr_nappend(DynStr *__restrict ds, const char *cstr, int len)
{
DynStrElem *dse = malloc(sizeof(*dse));
int cstrlen = BLI_strnlen(cstr, len);
@@ -111,7 +130,7 @@ void BLI_dynstr_nappend(DynStr *ds, const char *cstr, int len)
ds->curlen += cstrlen;
}
-void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args)
+void BLI_dynstr_vappendf(DynStr *__restrict ds, const char *__restrict format, va_list args)
{
char *message, fixedmessage[256];
int len = sizeof(fixedmessage);
@@ -164,7 +183,13 @@ void BLI_dynstr_vappendf(DynStr *ds, const char *format, va_list args)
}
}
-void BLI_dynstr_appendf(DynStr *ds, const char *format, ...)
+/**
+ * Append a c-string to a DynStr, but with formatting like printf.
+ *
+ * \param ds The DynStr to append to.
+ * \param format The printf format string to use.
+ */
+void BLI_dynstr_appendf(DynStr *__restrict ds, const char *__restrict format, ...)
{
va_list args;
char *message, fixedmessage[256];
@@ -220,12 +245,26 @@ void BLI_dynstr_appendf(DynStr *ds, const char *format, ...)
}
}
+/**
+ * Find the length of a DynStr.
+ *
+ * \param ds The DynStr of interest.
+ * \return The length of \a ds.
+ */
int BLI_dynstr_get_len(DynStr *ds)
{
return ds->curlen;
}
-void BLI_dynstr_get_cstring_ex(DynStr *ds, char *rets)
+/**
+ * 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>
+ *
+ * \param ds The DynStr of interest.
+ * \param str The string to fill.
+ */
+void BLI_dynstr_get_cstring_ex(DynStr *__restrict ds, char *__restrict rets)
{
char *s;
DynStrElem *dse;
@@ -237,9 +276,18 @@ void BLI_dynstr_get_cstring_ex(DynStr *ds, char *rets)
s += slen;
}
+ BLI_assert((s - rets) == ds->curlen);
rets[ds->curlen] = '\0';
}
+/**
+ * Get a DynStr's contents as a c-string.
+ * <i> The returned c-string should be freed
+ * using MEM_freeN. </i>
+ *
+ * \param ds The DynStr of interest.
+ * \return The contents of \a ds as a c-string.
+ */
char *BLI_dynstr_get_cstring(DynStr *ds)
{
char *rets = MEM_mallocN(ds->curlen + 1, "dynstr_cstring");
@@ -247,6 +295,11 @@ char *BLI_dynstr_get_cstring(DynStr *ds)
return rets;
}
+/**
+ * Free the DynStr
+ *
+ * \param ds The DynStr to free.
+ */
void BLI_dynstr_free(DynStr *ds)
{
DynStrElem *dse;
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index 7b48744bcdf..6747e5c4e7e 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -155,7 +155,7 @@ BLI_INLINE Entry *ghash_lookup_entry_ex(GHash *gh, const void *key,
Entry *e;
for (e = gh->buckets[hash]; e; e = e->next) {
- if (UNLIKELY(gh->cmpfp(key, e->key) == 0)) {
+ if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
return e;
}
}
@@ -251,7 +251,7 @@ static Entry *ghash_remove_ex(GHash *gh, void *key, GHashKeyFreeFP keyfreefp, GH
Entry *e_prev = NULL;
for (e = gh->buckets[hash]; e; e = e->next) {
- if (UNLIKELY(gh->cmpfp(key, e->key) == 0)) {
+ if (UNLIKELY(gh->cmpfp(key, e->key) == false)) {
Entry *e_next = e->next;
if (keyfreefp) keyfreefp(e->key);
@@ -399,7 +399,7 @@ void *BLI_ghash_lookup_default(GHash *gh, const void *key, void *val_default)
* \param key The key to lookup.
* \returns the pointer to value for \a key or NULL.
*
- * \note This has 2 main benifits over #BLI_ghash_lookup.
+ * \note This has 2 main benefits over #BLI_ghash_lookup.
* - A NULL return always means that \a key isn't in \a gh.
* - The value can be modified in-place without further function calls (faster).
*/
@@ -570,12 +570,12 @@ void BLI_ghashIterator_init(GHashIterator *ghi, GHash *gh)
ghi->curEntry = NULL;
ghi->curBucket = UINT_MAX; /* wraps to zero */
if (gh->nentries) {
- while (!ghi->curEntry) {
+ do {
ghi->curBucket++;
if (UNLIKELY(ghi->curBucket == ghi->gh->nbuckets))
break;
ghi->curEntry = ghi->gh->buckets[ghi->curBucket];
- }
+ } while (!ghi->curEntry);
}
}
@@ -683,12 +683,9 @@ unsigned int BLI_ghashutil_ptrhash(const void *key)
return (unsigned int)y;
}
#endif
-int BLI_ghashutil_ptrcmp(const void *a, const void *b)
+bool BLI_ghashutil_ptrcmp(const void *a, const void *b)
{
- if (a == b)
- return 0;
- else
- return (a < b) ? -1 : 1;
+ return (a != b);
}
unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4])
@@ -704,6 +701,11 @@ unsigned int BLI_ghashutil_uinthash_v4(const unsigned int key[4])
return hash;
}
+bool BLI_ghashutil_uinthash_v4_cmp(const void *a, const void *b)
+{
+ return (memcmp(a, b, sizeof(unsigned int[4])) != 0);
+}
+
unsigned int BLI_ghashutil_uinthash(unsigned int key)
{
key += ~(key << 16);
@@ -730,19 +732,16 @@ unsigned int BLI_ghashutil_inthash_p(const void *ptr)
return (unsigned int)(key & 0xffffffff);
}
-int BLI_ghashutil_intcmp(const void *a, const void *b)
+bool BLI_ghashutil_intcmp(const void *a, const void *b)
{
- if (a == b)
- return 0;
- else
- return (a < b) ? -1 : 1;
+ return (a != b);
}
/**
* This function implements the widely used "djb" hash apparently posted
* by Daniel Bernstein to comp.lang.c some time ago. The 32 bit
* unsigned hash value starts at 5381 and for each byte 'c' in the
- * string, is updated: <literal>hash = hash * 33 + c</literal>. This
+ * string, is updated: ``hash = hash * 33 + c``. This
* function uses the signed value of each byte.
*
* note: this is the same hash method that glib 2.34.0 uses.
@@ -769,9 +768,9 @@ unsigned int BLI_ghashutil_strhash_p(const void *ptr)
return h;
}
-int BLI_ghashutil_strcmp(const void *a, const void *b)
+bool BLI_ghashutil_strcmp(const void *a, const void *b)
{
- return strcmp(a, b);
+ return (strcmp(a, b) != 0);
}
GHashPair *BLI_ghashutil_pairalloc(const void *first, const void *second)
@@ -789,15 +788,13 @@ unsigned int BLI_ghashutil_pairhash(const void *ptr)
return hash ^ BLI_ghashutil_ptrhash(pair->second);
}
-int BLI_ghashutil_paircmp(const void *a, const void *b)
+bool BLI_ghashutil_paircmp(const void *a, const void *b)
{
const GHashPair *A = a;
const GHashPair *B = b;
- int cmp = BLI_ghashutil_ptrcmp(A->first, B->first);
- if (cmp == 0)
- return BLI_ghashutil_ptrcmp(A->second, B->second);
- return cmp;
+ return (BLI_ghashutil_ptrcmp(A->first, B->first) ||
+ BLI_ghashutil_ptrcmp(A->second, B->second));
}
void BLI_ghashutil_pairfree(void *ptr)
@@ -901,6 +898,25 @@ void BLI_gset_insert(GSet *gs, void *key)
}
/**
+ * A version of BLI_gset_insert which checks first if the key is in the set.
+ * \returns true if a new key has been added.
+ *
+ * \note GHash has no equivalent to this because typically the value would be different.
+ */
+bool BLI_gset_add(GSet *gs, void *key)
+{
+ const unsigned int hash = ghash_keyhash((GHash *)gs, key);
+ Entry *e = ghash_lookup_entry_ex((GHash *)gs, key, hash);
+ if (e) {
+ return false;
+ }
+ else {
+ ghash_insert_ex_keyonly((GHash *)gs, key, hash);
+ return true;
+ }
+}
+
+/**
* Adds the key to the set (duplicates are managed).
* Matching #BLI_ghash_reinsert
*
@@ -948,6 +964,17 @@ void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
{
BLI_ghash_free((GHash *)gs, keyfreefp, NULL);
}
+
+void BLI_gset_flag_set(GSet *gs, unsigned int flag)
+{
+ ((GHash *)gs)->flag |= flag;
+}
+
+void BLI_gset_flag_clear(GSet *gs, unsigned int flag)
+{
+ ((GHash *)gs)->flag &= ~flag;
+}
+
/** \} */
@@ -977,3 +1004,41 @@ GSet *BLI_gset_pair_new(const char *info)
}
/** \} */
+
+
+/** \name Debugging & Introspection
+ * \{ */
+#ifdef DEBUG
+
+/**
+ * Measure how well the hash function performs
+ * (1.0 is approx as good as random distribution).
+ *
+ * Smaller is better!
+ */
+double BLI_ghash_calc_quality(GHash *gh)
+{
+ uint64_t sum = 0;
+ unsigned int i;
+
+ if (gh->nentries == 0)
+ return -1.0;
+
+ for (i = 0; i < gh->nbuckets; i++) {
+ uint64_t count = 0;
+ Entry *e;
+ for (e = gh->buckets[i]; e; e = e->next) {
+ count += 1;
+ }
+ sum += count * (count + 1);
+ }
+ return ((double)sum * (double)gh->nbuckets /
+ ((double)gh->nentries * (gh->nentries + 2 * gh->nbuckets - 1)));
+}
+double BLI_gset_calc_quality(GSet *gs)
+{
+ return BLI_ghash_calc_quality((GHash *)gs);
+}
+
+#endif
+/** \} */
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index 6b1fbe855a1..d28215ee8ed 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_stack.h"
#include "BLI_kdopbvh.h"
#include "BLI_math.h"
#include "BLI_strict_flags.h"
@@ -42,14 +43,30 @@
#include <omp.h>
#endif
+/* used for iterative_raycast */
+// #define USE_SKIP_LINKS
+
#define MAX_TREETYPE 32
+/* Setting zero so we can catch bugs in OpenMP/KDOPBVH.
+ * TODO(sergey): Deduplicate the limits with PBVH from BKE.
+ */
+#ifdef _OPENMP
+# ifdef DEBUG
+# define KDOPBVH_OMP_LIMIT 0
+# else
+# define KDOPBVH_OMP_LIMIT 1024
+# endif
+#endif
+
typedef unsigned char axis_t;
typedef struct BVHNode {
struct BVHNode **children;
struct BVHNode *parent; /* some user defined traversed need that */
+#ifdef USE_SKIP_LINKS
struct BVHNode *skip[2];
+#endif
float *bv; /* Bounding volume of all nodes, max 13 axis */
int index; /* face, edge, vertex index */
char totnode; /* how many nodes are used, used for speedup */
@@ -77,9 +94,7 @@ BLI_STATIC_ASSERT((sizeof(void *) == 8 && sizeof(BVHTree) <= 48) ||
typedef struct BVHOverlapData {
BVHTree *tree1, *tree2;
- BVHTreeOverlap *overlap;
- unsigned int i;
- unsigned int max_overlap; /* i is number of overlaps */
+ struct BLI_Stack *overlap; /* store BVHTreeOverlap */
axis_t start_axis, stop_axis;
} BVHOverlapData;
@@ -375,7 +390,7 @@ static int partition_nth_element(BVHNode **a, int _begin, int _end, int n, int a
return n;
}
-/* --- */
+#ifdef USE_SKIP_LINKS
static void build_skip_links(BVHTree *tree, BVHNode *node, BVHNode *left, BVHNode *right)
{
int i;
@@ -392,6 +407,7 @@ static void build_skip_links(BVHTree *tree, BVHNode *node, BVHNode *left, BVHNod
left = node->children[i];
}
}
+#endif
/*
* BVHTree bounding volumes functions
@@ -670,7 +686,7 @@ static int implicit_leafs_index(BVHBuildHelper *data, int depth, int child_index
/* This functions returns the number of branches needed to have the requested number of leafs. */
static int implicit_needed_branches(int tree_type, int leafs)
{
- return max_ii(1, (leafs + tree_type - 3) / (tree_type - 1) );
+ return max_ii(1, (leafs + tree_type - 3) / (tree_type - 1));
}
/**
@@ -750,7 +766,8 @@ static void non_recursive_bvh_div_nodes(BVHTree *tree, BVHNode *branches_array,
int j;
/* Loop all branches on this level */
-#pragma omp parallel for private(j) schedule(static)
+
+#pragma omp parallel for private(j) schedule(static) if (num_leafs > KDOPBVH_OMP_LIMIT)
for (j = i; j < end_j; j++) {
int k;
const int parent_level_index = j - i;
@@ -931,7 +948,10 @@ void BLI_bvhtree_balance(BVHTree *tree)
for (i = 0; i < tree->totbranch; i++)
tree->nodes[tree->totleaf + i] = branches_array + i;
+#ifdef USE_SKIP_LINKS
build_skip_links(tree, tree->nodes[tree->totleaf], NULL, NULL);
+#endif
+
/* bvhtree_info(tree); */
}
@@ -959,7 +979,7 @@ void BLI_bvhtree_insert(BVHTree *tree, int index, const float co[3], int numpoin
/* call before BLI_bvhtree_update_tree() */
-int BLI_bvhtree_update_node(BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints)
+bool BLI_bvhtree_update_node(BVHTree *tree, int index, const float co[3], const float co_moving[3], int numpoints)
{
BVHNode *node = NULL;
axis_t axis_iter;
@@ -1038,27 +1058,16 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2)
if (!node1->totnode) {
/* check if node2 is a leaf */
if (!node2->totnode) {
+ BVHTreeOverlap *overlap;
- if (node1 == node2) {
+ if (UNLIKELY(node1 == node2)) {
return;
}
- if (data->i >= data->max_overlap) {
- /* try to make alloc'ed memory bigger */
- data->overlap = realloc(data->overlap, sizeof(BVHTreeOverlap) * (size_t)data->max_overlap * 2);
-
- if (!data->overlap) {
- printf("Out of Memory in traverse\n");
- return;
- }
- data->max_overlap *= 2;
- }
-
/* both leafs, insert overlap! */
- data->overlap[data->i].indexA = node1->index;
- data->overlap[data->i].indexB = node2->index;
-
- data->i++;
+ overlap = BLI_stack_push_r(data->overlap);
+ overlap->indexA = node1->index;
+ overlap->indexB = node2->index;
}
else {
for (j = 0; j < data->tree2->tree_type; j++) {
@@ -1077,16 +1086,21 @@ static void traverse(BVHOverlapData *data, BVHNode *node1, BVHNode *node2)
return;
}
-BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int *result)
+BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int *r_overlap_tot)
{
int j;
- unsigned int total = 0;
+ size_t total = 0;
BVHTreeOverlap *overlap = NULL, *to = NULL;
BVHOverlapData **data;
/* check for compatibility of both trees (can't compare 14-DOP with 18-DOP) */
- if ((tree1->axis != tree2->axis) && (tree1->axis == 14 || tree2->axis == 14) && (tree1->axis == 18 || tree2->axis == 18))
+ if (UNLIKELY((tree1->axis != tree2->axis) &&
+ (tree1->axis == 14 || tree2->axis == 14) &&
+ (tree1->axis == 18 || tree2->axis == 18)))
+ {
+ BLI_assert(0);
return NULL;
+ }
/* fast check root nodes for collision before doing big splitting + traversal */
if (!tree_overlap(tree1->nodes[tree1->totleaf], tree2->nodes[tree2->totleaf],
@@ -1096,43 +1110,42 @@ BVHTreeOverlap *BLI_bvhtree_overlap(BVHTree *tree1, BVHTree *tree2, unsigned int
return NULL;
}
- data = MEM_callocN(sizeof(BVHOverlapData *) * tree1->tree_type, "BVHOverlapData_star");
+ data = MEM_mallocN(sizeof(BVHOverlapData *) * tree1->tree_type, "BVHOverlapData_star");
for (j = 0; j < tree1->tree_type; j++) {
- data[j] = MEM_callocN(sizeof(BVHOverlapData), "BVHOverlapData");
+ data[j] = MEM_mallocN(sizeof(BVHOverlapData), "BVHOverlapData");
/* init BVHOverlapData */
- data[j]->overlap = malloc(sizeof(BVHTreeOverlap) * (size_t)max_ii(tree1->totleaf, tree2->totleaf));
+ data[j]->overlap = BLI_stack_new(sizeof(BVHTreeOverlap), __func__);
data[j]->tree1 = tree1;
data[j]->tree2 = tree2;
- data[j]->max_overlap = (unsigned int)max_ii(tree1->totleaf, tree2->totleaf);
- data[j]->i = 0;
data[j]->start_axis = min_axis(tree1->start_axis, tree2->start_axis);
data[j]->stop_axis = min_axis(tree1->stop_axis, tree2->stop_axis);
}
-#pragma omp parallel for private(j) schedule(static)
+#pragma omp parallel for private(j) schedule(static) if (tree1->totleaf > KDOPBVH_OMP_LIMIT)
for (j = 0; j < MIN2(tree1->tree_type, tree1->nodes[tree1->totleaf]->totnode); j++) {
traverse(data[j], tree1->nodes[tree1->totleaf]->children[j], tree2->nodes[tree2->totleaf]);
}
for (j = 0; j < tree1->tree_type; j++)
- total += data[j]->i;
+ total += BLI_stack_count(data[j]->overlap);
- to = overlap = MEM_callocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap");
+ to = overlap = MEM_mallocN(sizeof(BVHTreeOverlap) * total, "BVHTreeOverlap");
for (j = 0; j < tree1->tree_type; j++) {
- memcpy(to, data[j]->overlap, data[j]->i * sizeof(BVHTreeOverlap));
- to += data[j]->i;
+ unsigned int count = (unsigned int)BLI_stack_count(data[j]->overlap);
+ BLI_stack_pop_n(data[j]->overlap, to, count);
+ BLI_stack_free(data[j]->overlap);
+ to += count;
}
for (j = 0; j < tree1->tree_type; j++) {
- free(data[j]->overlap);
MEM_freeN(data[j]);
}
MEM_freeN(data);
- (*result) = total;
+ *r_overlap_tot = (unsigned int)total;
return overlap;
}
@@ -1172,13 +1185,6 @@ static float calc_nearest_point_squared(const float proj[3], BVHNode *node, floa
return len_squared_v3v3(proj, nearest);
}
-
-typedef struct NodeDistance {
- BVHNode *node;
- float dist;
-
-} NodeDistance;
-
/* TODO: use a priority queue to reduce the number of nodes looked on */
static void dfs_find_nearest_dfs(BVHNearestData *data, BVHNode *node)
{
@@ -1226,6 +1232,12 @@ static void dfs_find_nearest_begin(BVHNearestData *data, BVHNode *node)
#if 0
+typedef struct NodeDistance {
+ BVHNode *node;
+ float dist;
+
+} NodeDistance;
+
#define DEFAULT_FIND_NEAREST_HEAP_SIZE 1024
#define NodeDistance_priority(a, b) ((a).dist < (b).dist)
diff --git a/source/blender/blenlib/intern/BLI_kdtree.c b/source/blender/blenlib/intern/BLI_kdtree.c
index ed6e6e3ab92..bf470d88578 100644
--- a/source/blender/blenlib/intern/BLI_kdtree.c
+++ b/source/blender/blenlib/intern/BLI_kdtree.c
@@ -207,7 +207,7 @@ int BLI_kdtree_find_nearest(
BLI_assert(tree->is_balanced == true);
#endif
- if (!tree->root)
+ if (UNLIKELY(!tree->root))
return -1;
stack = defaultstack;
@@ -322,7 +322,7 @@ int BLI_kdtree_find_nearest_n__normal(
BLI_assert(tree->is_balanced == true);
#endif
- if (!tree->root || n == 0)
+ if (UNLIKELY(!tree->root || n == 0))
return 0;
stack = defaultstack;
@@ -406,20 +406,22 @@ static int range_compare(const void *a, const void *b)
else
return 0;
}
-static void add_in_range(KDTreeNearest **ptn, unsigned int found, unsigned int *totfoundstack, int index, float dist, float *co)
+static void add_in_range(
+ KDTreeNearest **r_foundstack,
+ unsigned int *r_foundstack_tot_alloc,
+ unsigned int found,
+ const int index, const float dist, const float *co)
{
KDTreeNearest *to;
- if (found >= *totfoundstack) {
- KDTreeNearest *temp = MEM_mallocN((*totfoundstack + KD_FOUND_ALLOC_INC) * sizeof(KDTreeNode), "KDTree.treefoundstack");
- memcpy(temp, *ptn, *totfoundstack * sizeof(KDTreeNearest));
- if (*ptn)
- MEM_freeN(*ptn);
- *ptn = temp;
- *totfoundstack += KD_FOUND_ALLOC_INC;
+ if (UNLIKELY(found >= *r_foundstack_tot_alloc)) {
+ *r_foundstack = MEM_reallocN_id(
+ *r_foundstack,
+ (*r_foundstack_tot_alloc += KD_FOUND_ALLOC_INC) * sizeof(KDTreeNode),
+ __func__);
}
- to = (*ptn) + found;
+ to = (*r_foundstack) + found;
to->index = index;
to->dist = sqrtf(dist);
@@ -445,7 +447,7 @@ int BLI_kdtree_range_search__normal(
BLI_assert(tree->is_balanced == true);
#endif
- if (!tree->root)
+ if (UNLIKELY(!tree->root))
return 0;
stack = defaultstack;
@@ -464,7 +466,7 @@ int BLI_kdtree_range_search__normal(
else {
dist2 = squared_distance(root->co, co, nor);
if (dist2 <= range2)
- add_in_range(&foundstack, found++, &totfoundstack, root->index, dist2, root->co);
+ add_in_range(&foundstack, &totfoundstack, found++, root->index, dist2, root->co);
if (root->left)
stack[cur++] = root->left;
@@ -486,7 +488,7 @@ int BLI_kdtree_range_search__normal(
else {
dist2 = squared_distance(node->co, co, nor);
if (dist2 <= range2)
- add_in_range(&foundstack, found++, &totfoundstack, node->index, dist2, node->co);
+ add_in_range(&foundstack, &totfoundstack, found++, node->index, dist2, node->co);
if (node->left)
stack[cur++] = node->left;
diff --git a/source/blender/blenlib/intern/BLI_linklist.c b/source/blender/blenlib/intern/BLI_linklist.c
index 66fcfd21fbb..a0b61e7945c 100644
--- a/source/blender/blenlib/intern/BLI_linklist.c
+++ b/source/blender/blenlib/intern/BLI_linklist.c
@@ -38,17 +38,12 @@
int BLI_linklist_length(LinkNode *list)
{
- if (0) {
- return list ? (1 + BLI_linklist_length(list->next)) : 0;
- }
- else {
- int len;
+ int len;
- for (len = 0; list; list = list->next)
- len++;
-
- return len;
- }
+ for (len = 0; list; list = list->next)
+ len++;
+
+ return len;
}
int BLI_linklist_index(LinkNode *list, void *ptr)
diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c
index 448fefa5979..8fc5f97221d 100644
--- a/source/blender/blenlib/intern/BLI_mempool.c
+++ b/source/blender/blenlib/intern/BLI_mempool.c
@@ -409,7 +409,9 @@ void BLI_mempool_free(BLI_mempool *pool, void *addr)
#endif
/* nothing is in use; free all the chunks except the first */
- if (UNLIKELY(pool->totused == 0)) {
+ if (UNLIKELY(pool->totused == 0) &&
+ (pool->chunks->next))
+ {
const unsigned int esize = pool->esize;
BLI_freenode *curnode;
unsigned int j;
diff --git a/source/blender/blenlib/intern/boxpack2d.c b/source/blender/blenlib/intern/boxpack2d.c
index 5d01706ebb1..91495ce3c9c 100644
--- a/source/blender/blenlib/intern/boxpack2d.c
+++ b/source/blender/blenlib/intern/boxpack2d.c
@@ -91,7 +91,7 @@ typedef struct BoxVert {
BLI_INLINE int quad_flag(unsigned int q)
{
- BLI_assert(q < 4 && q >= 0);
+ BLI_assert(q < 4);
return (1 << q);
}
diff --git a/source/blender/blenlib/intern/buffer.c b/source/blender/blenlib/intern/buffer.c
index 4e570823319..9e96205a5e8 100644
--- a/source/blender/blenlib/intern/buffer.c
+++ b/source/blender/blenlib/intern/buffer.c
@@ -38,17 +38,14 @@ static void *buffer_alloc(BLI_Buffer *buffer, int len)
static void *buffer_realloc(BLI_Buffer *buffer, int len)
{
- if (buffer->flag & BLI_BUFFER_USE_CALLOC) {
- return MEM_recallocN(buffer->data, buffer->elem_size * len);
- }
- else {
- return MEM_reallocN(buffer->data, buffer->elem_size * len);
- }
+ return ((buffer->flag & BLI_BUFFER_USE_CALLOC) ?
+ MEM_recallocN_id : MEM_reallocN_id)
+ (buffer->data, buffer->elem_size * len, "BLI_Buffer.data");
}
void BLI_buffer_resize(BLI_Buffer *buffer, int new_count)
{
- if (new_count > buffer->alloc_count) {
+ if (UNLIKELY(new_count > buffer->alloc_count)) {
if (buffer->flag & BLI_BUFFER_USE_STATIC) {
void *orig = buffer->data;
@@ -65,12 +62,7 @@ void BLI_buffer_resize(BLI_Buffer *buffer, int new_count)
buffer->alloc_count = new_count;
}
- if (buffer->data) {
- buffer->data = buffer_realloc(buffer, buffer->alloc_count);
- }
- else {
- buffer->data = buffer_alloc(buffer, buffer->alloc_count);
- }
+ buffer->data = buffer_realloc(buffer, buffer->alloc_count);
}
}
diff --git a/source/blender/blenlib/intern/callbacks.c b/source/blender/blenlib/intern/callbacks.c
index 719809e6bcd..191be49263c 100644
--- a/source/blender/blenlib/intern/callbacks.c
+++ b/source/blender/blenlib/intern/callbacks.c
@@ -37,7 +37,7 @@ void BLI_callback_exec(struct Main *main, struct ID *self, eCbEvent evt)
ListBase *lb = &callback_slots[evt];
bCallbackFuncStore *funcstore;
- for (funcstore = (bCallbackFuncStore *)lb->first; funcstore; funcstore = (bCallbackFuncStore *)funcstore->next) {
+ for (funcstore = lb->first; funcstore; funcstore = funcstore->next) {
funcstore->func(main, self, funcstore->arg);
}
}
@@ -61,8 +61,8 @@ void BLI_callback_global_finalize(void)
ListBase *lb = &callback_slots[evt];
bCallbackFuncStore *funcstore;
bCallbackFuncStore *funcstore_next;
- for (funcstore = (bCallbackFuncStore *)lb->first; funcstore; funcstore = funcstore_next) {
- funcstore_next = (bCallbackFuncStore *)funcstore->next;
+ for (funcstore = lb->first; funcstore; funcstore = funcstore_next) {
+ funcstore_next = funcstore->next;
BLI_remlink(lb, funcstore);
if (funcstore->alloc) {
MEM_freeN(funcstore);
diff --git a/source/blender/blenlib/intern/convexhull2d.c b/source/blender/blenlib/intern/convexhull2d.c
index 34ee39d8a9b..361e4b4eadb 100644
--- a/source/blender/blenlib/intern/convexhull2d.c
+++ b/source/blender/blenlib/intern/convexhull2d.c
@@ -187,7 +187,7 @@ static int pointref_cmp_yx(const void *a_, const void *b_)
* \param points An array of 2D points.
* \param n The number of points in points.
* \param r_points An array of the convex hull vertex indices (max is n).
- * _must_ be allocated as ``n * 2`` becauise of how its used internally,
+ * _must_ be allocated as ``n * 2`` because of how its used internally,
* even though the final result will be no more then \a n in size.
* \returns the number of points in r_points.
*/
diff --git a/source/blender/blenlib/intern/easing.c b/source/blender/blenlib/intern/easing.c
index 1f39c2f57b5..80f02d54eaa 100644
--- a/source/blender/blenlib/intern/easing.c
+++ b/source/blender/blenlib/intern/easing.c
@@ -43,24 +43,18 @@
float BLI_easing_back_ease_in(float time, float begin, float change, float duration, float overshoot)
{
- if (overshoot == 0.0f)
- overshoot = 1.70158f;
time /= duration;
return change * time * time * ((overshoot + 1) * time - overshoot) + begin;
}
float BLI_easing_back_ease_out(float time, float begin, float change, float duration, float overshoot)
{
- if (overshoot == 0.0f)
- overshoot = 1.70158f;
time = time / duration - 1;
return change * (time * time * ((overshoot + 1) * time + overshoot) + 1) + begin;
}
float BLI_easing_back_ease_in_out(float time, float begin, float change, float duration, float overshoot)
{
- if (overshoot == 0.0f)
- overshoot = 1.70158f;
overshoot *= 1.525f;
if ((time /= duration / 2) < 1.0f) {
return change / 2 * (time * time * ((overshoot + 1) * time - overshoot)) + begin;
diff --git a/source/blender/blenlib/intern/edgehash.c b/source/blender/blenlib/intern/edgehash.c
index 51a22cc46ab..4ed82f8a473 100644
--- a/source/blender/blenlib/intern/edgehash.c
+++ b/source/blender/blenlib/intern/edgehash.c
@@ -93,7 +93,7 @@ BLI_INLINE unsigned int edgehash_keyhash(EdgeHash *eh, unsigned int v0, unsigned
{
BLI_assert(v0 < v1);
- return ((v0 * 39) ^ (v1 * 31)) % eh->nbuckets;
+ return ((v0 * 65) ^ (v1 * 31)) % eh->nbuckets;
}
/**
@@ -270,7 +270,7 @@ static void edgehash_free_cb(EdgeHash *eh, EdgeHashFreeFP valfreefp)
for (e = eh->buckets[i]; e; ) {
EdgeEntry *e_next = e->next;
- if (valfreefp) valfreefp(e->val);
+ valfreefp(e->val);
e = e_next;
}
@@ -463,14 +463,14 @@ void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
ehi->curEntry = NULL;
ehi->curBucket = UINT_MAX; /* wraps to zero */
if (eh->nentries) {
- while (!ehi->curEntry) {
+ do {
ehi->curBucket++;
if (UNLIKELY(ehi->curBucket == ehi->eh->nbuckets)) {
break;
}
ehi->curEntry = ehi->eh->buckets[ehi->curBucket];
- }
+ } while (!ehi->curEntry);
}
}
@@ -588,9 +588,12 @@ void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1)
}
/**
- * Assign a new value to a key that may already be in edgehash.
+ * A version of BLI_edgeset_insert which checks first if the key is in the set.
+ * \returns true if a new key has been added.
+ *
+ * \note EdgeHash has no equivalent to this because typically the value would be different.
*/
-bool BLI_edgeset_reinsert(EdgeSet *es, unsigned int v0, unsigned int v1)
+bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1)
{
unsigned int hash;
EdgeEntry *e;
@@ -619,4 +622,49 @@ void BLI_edgeset_free(EdgeSet *es)
BLI_edgehash_free((EdgeHash *)es, NULL);
}
+void BLI_edgeset_flag_set(EdgeSet *es, unsigned int flag)
+{
+ ((EdgeHash *)es)->flag |= flag;
+}
+
+void BLI_edgeset_flag_clear(EdgeSet *es, unsigned int flag)
+{
+ ((EdgeHash *)es)->flag &= ~flag;
+}
+
+/** \} */
+
+/** \name Debugging & Introspection
+ * \{ */
+#ifdef DEBUG
+
+/**
+ * Measure how well the hash function performs
+ * (1.0 is approx as good as random distribution).
+ */
+double BLI_edgehash_calc_quality(EdgeHash *eh)
+{
+ uint64_t sum = 0;
+ unsigned int i;
+
+ if (eh->nentries == 0)
+ return -1.0;
+
+ for (i = 0; i < eh->nbuckets; i++) {
+ uint64_t count = 0;
+ EdgeEntry *e;
+ for (e = eh->buckets[i]; e; e = e->next) {
+ count += 1;
+ }
+ sum += count * (count + 1);
+ }
+ return ((double)sum * (double)eh->nbuckets /
+ ((double)eh->nentries * (eh->nentries + 2 * eh->nbuckets - 1)));
+}
+double BLI_edgeset_calc_quality(EdgeSet *es)
+{
+ return BLI_edgehash_calc_quality((EdgeHash *)es);
+}
+
+#endif
/** \} */
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 39475d73ee0..f6bbd3273f9 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -48,10 +48,10 @@
# include <io.h>
# include "BLI_winstuff.h"
# include "BLI_callbacks.h"
+# include "BLI_fileops_types.h"
# include "utf_winfunc.h"
# include "utfconv.h"
#else
-# include <unistd.h> // for read close
# include <sys/param.h>
# include <dirent.h>
# include <unistd.h>
@@ -66,7 +66,7 @@
#include "BLI_fileops.h"
#include "BLI_sys_types.h" // for intptr_t support
-
+#if 0 /* UNUSED */
/* gzip the file in from and write it to "to".
* return -1 if zlib fails, -2 if the originating file does not exist
* note: will remove the "from" file
@@ -111,6 +111,7 @@ int BLI_file_gzip(const char *from, const char *to)
return rval;
}
+#endif
/* gzip the file in from_file and write it to memory to_mem, at most size bytes.
* return the unziped size
@@ -284,26 +285,72 @@ int BLI_access(const char *filename, int mode)
return uaccess(filename, mode);
}
-int BLI_delete(const char *file, bool dir, bool recursive)
+static bool delete_unique(const char *path, const bool dir)
{
- int err;
-
- UTF16_ENCODE(file);
+ bool err;
- if (recursive) {
- callLocalErrorCallBack("Recursive delete is unsupported on Windows");
- err = 1;
- }
- else if (dir) {
- err = !RemoveDirectoryW(file_16);
+ UTF16_ENCODE(path);
+
+ if (dir) {
+ err = !RemoveDirectoryW(path_16);
if (err) printf("Unable to remove directory");
}
else {
- err = !DeleteFileW(file_16);
+ err = !DeleteFileW(path_16);
if (err) callLocalErrorCallBack("Unable to delete file");
}
- UTF16_UN_ENCODE(file);
+ UTF16_UN_ENCODE(path);
+
+ return err;
+}
+
+static bool delete_recursive(const char *dir)
+{
+ struct direntry *filelist, *fl;
+ bool err = false;
+ unsigned int nbr, i;
+
+ i = nbr = BLI_dir_contents(dir, &filelist);
+ fl = filelist;
+ while (i--) {
+ char file[8];
+ BLI_split_file_part(fl->path, file, sizeof(file));
+ if (STREQ(file, ".") || STREQ(file, "..")) {
+ /* Skip! */
+ }
+ else if (S_ISDIR(fl->type)) {
+ if (delete_recursive(fl->path)) {
+ err = true;
+ }
+ }
+ else {
+ if (delete_unique(fl->path, false)) {
+ err = true;
+ }
+ }
+ ++fl;
+ }
+
+ if (!err && delete_unique(dir, true)) {
+ err = true;
+ }
+
+ BLI_free_filelist(filelist, nbr);
+
+ return err;
+}
+
+int BLI_delete(const char *file, bool dir, bool recursive)
+{
+ int err;
+
+ if (recursive) {
+ err = delete_recursive(file);
+ }
+ else {
+ err = delete_unique(file, dir);
+ }
return err;
}
@@ -635,21 +682,15 @@ int BLI_access(const char *filename, int mode)
*/
int BLI_delete(const char *file, bool dir, bool recursive)
{
- if (strchr(file, '"')) {
- printf("Error: not deleted file %s because of quote!\n", file);
+ if (recursive) {
+ return recursive_operation(file, NULL, NULL, delete_single_file, delete_callback_post);
+ }
+ else if (dir) {
+ return rmdir(file);
}
else {
- if (recursive) {
- return recursive_operation(file, NULL, NULL, delete_single_file, delete_callback_post);
- }
- else if (dir) {
- return rmdir(file);
- }
- else {
- return remove(file); //BLI_snprintf(str, sizeof(str), "/bin/rm -f \"%s\"", file);
- }
+ return remove(file);
}
- return -1;
}
/**
diff --git a/source/blender/blenlib/intern/gsqueue.c b/source/blender/blenlib/intern/gsqueue.c
index 6967742f89b..94d18ce3c77 100644
--- a/source/blender/blenlib/intern/gsqueue.c
+++ b/source/blender/blenlib/intern/gsqueue.c
@@ -27,6 +27,12 @@
/** \file blender/blenlib/intern/gsqueue.c
* \ingroup bli
+ *
+ * \brief A generic structure queue
+ * (a queue for fixed length generally small) structures.
+ *
+ * \note Only use this if you need (first-in-first-out),
+ * otherwise #BLI_stack is more efficient (first-in-last-out).
*/
#include <string.h>
@@ -40,12 +46,13 @@
typedef struct _GSQueueElem GSQueueElem;
struct _GSQueueElem {
GSQueueElem *next;
+ char data[0];
};
struct _GSQueue {
GSQueueElem *head;
GSQueueElem *tail;
- int elem_size;
+ size_t elem_size;
};
/**
@@ -54,7 +61,7 @@ struct _GSQueue {
* \param elem_size The size of the structures in the queue.
* \retval The new queue
*/
-GSQueue *BLI_gsqueue_new(int elem_size)
+GSQueue *BLI_gsqueue_new(size_t elem_size)
{
GSQueue *gq = MEM_mallocN(sizeof(*gq), "gqueue_new");
gq->head = gq->tail = NULL;
@@ -92,9 +99,9 @@ int BLI_gsqueue_size(GSQueue *gq)
* \param item_r A pointer to an appropriately
* sized structure (the size passed to BLI_gsqueue_new)
*/
-void BLI_gsqueue_peek(GSQueue *gq, void *item_r)
+void BLI_gsqueue_peek(GSQueue *gq, void *r_item)
{
- memcpy(item_r, &gq->head[1], (size_t)gq->elem_size);
+ memcpy(r_item, &gq->head->data, gq->elem_size);
}
/**
@@ -105,7 +112,7 @@ void BLI_gsqueue_peek(GSQueue *gq, void *item_r)
* sized structure (the size passed to BLI_gsqueue_new).
* Can be NULL if desired.
*/
-void BLI_gsqueue_pop(GSQueue *gq, void *item_r)
+void BLI_gsqueue_pop(GSQueue *gq, void *r_item)
{
GSQueueElem *elem = gq->head;
if (elem == gq->tail) {
@@ -115,7 +122,9 @@ void BLI_gsqueue_pop(GSQueue *gq, void *item_r)
gq->head = gq->head->next;
}
- if (item_r) memcpy(item_r, &elem[1], (size_t)gq->elem_size);
+ if (r_item) {
+ memcpy(r_item, elem->data, gq->elem_size);
+ }
MEM_freeN(elem);
}
@@ -125,17 +134,17 @@ void BLI_gsqueue_pop(GSQueue *gq, void *item_r)
* \param item A pointer to an appropriately
* sized structure (the size passed to BLI_gsqueue_new).
*/
-void BLI_gsqueue_push(GSQueue *gq, void *item)
+void BLI_gsqueue_push(GSQueue *gq, const void *item)
{
GSQueueElem *elem;
/* compare: prevent events added double in row */
if (!BLI_gsqueue_is_empty(gq)) {
- if (0 == memcmp(item, &gq->head[1], (size_t)gq->elem_size))
+ if (0 == memcmp(item, gq->head->data, gq->elem_size))
return;
}
- elem = MEM_mallocN(sizeof(*elem) + (size_t)gq->elem_size, "gqueue_push");
- memcpy(&elem[1], item, (size_t)gq->elem_size);
+ elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push");
+ memcpy(elem->data, item, gq->elem_size);
elem->next = NULL;
if (BLI_gsqueue_is_empty(gq)) {
@@ -153,10 +162,10 @@ void BLI_gsqueue_push(GSQueue *gq, void *item)
* \param item A pointer to an appropriately
* sized structure (the size passed to BLI_gsqueue_new).
*/
-void BLI_gsqueue_pushback(GSQueue *gq, void *item)
+void BLI_gsqueue_pushback(GSQueue *gq, const void *item)
{
- GSQueueElem *elem = MEM_mallocN(sizeof(*elem) + (size_t)gq->elem_size, "gqueue_push");
- memcpy(&elem[1], item, (size_t)gq->elem_size);
+ GSQueueElem *elem = MEM_mallocN(sizeof(*elem) + gq->elem_size, "gqueue_push");
+ memcpy(elem->data, item, gq->elem_size);
elem->next = gq->head;
if (BLI_gsqueue_is_empty(gq)) {
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index 17e7bf8a99b..6fcc5888382 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -130,6 +130,44 @@ bool BLI_remlink_safe(ListBase *listbase, void *vlink)
}
/**
+ * Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
+ */
+void BLI_listbase_swaplinks(ListBase *listbase, void *vlinka, void *vlinkb)
+{
+ Link *linka = vlinka;
+ Link *linkb = vlinkb;
+
+ if (!linka || !linkb)
+ return;
+
+ if (linkb->next == linka) {
+ SWAP(Link *, linka, linkb);
+ }
+
+ if (linka->next == linkb) {
+ linka->next = linkb->next;
+ linkb->prev = linka->prev;
+ linka->prev = linkb;
+ linkb->next = linka;
+ }
+ else { /* Non-contiguous items, we can safely swap. */
+ SWAP(Link *, linka->prev, linkb->prev);
+ SWAP(Link *, linka->next, linkb->next);
+ }
+
+ /* Update neighbors of linka and linkb. */
+ if (linka->prev) linka->prev->next = linka;
+ if (linka->next) linka->next->prev = linka;
+ if (linkb->prev) linkb->prev->next = linkb;
+ if (linkb->next) linkb->next->prev = linkb;
+
+ if (listbase->last == linka) listbase->last = linkb;
+ else if (listbase->last == linkb) listbase->last = linka;
+ if (listbase->first == linka) listbase->first = linkb;
+ else if (listbase->first == linkb) listbase->first = linka;
+}
+
+/**
* Removes the head from \a listbase and returns it.
*/
void *BLI_pophead(ListBase *listbase)
@@ -173,7 +211,7 @@ void BLI_freelinkN(ListBase *listbase, void *vlink)
* (which should return 1 iff its first arg should come after its second arg).
* This uses insertion sort, so NOT ok for large list.
*/
-void BLI_sortlist(ListBase *listbase, int (*cmp)(void *, void *))
+void BLI_sortlist(ListBase *listbase, int (*cmp)(const void *, const void *))
{
Link *current = NULL;
Link *previous = NULL;
@@ -195,7 +233,7 @@ void BLI_sortlist(ListBase *listbase, int (*cmp)(void *, void *))
}
}
-void BLI_sortlist_r(ListBase *listbase, void *thunk, int (*cmp)(void *, void *, void *))
+void BLI_sortlist_r(ListBase *listbase, void *thunk, int (*cmp)(void *, const void *, const void *))
{
Link *current = NULL;
Link *previous = NULL;
@@ -313,9 +351,8 @@ void BLI_freelist(ListBase *listbase)
free(link);
link = next;
}
-
- listbase->first = NULL;
- listbase->last = NULL;
+
+ BLI_listbase_clear(listbase);
}
/**
@@ -331,9 +368,8 @@ void BLI_freelistN(ListBase *listbase)
MEM_freeN(link);
link = next;
}
-
- listbase->first = NULL;
- listbase->last = NULL;
+
+ BLI_listbase_clear(listbase);
}
@@ -356,7 +392,7 @@ int BLI_countlist(const ListBase *listbase)
}
/**
- * Returns the nth element of \a listbase, numbering from 1.
+ * Returns the nth element of \a listbase, numbering from 0.
*/
void *BLI_findlink(const ListBase *listbase, int number)
{
@@ -374,7 +410,7 @@ void *BLI_findlink(const ListBase *listbase, int number)
}
/**
- * Returns the nth-last element of \a listbase, numbering from 1.
+ * Returns the nth-last element of \a listbase, numbering from 0.
*/
void *BLI_rfindlink(const ListBase *listbase, int number)
{
@@ -392,7 +428,7 @@ void *BLI_rfindlink(const ListBase *listbase, int number)
}
/**
- * Returns the position of \a vlink within \a listbase, numbering from 1, or -1 if not found.
+ * Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
*/
int BLI_findindex(const ListBase *listbase, const void *vlink)
{
@@ -579,7 +615,7 @@ void BLI_duplicatelist(ListBase *dst, const ListBase *src)
}
}
-void BLI_reverselist(ListBase *lb)
+void BLI_listbase_reverse(ListBase *lb)
{
struct Link *curr = lb->first;
struct Link *prev = NULL;
@@ -601,7 +637,7 @@ void BLI_reverselist(ListBase *lb)
/**
* \param vlink Link to make first.
*/
-void BLI_rotatelist_first(ListBase *lb, void *vlink)
+void BLI_listbase_rotate_first(ListBase *lb, void *vlink)
{
/* make circular */
((Link *)lb->first)->prev = lb->last;
@@ -617,7 +653,7 @@ void BLI_rotatelist_first(ListBase *lb, void *vlink)
/**
* \param vlink Link to make last.
*/
-void BLI_rotatelist_last(ListBase *lb, void *vlink)
+void BLI_listbase_rotate_last(ListBase *lb, void *vlink)
{
/* make circular */
((Link *)lb->first)->prev = lb->last;
diff --git a/source/blender/blenlib/intern/math_color.c b/source/blender/blenlib/intern/math_color.c
index 57a48bb5fa8..3ed7230b1d2 100644
--- a/source/blender/blenlib/intern/math_color.c
+++ b/source/blender/blenlib/intern/math_color.c
@@ -37,112 +37,38 @@
void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b)
{
- if (s != 0.0f) {
- float i, f, p;
- h = (h - floorf(h)) * 6.0f;
-
- i = floorf(h);
- f = h - i;
-
- /* avoid computing q/t when not needed */
- p = (v * (1.0f - s));
-#define q (v * (1.0f - (s * f)))
-#define t (v * (1.0f - (s * (1.0f - f))))
-
- /* faster to compare floats then int conversion */
- if (i < 1.0f) {
- *r = v;
- *g = t;
- *b = p;
- }
- else if (i < 2.0f) {
- *r = q;
- *g = v;
- *b = p;
- }
- else if (i < 3.0f) {
- *r = p;
- *g = v;
- *b = t;
- }
- else if (i < 4.0f) {
- *r = p;
- *g = q;
- *b = v;
- }
- else if (i < 5.0f) {
- *r = t;
- *g = p;
- *b = v;
- }
- else {
- *r = v;
- *g = p;
- *b = q;
- }
+ float nr, ng, nb;
-#undef q
-#undef t
+ nr = fabsf(h * 6.0f - 3.0f) - 1.0f;
+ ng = 2.0f - fabsf(h * 6.0f - 2.0f);
+ nb = 2.0f - fabsf(h * 6.0f - 4.0f);
- }
- else {
- *r = v;
- *g = v;
- *b = v;
- }
+ CLAMP(nr, 0.0f, 1.0f);
+ CLAMP(nb, 0.0f, 1.0f);
+ CLAMP(ng, 0.0f, 1.0f);
+
+ *r = ((nr - 1.0f) * s + 1.0f) * v;
+ *g = ((ng - 1.0f) * s + 1.0f) * v;
+ *b = ((nb - 1.0f) * s + 1.0f) * v;
}
-/* HSL to rgb conversion from https://en.wikipedia.org/wiki/HSL_and_HSV */
void hsl_to_rgb(float h, float s, float l, float *r, float *g, float *b)
{
- float i, f, c;
- h = (h - floorf(h)) * 6.0f;
- c = (l > 0.5f) ? (2.0f * (1.0f - l) * s) : (2.0f * l * s);
- i = floorf(h);
- f = h - i;
+ float nr, ng, nb, chroma;
-#define x2 (c * f)
-#define x1 (c * (1.0f - f))
+ nr = fabsf(h * 6.0f - 3.0f) - 1.0f;
+ ng = 2.0f - fabsf(h * 6.0f - 2.0f);
+ nb = 2.0f - fabsf(h * 6.0f - 4.0f);
- /* faster to compare floats then int conversion */
- if (i < 1.0f) {
- *r = c;
- *g = x2;
- *b = 0;
- }
- else if (i < 2.0f) {
- *r = x1;
- *g = c;
- *b = 0;
- }
- else if (i < 3.0f) {
- *r = 0;
- *g = c;
- *b = x2;
- }
- else if (i < 4.0f) {
- *r = 0;
- *g = x1;
- *b = c;
- }
- else if (i < 5.0f) {
- *r = x2;
- *g = 0;
- *b = c;
- }
- else {
- *r = c;
- *g = 0;
- *b = x1;
- }
+ CLAMP(nr, 0.0f, 1.0f);
+ CLAMP(nb, 0.0f, 1.0f);
+ CLAMP(ng, 0.0f, 1.0f);
-#undef x1
-#undef x2
+ chroma = (1.0f - fabsf(2.0f * l - 1.0f)) * s;
- f = l - 0.5f * c;
- *r += f;
- *g += f;
- *b += f;
+ *r = (nr - 0.5f) * chroma + l;
+ *g = (ng - 0.5f) * chroma + l;
+ *b = (nb - 0.5f) * chroma + l;
}
/* convenience function for now */
@@ -152,9 +78,9 @@ void hsv_to_rgb_v(const float hsv[3], float r_rgb[3])
}
/* convenience function for now */
-void hsl_to_rgb_v(const float hcl[3], float r_rgb[3])
+void hsl_to_rgb_v(const float hsl[3], float r_rgb[3])
{
- hsl_to_rgb(hcl[0], hcl[1], hcl[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
+ hsl_to_rgb(hsl[0], hsl[1], hsl[2], &r_rgb[0], &r_rgb[1], &r_rgb[2]);
}
void rgb_to_yuv(float r, float g, float b, float *ly, float *lu, float *lv)
@@ -187,7 +113,7 @@ void yuv_to_rgb(float y, float u, float v, float *lr, float *lg, float *lb)
void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, int colorspace)
{
float sr, sg, sb;
- float y = 128.f, cr = 128.f, cb = 128.f;
+ float y = 128.0f, cr = 128.0f, cb = 128.0f;
sr = 255.0f * r;
sg = 255.0f * g;
@@ -226,7 +152,7 @@ void rgb_to_ycc(float r, float g, float b, float *ly, float *lcb, float *lcr, in
/* FIXME comment above must be wrong because BLI_YCC_ITU_BT601 y 16.0 cr 16.0 -> r -0.7009 */
void ycc_to_rgb(float y, float cb, float cr, float *lr, float *lg, float *lb, int colorspace)
{
- float r = 128.f, g = 128.f, b = 128.f;
+ float r = 128.0f, g = 128.0f, b = 128.0f;
switch (colorspace) {
case BLI_YCC_ITU_BT601:
@@ -284,57 +210,26 @@ void hex_to_rgb(char *hexcol, float *r, float *g, float *b)
void rgb_to_hsv(float r, float g, float b, float *lh, float *ls, float *lv)
{
- float h, s, v;
- float cmax, cmin;
-
- cmax = r;
- cmin = r;
- cmax = (g > cmax ? g : cmax);
- cmin = (g < cmin ? g : cmin);
- cmax = (b > cmax ? b : cmax);
- cmin = (b < cmin ? b : cmin);
-
- v = cmax; /* value */
- if (cmax != 0.0f) {
- float cdelta;
-
- cdelta = cmax - cmin;
- s = cdelta / cmax;
-
- if (s != 0.0f) {
- float rc, gc, bc;
-
- rc = (cmax - r) / cdelta;
- gc = (cmax - g) / cdelta;
- bc = (cmax - b) / cdelta;
-
- if (r == cmax) {
- h = bc - gc;
- if (h < 0.0f) {
- h += 6.0f;
- }
- }
- else if (g == cmax) {
- h = 2.0f + rc - bc;
- }
- else {
- h = 4.0f + gc - rc;
- }
-
- h *= (1.0f / 6.0f);
- }
- else {
- h = 0.0f;
- }
+ float k = 0.0f;
+ float chroma;
+ float min_gb;
+
+ if (g < b) {
+ SWAP(float, g, b);
+ k = -1.0f;
}
- else {
- h = 0.0f;
- s = 0.0f;
+ min_gb = b;
+ if (r < g) {
+ SWAP(float, r, g);
+ k = -2.0f / 6.0f - k;
+ min_gb = min_ff(g, b);
}
- *lh = h;
- *ls = s;
- *lv = v;
+ chroma = r - min_gb;
+
+ *lh = fabsf(k + (g - b) / (6.0f * chroma + 1e-20f));
+ *ls = chroma / (r + 1e-20f);
+ *lv = r;
}
/* convenience function for now */
@@ -374,8 +269,8 @@ void rgb_to_hsl(float r, float g, float b, float *lh, float *ls, float *ll)
void rgb_to_hsl_compat(float r, float g, float b, float *lh, float *ls, float *ll)
{
- float orig_s = *ls;
- float orig_h = *lh;
+ const float orig_s = *ls;
+ const float orig_h = *lh;
rgb_to_hsl(r, g, b, lh, ls, ll);
@@ -407,8 +302,8 @@ void rgb_to_hsl_v(const float rgb[3], float r_hsl[3])
void rgb_to_hsv_compat(float r, float g, float b, float *lh, float *ls, float *lv)
{
- float orig_h = *lh;
- float orig_s = *ls;
+ const float orig_h = *lh;
+ const float orig_s = *ls;
rgb_to_hsv(r, g, b, lh, ls, lv);
@@ -703,11 +598,12 @@ static float index_to_float(const unsigned short i)
void BLI_init_srgb_conversion(void)
{
- static int initialized = 0;
+ static bool initialized = false;
unsigned int i, b;
- if (initialized) return;
- initialized = 1;
+ if (initialized)
+ return;
+ initialized = true;
/* Fill in the lookup table to convert floats to bytes: */
for (i = 0; i < 0x10000; i++) {
@@ -736,6 +632,9 @@ static float inverse_srgb_companding(float v)
}
}
+/**
+ * \note Does sRGB to linear conversion
+ */
void rgb_to_xyz(float r, float g, float b, float *x, float *y, float *z)
{
r = inverse_srgb_companding(r) * 100.0f;
@@ -762,13 +661,13 @@ static float xyz_to_lab_component(float v)
void xyz_to_lab(float x, float y, float z, float *l, float *a, float *b)
{
- float xr = x / 95.047f;
- float yr = y / 100.0f;
- float zr = z / 108.883f;
+ const float xr = x / 95.047f;
+ const float yr = y / 100.0f;
+ const float zr = z / 108.883f;
- float fx = xyz_to_lab_component(xr);
- float fy = xyz_to_lab_component(yr);
- float fz = xyz_to_lab_component(zr);
+ const float fx = xyz_to_lab_component(xr);
+ const float fy = xyz_to_lab_component(yr);
+ const float fz = xyz_to_lab_component(zr);
*l = 116.0f * fy - 16.0f;
*a = 500.0f * (fx - fy);
diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c
index 4810fe757fa..73a7259ddcd 100644
--- a/source/blender/blenlib/intern/math_color_blend_inline.c
+++ b/source/blender/blenlib/intern/math_color_blend_inline.c
@@ -30,11 +30,16 @@
#include "BLI_math_base.h"
#include "BLI_math_color.h"
#include "BLI_math_color_blend.h"
+#include "BLI_math_vector.h"
#include "BLI_utildefines.h"
#ifndef __MATH_COLOR_BLEND_INLINE_C__
#define __MATH_COLOR_BLEND_INLINE_C__
+/* don't add any saturation to a completly black and white image */
+#define EPS_SATURATION 0.0005f
+#define EPS_ALPHA 0.0005f
+
/***************************** Color Blending ********************************
*
* - byte colors are assumed to be straight alpha
@@ -67,10 +72,7 @@ MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4_char((char *)dst, (char *)src1);
}
}
@@ -92,10 +94,7 @@ MINLINE void blend_color_add_byte(unsigned char dst[4], const unsigned char src1
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4_char((char *)dst, (char *)src1);
}
}
@@ -117,10 +116,7 @@ MINLINE void blend_color_sub_byte(unsigned char dst[4], const unsigned char src1
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4_char((char *)dst, (char *)src1);
}
}
@@ -143,10 +139,7 @@ MINLINE void blend_color_mul_byte(unsigned char dst[4], const unsigned char src1
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4_char((char *)dst, (char *)src1);
}
}
@@ -169,10 +162,7 @@ MINLINE void blend_color_lighten_byte(unsigned char dst[4], const unsigned char
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4_char((char *)dst, (char *)src1);
}
}
@@ -195,10 +185,7 @@ MINLINE void blend_color_darken_byte(unsigned char dst[4], const unsigned char s
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4_char((char *)dst, (char *)src1);
}
}
@@ -215,10 +202,7 @@ MINLINE void blend_color_erase_alpha_byte(unsigned char dst[4], const unsigned c
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4_char((char *)dst, (char *)src1);
}
}
@@ -235,11 +219,391 @@ MINLINE void blend_color_add_alpha_byte(unsigned char dst[4], const unsigned cha
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+MINLINE void blend_color_overlay_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = (int)src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ int temp;
+
+ if (src1[i] > 127) {
+ temp = 255 - ((255 - 2 * (src1[i] - 127)) * (255 - src2[i]) / 255);
+ }
+ else {
+ temp = (2 * src1[i] * src2[i]) >> 8;
+ }
+ dst[i] = (unsigned char)min_ii((temp * fac + src1[i] * mfac) / 255, 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+MINLINE void blend_color_hardlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = (int)src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ int temp;
+
+ if (src2[i] > 127) {
+ temp = 255 - ((255 - 2 * (src2[i] - 127)) * (255 - src1[i]) / 255);
+ }
+ else {
+ temp = (2 * src2[i] * src1[i]) >> 8;
+ }
+ dst[i] = (unsigned char)min_ii((temp * fac + src1[i] * mfac) / 255, 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+MINLINE void blend_color_burn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ const int temp = (src2[i] == 0) ? 0 : max_ii(255 - ((255 - src1[i]) * 255) / src2[i], 0);
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+MINLINE void blend_color_linearburn_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ const int temp = max_ii(src1[i] + src2[i] - 255, 0);
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+MINLINE void blend_color_dodge_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ const int temp = (src2[i] == 255) ? 255 : min_ii((src1[i] * 255) / (255 - src2[i]), 255);
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+MINLINE void blend_color_screen_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ const int temp = max_ii(255 - (((255 - src1[i]) * (255 - src2[i])) / 255), 0);
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+MINLINE void blend_color_softlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ int temp;
+
+ if (src1[i] < 127) {
+ temp = ((2 * ((src2[i] / 2) + 64)) * src1[i]) / 255;
+ }
+ else {
+ temp = 255 - (2 * (255 - ((src2[i] / 2) + 64)) * (255 - src1[i]) / 255);
+ }
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+MINLINE void blend_color_pinlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ int temp;
+
+ if (src2[i] > 127) {
+ temp = max_ii(2 * (src2[i] - 127), src1[i]);
+ }
+ else {
+ temp = min_ii(2 * src2[i], src1[i]);
+ }
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+MINLINE void blend_color_linearlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ int temp;
+
+ if (src2[i] > 127) {
+ temp = min_ii(src1[i] + 2 * (src2[i] - 127), 255);
+ }
+ else {
+ temp = max_ii(src1[i] + 2 * src2[i] - 255, 0);
+ }
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+MINLINE void blend_color_vividlight_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ int temp;
+
+ if (src2[i] == 255) {
+ temp = 255;
+ }
+ else if (src2[i] == 0) {
+ temp = 0;
+ }
+ else if (src2[i] > 127) {
+ temp = min_ii(((src1[i]) * 255) / (2 * (255 - src2[i])), 255);
+ }
+ else {
+ temp = max_ii(255 - ((255 - src1[i]) * 255 / (2 * src2[i])), 0);
+ }
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+
+MINLINE void blend_color_difference_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ const int temp = abs(src1[i] - src2[i]);
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+
+MINLINE void blend_color_exclusion_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ int i = 3;
+
+ while (i--) {
+ const int temp = 127 - ((2 * (src1[i] - 127) * (src2[i] - 127)) / 255);
+ dst[i] = (unsigned char)((temp * fac + src1[i] * mfac) / 255);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+MINLINE void blend_color_color_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
+
+
+ h1 = h2;
+ s1 = s2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255);
+ dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255);
+ dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255);
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+MINLINE void blend_color_hue_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
+
+
+ h1 = h2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255);
+ dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255);
+ dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255);
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+
+}
+
+MINLINE void blend_color_saturation_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
+
+ if (s1 > EPS_SATURATION) {
+ s1 = s2;
+ }
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255);
+ dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255);
+ dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255);
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
+ }
+}
+
+MINLINE void blend_color_luminosity_byte(unsigned char dst[4], unsigned const char src1[4], unsigned const char src2[4])
+{
+ const int fac = src2[3];
+ if (fac != 0) {
+ const int mfac = 255 - fac;
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+ rgb_to_hsv(src1[0] / 255.0f, src1[1] / 255.0f, src1[2] / 255.0f, &h1, &s1, &v1);
+ rgb_to_hsv(src2[0] / 255.0f, src2[1] / 255.0f, src2[2] / 255.0f, &h2, &s2, &v2);
+
+ v1 = v2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ dst[0] = (unsigned char)(((int)(r * 255.0f) * fac + src1[0] * mfac) / 255);
+ dst[1] = (unsigned char)(((int)(g * 255.0f) * fac + src1[1] * mfac) / 255);
+ dst[2] = (unsigned char)(((int)(b * 255.0f) * fac + src1[2] * mfac) / 255);
+
+ }
+ else {
+ /* no op */
+ copy_v4_v4_char((char *)dst, (char *)src1);
}
+
}
MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4], float ft)
@@ -257,10 +621,7 @@ MINLINE void blend_color_interpolate_byte(unsigned char dst[4], const unsigned c
dst[3] = (unsigned char)divide_round_i(tmp, 255);
}
else {
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4_char((char *)dst, (char *)src1);
}
}
@@ -280,10 +641,7 @@ MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const floa
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4(dst, src1);
}
}
@@ -298,10 +656,7 @@ MINLINE void blend_color_add_float(float dst[4], const float src1[4], const floa
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4(dst, src1);
}
}
@@ -316,10 +671,7 @@ MINLINE void blend_color_sub_float(float dst[4], const float src1[4], const floa
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4(dst, src1);
}
}
@@ -337,10 +689,7 @@ MINLINE void blend_color_mul_float(float dst[4], const float src1[4], const floa
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4(dst, src1);
}
}
@@ -360,10 +709,7 @@ MINLINE void blend_color_lighten_float(float dst[4], const float src1[4], const
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4(dst, src1);
}
}
@@ -383,10 +729,7 @@ MINLINE void blend_color_darken_float(float dst[4], const float src1[4], const f
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4(dst, src1);
}
}
@@ -397,8 +740,9 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co
float alpha = max_ff(src1[3] - src2[3], 0.0f);
float map_alpha;
- if (alpha <= 0.0005f)
+ if (alpha <= EPS_ALPHA) {
alpha = 0.0f;
+ }
map_alpha = alpha / src1[3];
@@ -409,10 +753,7 @@ MINLINE void blend_color_erase_alpha_float(float dst[4], const float src1[4], co
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4(dst, src1);
}
}
@@ -423,8 +764,9 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons
float alpha = min_ff(src1[3] + src2[3], 1.0f);
float map_alpha;
- if (alpha >= 1.0f - 0.0005f)
+ if (alpha >= 1.0f - EPS_ALPHA) {
alpha = 1.0f;
+ }
map_alpha = (src1[3] > 0.0f) ? alpha / src1[3] : 1.0f;
@@ -435,17 +777,390 @@ MINLINE void blend_color_add_alpha_float(float dst[4], const float src1[4], cons
}
else {
/* no op */
- dst[0] = src1[0];
- dst[1] = src1[1];
- dst[2] = src1[2];
- dst[3] = src1[3];
+ copy_v4_v4(dst, src1);
+ }
+}
+
+MINLINE void blend_color_overlay_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ float temp;
+
+ if (src1[i] > 0.5f) {
+ temp = 1.0f - (1.0f - 2.0f * (src1[i] - 0.5f)) * (1.0f - src2[i]);
+ }
+ else {
+ temp = 2.0f * src1[i] * src2[i];
+ }
+ dst[i] = min_ff(temp * fac + src1[i] * mfac, 1.0f);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+
+MINLINE void blend_color_hardlight_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ float temp;
+
+ if (src2[i] > 0.5f) {
+ temp = 1.0f - ((1.0f - 2.0f * (src2[i] - 0.5f)) * (1.0f - src1[i]));
+ }
+ else {
+ temp = 2.0f * src2[i] * src1[i];
+ }
+ dst[i] = min_ff((temp * fac + src1[i] * mfac) / 1.0f, 1.0f);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+MINLINE void blend_color_burn_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ const float temp = (src2[i] == 0.0f) ? 0.0f : max_ff(1.0f - ((1.0f - src1[i]) / src2[i]), 0.0f);
+ dst[i] = (temp * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+MINLINE void blend_color_linearburn_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ const float temp = max_ff(src1[i] + src2[i] - 1.0f, 0.0f);
+ dst[i] = (temp * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+
+MINLINE void blend_color_dodge_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ const float temp = (src2[i] >= 1.0f) ? 1.0f : min_ff(src1[i] / (1.0f - src2[i]), 1.0f);
+ dst[i] = (temp * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+MINLINE void blend_color_screen_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ const float temp = max_ff(1.0f - ((1.0f - src1[i]) * (1.0f - src2[i])), 0.0f);
+ dst[i] = (temp * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ float temp;
+
+ if (src1[i] < 0.5f) {
+ temp = (src2[i] + 0.5f) * src1[i];
+ }
+ else {
+ temp = 1.0f - ((1.0f - (src2[i] + 0.5f)) * (1.0f - src1[i]));
+ }
+ dst[i] = (temp * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+MINLINE void blend_color_pinlight_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ float temp;
+
+ if (src2[i] > 0.5f) {
+ temp = max_ff(2.0f * (src2[i] - 0.5f), src1[i]);
+ }
+ else {
+ temp = min_ff(2.0f * src2[i], src1[i]);
+ }
+ dst[i] = (temp * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+
+MINLINE void blend_color_linearlight_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ float temp;
+
+ if (src2[i] > 0.5f) {
+ temp = min_ff(src1[i] + 2.0f * (src2[i] - 0.5f), 1.0f);
+ }
+ else {
+ temp = max_ff(src1[i] + 2.0f * src2[i] - 1.0f, 0.0f);
+ }
+ dst[i] = (temp * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+
+MINLINE void blend_color_vividlight_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ float temp;
+
+ if (src2[i] == 1.0f) {
+ temp = 1.0f;
+ }
+ else if (src2[i] == 0.0f) {
+ temp = 0.0f;
+ }
+ else if (src2[i] > 0.5f) {
+ temp = min_ff(((src1[i]) * 1.0f) / (2.0f * (1.0f - src2[i])), 1.0f);
+ }
+ else {
+ temp = max_ff(1.0f - ((1.0f - src1[i]) * 1.0f / (2.0f * src2[i])), 0.0f);
+ }
+ dst[i] = (temp * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+MINLINE void blend_color_difference_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ dst[i] = (fabsf(src1[i] - src2[i]) * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
}
}
+
+MINLINE void blend_color_exclusion_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ int i = 3;
+
+ while (i--) {
+ const float temp = 0.5f - ((2 * (src1[i] - 0.5f) * (src2[i] - 0.5f)));
+ dst[i] = (temp * fac + src1[i] * mfac);
+ }
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+
+}
+
+MINLINE void blend_color_color_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+
+ rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
+ rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
+
+ h1 = h2;
+ s1 = s2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ dst[0] = (r * fac + src1[0] * mfac);
+ dst[1] = (g * fac + src1[1] * mfac);
+ dst[2] = (b * fac + src1[2] * mfac);
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+
+MINLINE void blend_color_hue_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+
+ rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
+ rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
+
+ h1 = h2;
+
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ dst[0] = (r * fac + src1[0] * mfac);
+ dst[1] = (g * fac + src1[1] * mfac);
+ dst[2] = (b * fac + src1[2] * mfac);
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+MINLINE void blend_color_saturation_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+
+ rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
+ rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
+
+ if (s1 > EPS_SATURATION) {
+ s1 = s2;
+ }
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ dst[0] = (r * fac + src1[0] * mfac);
+ dst[1] = (g * fac + src1[1] * mfac);
+ dst[2] = (b * fac + src1[2] * mfac);
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+MINLINE void blend_color_luminosity_float(float dst[4], const float src1[4], const float src2[4])
+{
+ const float fac = src2[3];
+ if (fac != 0.0f && fac < 1.0f) {
+ const float mfac = 1.0f - fac;
+ float h1, s1, v1;
+ float h2, s2, v2;
+ float r, g, b;
+
+ rgb_to_hsv(src1[0], src1[1], src1[2], &h1, &s1, &v1);
+ rgb_to_hsv(src2[0], src2[1], src2[2], &h2, &s2, &v2);
+
+ v1 = v2;
+ hsv_to_rgb(h1, s1, v1, &r, &g, &b);
+
+ dst[0] = (r * fac + src1[0] * mfac);
+ dst[1] = (g * fac + src1[1] * mfac);
+ dst[2] = (b * fac + src1[2] * mfac);
+ }
+ else {
+ /* no op */
+ copy_v4_v4(dst, src1);
+ }
+}
+
+
MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], const float src2[4], float t)
{
/* interpolation, colors are premultiplied so it goes fine */
- float mt = 1.0f - t;
+ const float mt = 1.0f - t;
dst[0] = mt * src1[0] + t * src2[0];
dst[1] = mt * src1[1] + t * src2[1];
@@ -453,4 +1168,7 @@ MINLINE void blend_color_interpolate_float(float dst[4], const float src1[4], co
dst[3] = mt * src1[3] + t * src2[3];
}
+#undef EPS_SATURATION
+#undef EPS_ALPHA
+
#endif /* __MATH_COLOR_BLEND_INLINE_C__ */
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index bb2201541d9..9233749d5df 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -255,11 +255,11 @@ MINLINE float rgb_to_luma_y(const float rgb[3])
MINLINE int compare_rgb_uchar(const unsigned char col_a[3], const unsigned char col_b[3], const int limit)
{
- int r = (int)col_a[0] - (int)col_b[0];
+ const int r = (int)col_a[0] - (int)col_b[0];
if (ABS(r) < limit) {
- int g = (int)col_a[1] - (int)col_b[1];
+ const int g = (int)col_a[1] - (int)col_b[1];
if (ABS(g) < limit) {
- int b = (int)col_a[2] - (int)col_b[2];
+ const int b = (int)col_a[2] - (int)col_b[2];
if (ABS(b) < limit) {
return 1;
}
@@ -280,7 +280,7 @@ MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
straight[3] = premul[3];
}
else {
- float alpha_inv = 1.0f / premul[3];
+ const float alpha_inv = 1.0f / premul[3];
straight[0] = premul[0] * alpha_inv;
straight[1] = premul[1] * alpha_inv;
straight[2] = premul[2] * alpha_inv;
@@ -295,7 +295,7 @@ MINLINE void premul_to_straight_v4(float color[4])
MINLINE void straight_to_premul_v4_v4(float premul[4], const float straight[4])
{
- float alpha = straight[3];
+ const float alpha = straight[3];
premul[0] = straight[0] * alpha;
premul[1] = straight[1] * alpha;
premul[2] = straight[2] * alpha;
@@ -309,8 +309,8 @@ MINLINE void straight_to_premul_v4(float color[4])
MINLINE void straight_uchar_to_premul_float(float result[4], const unsigned char color[4])
{
- float alpha = color[3] * (1.0f / 255.0f);
- float fac = alpha * (1.0f / 255.0f);
+ const float alpha = color[3] * (1.0f / 255.0f);
+ const float fac = alpha * (1.0f / 255.0f);
result[0] = color[0] * fac;
result[1] = color[1] * fac;
@@ -327,7 +327,7 @@ MINLINE void premul_float_to_straight_uchar(unsigned char *result, const float c
result[3] = FTOCHAR(color[3]);
}
else {
- float alpha_inv = 1.0f / color[3];
+ const float alpha_inv = 1.0f / color[3];
/* hopefully this would be optimized */
result[0] = FTOCHAR(color[0] * alpha_inv);
diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c
index 5f3ab5eb73e..015313431cb 100644
--- a/source/blender/blenlib/intern/math_geom.c
+++ b/source/blender/blenlib/intern/math_geom.c
@@ -160,6 +160,12 @@ float area_poly_v3(const float verts[][3], unsigned int nr)
return normal_poly_v3(n, verts, nr) * 0.5f;
}
+/**
+ * Scalar cross product of a 2d polygon.
+ *
+ * - equivalent to ``area * 2``
+ * - useful for checking polygon winding (a positive value is clockwise).
+ */
float cross_poly_v2(const float verts[][2], unsigned int nr)
{
unsigned int a;
@@ -238,6 +244,18 @@ float volume_tetrahedron_v3(const float v1[3], const float v2[3], const float v3
return fabsf(determinant_m3_array(m)) / 6.0f;
}
+/**
+ * The volume from a tetrahedron, normal pointing inside gives negative volume
+ */
+float volume_tetrahedron_signed_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3])
+{
+ float m[3][3];
+ sub_v3_v3v3(m[0], v1, v2);
+ sub_v3_v3v3(m[1], v2, v3);
+ sub_v3_v3v3(m[2], v3, v4);
+ return determinant_m3_array(m) / 6.0f;
+}
+
/********************************* Distance **********************************/
@@ -364,24 +382,36 @@ void closest_to_plane_v3(float r_close[3], const float plane[4], const float pt[
madd_v3_v3v3fl(r_close, pt, plane, -side / len_sq);
}
-float dist_squared_to_plane_v3(const float pt[3], const float plane[4])
+float dist_signed_squared_to_plane_v3(const float pt[3], const float plane[4])
{
const float len_sq = len_squared_v3(plane);
const float side = plane_point_side_v3(plane, pt);
const float fac = side / len_sq;
return copysignf(len_sq * (fac * fac), side);
}
+float dist_squared_to_plane_v3(const float pt[3], const float plane[4])
+{
+ const float len_sq = len_squared_v3(plane);
+ const float side = plane_point_side_v3(plane, pt);
+ 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.
*/
-float dist_to_plane_v3(const float pt[3], const float plane[4])
+float dist_signed_to_plane_v3(const float pt[3], const float plane[4])
{
const float len_sq = len_squared_v3(plane);
const float side = plane_point_side_v3(plane, pt);
const float fac = side / len_sq;
return sqrtf(len_sq) * fac;
}
+float dist_to_plane_v3(const float pt[3], const float plane[4])
+{
+ return fabsf(dist_signed_to_plane_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])
@@ -556,7 +586,7 @@ int isect_seg_seg_v2_point(const float v1[2], const float v2[2], const float v3[
{
float a1, a2, b1, b2, c1, c2, d;
float u, v;
- const float eps = 0.000001f;
+ const float eps = 1e-6f;
const float eps_sq = eps * eps;
a1 = v2[0] - v1[0];
@@ -953,7 +983,7 @@ bool isect_line_tri_v3(const float p1[3], const float p2[3],
cross_v3_v3v3(p, d, e2);
a = dot_v3v3(e1, p);
- if ((a > -0.000001f) && (a < 0.000001f)) return 0;
+ if (a == 0.0f) return 0;
f = 1.0f / a;
sub_v3_v3v3(s, p1, v0);
@@ -992,7 +1022,7 @@ bool isect_line_tri_epsilon_v3(const float p1[3], const float p2[3],
cross_v3_v3v3(p, d, e2);
a = dot_v3v3(e1, p);
- if ((a > -0.000001f) && (a < 0.000001f)) return 0;
+ if (a == 0.0f) return 0;
f = 1.0f / a;
sub_v3_v3v3(s, p1, v0);
@@ -1266,13 +1296,13 @@ bool isect_plane_plane_v3(float r_isect_co[3], float r_isect_no[3],
static bool getLowestRoot(const float a, const float b, const float c, const float maxR, float *root)
{
/* Check if a solution exists */
- float determinant = b * b - 4.0f * a * c;
+ const float determinant = b * b - 4.0f * a * c;
/* If determinant is negative it means no solutions. */
if (determinant >= 0.0f) {
/* calculate the two roots: (if determinant == 0 then
* x1==x2 but lets disregard that slight optimization) */
- float sqrtD = sqrtf(determinant);
+ const float sqrtD = sqrtf(determinant);
float r1 = (-b - sqrtD) / (2.0f * a);
float r2 = (-b + sqrtD) / (2.0f * a);
@@ -1283,18 +1313,18 @@ static bool getLowestRoot(const float a, const float b, const float c, const flo
/* Get lowest root: */
if (r1 > 0.0f && r1 < maxR) {
*root = r1;
- return 1;
+ return true;
}
/* It is possible that we want x2 - this can happen */
/* if x1 < 0 */
if (r2 > 0.0f && r2 < maxR) {
*root = r2;
- return 1;
+ return true;
}
}
/* No (valid) solutions */
- return 0;
+ return false;
}
bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const float radius,
@@ -1323,7 +1353,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl
if (fabsf(nordotv) < 0.000001f) {
if (fabsf(a) >= radius) {
- return 0;
+ return false;
}
}
else {
@@ -1365,7 +1395,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl
//(((unsigned int)z)& ~(((unsigned int)x)|((unsigned int)y))) & 0x80000000) {
*r_lambda = t0;
copy_v3_v3(ipoint, point);
- return 1;
+ return true;
}
}
@@ -1382,7 +1412,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl
if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) {
copy_v3_v3(ipoint, v0);
- found_by_sweep = 1;
+ found_by_sweep = true;
}
/*v1*/
@@ -1392,7 +1422,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl
if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) {
copy_v3_v3(ipoint, v1);
- found_by_sweep = 1;
+ found_by_sweep = true;
}
/*v2*/
@@ -1402,7 +1432,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl
if (getLowestRoot(a, b, c, *r_lambda, r_lambda)) {
copy_v3_v3(ipoint, v2);
- found_by_sweep = 1;
+ found_by_sweep = true;
}
/*---test edges---*/
@@ -1428,7 +1458,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl
copy_v3_v3(ipoint, e1);
mul_v3_fl(ipoint, e);
add_v3_v3(ipoint, v0);
- found_by_sweep = 1;
+ found_by_sweep = true;
}
}
@@ -1450,7 +1480,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl
copy_v3_v3(ipoint, e2);
mul_v3_fl(ipoint, e);
add_v3_v3(ipoint, v0);
- found_by_sweep = 1;
+ found_by_sweep = true;
}
}
@@ -1477,7 +1507,7 @@ bool isect_sweeping_sphere_tri_v3(const float p1[3], const float p2[3], const fl
copy_v3_v3(ipoint, e3);
mul_v3_fl(ipoint, e);
add_v3_v3(ipoint, v1);
- found_by_sweep = 1;
+ found_by_sweep = true;
}
}
@@ -1496,10 +1526,10 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3
return isect_line_tri_v3(p1, p2, v0, v1, v2, lambda);
/* first a simple bounding box test */
- if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return 0;
- if (min_fff(v0[a2], v1[a2], v2[a2]) > p1[a2]) return 0;
- if (max_fff(v0[a1], v1[a1], v2[a1]) < p1[a1]) return 0;
- if (max_fff(v0[a2], v1[a2], v2[a2]) < p1[a2]) return 0;
+ if (min_fff(v0[a1], v1[a1], v2[a1]) > p1[a1]) return false;
+ if (min_fff(v0[a2], v1[a2], v2[a2]) > p1[a2]) return false;
+ if (max_fff(v0[a1], v1[a1], v2[a1]) < p1[a1]) return false;
+ if (max_fff(v0[a2], v1[a2], v2[a2]) < p1[a2]) return false;
/* then a full intersection test */
#endif
@@ -1509,7 +1539,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3
sub_v3_v3v3(p, v0, p1);
f = (e2[a1] * e1[a2] - e2[a2] * e1[a1]);
- if ((f > -0.000001f) && (f < 0.000001f)) return 0;
+ if ((f > -0.000001f) && (f < 0.000001f)) return false;
v = (p[a2] * e1[a1] - p[a1] * e1[a2]) / f;
if ((v < 0.0f) || (v > 1.0f)) return 0;
@@ -1517,7 +1547,7 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3
f = e1[a1];
if ((f > -0.000001f) && (f < 0.000001f)) {
f = e1[a2];
- if ((f > -0.000001f) && (f < 0.000001f)) return 0;
+ if ((f > -0.000001f) && (f < 0.000001f)) return false;
u = (-p[a2] - v * e2[a2]) / f;
}
else
@@ -1527,9 +1557,9 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3
*r_lambda = (p[a0] + u * e1[a0] + v * e2[a0]) / (p2[a0] - p1[a0]);
- if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return 0;
+ if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f)) return false;
- return 1;
+ return true;
}
/**
@@ -1538,7 +1568,10 @@ bool isect_axial_line_tri_v3(const int axis, const float p1[3], const float p2[3
* 1 - lines are coplanar, i1 is set to intersection
* 2 - i1 and i2 are the nearest points on line 1 (v1, v2) and line 2 (v3, v4) respectively
*/
-int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3], const float v4[3], float i1[3], float i2[3])
+int isect_line_line_epsilon_v3(
+ const float v1[3], const float v2[3],
+ const float v3[3], const float v4[3], float i1[3], float i2[3],
+ const float epsilon)
{
float a[3], b[3], c[3], ab[3], cb[3], dir1[3], dir2[3];
float d, div;
@@ -1564,7 +1597,7 @@ int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3],
return 0;
}
/* test if the two lines are coplanar */
- else if (d > -0.000001f && d < 0.000001f) {
+ else if (UNLIKELY(fabsf(d) <= epsilon)) {
cross_v3_v3v3(cb, c, b);
mul_v3_fl(a, dot_v3v3(cb, ab) / div);
@@ -1604,9 +1637,17 @@ int isect_line_line_v3(const float v1[3], const float v2[3], const float v3[3],
}
}
-/* Intersection point strictly between the two lines
- * 0 when no intersection is found
- * */
+int isect_line_line_v3(
+ const float v1[3], const float v2[3],
+ const float v3[3], const float v4[3], float i1[3], float i2[3])
+{
+ const float epsilon = 0.000001f;
+ return isect_line_line_epsilon_v3(v1, v2, v3, v4, i1, i2, epsilon);
+}
+
+/** Intersection point strictly between the two lines
+ * \return false when no intersection is found
+ */
bool isect_line_line_strict_v3(const float v1[3], const float v2[3],
const float v3[3], const float v4[3],
float vi[3], float *r_lambda)
@@ -1623,7 +1664,7 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3],
d = dot_v3v3(dir1, dir2);
if (d == 1.0f || d == -1.0f || d == 0) {
/* colinear or one vector is zero-length*/
- return 0;
+ return false;
}
cross_v3_v3v3(ab, a, b);
@@ -1632,7 +1673,7 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3],
/* test zero length line */
if (UNLIKELY(div == 0.0f)) {
- return 0;
+ return false;
}
/* test if the two lines are coplanar */
else if (d > -0.000001f && d < 0.000001f) {
@@ -1651,14 +1692,14 @@ bool isect_line_line_strict_v3(const float v1[3], const float v2[3],
if (r_lambda) *r_lambda = f1;
- return 1; /* intersection found */
+ return true; /* intersection found */
}
else {
- return 0;
+ return false;
}
}
else {
- return 0;
+ return false;
}
}
@@ -1676,9 +1717,9 @@ void isect_ray_aabb_initialize(IsectRayAABBData *data, const float ray_start[3],
data->ray_inv_dir[1] = 1.0f / ray_direction[1];
data->ray_inv_dir[2] = 1.0f / ray_direction[2];
- data->sign[0] = data->ray_inv_dir[0] < 0;
- data->sign[1] = data->ray_inv_dir[1] < 0;
- data->sign[2] = data->ray_inv_dir[2] < 0;
+ data->sign[0] = data->ray_inv_dir[0] < 0.0f;
+ data->sign[1] = data->ray_inv_dir[1] < 0.0f;
+ data->sign[2] = data->ray_inv_dir[2] < 0.0f;
}
/* Adapted from http://www.gamedev.net/community/forums/topic.asp?topic_id=459973 */
@@ -1715,8 +1756,8 @@ bool isect_ray_aabb(const IsectRayAABBData *data, const float bb_min[3],
if (tzmin > tmin)
tmin = tzmin;
- /* XXX jwilkins: tmax does not need to be updated since we don't use it
- * keeping this here for future reference */
+ /* Note: tmax does not need to be updated since we don't use it
+ * keeping this here for future reference - jwilkins */
//if (tzmax < tmax) tmax = tzmax;
if (tmin_out)
@@ -1751,7 +1792,10 @@ float closest_to_line_v2(float cp[2], const float p[2], const float l1[2], const
return lambda;
}
-/* little sister we only need to know lambda */
+/**
+ * A simplified version of #closest_to_line_v3
+ * we only need to return the ``lambda``
+ */
float line_point_factor_v3(const float p[3], const float l1[3], const float l2[3])
{
float h[3], u[3];
@@ -1796,8 +1840,9 @@ float line_plane_factor_v3(const float plane_co[3], const float plane_no[3],
return (dot != 0.0f) ? -dot_v3v3(plane_no, h) / dot : 0.0f;
}
-/* ensure the distance between these points is no greater then 'dist'
- * if it is, scale then both into the center */
+/** Ensure the distance between these points is no greater then 'dist'.
+ * If it is, scale then both into the center.
+ */
void limit_dist_v3(float v1[3], float v2[3], const float dist)
{
const float dist_old = len_v3v3(v1, v2);
@@ -1862,8 +1907,7 @@ static bool point_in_slice(const float p[3], const float v1[3], const float l1[3
sub_v3_v3v3(rp, p, v1);
h = dot_v3v3(q, rp) / dot_v3v3(q, q);
- if (h < 0.0f || h > 1.0f) return 0;
- return 1;
+ return (h < 0.0f || h > 1.0f) ? false : true;
}
#if 0
@@ -1892,10 +1936,43 @@ static int point_in_slice_m(float p[3], float origin[3], float normal[3], float
bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3])
{
- if (!point_in_slice(p, v1, v2, v3)) return 0;
- if (!point_in_slice(p, v2, v3, v1)) return 0;
- if (!point_in_slice(p, v3, v1, v2)) return 0;
- return 1;
+ if (!point_in_slice(p, v1, v2, v3)) return false;
+ if (!point_in_slice(p, v2, v3, v1)) return false;
+ if (!point_in_slice(p, v3, v1, v2)) return false;
+ return true;
+}
+
+/**
+ * \param r_vi The point \a p projected onto the triangle.
+ * \return True when \a p is inside the triangle.
+ * \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin.
+ */
+bool isect_point_tri_v3(const float p[3], const float v1[3], const float v2[3], const float v3[3],
+ float r_vi[3])
+{
+ if (isect_point_tri_prism_v3(p, v1, v2, v3)) {
+ float no[3], n1[3], n2[3];
+
+ /* Could use normal_tri_v3, but doesn't have to be unit-length */
+ sub_v3_v3v3(n1, v1, v2);
+ sub_v3_v3v3(n2, v2, v3);
+ cross_v3_v3v3(no, n1, n2);
+
+ if (LIKELY(len_squared_v3(no) != 0.0f)) {
+ float plane[4];
+ plane_from_point_normal_v3(plane, v1, no);
+ closest_to_plane_v3(r_vi, plane, p);
+ }
+ else {
+ /* degenerate */
+ copy_v3_v3(r_vi, p);
+ }
+
+ return true;
+ }
+ else {
+ return false;
+ }
}
bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4])
@@ -1906,7 +1983,7 @@ bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4])
div = dot_v3v3(dp, plane);
if (div == 0.0f) /* parallel */
- return 1;
+ return true;
t = -plane_point_side_v3(plane, p1) / div;
@@ -1915,34 +1992,34 @@ bool clip_segment_v3_plane(float p1[3], float p2[3], const float plane[4])
if (t >= 1.0f) {
zero_v3(p1);
zero_v3(p2);
- return 0;
+ return false;
}
/* intersect plane */
if (t > 0.0f) {
madd_v3_v3v3fl(pc, p1, dp, t);
copy_v3_v3(p1, pc);
- return 1;
+ return true;
}
- return 1;
+ return true;
}
else {
/* behind plane, completely clipped */
if (t <= 0.0f) {
zero_v3(p1);
zero_v3(p2);
- return 0;
+ return false;
}
/* intersect plane */
if (t < 1.0f) {
madd_v3_v3v3fl(pc, p1, dp, t);
copy_v3_v3(p2, pc);
- return 1;
+ return true;
}
- return 1;
+ return true;
}
}
@@ -2171,12 +2248,12 @@ static bool barycentric_weights(const float v1[3], const float v2[3], const floa
if (fabsf(wtot) > FLT_EPSILON) {
mul_v3_fl(w, 1.0f / wtot);
- return 0;
+ return false;
}
else {
/* zero area triangle */
copy_v3_fl(w, 1.0f / 3.0f);
- return 1;
+ return true;
}
}
@@ -2227,8 +2304,9 @@ void interp_weights_face_v3(float w[4], const float v1[3], const float v2[3], co
}
}
}
- else
+ else {
barycentric_weights(v1, v2, v3, co, n, w);
+ }
}
}
@@ -2254,11 +2332,11 @@ int barycentric_inside_triangle_v2(const float w[3])
/* returns 0 for degenerated triangles */
bool barycentric_coords_v2(const float v1[2], const float v2[2], const float v3[2], const float co[2], float w[3])
{
- float x = co[0], y = co[1];
- float x1 = v1[0], y1 = v1[1];
- float x2 = v2[0], y2 = v2[1];
- float x3 = v3[0], y3 = v3[1];
- float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3);
+ const float x = co[0], y = co[1];
+ const float x1 = v1[0], y1 = v1[1];
+ const float x2 = v2[0], y2 = v2[1];
+ const float x3 = v3[0], y3 = v3[1];
+ const float det = (y2 - y3) * (x1 - x3) + (x3 - x2) * (y1 - y3);
if (fabsf(det) > FLT_EPSILON) {
w[0] = ((y2 - y3) * (x - x3) + (x3 - x2) * (y - y3)) / det;
@@ -2307,8 +2385,9 @@ void barycentric_weights_v2_persp(const float v1[4], const float v2[4], const fl
if (wtot != 0.0f) {
mul_v3_fl(w, 1.0f / wtot);
}
- else /* dummy values for zero area face */
+ else { /* dummy values for zero area face */
w[0] = w[1] = w[2] = 1.0f / 3.0f;
+ }
}
/* same as #barycentric_weights_v2 but works with a quad,
@@ -2343,8 +2422,7 @@ void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const flo
if (UNLIKELY(lens[0] < FLT_EPSILON)) { w[0] = 1.0f; w[1] = w[2] = w[3] = 0.0f; }
else if (UNLIKELY(lens[1] < FLT_EPSILON)) { w[1] = 1.0f; w[0] = w[2] = w[3] = 0.0f; }
else if (UNLIKELY(lens[2] < FLT_EPSILON)) { w[2] = 1.0f; w[0] = w[1] = w[3] = 0.0f; }
- else if (UNLIKELY(lens[3] < FLT_EPSILON)) { w[3] = 1.0f; w[0] = w[1] = w[2] = 0.0f;
- }
+ else if (UNLIKELY(lens[3] < FLT_EPSILON)) { w[3] = 1.0f; w[0] = w[1] = w[2] = 0.0f; }
else {
float wtot, area;
@@ -2388,9 +2466,10 @@ void barycentric_weights_v2_quad(const float v1[2], const float v2[2], const flo
/* given 2 triangles in 3D space, and a point in relation to the first triangle.
* calculate the location of a point in relation to the second triangle.
* Useful for finding relative positions with geometry */
-void barycentric_transform(float pt_tar[3], float const pt_src[3],
- const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3],
- const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3])
+void transform_point_by_tri_v3(
+ float pt_tar[3], float const pt_src[3],
+ const float tri_tar_p1[3], const float tri_tar_p2[3], const float tri_tar_p3[3],
+ const float tri_src_p1[3], const float tri_src_p2[3], const float tri_src_p3[3])
{
/* this works by moving the source triangle so its normal is pointing on the Z
* axis where its barycentric weights can be calculated in 2D and its Z offset can
@@ -2427,6 +2506,19 @@ void barycentric_transform(float pt_tar[3], float const pt_src[3],
madd_v3_v3v3fl(pt_tar, pt_tar, no_tar, (z_ofs_src / area_src) * area_tar);
}
+/**
+ * Simply re-interpolates,
+ * assumes p_src is between \a l_src_p1-l_src_p2
+ */
+void transform_point_by_seg_v3(
+ float p_dst[3], const float p_src[3],
+ const float l_dst_p1[3], const float l_dst_p2[3],
+ const float l_src_p1[3], const float l_src_p2[3])
+{
+ float t = line_point_factor_v3(p_src, l_src_p1, l_src_p2);
+ interp_v3_v3v3(p_dst, l_dst_p1, l_dst_p2, t);
+}
+
/* given an array with some invalid values this function interpolates valid values
* replacing the invalid ones */
int interp_sparse_array(float *array, const int list_size, const float skipval)
@@ -2551,7 +2643,7 @@ static float mean_value_half_tan_v2(const float v1[2], const float v2[2], const
void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[3])
{
- const float eps = 0.00001f; /* take care, low values cause [#36105] */
+ const float eps = 1e-5f; /* take care, low values cause [#36105] */
const float eps_sq = eps * eps;
const float *v_curr, *v_next;
float ht_prev, ht; /* half tangents */
@@ -2620,7 +2712,7 @@ void interp_weights_poly_v3(float *w, float v[][3], const int n, const float co[
void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[2])
{
- const float eps = 0.00001f; /* take care, low values cause [#36105] */
+ const float eps = 1e-5f; /* take care, low values cause [#36105] */
const float eps_sq = eps * eps;
const float *v_curr, *v_next;
float ht_prev, ht; /* half tangents */
@@ -2690,8 +2782,8 @@ void interp_weights_poly_v2(float *w, float v[][2], const int n, const float co[
void interp_cubic_v3(float x[3], float v[3], const float x1[3], const float v1[3], const float x2[3], const float v2[3], const float t)
{
float a[3], b[3];
- float t2 = t * t;
- float t3 = t2 * t;
+ const float t2 = t * t;
+ const float t3 = t2 * t;
/* cubic interpolation */
a[0] = v1[0] + v2[0] + 2 * (x1[0] - x2[0]);
@@ -2916,11 +3008,9 @@ void orthographic_m4(float matrix[4][4], const float left, const float right, co
void perspective_m4(float mat[4][4], const float left, const float right, const float bottom, const float top,
const float nearClip, const float farClip)
{
- float Xdelta, Ydelta, Zdelta;
-
- Xdelta = right - left;
- Ydelta = top - bottom;
- Zdelta = farClip - nearClip;
+ const float Xdelta = right - left;
+ const float Ydelta = top - bottom;
+ const float Zdelta = farClip - nearClip;
if (Xdelta == 0.0f || Ydelta == 0.0f || Zdelta == 0.0f) {
return;
@@ -2934,7 +3024,7 @@ void perspective_m4(float mat[4][4], const float left, const float right, const
mat[3][2] = (-2.0f * nearClip * farClip) / Zdelta;
mat[0][1] = mat[0][2] = mat[0][3] =
mat[1][0] = mat[1][2] = mat[1][3] =
- mat[3][0] = mat[3][1] = mat[3][3] = 0.0;
+ mat[3][0] = mat[3][1] = mat[3][3] = 0.0f;
}
@@ -2983,7 +3073,6 @@ static void i_multmatrix(float icand[4][4], float Vm[4][4])
void polarview_m4(float Vm[4][4], float dist, float azimuth, float incidence, float twist)
{
-
unit_m4(Vm);
translate_m4(Vm, 0.0, 0.0, -dist);
@@ -3005,16 +3094,16 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py
dx = px - vx;
dy = py - vy;
dz = pz - vz;
- hyp = dx * dx + dz * dz; /* hyp squared */
+ hyp = dx * dx + dz * dz; /* hyp squared */
hyp1 = sqrtf(dy * dy + hyp);
- hyp = sqrtf(hyp); /* the real hyp */
+ hyp = sqrtf(hyp); /* the real hyp */
- if (hyp1 != 0.0f) { /* rotate X */
+ if (hyp1 != 0.0f) { /* rotate X */
sine = -dy / hyp1;
cosine = hyp / hyp1;
}
else {
- sine = 0;
+ sine = 0.0f;
cosine = 1.0f;
}
mat1[1][1] = cosine;
@@ -3024,16 +3113,16 @@ void lookat_m4(float mat[4][4], float vx, float vy, float vz, float px, float py
i_multmatrix(mat1, mat);
- mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */
- mat1[1][2] = mat1[2][1] = 0.0; /* those modified by the last */
+ mat1[1][1] = mat1[2][2] = 1.0f; /* be careful here to reinit */
+ mat1[1][2] = mat1[2][1] = 0.0f; /* those modified by the last */
- /* paragraph */
- if (hyp != 0.0f) { /* rotate Y */
+ /* paragraph */
+ if (hyp != 0.0f) { /* rotate Y */
sine = dx / hyp;
cosine = -dz / hyp;
}
else {
- sine = 0;
+ sine = 0.0f;
cosine = 1.0f;
}
mat1[0][0] = cosine;
@@ -3113,7 +3202,7 @@ void map_to_tube(float *r_u, float *r_v, const float x, const float y, const flo
len = sqrtf(x * x + y * y);
if (len > 0.0f) {
- *r_u = (float)((1.0 - (atan2(x / len, y / len) / M_PI)) / 2.0);
+ *r_u = (1.0f - (atan2f(x / len, y / len) / (float)M_PI)) / 2.0f;
}
else {
*r_v = *r_u = 0.0f; /* to avoid un-initialized variables */
@@ -3126,8 +3215,12 @@ void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const f
len = sqrtf(x * x + y * y + z * z);
if (len > 0.0f) {
- if (x == 0.0f && y == 0.0f) *r_u = 0.0f; /* othwise domain error */
- else *r_u = (1.0f - atan2f(x, y) / (float)M_PI) / 2.0f;
+ if (UNLIKELY(x == 0.0f && y == 0.0f)) {
+ *r_u = 0.0f; /* othwise domain error */
+ }
+ else {
+ *r_u = (1.0f - atan2f(x, y) / (float)M_PI) / 2.0f;
+ }
*r_v = 1.0f - saacos(z / len) / (float)M_PI;
}
@@ -3138,9 +3231,10 @@ void map_to_sphere(float *r_u, float *r_v, const float x, const float y, const f
/********************************* Normals **********************************/
-void accumulate_vertex_normals(float n1[3], float n2[3], float n3[3],
- float n4[3], const float f_no[3], const float co1[3], const float co2[3],
- const float co3[3], const float co4[3])
+void accumulate_vertex_normals(
+ float n1[3], float n2[3], float n3[3], float n4[3],
+ const float f_no[3],
+ const float co1[3], const float co2[3], const float co3[3], const float co4[3])
{
float vdiffs[4][3];
const int nverts = (n4 != NULL && co4 != NULL) ? 4 : 3;
@@ -3212,15 +3306,20 @@ void accumulate_vertex_normals_poly(float **vertnos, const float polyno[3],
/********************************* Tangents **********************************/
-void tangent_from_uv(float uv1[2], float uv2[2], float uv3[3], float co1[3], float co2[3], float co3[3], float n[3], float tang[3])
+void tangent_from_uv(
+ const float uv1[2], const float uv2[2], const float uv3[3],
+ const float co1[3], const float co2[3], const float co3[3],
+ const float n[3],
+ float r_tang[3])
{
- float s1 = uv2[0] - uv1[0];
- float s2 = uv3[0] - uv1[0];
- float t1 = uv2[1] - uv1[1];
- float t2 = uv3[1] - uv1[1];
+ const float s1 = uv2[0] - uv1[0];
+ const float s2 = uv3[0] - uv1[0];
+ const float t1 = uv2[1] - uv1[1];
+ const float t2 = uv3[1] - uv1[1];
float det = (s1 * t2 - s2 * t1);
- if (det != 0.0f) { /* otherwise 'tang' becomes nan */
+ /* otherwise 'r_tang' becomes nan */
+ if (det != 0.0f) {
float tangv[3], ct[3], e1[3], e2[3];
det = 1.0f / det;
@@ -3228,21 +3327,21 @@ void tangent_from_uv(float uv1[2], float uv2[2], float uv3[3], float co1[3], flo
/* normals in render are inversed... */
sub_v3_v3v3(e1, co1, co2);
sub_v3_v3v3(e2, co1, co3);
- tang[0] = (t2 * e1[0] - t1 * e2[0]) * det;
- tang[1] = (t2 * e1[1] - t1 * e2[1]) * det;
- tang[2] = (t2 * e1[2] - t1 * e2[2]) * det;
+ r_tang[0] = (t2 * e1[0] - t1 * e2[0]) * det;
+ r_tang[1] = (t2 * e1[1] - t1 * e2[1]) * det;
+ r_tang[2] = (t2 * e1[2] - t1 * e2[2]) * det;
tangv[0] = (s1 * e2[0] - s2 * e1[0]) * det;
tangv[1] = (s1 * e2[1] - s2 * e1[1]) * det;
tangv[2] = (s1 * e2[2] - s2 * e1[2]) * det;
- cross_v3_v3v3(ct, tang, tangv);
+ cross_v3_v3v3(ct, r_tang, tangv);
/* check flip */
if (dot_v3v3(ct, n) < 0.0f) {
- negate_v3(tang);
+ negate_v3(r_tang);
}
}
else {
- tang[0] = tang[1] = tang[2] = 0.0;
+ zero_v3(r_tang);
}
}
@@ -3275,7 +3374,8 @@ void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, fl
float lloc[3], float rloc[3], float lrot[3][3], float lscale[3][3])
{
float accu_com[3] = {0.0f, 0.0f, 0.0f}, accu_rcom[3] = {0.0f, 0.0f, 0.0f};
- float accu_weight = 0.0f, accu_rweight = 0.0f, eps = 0.000001f;
+ float accu_weight = 0.0f, accu_rweight = 0.0f;
+ const float eps = 1e-6f;
int a;
/* first set up a nice default response */
@@ -3369,7 +3469,7 @@ void vcloud_estimate_transform(int list_size, float (*pos)[3], float *weight, fl
/* this is pretty much Polardecompose 'inline' the algo based on Higham's thesis */
/* without the far case ... but seems to work here pretty neat */
- odet = 0.f;
+ odet = 0.0f;
ndet = determinant_m3_array(q);
while ((odet - ndet) * (odet - ndet) > eps && i < imax) {
invert_m3_m3(qi, q);
@@ -3410,9 +3510,8 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
float q0[3], float q1[3], float q2[3], float q3[3])
{
static const float epsilon = 1e-6f;
- float c, sd[3];
-
- c = dot_v3v3(n, p);
+ float sd[3];
+ const float c = dot_v3v3(n, p);
/* signed distances from the vertices to the plane. */
sd[0] = dot_v3v3(n, v0) - c;
@@ -3423,16 +3522,16 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
if (fabsf(sd[1]) < epsilon) sd[1] = 0.0f;
if (fabsf(sd[2]) < epsilon) sd[2] = 0.0f;
- if (sd[0] > 0) {
- if (sd[1] > 0) {
- if (sd[2] > 0) {
+ if (sd[0] > 0.0f) {
+ if (sd[1] > 0.0f) {
+ if (sd[2] > 0.0f) {
/* +++ */
copy_v3_v3(q0, v0);
copy_v3_v3(q1, v1);
copy_v3_v3(q2, v2);
copy_v3_v3(q3, q2);
}
- else if (sd[2] < 0) {
+ else if (sd[2] < 0.0f) {
/* ++- */
copy_v3_v3(q0, v0);
copy_v3_v3(q1, v1);
@@ -3447,15 +3546,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
copy_v3_v3(q3, q2);
}
}
- else if (sd[1] < 0) {
- if (sd[2] > 0) {
+ else if (sd[1] < 0.0f) {
+ if (sd[2] > 0.0f) {
/* +-+ */
copy_v3_v3(q0, v0);
vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1])));
vec_add_dir(q2, v1, v2, (sd[1] / (sd[1] - sd[2])));
copy_v3_v3(q3, v2);
}
- else if (sd[2] < 0) {
+ else if (sd[2] < 0.0f) {
/* +-- */
copy_v3_v3(q0, v0);
vec_add_dir(q1, v0, v1, (sd[0] / (sd[0] - sd[1])));
@@ -3471,14 +3570,14 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
}
}
else {
- if (sd[2] > 0) {
+ if (sd[2] > 0.0f) {
/* +0+ */
copy_v3_v3(q0, v0);
copy_v3_v3(q1, v1);
copy_v3_v3(q2, v2);
copy_v3_v3(q3, q2);
}
- else if (sd[2] < 0) {
+ else if (sd[2] < 0.0f) {
/* +0- */
copy_v3_v3(q0, v0);
copy_v3_v3(q1, v1);
@@ -3494,16 +3593,16 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
}
}
}
- else if (sd[0] < 0) {
- if (sd[1] > 0) {
- if (sd[2] > 0) {
+ else if (sd[0] < 0.0f) {
+ if (sd[1] > 0.0f) {
+ if (sd[2] > 0.0f) {
/* -++ */
vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1])));
copy_v3_v3(q1, v1);
copy_v3_v3(q2, v2);
vec_add_dir(q3, v0, v2, (sd[0] / (sd[0] - sd[2])));
}
- else if (sd[2] < 0) {
+ else if (sd[2] < 0.0f) {
/* -+- */
vec_add_dir(q0, v0, v1, (sd[0] / (sd[0] - sd[1])));
copy_v3_v3(q1, v1);
@@ -3518,15 +3617,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
copy_v3_v3(q3, q2);
}
}
- else if (sd[1] < 0) {
- if (sd[2] > 0) {
+ else if (sd[1] < 0.0f) {
+ if (sd[2] > 0.0f) {
/* --+ */
vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2])));
vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2])));
copy_v3_v3(q2, v2);
copy_v3_v3(q3, q2);
}
- else if (sd[2] < 0) {
+ else if (sd[2] < 0.0f) {
/* --- */
return false;
}
@@ -3536,14 +3635,14 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
}
}
else {
- if (sd[2] > 0) {
+ if (sd[2] > 0.0f) {
/* -0+ */
vec_add_dir(q0, v0, v2, (sd[0] / (sd[0] - sd[2])));
copy_v3_v3(q1, v1);
copy_v3_v3(q2, v2);
copy_v3_v3(q3, q2);
}
- else if (sd[2] < 0) {
+ else if (sd[2] < 0.0f) {
/* -0- */
return false;
}
@@ -3554,15 +3653,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
}
}
else {
- if (sd[1] > 0) {
- if (sd[2] > 0) {
+ if (sd[1] > 0.0f) {
+ if (sd[2] > 0.0f) {
/* 0++ */
copy_v3_v3(q0, v0);
copy_v3_v3(q1, v1);
copy_v3_v3(q2, v2);
copy_v3_v3(q3, q2);
}
- else if (sd[2] < 0) {
+ else if (sd[2] < 0.0f) {
/* 0+- */
copy_v3_v3(q0, v0);
copy_v3_v3(q1, v1);
@@ -3577,15 +3676,15 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
copy_v3_v3(q3, q2);
}
}
- else if (sd[1] < 0) {
- if (sd[2] > 0) {
+ else if (sd[1] < 0.0f) {
+ if (sd[2] > 0.0f) {
/* 0-+ */
copy_v3_v3(q0, v0);
vec_add_dir(q1, v1, v2, (sd[1] / (sd[1] - sd[2])));
copy_v3_v3(q2, v2);
copy_v3_v3(q3, q2);
}
- else if (sd[2] < 0) {
+ else if (sd[2] < 0.0f) {
/* 0-- */
return false;
}
@@ -3595,14 +3694,14 @@ bool form_factor_visible_quad(const float p[3], const float n[3],
}
}
else {
- if (sd[2] > 0) {
+ if (sd[2] > 0.0f) {
/* 00+ */
copy_v3_v3(q0, v0);
copy_v3_v3(q1, v1);
copy_v3_v3(q2, v2);
copy_v3_v3(q3, q2);
}
- else if (sd[2] < 0) {
+ else if (sd[2] < 0.0f) {
/* 00- */
return false;
}
@@ -3757,7 +3856,7 @@ static void ff_normalize(float n[3])
d = dot_v3v3(n, n);
- if (d > 1.0e-35F) {
+ if (d > 1.0e-35f) {
d = 1.0f / sqrtf(d);
n[0] *= d;
diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c
index 9af1c8677df..4feb954a31a 100644
--- a/source/blender/blenlib/intern/math_interp.c
+++ b/source/blender/blenlib/intern/math_interp.c
@@ -62,7 +62,11 @@ static float P(float k)
/* older, slower function, works the same as above */
static float P(float k)
{
- return (float)(1.0f / 6.0f) * (pow(MAX2(k + 2.0f, 0), 3.0f) - 4.0f * pow(MAX2(k + 1.0f, 0), 3.0f) + 6.0f * pow(MAX2(k, 0), 3.0f) - 4.0f * pow(MAX2(k - 1.0f, 0), 3.0f));
+ return (float)(1.0f / 6.0f) *
+ (pow(MAX2(k + 2.0f, 0), 3.0f) - 4.0f *
+ pow(MAX2(k + 1.0f, 0), 3.0f) + 6.0f *
+ pow(MAX2(k, 0), 3.0f) - 4.0f *
+ pow(MAX2(k - 1.0f, 0), 3.0f));
}
#endif
@@ -366,3 +370,192 @@ void BLI_bilinear_interpolation_char(const unsigned char *buffer, unsigned char
{
bilinear_interpolation(buffer, NULL, output, NULL, width, height, components, u, v);
}
+
+/**************************************************************************
+ * Filtering method based on
+ * "Creating raster omnimax images from multiple perspective views using the elliptical weighted average filter"
+ * by Ned Greene and Paul S. Heckbert (1986)
+ ***************************************************************************/
+
+/* table of (exp(ar) - exp(a)) / (1 - exp(a)) for r in range [0, 1] and a = -2
+ * used instead of actual gaussian, otherwise at high texture magnifications circular artifacts are visible */
+#define EWA_MAXIDX 255
+const float EWA_WTS[EWA_MAXIDX + 1] = {
+ 1.f, 0.990965f, 0.982f, 0.973105f, 0.96428f, 0.955524f, 0.946836f, 0.938216f, 0.929664f,
+ 0.921178f, 0.912759f, 0.904405f, 0.896117f, 0.887893f, 0.879734f, 0.871638f, 0.863605f,
+ 0.855636f, 0.847728f, 0.839883f, 0.832098f, 0.824375f, 0.816712f, 0.809108f, 0.801564f,
+ 0.794079f, 0.786653f, 0.779284f, 0.771974f, 0.76472f, 0.757523f, 0.750382f, 0.743297f,
+ 0.736267f, 0.729292f, 0.722372f, 0.715505f, 0.708693f, 0.701933f, 0.695227f, 0.688572f,
+ 0.68197f, 0.67542f, 0.66892f, 0.662471f, 0.656073f, 0.649725f, 0.643426f, 0.637176f,
+ 0.630976f, 0.624824f, 0.618719f, 0.612663f, 0.606654f, 0.600691f, 0.594776f, 0.588906f,
+ 0.583083f, 0.577305f, 0.571572f, 0.565883f, 0.56024f, 0.55464f, 0.549084f, 0.543572f,
+ 0.538102f, 0.532676f, 0.527291f, 0.521949f, 0.516649f, 0.511389f, 0.506171f, 0.500994f,
+ 0.495857f, 0.490761f, 0.485704f, 0.480687f, 0.475709f, 0.470769f, 0.465869f, 0.461006f,
+ 0.456182f, 0.451395f, 0.446646f, 0.441934f, 0.437258f, 0.432619f, 0.428017f, 0.42345f,
+ 0.418919f, 0.414424f, 0.409963f, 0.405538f, 0.401147f, 0.39679f, 0.392467f, 0.388178f,
+ 0.383923f, 0.379701f, 0.375511f, 0.371355f, 0.367231f, 0.363139f, 0.359079f, 0.355051f,
+ 0.351055f, 0.347089f, 0.343155f, 0.339251f, 0.335378f, 0.331535f, 0.327722f, 0.323939f,
+ 0.320186f, 0.316461f, 0.312766f, 0.3091f, 0.305462f, 0.301853f, 0.298272f, 0.294719f,
+ 0.291194f, 0.287696f, 0.284226f, 0.280782f, 0.277366f, 0.273976f, 0.270613f, 0.267276f,
+ 0.263965f, 0.26068f, 0.257421f, 0.254187f, 0.250979f, 0.247795f, 0.244636f, 0.241502f,
+ 0.238393f, 0.235308f, 0.232246f, 0.229209f, 0.226196f, 0.223206f, 0.220239f, 0.217296f,
+ 0.214375f, 0.211478f, 0.208603f, 0.20575f, 0.20292f, 0.200112f, 0.197326f, 0.194562f,
+ 0.191819f, 0.189097f, 0.186397f, 0.183718f, 0.18106f, 0.178423f, 0.175806f, 0.17321f,
+ 0.170634f, 0.168078f, 0.165542f, 0.163026f, 0.16053f, 0.158053f, 0.155595f, 0.153157f,
+ 0.150738f, 0.148337f, 0.145955f, 0.143592f, 0.141248f, 0.138921f, 0.136613f, 0.134323f,
+ 0.132051f, 0.129797f, 0.12756f, 0.125341f, 0.123139f, 0.120954f, 0.118786f, 0.116635f,
+ 0.114501f, 0.112384f, 0.110283f, 0.108199f, 0.106131f, 0.104079f, 0.102043f, 0.100023f,
+ 0.0980186f, 0.09603f, 0.094057f, 0.0920994f, 0.0901571f, 0.08823f, 0.0863179f, 0.0844208f,
+ 0.0825384f, 0.0806708f, 0.0788178f, 0.0769792f, 0.0751551f, 0.0733451f, 0.0715493f, 0.0697676f,
+ 0.0679997f, 0.0662457f, 0.0645054f, 0.0627786f, 0.0610654f, 0.0593655f, 0.0576789f, 0.0560055f,
+ 0.0543452f, 0.0526979f, 0.0510634f, 0.0494416f, 0.0478326f, 0.0462361f, 0.0446521f, 0.0430805f,
+ 0.0415211f, 0.039974f, 0.0384389f, 0.0369158f, 0.0354046f, 0.0339052f, 0.0324175f, 0.0309415f,
+ 0.029477f, 0.0280239f, 0.0265822f, 0.0251517f, 0.0237324f, 0.0223242f, 0.020927f, 0.0195408f,
+ 0.0181653f, 0.0168006f, 0.0154466f, 0.0141031f, 0.0127701f, 0.0114476f, 0.0101354f, 0.00883339f,
+ 0.00754159f, 0.00625989f, 0.00498819f, 0.00372644f, 0.00247454f, 0.00123242f, 0.f
+};
+
+static void radangle2imp(float a2, float b2, float th, float *A, float *B, float *C, float *F)
+{
+ float ct2 = cosf(th);
+ const float st2 = 1.0f - ct2 * ct2; /* <- sin(th)^2 */
+ ct2 *= ct2;
+ *A = a2 * st2 + b2 * ct2;
+ *B = (b2 - a2) * sinf(2.0f * th);
+ *C = a2 * ct2 + b2 * st2;
+ *F = a2 * b2;
+}
+
+/* all tests here are done to make sure possible overflows are hopefully minimized */
+void BLI_ewa_imp2radangle(float A, float B, float C, float F, float *a, float *b, float *th, float *ecc)
+{
+ if (F <= 1e-5f) { /* use arbitrary major radius, zero minor, infinite eccentricity */
+ *a = sqrtf(A > C ? A : C);
+ *b = 0.0f;
+ *ecc = 1e10f;
+ *th = 0.5f * (atan2f(B, A - C) + (float)M_PI);
+ }
+ else {
+ const float AmC = A - C, ApC = A + C, F2 = F * 2.0f;
+ const float r = sqrtf(AmC * AmC + B * B);
+ float d = ApC - r;
+ *a = (d <= 0.0f) ? sqrtf(A > C ? A : C) : sqrtf(F2 / d);
+ d = ApC + r;
+ if (d <= 0.0f) {
+ *b = 0.0f;
+ *ecc = 1e10f;
+ }
+ else {
+ *b = sqrtf(F2 / d);
+ *ecc = *a / *b;
+ }
+ /* incr theta by 0.5*pi (angle of major axis) */
+ *th = 0.5f * (atan2f(B, AmC) + (float)M_PI);
+ }
+}
+
+void BLI_ewa_filter(const int width, const int height,
+ const bool intpol,
+ const bool use_alpha,
+ const float uv[2],
+ const float du[2],
+ const float dv[2],
+ ewa_filter_read_pixel_cb read_pixel_cb,
+ void *userdata,
+ float result[4])
+{
+ /* scaling dxt/dyt by full resolution can cause overflow because of huge A/B/C and esp. F values,
+ * scaling by aspect ratio alone does the opposite, so try something in between instead... */
+ const float ff2 = (float)width, ff = sqrtf(ff2), q = (float)height / ff;
+ const float Ux = du[0] * ff, Vx = dv[0] * q, Uy = du[1] * ff, Vy = dv[1] * q;
+ float A = Vx * Vx + Vy * Vy;
+ float B = -2.0f * (Ux * Vx + Uy * Vy);
+ float C = Ux * Ux + Uy * Uy;
+ float F = A * C - B * B * 0.25f;
+ float a, b, th, ecc, a2, b2, ue, ve, U0, V0, DDQ, U, ac1, ac2, BU, d;
+ int u, v, u1, u2, v1, v2;
+
+ /* The so-called 'high' quality ewa method simply adds a constant of 1 to both A & C,
+ * so the ellipse always covers at least some texels. But since the filter is now always larger,
+ * it also means that everywhere else it's also more blurry then ideally should be the case.
+ * So instead here the ellipse radii are modified instead whenever either is too low.
+ * Use a different radius based on interpolation switch, just enough to anti-alias when interpolation is off,
+ * and slightly larger to make result a bit smoother than bilinear interpolation when interpolation is on
+ * (minimum values: const float rmin = intpol ? 1.f : 0.5f;) */
+ const float rmin = (intpol ? 1.5625f : 0.765625f) / ff2;
+ BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
+ if ((b2 = b * b) < rmin) {
+ if ((a2 = a * a) < rmin) {
+ B = 0.0f;
+ A = C = rmin;
+ F = A * C;
+ }
+ else {
+ b2 = rmin;
+ radangle2imp(a2, b2, th, &A, &B, &C, &F);
+ }
+ }
+
+ ue = ff * sqrtf(C);
+ ve = ff * sqrtf(A);
+ d = (float)(EWA_MAXIDX + 1) / (F * ff2);
+ A *= d;
+ B *= d;
+ C *= d;
+
+ U0 = uv[0] * (float)width;
+ V0 = uv[1] * (float)height;
+ u1 = (int)(floorf(U0 - ue));
+ u2 = (int)(ceilf(U0 + ue));
+ v1 = (int)(floorf(V0 - ve));
+ v2 = (int)(ceilf(V0 + ve));
+
+ /* sane clamping to avoid unnecessarily huge loops */
+ /* note: if eccentricity gets clamped (see above),
+ * the ue/ve limits can also be lowered accordingly
+ */
+ if (U0 - (float)u1 > EWA_MAXIDX) u1 = (int)U0 - EWA_MAXIDX;
+ if ((float)u2 - U0 > EWA_MAXIDX) u2 = (int)U0 + EWA_MAXIDX;
+ if (V0 - (float)v1 > EWA_MAXIDX) v1 = (int)V0 - EWA_MAXIDX;
+ if ((float)v2 - V0 > EWA_MAXIDX) v2 = (int)V0 + EWA_MAXIDX;
+
+ /* Early output check for cases the whole region is outside of the buffer. */
+ if ((u2 < 0 || u1 >= width) || (v2 < 0 || v1 >= height)) {
+ zero_v4(result);
+ return;
+ }
+
+ U0 -= 0.5f;
+ V0 -= 0.5f;
+ DDQ = 2.0f * A;
+ U = (float)u1 - U0;
+ ac1 = A * (2.0f * U + 1.0f);
+ ac2 = A * U * U;
+ BU = B * U;
+
+ d = 0.0f;
+ zero_v4(result);
+ for (v = v1; v <= v2; ++v) {
+ const float V = (float)v - V0;
+ float DQ = ac1 + B * V;
+ float Q = (C * V + BU) * V + ac2;
+ for (u = u1; u <= u2; ++u) {
+ if (Q < (float)(EWA_MAXIDX + 1)) {
+ float tc[4];
+ const float wt = EWA_WTS[(Q < 0.0f) ? 0 : (unsigned int)Q];
+ read_pixel_cb(userdata, u, v, tc);
+ madd_v3_v3fl(result, tc, wt);
+ result[3] += use_alpha ? tc[3] * wt : 0.0f;
+ d += wt;
+ }
+ Q += DQ;
+ DQ += DDQ;
+ }
+ }
+
+ /* d should hopefully never be zero anymore */
+ d = 1.0f / d;
+ mul_v3_fl(result, d);
+ /* clipping can be ignored if alpha used, texr->ta already includes filtered edge */
+ result[3] = use_alpha ? result[3] * d : 1.0f;
+}
diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c
index 4cbe1a76f58..af42af88582 100644
--- a/source/blender/blenlib/intern/math_matrix.c
+++ b/source/blender/blenlib/intern/math_matrix.c
@@ -35,42 +35,59 @@
/********************************* Init **************************************/
+void zero_m2(float m[2][2])
+{
+ memset(m, 0, sizeof(float[2][2]));
+}
+
void zero_m3(float m[3][3])
{
- memset(m, 0, 3 * 3 * sizeof(float));
+ memset(m, 0, sizeof(float[3][3]));
}
void zero_m4(float m[4][4])
{
- memset(m, 0, 4 * 4 * sizeof(float));
+ memset(m, 0, sizeof(float[4][4]));
+}
+
+void unit_m2(float m[2][2])
+{
+ m[0][0] = m[1][1] = 1.0f;
+ m[0][1] = 0.0f;
+ m[1][0] = 0.0f;
}
void unit_m3(float m[3][3])
{
- m[0][0] = m[1][1] = m[2][2] = 1.0;
- m[0][1] = m[0][2] = 0.0;
- m[1][0] = m[1][2] = 0.0;
- m[2][0] = m[2][1] = 0.0;
+ m[0][0] = m[1][1] = m[2][2] = 1.0f;
+ m[0][1] = m[0][2] = 0.0f;
+ m[1][0] = m[1][2] = 0.0f;
+ m[2][0] = m[2][1] = 0.0f;
}
void unit_m4(float m[4][4])
{
- m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0;
- m[0][1] = m[0][2] = m[0][3] = 0.0;
- m[1][0] = m[1][2] = m[1][3] = 0.0;
- m[2][0] = m[2][1] = m[2][3] = 0.0;
- m[3][0] = m[3][1] = m[3][2] = 0.0;
+ m[0][0] = m[1][1] = m[2][2] = m[3][3] = 1.0f;
+ m[0][1] = m[0][2] = m[0][3] = 0.0f;
+ m[1][0] = m[1][2] = m[1][3] = 0.0f;
+ m[2][0] = m[2][1] = m[2][3] = 0.0f;
+ m[3][0] = m[3][1] = m[3][2] = 0.0f;
+}
+
+void copy_m2_m2(float m1[2][2], float m2[2][2])
+{
+ memcpy(m1, m2, sizeof(float[2][2]));
}
void copy_m3_m3(float m1[3][3], float m2[3][3])
{
/* destination comes first: */
- memcpy(&m1[0], &m2[0], 9 * sizeof(float));
+ memcpy(m1, m2, sizeof(float[3][3]));
}
void copy_m4_m4(float m1[4][4], float m2[4][4])
{
- memcpy(m1, m2, 4 * 4 * sizeof(float));
+ memcpy(m1, m2, sizeof(float[4][4]));
}
void copy_m3_m4(float m1[3][3], float m2[4][4])
@@ -103,14 +120,14 @@ void copy_m4_m3(float m1[4][4], float m2[3][3]) /* no clear */
m1[2][2] = m2[2][2];
/* Reevan's Bugfix */
- m1[0][3] = 0.0F;
- m1[1][3] = 0.0F;
- m1[2][3] = 0.0F;
+ m1[0][3] = 0.0f;
+ m1[1][3] = 0.0f;
+ m1[2][3] = 0.0f;
- m1[3][0] = 0.0F;
- m1[3][1] = 0.0F;
- m1[3][2] = 0.0F;
- m1[3][3] = 1.0F;
+ m1[3][0] = 0.0f;
+ m1[3][1] = 0.0f;
+ m1[3][2] = 0.0f;
+ m1[3][3] = 1.0f;
}
@@ -274,71 +291,148 @@ void mul_m4_m3m4(float m1[4][4], float m3_[3][3], float m2_[4][4])
m1[2][2] = m2[2][0] * m3[0][2] + m2[2][1] * m3[1][2] + m2[2][2] * m3[2][2];
}
-void mul_serie_m3(float answ[3][3],
- float m1[3][3], float m2[3][3], float m3[3][3],
- float m4[3][3], float m5[3][3], float m6[3][3],
- float m7[3][3], float m8[3][3])
-{
- float temp[3][3];
-
- if (m1 == NULL || m2 == NULL) return;
-
- mul_m3_m3m3(answ, m2, m1);
- if (m3) {
- mul_m3_m3m3(temp, m3, answ);
- if (m4) {
- mul_m3_m3m3(answ, m4, temp);
- if (m5) {
- mul_m3_m3m3(temp, m5, answ);
- if (m6) {
- mul_m3_m3m3(answ, m6, temp);
- if (m7) {
- mul_m3_m3m3(temp, m7, answ);
- if (m8) {
- mul_m3_m3m3(answ, m8, temp);
- }
- else copy_m3_m3(answ, temp);
- }
- }
- else copy_m3_m3(answ, temp);
- }
- }
- else copy_m3_m3(answ, temp);
- }
-}
-void mul_serie_m4(float answ[4][4], float m1[4][4],
- float m2[4][4], float m3[4][4], float m4[4][4],
- float m5[4][4], float m6[4][4], float m7[4][4],
- float m8[4][4])
-{
- float temp[4][4];
-
- if (m1 == NULL || m2 == NULL) return;
-
- mul_m4_m4m4(answ, m1, m2);
- if (m3) {
- mul_m4_m4m4(temp, answ, m3);
- if (m4) {
- mul_m4_m4m4(answ, temp, m4);
- if (m5) {
- mul_m4_m4m4(temp, answ, m5);
- if (m6) {
- mul_m4_m4m4(answ, temp, m6);
- if (m7) {
- mul_m4_m4m4(temp, answ, m7);
- if (m8) {
- mul_m4_m4m4(answ, temp, m8);
- }
- else copy_m4_m4(answ, temp);
- }
- }
- else copy_m4_m4(answ, temp);
- }
- }
- else copy_m4_m4(answ, temp);
- }
-}
+/** \name Macro helpers for: mul_m3_series
+ * \{ */
+void _va_mul_m3_series_3(
+ float r[3][3],
+ float m1[3][3], float m2[3][3])
+{
+ mul_m3_m3m3(r, m1, m2);
+}
+void _va_mul_m3_series_4(
+ float r[3][3],
+ float m1[3][3], float m2[3][3], float m3[3][3])
+{
+ mul_m3_m3m3(r, m1, m2);
+ mul_m3_m3m3(r, r, m3);
+}
+void _va_mul_m3_series_5(
+ float r[3][3],
+ float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3])
+{
+ mul_m3_m3m3(r, m1, m2);
+ mul_m3_m3m3(r, r, m3);
+ mul_m3_m3m3(r, r, m4);
+}
+void _va_mul_m3_series_6(
+ float r[3][3],
+ float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3],
+ float m5[3][3])
+{
+ mul_m3_m3m3(r, m1, m2);
+ mul_m3_m3m3(r, r, m3);
+ mul_m3_m3m3(r, r, m4);
+ mul_m3_m3m3(r, r, m5);
+}
+void _va_mul_m3_series_7(
+ float r[3][3],
+ float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3],
+ float m5[3][3], float m6[3][3])
+{
+ mul_m3_m3m3(r, m1, m2);
+ mul_m3_m3m3(r, r, m3);
+ mul_m3_m3m3(r, r, m4);
+ mul_m3_m3m3(r, r, m5);
+ mul_m3_m3m3(r, r, m6);
+}
+void _va_mul_m3_series_8(
+ float r[3][3],
+ float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3],
+ float m5[3][3], float m6[3][3], float m7[3][3])
+{
+ mul_m3_m3m3(r, m1, m2);
+ mul_m3_m3m3(r, r, m3);
+ mul_m3_m3m3(r, r, m4);
+ mul_m3_m3m3(r, r, m5);
+ mul_m3_m3m3(r, r, m6);
+ mul_m3_m3m3(r, r, m7);
+}
+void _va_mul_m3_series_9(
+ float r[3][3],
+ float m1[3][3], float m2[3][3], float m3[3][3], float m4[3][3],
+ float m5[3][3], float m6[3][3], float m7[3][3], float m8[3][3])
+{
+ mul_m3_m3m3(r, m1, m2);
+ mul_m3_m3m3(r, r, m3);
+ mul_m3_m3m3(r, r, m4);
+ mul_m3_m3m3(r, r, m5);
+ mul_m3_m3m3(r, r, m6);
+ mul_m3_m3m3(r, r, m7);
+ mul_m3_m3m3(r, r, m8);
+}
+/** \} */
+
+/** \name Macro helpers for: mul_m4_series
+ * \{ */
+void _va_mul_m4_series_3(
+ float r[4][4],
+ float m1[4][4], float m2[4][4])
+{
+ mul_m4_m4m4(r, m1, m2);
+}
+void _va_mul_m4_series_4(
+ float r[4][4],
+ float m1[4][4], float m2[4][4], float m3[4][4])
+{
+ mul_m4_m4m4(r, m1, m2);
+ mul_m4_m4m4(r, r, m3);
+}
+void _va_mul_m4_series_5(
+ float r[4][4],
+ float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4])
+{
+ mul_m4_m4m4(r, m1, m2);
+ mul_m4_m4m4(r, r, m3);
+ mul_m4_m4m4(r, r, m4);
+}
+void _va_mul_m4_series_6(
+ float r[4][4],
+ float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4],
+ float m5[4][4])
+{
+ mul_m4_m4m4(r, m1, m2);
+ mul_m4_m4m4(r, r, m3);
+ mul_m4_m4m4(r, r, m4);
+ mul_m4_m4m4(r, r, m5);
+}
+void _va_mul_m4_series_7(
+ float r[4][4],
+ float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4],
+ float m5[4][4], float m6[4][4])
+{
+ mul_m4_m4m4(r, m1, m2);
+ mul_m4_m4m4(r, r, m3);
+ mul_m4_m4m4(r, r, m4);
+ mul_m4_m4m4(r, r, m5);
+ mul_m4_m4m4(r, r, m6);
+}
+void _va_mul_m4_series_8(
+ float r[4][4],
+ float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4],
+ float m5[4][4], float m6[4][4], float m7[4][4])
+{
+ mul_m4_m4m4(r, m1, m2);
+ mul_m4_m4m4(r, r, m3);
+ mul_m4_m4m4(r, r, m4);
+ mul_m4_m4m4(r, r, m5);
+ mul_m4_m4m4(r, r, m6);
+ mul_m4_m4m4(r, r, m7);
+}
+void _va_mul_m4_series_9(
+ float r[4][4],
+ float m1[4][4], float m2[4][4], float m3[4][4], float m4[4][4],
+ float m5[4][4], float m6[4][4], float m7[4][4], float m8[4][4])
+{
+ mul_m4_m4m4(r, m1, m2);
+ mul_m4_m4m4(r, r, m3);
+ mul_m4_m4m4(r, r, m4);
+ mul_m4_m4m4(r, r, m5);
+ mul_m4_m4m4(r, r, m6);
+ mul_m4_m4m4(r, r, m7);
+ mul_m4_m4m4(r, r, m8);
+}
+/** \} */
void mul_v2_m3v2(float r[2], float m[3][3], float v[2])
{
@@ -360,10 +454,9 @@ void mul_m3_v2(float m[3][3], float r[2])
void mul_m4_v3(float mat[4][4], float vec[3])
{
- float x, y;
+ const float x = vec[0];
+ const float y = vec[1];
- x = vec[0];
- y = vec[1];
vec[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2] + mat[3][0];
vec[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2] + mat[3][1];
vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2];
@@ -371,10 +464,9 @@ void mul_m4_v3(float mat[4][4], float vec[3])
void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3])
{
- float x, y;
+ const float x = vec[0];
+ const float y = vec[1];
- x = vec[0];
- y = vec[1];
r[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2] + mat[3][0];
r[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2] + mat[3][1];
r[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2] + mat[3][2];
@@ -382,18 +474,16 @@ void mul_v3_m4v3(float r[3], float mat[4][4], const float vec[3])
void mul_v2_m4v3(float r[2], float mat[4][4], const float vec[3])
{
- float x;
+ const float x = vec[0];
- x = vec[0];
r[0] = x * mat[0][0] + vec[1] * mat[1][0] + mat[2][0] * vec[2] + mat[3][0];
r[1] = x * mat[0][1] + vec[1] * mat[1][1] + mat[2][1] * vec[2] + mat[3][1];
}
void mul_v2_m2v2(float r[2], float mat[2][2], const float vec[2])
{
- float x;
+ const float x = vec[0];
- x = vec[0];
r[0] = mat[0][0] * x + mat[1][0] * vec[1];
r[1] = mat[0][1] * x + mat[1][1] * vec[1];
}
@@ -406,10 +496,9 @@ void mul_m2v2(float mat[2][2], float vec[2])
/* same as mul_m4_v3() but doesnt apply translation component */
void mul_mat3_m4_v3(float mat[4][4], float vec[3])
{
- float x, y;
+ const float x = vec[0];
+ const float y = vec[1];
- x = vec[0];
- y = vec[1];
vec[0] = x * mat[0][0] + y * mat[1][0] + mat[2][0] * vec[2];
vec[1] = x * mat[0][1] + y * mat[1][1] + mat[2][1] * vec[2];
vec[2] = x * mat[0][2] + y * mat[1][2] + mat[2][2] * vec[2];
@@ -425,6 +514,16 @@ void mul_project_m4_v3(float mat[4][4], float vec[3])
vec[2] /= w;
}
+void mul_v3_project_m4_v3(float r[3], float mat[4][4], const float vec[3])
+{
+ const float w = mul_project_m4_v3_zfac(mat, vec);
+ mul_v3_m4v3(r, mat, vec);
+
+ r[0] /= w;
+ r[1] /= w;
+ r[2] /= w;
+}
+
void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3])
{
const float w = mul_project_m4_v3_zfac(mat, vec);
@@ -436,11 +535,9 @@ void mul_v2_project_m4_v3(float r[2], float mat[4][4], const float vec[3])
void mul_v4_m4v4(float r[4], float mat[4][4], const float v[4])
{
- float x, y, z;
-
- x = v[0];
- y = v[1];
- z = v[2];
+ const float x = v[0];
+ const float y = v[1];
+ const float z = v[2];
r[0] = x * mat[0][0] + y * mat[1][0] + z * mat[2][0] + mat[3][0] * v[3];
r[1] = x * mat[0][1] + y * mat[1][1] + z * mat[2][1] + mat[3][1] * v[3];
@@ -455,11 +552,9 @@ void mul_m4_v4(float mat[4][4], float r[4])
void mul_v4d_m4v4d(double r[4], float mat[4][4], double v[4])
{
- double x, y, z;
-
- x = v[0];
- y = v[1];
- z = v[2];
+ const double x = v[0];
+ const double y = v[1];
+ const double z = v[2];
r[0] = x * (double)mat[0][0] + y * (double)mat[1][0] + z * (double)mat[2][0] + (double)mat[3][0] * v[3];
r[1] = x * (double)mat[0][1] + y * (double)mat[1][1] + z * (double)mat[2][1] + (double)mat[3][1] * v[3];
@@ -499,10 +594,9 @@ void mul_m3_v3(float M[3][3], float r[3])
void mul_transposed_m3_v3(float mat[3][3], float vec[3])
{
- float x, y;
+ const float x = vec[0];
+ const float y = vec[1];
- x = vec[0];
- y = vec[1];
vec[0] = x * mat[0][0] + y * mat[0][1] + mat[0][2] * vec[2];
vec[1] = x * mat[1][0] + y * mat[1][1] + mat[1][2] * vec[2];
vec[2] = x * mat[2][0] + y * mat[2][1] + mat[2][2] * vec[2];
@@ -510,16 +604,14 @@ void mul_transposed_m3_v3(float mat[3][3], float vec[3])
void mul_transposed_mat3_m4_v3(float mat[4][4], float vec[3])
{
- float x, y;
+ const float x = vec[0];
+ const float y = vec[1];
- x = vec[0];
- y = vec[1];
vec[0] = x * mat[0][0] + y * mat[0][1] + mat[0][2] * vec[2];
vec[1] = x * mat[1][0] + y * mat[1][1] + mat[1][2] * vec[2];
vec[2] = x * mat[2][0] + y * mat[2][1] + mat[2][2] * vec[2];
}
-
void mul_m3_fl(float m[3][3], float f)
{
int i, j;
@@ -547,12 +639,29 @@ void mul_mat3_m4_fl(float m[4][4], float f)
m[i][j] *= f;
}
+void negate_m3(float m[4][4])
+{
+ int i, j;
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ m[i][j] *= -1.0f;
+}
+
+void negate_m4(float m[4][4])
+{
+ int i, j;
+
+ for (i = 0; i < 4; i++)
+ for (j = 0; j < 4; j++)
+ m[i][j] *= -1.0f;
+}
+
void mul_m3_v3_double(float mat[3][3], double vec[3])
{
- double x, y;
+ const double x = vec[0];
+ const double y = vec[1];
- x = vec[0];
- y = vec[1];
vec[0] = x * (double)mat[0][0] + y * (double)mat[1][0] + (double)mat[2][0] * vec[2];
vec[1] = x * (double)mat[0][1] + y * (double)mat[1][1] + (double)mat[2][1] * vec[2];
vec[2] = x * (double)mat[0][2] + y * (double)mat[1][2] + (double)mat[2][2] * vec[2];
@@ -604,11 +713,9 @@ float determinant_m3_array(float m[3][3])
bool invert_m3_ex(float m[3][3], const float epsilon)
{
float tmp[3][3];
- bool success;
+ const bool success = invert_m3_m3_ex(tmp, m, epsilon);
- success = invert_m3_m3_ex(tmp, m, epsilon);
copy_m3_m3(m, tmp);
-
return success;
}
@@ -642,11 +749,9 @@ bool invert_m3_m3_ex(float m1[3][3], float m2[3][3], const float epsilon)
bool invert_m3(float m[3][3])
{
float tmp[3][3];
- bool success;
+ const bool success = invert_m3_m3(tmp, m);
- success = invert_m3_m3(tmp, m);
copy_m3_m3(m, tmp);
-
return success;
}
@@ -679,11 +784,9 @@ bool invert_m3_m3(float m1[3][3], float m2[3][3])
bool invert_m4(float m[4][4])
{
float tmp[4][4];
- bool success;
+ const bool success = invert_m4_m4(tmp, m);
- success = invert_m4_m4(tmp, m);
copy_m4_m4(m, tmp);
-
return success;
}
@@ -1059,10 +1162,17 @@ bool is_uniform_scaled_m3(float m[3][3])
fabsf(l5 - l1) <= eps &&
fabsf(l6 - l1) <= eps)
{
- return 1;
+ return true;
}
- return 0;
+ return false;
+}
+
+bool is_uniform_scaled_m4(float m[4][4])
+{
+ float t[3][3];
+ copy_m3_m4(t, m);
+ return is_uniform_scaled_m3(t);
}
void normalize_m3(float mat[3][3])
@@ -1277,7 +1387,7 @@ float mat3_to_scale(float mat[3][3])
{
/* unit length vector */
float unit_vec[3];
- copy_v3_fl(unit_vec, 0.577350269189626f);
+ copy_v3_fl(unit_vec, (float)(1.0 / M_SQRT3));
mul_m3_v3(mat, unit_vec);
return len_v3(unit_vec);
}
@@ -1286,7 +1396,7 @@ float mat4_to_scale(float mat[4][4])
{
/* unit length vector */
float unit_vec[3];
- copy_v3_fl(unit_vec, 0.577350269189626f);
+ copy_v3_fl(unit_vec, (float)(1.0 / M_SQRT3));
mul_mat3_m4_v3(mat, unit_vec);
return len_v3(unit_vec);
}
@@ -2091,7 +2201,7 @@ void pseudoinverse_m4_m4(float Ainv[4][4], float A[4][4], float epsilon)
transpose_m4(V);
- mul_serie_m4(Ainv, U, Wm, V, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(Ainv, U, Wm, V);
}
void pseudoinverse_m3_m3(float Ainv[3][3], float A[3][3], float epsilon)
@@ -2132,3 +2242,51 @@ void invert_m4_m4_safe(float Ainv[4][4], float A[4][4])
}
}
}
+
+/**
+ * SpaceTransform struct encapsulates all needed data to convert between two coordinate spaces
+ * (where conversion can be represented by a matrix multiplication).
+ *
+ * A SpaceTransform is initialized using:
+ * BLI_SPACE_TRANSFORM_SETUP(&data, ob1, ob2)
+ *
+ * After that the following calls can be used:
+ * BLI_space_transform_apply(&data, co); // converts a coordinate in ob1 space to the corresponding ob2 space
+ * BLI_space_transform_invert(&data, co); // converts a coordinate in ob2 space to the corresponding ob1 space
+ *
+ * Same concept as BLI_space_transform_apply and BLI_space_transform_invert, but no is normalized after conversion
+ * (and not translated at all!):
+ * BLI_space_transform_apply_normal(&data, no);
+ * BLI_space_transform_invert_normal(&data, no);
+ *
+ */
+
+void BLI_space_transform_from_matrices(SpaceTransform *data, float local[4][4], float target[4][4])
+{
+ float itarget[4][4];
+ invert_m4_m4(itarget, target);
+ mul_m4_m4m4(data->local2target, itarget, local);
+ invert_m4_m4(data->target2local, data->local2target);
+}
+
+void BLI_space_transform_apply(const SpaceTransform *data, float co[3])
+{
+ mul_v3_m4v3(co, ((SpaceTransform *)data)->local2target, co);
+}
+
+void BLI_space_transform_invert(const SpaceTransform *data, float co[3])
+{
+ mul_v3_m4v3(co, ((SpaceTransform *)data)->target2local, co);
+}
+
+void BLI_space_transform_apply_normal(const SpaceTransform *data, float no[3])
+{
+ mul_mat3_m4_v3(((SpaceTransform *)data)->local2target, no);
+ normalize_v3(no);
+}
+
+void BLI_space_transform_invert_normal(const SpaceTransform *data, float no[3])
+{
+ mul_mat3_m4_v3(((SpaceTransform *)data)->target2local, no);
+ normalize_v3(no);
+}
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index de272b12ebd..9a6515daf68 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -139,7 +139,7 @@ float dot_qtqt(const float q1[4], const float q2[4])
void invert_qt(float q[4])
{
- float f = dot_qtqt(q, q);
+ const float f = dot_qtqt(q, q);
if (f == 0.0f)
return;
@@ -366,7 +366,7 @@ void mat3_to_quat_is_ok(float q[4], float wmat[3][3])
mul_m3_v3(matn, mat[0]);
/* and align x-axes */
- angle = (float)(0.5 * atan2(mat[0][1], mat[0][0]));
+ angle = 0.5f * atan2f(mat[0][1], mat[0][0]);
co = cosf(angle);
si = sinf(angle);
@@ -380,9 +380,8 @@ void mat3_to_quat_is_ok(float q[4], float wmat[3][3])
float normalize_qt(float q[4])
{
- float len;
+ const float len = sqrtf(dot_qtqt(q, q));
- len = sqrtf(dot_qtqt(q, q));
if (len != 0.0f) {
mul_qt_fl(q, 1.0f / len);
}
@@ -520,7 +519,7 @@ float angle_qtqt(const float q1[4], const float q2[4])
void vec_to_quat(float q[4], const float vec[3], short axis, const short upflag)
{
- const float eps = 0.0001f;
+ const float eps = 1e-4f;
float nor[3], tvec[3];
float angle, si, co, len;
@@ -669,7 +668,7 @@ void QuatInterpolW(float *result, float quat1[4], float quat2[4], float t)
*/
void interp_dot_slerp(const float t, const float cosom, float r_w[2])
{
- const float eps = 0.0001f;
+ const float eps = 1e-4f;
BLI_assert(IN_RANGE_INCL(cosom, -1.0001f, 1.0001f));
@@ -766,7 +765,7 @@ void tri_to_quat_ex(float quat[4], const float v1[3], const float v2[3], const f
vec[2] = 0.0f;
normalize_v3(vec);
- angle = (float)(0.5 * atan2(vec[1], vec[0]));
+ angle = 0.5f * atan2f(vec[1], vec[0]);
co = cosf(angle);
si = sinf(angle);
q2[0] = co;
@@ -783,9 +782,8 @@ void tri_to_quat_ex(float quat[4], const float v1[3], const float v2[3], const f
float tri_to_quat(float quat[4], const float v1[3], const float v2[3], const float v3[3])
{
float vec[3];
- float len;
+ const float len = normal_tri_v3(vec, v1, v2, v3);
- len = normal_tri_v3(vec, v1, v2, v3);
tri_to_quat_ex(quat, v1, v2, v3, vec);
return len;
}
@@ -872,8 +870,8 @@ void eulO_to_axis_angle(float axis[3], float *angle, const float eul[3], const s
* This takes the angle with sin/cos applied so we can avoid calculating it in some cases.
*
* \param axis rotation axis (must be normalized).
- * \param co cos(angle)
- * \param si sin(angle)
+ * \param angle_sin sin(angle)
+ * \param angle_cos cos(angle)
*/
void axis_angle_normalized_to_mat3_ex(float mat[3][3], const float axis[3],
const float angle_sin, const float angle_cos)
@@ -1088,25 +1086,24 @@ static void mat3_to_eul2(float tmat[3][3], float eul1[3], float eul2[3])
mat3_to_quat(quat, tmat);
quat_to_mat3(mat, quat);
- copy_m3_m3(mat, tmat);
- normalize_m3(mat);
+ normalize_m3_m3(mat, tmat);
- cy = sqrtf(mat[0][0] * mat[0][0] + mat[0][1] * mat[0][1]);
+ cy = hypotf(mat[0][0], mat[0][1]);
if (cy > 16.0f * FLT_EPSILON) {
- eul1[0] = (float)atan2(mat[1][2], mat[2][2]);
- eul1[1] = (float)atan2(-mat[0][2], cy);
- eul1[2] = (float)atan2(mat[0][1], mat[0][0]);
+ eul1[0] = atan2f(mat[1][2], mat[2][2]);
+ eul1[1] = atan2f(-mat[0][2], cy);
+ eul1[2] = atan2f(mat[0][1], mat[0][0]);
- eul2[0] = (float)atan2(-mat[1][2], -mat[2][2]);
- eul2[1] = (float)atan2(-mat[0][2], -cy);
- eul2[2] = (float)atan2(-mat[0][1], -mat[0][0]);
+ eul2[0] = atan2f(-mat[1][2], -mat[2][2]);
+ eul2[1] = atan2f(-mat[0][2], -cy);
+ eul2[2] = atan2f(-mat[0][1], -mat[0][0]);
}
else {
- eul1[0] = (float)atan2(-mat[2][1], mat[1][1]);
- eul1[1] = (float)atan2(-mat[0][2], cy);
+ eul1[0] = atan2f(-mat[2][1], mat[1][1]);
+ eul1[1] = atan2f(-mat[0][2], cy);
eul1[2] = 0.0f;
copy_v3_v3(eul2, eul1);
@@ -1380,44 +1377,38 @@ 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 e1[3], float e2[3], const short order)
+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);
short i = R->axis[0], j = R->axis[1], k = R->axis[2];
- float m[3][3];
- double cy;
+ float mat[3][3];
+ float cy;
/* process the matrix first */
- copy_m3_m3(m, M);
- normalize_m3(m);
+ normalize_m3_m3(mat, M);
- cy = sqrt(m[i][i] * m[i][i] + m[i][j] * m[i][j]);
+ cy = hypotf(mat[i][i], mat[i][j]);
- if (cy > 16.0 * (double)FLT_EPSILON) {
- e1[i] = atan2f(m[j][k], m[k][k]);
- e1[j] = atan2f(-m[i][k], (float)cy);
- e1[k] = atan2f(m[i][j], m[i][i]);
+ if (cy > 16.0f * FLT_EPSILON) {
+ eul1[i] = atan2f(mat[j][k], mat[k][k]);
+ eul1[j] = atan2f(-mat[i][k], cy);
+ eul1[k] = atan2f(mat[i][j], mat[i][i]);
- e2[i] = atan2f(-m[j][k], -m[k][k]);
- e2[j] = atan2f(-m[i][k], (float)-cy);
- e2[k] = atan2f(-m[i][j], -m[i][i]);
+ eul2[i] = atan2f(-mat[j][k], -mat[k][k]);
+ eul2[j] = atan2f(-mat[i][k], -cy);
+ eul2[k] = atan2f(-mat[i][j], -mat[i][i]);
}
else {
- e1[i] = atan2f(-m[k][j], m[j][j]);
- e1[j] = atan2f(-m[i][k], (float)cy);
- e1[k] = 0;
+ eul1[i] = atan2f(-mat[k][j], mat[j][j]);
+ eul1[j] = atan2f(-mat[i][k], cy);
+ eul1[k] = 0;
- copy_v3_v3(e2, e1);
+ copy_v3_v3(eul2, eul1);
}
if (R->parity) {
- e1[0] = -e1[0];
- e1[1] = -e1[1];
- e1[2] = -e1[2];
-
- e2[0] = -e2[0];
- e2[1] = -e2[1];
- e2[2] = -e2[2];
+ negate_v3(eul1);
+ negate_v3(eul2);
}
}
@@ -1613,7 +1604,7 @@ void mat4_to_dquat(DualQuat *dq, float basemat[4][4], float mat[4][4])
mul_m4_m4m4(S, baseRinv, baseRS);
/* set scaling part */
- mul_serie_m4(dq->scale, basemat, S, baseinv, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(dq->scale, basemat, S, baseinv);
dq->scale_weight = 1.0f;
}
else {
@@ -1665,7 +1656,7 @@ void add_weighted_dq_dq(DualQuat *dqsum, const DualQuat *dq, float weight)
/* make sure we interpolate quats in the right direction */
if (dot_qtqt(dq->quat, dqsum->quat) < 0) {
- flipped = 1;
+ flipped = true;
weight = -weight;
}
@@ -1696,7 +1687,7 @@ void add_weighted_dq_dq(DualQuat *dqsum, const DualQuat *dq, float weight)
void normalize_dq(DualQuat *dq, float totweight)
{
- float scale = 1.0f / totweight;
+ const float scale = 1.0f / totweight;
mul_qt_fl(dq->quat, scale);
mul_qt_fl(dq->trans, scale);
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 7d3829f04d3..887ec7d4d2c 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -35,7 +35,7 @@
void interp_v2_v2v2(float target[2], const float a[2], const float b[2], const float t)
{
- float s = 1.0f - t;
+ const float s = 1.0f - t;
target[0] = s * a[0] + t * b[0];
target[1] = s * a[1] + t * b[1];
@@ -51,7 +51,7 @@ void interp_v2_v2v2v2(float p[2], const float v1[2], const float v2[2], const fl
void interp_v3_v3v3(float target[3], const float a[3], const float b[3], const float t)
{
- float s = 1.0f - t;
+ const float s = 1.0f - t;
target[0] = s * a[0] + t * b[0];
target[1] = s * a[1] + t * b[1];
@@ -60,7 +60,7 @@ void interp_v3_v3v3(float target[3], const float a[3], const float b[3], const f
void interp_v4_v4v4(float target[4], const float a[4], const float b[4], const float t)
{
- float s = 1.0f - t;
+ const float s = 1.0f - t;
target[0] = s * a[0] + t * b[0];
target[1] = s * a[1] + t * b[1];
@@ -119,8 +119,7 @@ bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], c
}
/**
- * Same as #interp_v3_v3v3_slerp buy uses fallback values
- * for opposite vectors.
+ * Same as #interp_v3_v3v3_slerp but uses fallback values for opposite vectors.
*/
void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t)
{
@@ -208,7 +207,7 @@ void interp_v3_v3v3v3_uv(float p[3], const float v1[3], const float v2[3], const
void interp_v3_v3v3_uchar(char unsigned target[3], const unsigned char a[3], const unsigned char b[3], const float t)
{
- float s = 1.0f - t;
+ const float s = 1.0f - t;
target[0] = (char)floorf(s * a[0] + t * b[0]);
target[1] = (char)floorf(s * a[1] + t * b[1]);
@@ -221,7 +220,7 @@ void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], const
void interp_v4_v4v4_uchar(char unsigned target[4], const unsigned char a[4], const unsigned char b[4], const float t)
{
- float s = 1.0f - t;
+ const float s = 1.0f - t;
target[0] = (char)floorf(s * a[0] + t * b[0]);
target[1] = (char)floorf(s * a[1] + t * b[1]);
@@ -467,6 +466,32 @@ float angle_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float
return angle_v3v3(v1_proj, v2_proj);
}
+float angle_signed_on_axis_v3v3v3_v3(const float v1[3], const float v2[3], const float v3[3], const float axis[3])
+{
+ float v1_proj[3], v2_proj[3], tproj[3];
+ float angle;
+
+ sub_v3_v3v3(v1_proj, v1, v2);
+ sub_v3_v3v3(v2_proj, v3, v2);
+
+ /* project the vectors onto the axis */
+ project_v3_v3v3(tproj, v1_proj, axis);
+ sub_v3_v3(v1_proj, tproj);
+
+ project_v3_v3v3(tproj, v2_proj, axis);
+ sub_v3_v3(v2_proj, tproj);
+
+ angle = angle_v3v3(v1_proj, v2_proj);
+
+ /* calculate the sign (reuse 'tproj') */
+ cross_v3_v3v3(tproj, v2_proj, v1_proj);
+ if (dot_v3v3(tproj, axis) < 0.0f) {
+ angle = ((float)(M_PI * 2.0)) - angle;
+ }
+
+ return angle;
+}
+
void angle_tri_v3(float angles[3], const float v1[3], const float v2[3], const float v3[3])
{
float ed1[3], ed2[3], ed3[3];
@@ -524,8 +549,7 @@ void angle_poly_v3(float *angles, const float *verts[3], int len)
/* Project v1 on v2 */
void project_v2_v2v2(float c[2], const float v1[2], const float v2[2])
{
- float mul;
- mul = dot_v2v2(v1, v2) / dot_v2v2(v2, v2);
+ const float mul = dot_v2v2(v1, v2) / dot_v2v2(v2, v2);
c[0] = mul * v2[0];
c[1] = mul * v2[1];
@@ -534,8 +558,7 @@ void project_v2_v2v2(float c[2], const float v1[2], const float v2[2])
/* Project v1 on v2 */
void project_v3_v3v3(float c[3], const float v1[3], const float v2[3])
{
- float mul;
- mul = dot_v3v3(v1, v2) / dot_v3v3(v2, v2);
+ const float mul = dot_v3v3(v1, v2) / dot_v3v3(v2, v2);
c[0] = mul * v2[0];
c[1] = mul * v2[1];
@@ -646,7 +669,7 @@ void ortho_v3_v3(float p[3], const float v[3])
/**
* no brainer compared to v3, just have for consistency.
*/
-void ortho_v2_v2(float p[3], const float v[3])
+void ortho_v2_v2(float p[2], const float v[2])
{
BLI_assert(p != v);
@@ -691,17 +714,17 @@ void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], const f
void print_v2(const char *str, const float v[2])
{
- printf("%s: %.3f %.3f\n", str, v[0], v[1]);
+ printf("%s: %.8f %.8f\n", str, v[0], v[1]);
}
void print_v3(const char *str, const float v[3])
{
- printf("%s: %.3f %.3f %.3f\n", str, v[0], v[1], v[2]);
+ printf("%s: %.8f %.8f %.8f\n", str, v[0], v[1], v[2]);
}
void print_v4(const char *str, const float v[4])
{
- printf("%s: %.3f %.3f %.3f %.3f\n", str, v[0], v[1], v[2], v[3]);
+ printf("%s: %.8f %.8f %.8f %.8f\n", str, v[0], v[1], v[2], v[3]);
}
void print_vn(const char *str, const float v[], const int n)
@@ -709,7 +732,7 @@ void print_vn(const char *str, const float v[], const int n)
int i = 0;
printf("%s[%d]:", str, n);
while (i < n) {
- printf(" %.3f", v[i++]);
+ printf(" %.8f", v[i++]);
}
printf("\n");
}
@@ -811,7 +834,7 @@ double len_squared_vn(const float *array, const int size)
float normalize_vn_vn(float *array_tar, const float *array_src, const int size)
{
- double d = len_squared_vn(array_src, size);
+ const double d = len_squared_vn(array_src, size);
float d_sqrt;
if (d > 1.0e-35) {
d_sqrt = (float)sqrt(d);
diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c
index aed604eddb4..da9d5bd3f49 100644
--- a/source/blender/blenlib/intern/math_vector_inline.c
+++ b/source/blender/blenlib/intern/math_vector_inline.c
@@ -466,7 +466,7 @@ MINLINE float mul_project_m4_v3_zfac(float mat[4][4], const float co[3])
}
/**
- * Has the effect of mul_m3_v3(), on a single axis.
+ * Has the effect of #mul_m3_v3(), on a single axis.
*/
MINLINE float dot_m3_v3_row_x(float M[3][3], const float a[3])
{
@@ -482,7 +482,8 @@ MINLINE float dot_m3_v3_row_z(float M[3][3], const float a[3])
}
/**
- * Almost like mul_m4_v3(), misses adding translation.
+ * Has the effect of #mul_mat3_m4_v3(), on a single axis.
+ * (no adding translation)
*/
MINLINE float dot_m4_v3_row_x(float M[4][4], const float a[3])
{
@@ -850,17 +851,17 @@ MINLINE void normal_float_to_short_v3(short out[3], const float in[3])
MINLINE bool is_zero_v2(const float v[2])
{
- return (v[0] == 0 && v[1] == 0);
+ return (v[0] == 0.0f && v[1] == 0.0f);
}
MINLINE bool is_zero_v3(const float v[3])
{
- return (v[0] == 0 && v[1] == 0 && v[2] == 0);
+ return (v[0] == 0.0f && v[1] == 0.0f && v[2] == 0.0f);
}
MINLINE bool is_zero_v4(const float v[4])
{
- return (v[0] == 0 && v[1] == 0 && v[2] == 0 && v[3] == 0);
+ return (v[0] == 0.0f && v[1] == 0.0f && v[2] == 0.0f && v[3] == 0.0f);
}
MINLINE bool is_finite_v2(const float v[2])
@@ -880,9 +881,15 @@ MINLINE bool is_finite_v4(const float v[4])
MINLINE bool is_one_v3(const float v[3])
{
- return (v[0] == 1 && v[1] == 1 && v[2] == 1);
+ return (v[0] == 1.0f && v[1] == 1.0f && v[2] == 1.0f);
}
+
+/** \name Vector Comparison
+ *
+ * \note use ``value <= limit``, so a limit of zero doesn't fail on an exact match.
+ * \{ */
+
MINLINE bool equals_v2v2(const float v1[2], const float v2[2])
{
return ((v1[0] == v2[0]) && (v1[1] == v2[1]));
@@ -900,8 +907,8 @@ MINLINE bool equals_v4v4(const float v1[4], const float v2[4])
MINLINE bool compare_v2v2(const float v1[2], const float v2[2], const float limit)
{
- if (fabsf(v1[0] - v2[0]) < limit)
- if (fabsf(v1[1] - v2[1]) < limit)
+ if (fabsf(v1[0] - v2[0]) <= limit)
+ if (fabsf(v1[1] - v2[1]) <= limit)
return true;
return false;
@@ -909,9 +916,9 @@ MINLINE bool compare_v2v2(const float v1[2], const float v2[2], const float limi
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], const float limit)
{
- if (fabsf(v1[0] - v2[0]) < limit)
- if (fabsf(v1[1] - v2[1]) < limit)
- if (fabsf(v1[2] - v2[2]) < limit)
+ if (fabsf(v1[0] - v2[0]) <= limit)
+ if (fabsf(v1[1] - v2[1]) <= limit)
+ if (fabsf(v1[2] - v2[2]) <= limit)
return true;
return false;
@@ -925,24 +932,49 @@ MINLINE bool compare_len_v3v3(const float v1[3], const float v2[3], const float
y = v1[1] - v2[1];
z = v1[2] - v2[2];
- return ((x * x + y * y + z * z) < (limit * limit));
+ return ((x * x + y * y + z * z) <= (limit * limit));
+}
+
+MINLINE bool compare_len_squared_v3v3(const float v1[3], const float v2[3], const float limit_sq)
+{
+ float x, y, z;
+
+ x = v1[0] - v2[0];
+ y = v1[1] - v2[1];
+ z = v1[2] - v2[2];
+
+ return ((x * x + y * y + z * z) <= limit_sq);
}
MINLINE bool compare_v4v4(const float v1[4], const float v2[4], const float limit)
{
- if (fabsf(v1[0] - v2[0]) < limit)
- if (fabsf(v1[1] - v2[1]) < limit)
- if (fabsf(v1[2] - v2[2]) < limit)
- if (fabsf(v1[3] - v2[3]) < limit)
+ if (fabsf(v1[0] - v2[0]) <= limit)
+ if (fabsf(v1[1] - v2[1]) <= limit)
+ if (fabsf(v1[2] - v2[2]) <= limit)
+ if (fabsf(v1[3] - v2[3]) <= limit)
return true;
return false;
}
+/**
+ * <pre>
+ * + l1
+ * |
+ * neg <- | -> pos
+ * |
+ * + l2
+ * </pre>
+ *
+ * \return Positive value when 'pt' is left-of-line
+ * (looking from 'l1' -> 'l2').
+ */
MINLINE float line_point_side_v2(const float l1[2], const float l2[2], const float pt[2])
{
return (((l1[0] - pt[0]) * (l2[1] - pt[1])) -
((l2[0] - pt[0]) * (l1[1] - pt[1])));
}
+/** \} */
+
#endif /* __MATH_VECTOR_INLINE_C__ */
diff --git a/source/blender/blenlib/intern/md5.c b/source/blender/blenlib/intern/md5.c
index 4a09afe2e3d..3d1a9cdb7a4 100644
--- a/source/blender/blenlib/intern/md5.c
+++ b/source/blender/blenlib/intern/md5.c
@@ -1,417 +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.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Copyright (C) 1995 Software Foundation, Inc.
+ *
+ * Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>.
+ */
+
/** \file blender/blenlib/intern/md5.c
- * \ingroup imbuf
+ * \ingroup bli
+ *
+ * Functions to compute MD5 message digest of files or memory blocks
+ * according to the definition of MD5 in RFC 1321 from April 1992.
*/
#include "BLI_md5.h" /* own include */
-/* md5.c - Functions to compute MD5 message digest of files or memory blocks
- according to the definition of MD5 in RFC 1321 from April 1992.
- Copyright (C) 1995 Software Foundation, Inc.
-
- 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>. */
-
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#if defined HAVE_LIMITS_H || defined _LIBC
-# include <limits.h>
+# include <limits.h>
#endif
-/* The following contortions are an attempt to use the C preprocessor
- to determine an unsigned integral type that is 32 bits wide. An
- alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
- doing that would require that the configure script compile and *run*
- the resulting executable. Locally running cross-compiled executables
- is usually not possible. */
+/* The following contortions are an attempt to use the C preprocessor to determine an unsigned integral type
+ * that is 32 bits wide. An alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but doing that
+ * would require that the configure script compile and *run* the resulting executable.
+ * Locally running cross-compiled executables is usually not possible.
+ */
#if defined __STDC__ && __STDC__
-# define UINT_MAX_32_BITS 4294967295U
+# define UINT_MAX_32_BITS 4294967295U
#else
-# define UINT_MAX_32_BITS 0xFFFFFFFF
+# define UINT_MAX_32_BITS 0xFFFFFFFF
#endif
/* If UINT_MAX isn't defined, assume it's a 32-bit type.
- This should be valid for all systems GNU cares about because
- that doesn't include 16-bit systems, and only modern systems
- (that certainly have <limits.h>) have 64+-bit integral types. */
+ * This should be valid for all systems GNU cares about because that doesn't include 16-bit systems,
+ * and only modern systems (that certainly have <limits.h>) have 64+-bit integral types.
+ */
#ifndef UINT_MAX
-# define UINT_MAX UINT_MAX_32_BITS
+# define UINT_MAX UINT_MAX_32_BITS
#endif
#if UINT_MAX == UINT_MAX_32_BITS
- typedef unsigned int md5_uint32;
+ typedef unsigned int md5_uint32;
#else
-# if USHRT_MAX == UINT_MAX_32_BITS
- typedef unsigned short md5_uint32;
-# else
-# if ULONG_MAX == UINT_MAX_32_BITS
- typedef unsigned long md5_uint32;
+# if USHRT_MAX == UINT_MAX_32_BITS
+ typedef unsigned short md5_uint32;
# else
- /* The following line is intended to evoke an error.
- Using #error is not portable enough. */
- "Cannot determine unsigned 32-bit data type."
+# if ULONG_MAX == UINT_MAX_32_BITS
+ typedef unsigned long md5_uint32;
+# else
+ /* The following line is intended to evoke an error. Using #error is not portable enough. */
+ "Cannot determine unsigned 32-bit data type."
+# endif
# endif
-# endif
#endif
-/* Structure to save state of computation between the single steps. */
+
+/* Following code is low level, upon which are built up the functions 'md5_stream' and 'md5_buffer'. */
+
+/* Structure to save state of computation between the single steps. */
struct md5_ctx
{
- md5_uint32 A;
- md5_uint32 B;
- md5_uint32 C;
- md5_uint32 D;
+ md5_uint32 A;
+ md5_uint32 B;
+ md5_uint32 C;
+ md5_uint32 D;
};
-/*
- * The following three functions are build up the low level used in
- * the functions `md5_stream' and `md5_buffer'.
- */
+#ifdef __BIG_ENDIAN__
+# define SWAP(n) (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
+#else
+# define SWAP(n) (n)
+#endif
-/* Initialize structure containing state of computation.
- (RFC 1321, 3.3: Step 3) */
-static void md5_init_ctx(struct md5_ctx *ctx);
+/* This array contains the bytes used to pad the buffer to the next 64-byte boundary. (RFC 1321, 3.1: Step 1) */
+static const unsigned char fillbuf[64] = {0x80, 0 /* , 0, 0, ... */};
-/* Starting with the result of former calls of this function (or the
- initialzation function update the context for the next LEN bytes
- starting at BUFFER.
- It is necessary that LEN is a multiple of 64!!! */
-static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx);
+/** Initialize structure containing state of computation.
+ * (RFC 1321, 3.3: Step 3)
+ */
+static void md5_init_ctx(struct md5_ctx *ctx)
+{
+ ctx->A = 0x67452301;
+ ctx->B = 0xefcdab89;
+ ctx->C = 0x98badcfe;
+ ctx->D = 0x10325476;
+}
-/* Put result from CTX in first 16 bytes following RESBUF. The result is
- always in little endian byte order, so that a byte-wise output yields
- to the wanted ASCII representation of the message digest. */
-static void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf);
+/** Starting with the result of former calls of this function (or the initialization), this function updates
+ * the 'ctx' context for the next 'len' bytes starting at 'buffer'.
+ * It is necessary that 'len' is a multiple of 64!!!
+ */
+static void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
+{
+/* These are the four functions used in the four steps of the MD5 algorithm and defined in the RFC 1321.
+ * The first function is a little bit optimized (as found in Colin Plumbs public domain implementation).
+ */
+/* #define FF(b, c, d) ((b & c) | (~b & d)) */
+#define FF(b, c, d) (d ^ (b & (c ^ d)))
+#define FG(b, c, d) FF (d, b, c)
+#define FH(b, c, d) (b ^ c ^ d)
+#define FI(b, c, d) (c ^ (b | ~d))
+/* It is unfortunate that C does not provide an operator for cyclic rotation. Hope the C compiler is smart enough. */
+#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
-#ifdef __BIG_ENDIAN__
-# define SWAP(n) \
- (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
-#else
-# define SWAP(n) (n)
-#endif
+ md5_uint32 correct_words[16];
+ const md5_uint32 *words = buffer;
+ size_t nwords = len / sizeof(md5_uint32);
+ const md5_uint32 *endp = words + nwords;
+ md5_uint32 A = ctx->A;
+ md5_uint32 B = ctx->B;
+ md5_uint32 C = ctx->C;
+ md5_uint32 D = ctx->D;
+
+ /* Process all bytes in the buffer with 64 bytes in each round of the loop. */
+ while (words < endp) {
+ md5_uint32 *cwp = correct_words;
+ md5_uint32 A_save = A;
+ md5_uint32 B_save = B;
+ md5_uint32 C_save = C;
+ md5_uint32 D_save = D;
+
+ /* First round: using the given function, the context and a constant the next context is computed.
+ * Because the algorithms processing unit is a 32-bit word and it is determined to work on words in
+ * little endian byte order we perhaps have to change the byte order before the computation.
+ * To reduce the work for the next steps we store the swapped words in the array CORRECT_WORDS.
+ */
+#define OP(a, b, c, d, s, T) \
+ a += FF(b, c, d) + (*cwp++ = SWAP(*words)) + T; \
+ ++words; \
+ CYCLIC(a, s); \
+ a += b; \
+ (void)0
+
+ /* Before we start, one word to the strange constants. They are defined in RFC 1321 as:
+ * T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
+ */
+
+ /* Round 1. */
+ OP(A, B, C, D, 7, 0xd76aa478);
+ OP(D, A, B, C, 12, 0xe8c7b756);
+ OP(C, D, A, B, 17, 0x242070db);
+ OP(B, C, D, A, 22, 0xc1bdceee);
+ OP(A, B, C, D, 7, 0xf57c0faf);
+ OP(D, A, B, C, 12, 0x4787c62a);
+ OP(C, D, A, B, 17, 0xa8304613);
+ OP(B, C, D, A, 22, 0xfd469501);
+ OP(A, B, C, D, 7, 0x698098d8);
+ OP(D, A, B, C, 12, 0x8b44f7af);
+ OP(C, D, A, B, 17, 0xffff5bb1);
+ OP(B, C, D, A, 22, 0x895cd7be);
+ OP(A, B, C, D, 7, 0x6b901122);
+ OP(D, A, B, C, 12, 0xfd987193);
+ OP(C, D, A, B, 17, 0xa679438e);
+ OP(B, C, D, A, 22, 0x49b40821);
+#undef OP
-/* This array contains the bytes used to pad the buffer to the next
- 64-byte boundary. (RFC 1321, 3.1: Step 1) */
-static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ };
+ /* For the second to fourth round we have the possibly swapped words in CORRECT_WORDS.
+ * Redefine the macro to take an additional first argument specifying the function to use.
+ */
+#define OP(f, a, b, c, d, k, s, T) \
+ a += f(b, c, d) + correct_words[k] + T; \
+ CYCLIC(a, s); \
+ a += b; \
+ (void)0
+
+ /* Round 2. */
+ OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
+ OP(FG, D, A, B, C, 6, 9, 0xc040b340);
+ OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
+ OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
+ OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
+ OP(FG, D, A, B, C, 10, 9, 0x02441453);
+ OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
+ OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
+ OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
+ OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
+ OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
+ OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
+ OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
+ OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
+ OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
+ OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
+
+ /* Round 3. */
+ OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
+ OP(FH, D, A, B, C, 8, 11, 0x8771f681);
+ OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
+ OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
+ OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
+ OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
+ OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
+ OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
+ OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
+ OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
+ OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
+ OP(FH, B, C, D, A, 6, 23, 0x04881d05);
+ OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
+ OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
+ OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
+ OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
+
+ /* Round 4. */
+ OP(FI, A, B, C, D, 0, 6, 0xf4292244);
+ OP(FI, D, A, B, C, 7, 10, 0x432aff97);
+ OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
+ OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
+ OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
+ OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
+ OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
+ OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
+ OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
+ OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
+ OP(FI, C, D, A, B, 6, 15, 0xa3014314);
+ OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
+ OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
+ OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
+ OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
+ OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
+#undef OP
-/* Initialize structure containing state of computation.
- (RFC 1321, 3.3: Step 3) */
-static void md5_init_ctx(struct md5_ctx *ctx)
-{
- ctx->A = 0x67452301;
- ctx->B = 0xefcdab89;
- ctx->C = 0x98badcfe;
- ctx->D = 0x10325476;
+ /* Add the starting values of the context. */
+ A += A_save;
+ B += B_save;
+ C += C_save;
+ D += D_save;
+ }
+
+ /* Put checksum in context given as argument. */
+ ctx->A = A;
+ ctx->B = B;
+ ctx->C = C;
+ ctx->D = D;
+
+#undef FF
+#undef FG
+#undef FH
+#undef FI
+#undef CYCLIC
}
-/* Put result from CTX in first 16 bytes following RESBUF. The result must
- be in little endian byte order. */
+/** Put result from 'ctx' in first 16 bytes of 'resbuf'. The result is always in little endian byte order,
+ * so that a byte-wise output yields to the wanted ASCII representation of the message digest.
+ */
static void *md5_read_ctx(const struct md5_ctx *ctx, void *resbuf)
{
- ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
- ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
- ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
- ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
+ md5_uint32 *digest = resbuf;
+ digest[0] = SWAP(ctx->A);
+ digest[1] = SWAP(ctx->B);
+ digest[2] = SWAP(ctx->C);
+ digest[3] = SWAP(ctx->D);
- return resbuf;
+ return resbuf;
}
-/* Compute MD5 message digest for bytes read from STREAM. The
- resulting message digest number will be written into the 16 bytes
- beginning at RESBLOCK. */
+/* Top level public functions. */
+
+/** Compute MD5 message digest for bytes read from 'stream'.
+ * The resulting message digest number will be written into the 16 bytes beginning at 'resblock'.
+ * \return Non-zero if an error occurred.
+ */
int md5_stream(FILE *stream, void *resblock)
{
- /* Important: BLOCKSIZE must be a multiple of 64. */
-#define BLOCKSIZE 4096
- struct md5_ctx ctx;
- md5_uint32 len[2];
- char buffer[BLOCKSIZE + 72];
- size_t pad, sum;
-
- /* Initialize the computation context. */
- md5_init_ctx (&ctx);
-
- len[0] = 0;
- len[1] = 0;
-
- /* Iterate over full file contents. */
- while (1)
- {
- /* We read the file in blocks of BLOCKSIZE bytes. One call of the
- computation function processes the whole buffer so that with the
- next round of the loop another block can be read. */
- size_t n;
- sum = 0;
-
- /* Read block. Take care for partial reads. */
- do
- {
- n = fread (buffer, 1, BLOCKSIZE - sum, stream);
-
- sum += n;
- }
- while (sum < BLOCKSIZE && n != 0);
- if (n == 0 && ferror (stream))
- return 1;
-
- /* RFC 1321 specifies the possible length of the file up to 2^64 bits.
- Here we only compute the number of bytes. Do a double word
- increment. */
- len[0] += sum;
- if (len[0] < sum)
- ++len[1];
-
- /* If end of file is reached, end the loop. */
- if (n == 0)
- break;
-
- /* Process buffer with BLOCKSIZE bytes. Note that
- BLOCKSIZE % 64 == 0
- */
- md5_process_block (buffer, BLOCKSIZE, &ctx);
+#define BLOCKSIZE 4096 /* Important: must be a multiple of 64. */
+ struct md5_ctx ctx;
+ md5_uint32 len[2];
+ char buffer[BLOCKSIZE + 72];
+ size_t pad, sum;
+
+ /* Initialize the computation context. */
+ md5_init_ctx(&ctx);
+
+ len[0] = 0;
+ len[1] = 0;
+
+ /* Iterate over full file contents. */
+ while (1) {
+ /* We read the file in blocks of BLOCKSIZE bytes. One call of the computation function processes
+ * the whole buffer so that with the next round of the loop another block can be read.
+ */
+ size_t n;
+ sum = 0;
+
+ /* Read block. Take care for partial reads. */
+ do {
+ n = fread(buffer, 1, BLOCKSIZE - sum, stream);
+ sum += n;
+ } while (sum < BLOCKSIZE && n != 0);
+
+ if (n == 0 && ferror(stream))
+ return 1;
+
+ /* RFC 1321 specifies the possible length of the file up to 2^64 bits.
+ * Here we only compute the number of bytes. Do a double word increment.
+ */
+ len[0] += sum;
+ if (len[0] < sum)
+ ++len[1];
+
+ /* If end of file is reached, end the loop. */
+ if (n == 0)
+ break;
+
+ /* Process buffer with BLOCKSIZE bytes. Note that BLOCKSIZE % 64 == 0. */
+ md5_process_block(buffer, BLOCKSIZE, &ctx);
}
- /* We can copy 64 byte because the buffer is always big enough. FILLBUF
- contains the needed bits. */
- memcpy (&buffer[sum], fillbuf, 64);
+ /* We can copy 64 bytes because the buffer is always big enough. 'fillbuf' contains the needed bits. */
+ memcpy(&buffer[sum], fillbuf, 64);
- /* Compute amount of padding bytes needed. Alignment is done to
- (N + PAD) % 64 == 56
- There is always at least one byte padded. I.e. even the alignment
- is correctly aligned 64 padding bytes are added. */
- pad = sum & 63;
- pad = pad >= 56 ? 64 + 56 - pad : 56 - pad;
+ /* Compute amount of padding bytes needed. Alignment is done to (N + PAD) % 64 == 56.
+ * There is always at least one byte padded, i.e. if the alignment is correctly aligned,
+ * 64 padding bytes are added.
+ */
+ pad = sum & 63;
+ pad = pad >= 56 ? 64 + 56 - pad : 56 - pad;
- /* Put the 64-bit file length in *bits* at the end of the buffer. */
- *(md5_uint32 *) &buffer[sum + pad] = SWAP (len[0] << 3);
- *(md5_uint32 *) &buffer[sum + pad + 4] = SWAP ((len[1] << 3)
- | (len[0] >> 29));
+ /* Put the 64-bit file length in *bits* at the end of the buffer. */
+ *(md5_uint32 *) &buffer[sum + pad] = SWAP(len[0] << 3);
+ *(md5_uint32 *) &buffer[sum + pad + 4] = SWAP((len[1] << 3) | (len[0] >> 29));
- /* Process last bytes. */
- md5_process_block (buffer, sum + pad + 8, &ctx);
+ /* Process last bytes. */
+ md5_process_block(buffer, sum + pad + 8, &ctx);
- /* Construct result in desired memory. */
- md5_read_ctx (&ctx, resblock);
- return 0;
+ /* Construct result in desired memory. */
+ md5_read_ctx(&ctx, resblock);
+ return 0;
}
-/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
- result is always in little endian byte order, so that a byte-wise
- output yields to the wanted ASCII representation of the message
- digest. */
+/** Compute MD5 message digest for 'len' bytes beginning at 'buffer'.
+ * The result is always in little endian byte order, so that a byte-wise output yields to the wanted
+ * ASCII representation of the message digest.
+ */
void *md5_buffer(const char *buffer, size_t len, void *resblock)
{
- struct md5_ctx ctx;
- char restbuf[64 + 72];
- size_t blocks = len & ~63;
- size_t pad, rest;
-
- /* Initialize the computation context. */
- md5_init_ctx (&ctx);
-
- /* Process whole buffer but last len % 64 bytes. */
- md5_process_block (buffer, blocks, &ctx);
-
- /* REST bytes are not processed yet. */
- rest = len - blocks;
- /* Copy to own buffer. */
- memcpy (restbuf, &buffer[blocks], rest);
- /* Append needed fill bytes at end of buffer. We can copy 64 byte
- because the buffer is always big enough. */
- memcpy (&restbuf[rest], fillbuf, 64);
-
- /* PAD bytes are used for padding to correct alignment. Note that
- always at least one byte is padded. */
- pad = rest >= 56 ? 64 + 56 - rest : 56 - rest;
-
- /* Put length of buffer in *bits* in last eight bytes. */
- *(md5_uint32 *) &restbuf[rest + pad] = (md5_uint32) SWAP (len << 3);
- *(md5_uint32 *) &restbuf[rest + pad + 4] = (md5_uint32) SWAP (len >> 29);
-
- /* Process last bytes. */
- md5_process_block (restbuf, rest + pad + 8, &ctx);
-
- /* Put result in desired memory area. */
- return md5_read_ctx (&ctx, resblock);
-}
+ struct md5_ctx ctx;
+ char restbuf[64 + 72];
+ size_t blocks = len & ~63;
+ size_t pad, rest;
+ /* Initialize the computation context. */
+ md5_init_ctx(&ctx);
-/* These are the four functions used in the four steps of the MD5 algorithm
- and defined in the RFC 1321. The first function is a little bit optimized
- (as found in Colin Plumbs public domain implementation). */
-/* #define FF(b, c, d) ((b & c) | (~b & d)) */
-#define FF(b, c, d) (d ^ (b & (c ^ d)))
-#define FG(b, c, d) FF (d, b, c)
-#define FH(b, c, d) (b ^ c ^ d)
-#define FI(b, c, d) (c ^ (b | ~d))
+ /* Process whole buffer but last len % 64 bytes. */
+ md5_process_block(buffer, blocks, &ctx);
-/* Process LEN bytes of BUFFER, accumulating context into CTX.
- It is assumed that LEN % 64 == 0. */
+ /* REST bytes are not processed yet. */
+ rest = len - blocks;
+ /* Copy to own buffer. */
+ memcpy(restbuf, &buffer[blocks], rest);
+ /* Append needed fill bytes at end of buffer. We can copy 64 bytes because the buffer is always big enough. */
+ memcpy(&restbuf[rest], fillbuf, 64);
-void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx)
-{
- md5_uint32 correct_words[16];
- const md5_uint32 *words = buffer;
- size_t nwords = len / sizeof (md5_uint32);
- const md5_uint32 *endp = words + nwords;
- md5_uint32 A = ctx->A;
- md5_uint32 B = ctx->B;
- md5_uint32 C = ctx->C;
- md5_uint32 D = ctx->D;
-
- /* Process all bytes in the buffer with 64 bytes in each round of
- the loop. */
- while (words < endp)
- {
- md5_uint32 *cwp = correct_words;
- md5_uint32 A_save = A;
- md5_uint32 B_save = B;
- md5_uint32 C_save = C;
- md5_uint32 D_save = D;
-
- /* First round: using the given function, the context and a constant
- the next context is computed. Because the algorithms processing
- unit is a 32-bit word and it is determined to work on words in
- little endian byte order we perhaps have to change the byte order
- before the computation. To reduce the work for the next steps
- we store the swapped words in the array CORRECT_WORDS. */
-
-#define OP(a, b, c, d, s, T) \
- do \
- { \
- a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
- ++words; \
- CYCLIC (a, s); \
- a += b; \
- } \
- while (0)
-
- /* It is unfortunate that C does not provide an operator for
- cyclic rotation. Hope the C compiler is smart enough. */
-#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
+ /* PAD bytes are used for padding to correct alignment. Note that always at least one byte is padded. */
+ pad = rest >= 56 ? 64 + 56 - rest : 56 - rest;
- /* Before we start, one word to the strange constants.
- They are defined in RFC 1321 as
-
- T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
- */
-
- /* Round 1. */
- OP (A, B, C, D, 7, 0xd76aa478);
- OP (D, A, B, C, 12, 0xe8c7b756);
- OP (C, D, A, B, 17, 0x242070db);
- OP (B, C, D, A, 22, 0xc1bdceee);
- OP (A, B, C, D, 7, 0xf57c0faf);
- OP (D, A, B, C, 12, 0x4787c62a);
- OP (C, D, A, B, 17, 0xa8304613);
- OP (B, C, D, A, 22, 0xfd469501);
- OP (A, B, C, D, 7, 0x698098d8);
- OP (D, A, B, C, 12, 0x8b44f7af);
- OP (C, D, A, B, 17, 0xffff5bb1);
- OP (B, C, D, A, 22, 0x895cd7be);
- OP (A, B, C, D, 7, 0x6b901122);
- OP (D, A, B, C, 12, 0xfd987193);
- OP (C, D, A, B, 17, 0xa679438e);
- OP (B, C, D, A, 22, 0x49b40821);
-
- /* For the second to fourth round we have the possibly swapped words
- in CORRECT_WORDS. Redefine the macro to take an additional first
- argument specifying the function to use. */
-#undef OP
-#define OP(f, a, b, c, d, k, s, T) \
- do \
- { \
- a += f (b, c, d) + correct_words[k] + T; \
- CYCLIC (a, s); \
- a += b; \
- } \
- while (0)
-
- /* Round 2. */
- OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
- OP (FG, D, A, B, C, 6, 9, 0xc040b340);
- OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
- OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
- OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
- OP (FG, D, A, B, C, 10, 9, 0x02441453);
- OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
- OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
- OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
- OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
- OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
- OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
- OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
- OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
- OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
- OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
-
- /* Round 3. */
- OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
- OP (FH, D, A, B, C, 8, 11, 0x8771f681);
- OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
- OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
- OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
- OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
- OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
- OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
- OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
- OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
- OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
- OP (FH, B, C, D, A, 6, 23, 0x04881d05);
- OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
- OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
- OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
- OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
-
- /* Round 4. */
- OP (FI, A, B, C, D, 0, 6, 0xf4292244);
- OP (FI, D, A, B, C, 7, 10, 0x432aff97);
- OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
- OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
- OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
- OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
- OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
- OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
- OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
- OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
- OP (FI, C, D, A, B, 6, 15, 0xa3014314);
- OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
- OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
- OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
- OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
- OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
-
- /* Add the starting values of the context. */
- A += A_save;
- B += B_save;
- C += C_save;
- D += D_save;
- }
+ /* Put length of buffer in *bits* in last eight bytes. */
+ *(md5_uint32 *) &restbuf[rest + pad] = (md5_uint32) SWAP(len << 3);
+ *(md5_uint32 *) &restbuf[rest + pad + 4] = (md5_uint32) SWAP(len >> 29);
- /* Put checksum in context given as argument. */
- ctx->A = A;
- ctx->B = B;
- ctx->C = C;
- ctx->D = D;
+ /* Process last bytes. */
+ md5_process_block(restbuf, rest + pad + 8, &ctx);
+
+ /* Put result in desired memory area. */
+ return md5_read_ctx(&ctx, resblock);
}
+char *md5_to_hexdigest(void *resblock, char r_hex_digest[33])
+{
+ static const char hex_map[17] = "0123456789abcdef";
+ const unsigned char *p;
+ char *q;
+ short len;
+
+ for (q = r_hex_digest, p = (const unsigned char *)resblock, len = 0; len < 16; ++p, ++len) {
+ const unsigned char c = *p;
+ *q++ = hex_map[c >> 4];
+ *q++ = hex_map[c & 15];
+ }
+ *q = '\0';
+
+ return r_hex_digest;
+}
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 4226a04ca5b..d5af980e373 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -49,9 +49,9 @@
#include "GHOST_Path-api.h"
-#ifdef WIN32
-# include "MEM_guardedalloc.h"
+#include "MEM_guardedalloc.h"
+#ifdef WIN32
# include "utf_winfunc.h"
# include "utfconv.h"
# include <io.h>
@@ -66,6 +66,7 @@
# ifdef WITH_BINRELOC
# include "binreloc.h"
# endif
+# include <unistd.h> /* mkdtemp on OSX (and probably all *BSD?), not worth making specific check for this OS. */
#endif /* WIN32 */
/* local */
@@ -73,7 +74,8 @@
static char bprogname[FILE_MAX]; /* full path to program executable */
static char bprogdir[FILE_MAX]; /* full path to directory in which executable is located */
-static char btempdir[FILE_MAX]; /* temporary directory */
+static char btempdir_base[FILE_MAX]; /* persistent temporary directory */
+static char btempdir_session[FILE_MAX] = ""; /* volatile temporary directory */
/* implementation */
@@ -365,14 +367,6 @@ void BLI_cleanup_path(const char *relabase, char *path)
*/
#ifdef WIN32
-
- /* Note, this should really be moved to the file selector,
- * since this function is used in many areas */
- if (strcmp(path, ".") == 0) { /* happens for example in FILE_MAIN */
- get_default_root(path);
- return;
- }
-
while ( (start = strstr(path, "\\..\\")) ) {
eind = start + strlen("\\..\\") - 1;
a = start - path - 1;
@@ -400,12 +394,6 @@ void BLI_cleanup_path(const char *relabase, char *path)
memmove(start, eind, strlen(eind) + 1);
}
#else
- if (path[0] == '.') { /* happens, for example in FILE_MAIN */
- path[0] = '/';
- path[1] = 0;
- return;
- }
-
while ( (start = strstr(path, "/../")) ) {
a = start - path - 1;
if (a > 0) {
@@ -475,8 +463,6 @@ bool BLI_path_is_unc(const char *name)
* of a UNC path which can start with '\\' (short version)
* or '\\?\' (long version)
* If the path is not a UNC path, return 0
- *
- * \param name the path name
*/
static int BLI_path_unc_prefix_len(const char *path)
{
@@ -887,9 +873,12 @@ bool BLI_path_abs(char *path, const char *basepath)
char tmp[FILE_MAX];
char base[FILE_MAX];
#ifdef WIN32
- char vol[3] = {'\0', '\0', '\0'};
- BLI_strncpy(vol, path, 3);
+ /* without this: "" --> "C:\" */
+ if (*path == '\0') {
+ return wasrelative;
+ }
+
/* we are checking here if we have an absolute path that is not in the current
* blend file as a lib main - we are basically checking for the case that a
* UNIX root '/' is passed.
@@ -1189,7 +1178,13 @@ static bool get_path_local(char *targetpath, const char *folder_name, const char
}
/* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
+#ifdef __APPLE__
+ static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
+ sprintf(osx_resourses, "%s../Resources", bprogdir);
+ return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder);
+#else
return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder);
+#endif
}
/**
@@ -1429,7 +1424,7 @@ const char *BLI_get_folder_create(int folder_id, const char *subfolder)
const char *path;
/* only for user folders */
- if (!ELEM4(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE))
+ if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE))
return NULL;
path = BLI_get_folder(folder_id, subfolder);
@@ -1529,21 +1524,6 @@ void BLI_setenv_if_new(const char *env, const char *val)
BLI_setenv(env, val);
}
-
-/**
- * Changes to the path separators to the native ones for this OS.
- */
-void BLI_clean(char *path)
-{
-#ifdef WIN32
- if (path && BLI_strnlen(path, 3) > 2) {
- BLI_char_switch(path + 2, '/', '\\');
- }
-#else
- BLI_char_switch(path + BLI_path_unc_prefix_len(path), '\\', '/');
-#endif
-}
-
/**
* Change every \a from in \a string into \a to. The
* result will be in \a string
@@ -1695,7 +1675,7 @@ void BLI_make_file_string(const char *relabase, char *string, const char *dir, c
strcat(string, file);
/* Push all slashes to the system preferred direction */
- BLI_clean(string);
+ BLI_path_native_slash(string);
}
static bool testextensie_ex(const char *str, const size_t str_len,
@@ -1797,7 +1777,7 @@ bool BLI_replace_extension(char *path, size_t maxlen, const char *ext)
ssize_t a;
for (a = path_len - 1; a >= 0; a--) {
- if (ELEM3(path[a], '.', '/', '\\')) {
+ if (ELEM(path[a], '.', '/', '\\')) {
break;
}
}
@@ -1966,6 +1946,8 @@ const char *BLI_path_basename(const char *path)
return filename ? filename + 1 : path;
}
+/* UNUSED */
+#if 0
/**
* Produce image export path.
*
@@ -2092,6 +2074,8 @@ int BLI_rebase_path(char *abs, size_t abs_len,
return BLI_REBASE_OK;
}
+#endif
+
/**
* Returns pointer to the leftmost path separator in string. Not actually used anywhere.
@@ -2156,6 +2140,20 @@ void BLI_del_slash(char *string)
}
/**
+ * Changes to the path separators to the native ones for this OS.
+ */
+void BLI_path_native_slash(char *path)
+{
+#ifdef WIN32
+ if (path && BLI_strnlen(path, 3) > 2) {
+ BLI_char_switch(path + 2, '/', '\\');
+ }
+#else
+ BLI_char_switch(path + BLI_path_unc_prefix_len(path), '\\', '/');
+#endif
+}
+
+/**
* 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.
@@ -2331,14 +2329,21 @@ const char *BLI_program_dir(void)
*
* Also make sure the temp dir has a trailing slash
*
- * \param fullname The full path to the temp directory
+ * \param fullname The full path to the temporary temp directory
+ * \param basename The full path to the persistent temp directory (may be NULL)
* \param maxlen The size of the fullname buffer
* \param userdir Directory specified in user preferences
*/
-static void BLI_where_is_temp(char *fullname, const size_t maxlen, char *userdir)
+static void BLI_where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir)
{
+ /* Clear existing temp dir, if needed. */
+ BLI_temp_dir_session_purge();
+
fullname[0] = '\0';
-
+ if (basename) {
+ basename[0] = '\0';
+ }
+
if (userdir && BLI_is_dir(userdir)) {
BLI_strncpy(fullname, userdir, maxlen);
}
@@ -2380,23 +2385,59 @@ static void BLI_where_is_temp(char *fullname, const size_t maxlen, char *userdir
}
#endif
}
+
+ /* Now that we have a valid temp dir, add system-generated unique sub-dir. */
+ if (basename) {
+ /* 'XXXXXX' is kind of tag to be replaced by mktemp-familly by an uuid. */
+ char *tmp_name = BLI_strdupcat(fullname, "blender_XXXXXX");
+ const size_t ln = strlen(tmp_name) + 1;
+ if (ln <= maxlen) {
+#ifdef WIN32
+ if (_mktemp_s(tmp_name, ln) == 0) {
+ BLI_dir_create_recursive(tmp_name);
+ }
+#else
+ mkdtemp(tmp_name);
+#endif
+ }
+ if (BLI_is_dir(tmp_name)) {
+ BLI_strncpy(basename, fullname, maxlen);
+ BLI_strncpy(fullname, tmp_name, maxlen);
+ BLI_add_slash(fullname);
+ }
+ else {
+ printf("Warning! Could not generate a temp file name for '%s', falling back to '%s'\n", tmp_name, fullname);
+ }
+
+ MEM_freeN(tmp_name);
+ }
}
/**
- * Sets btempdir to userdir if specified and is a valid directory, otherwise
+ * Sets btempdir_base to userdir if specified and is a valid directory, otherwise
* chooses a suitable OS-specific temporary directory.
+ * Sets btempdir_session to a mkdtemp-generated sub-dir of btempdir_base.
*/
-void BLI_init_temporary_dir(char *userdir)
+void BLI_temp_dir_init(char *userdir)
{
- BLI_where_is_temp(btempdir, FILE_MAX, userdir);
+ BLI_where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
+;
}
/**
* Path to temporary directory (with trailing slash)
*/
-const char *BLI_temporary_dir(void)
+const char *BLI_temp_dir_session(void)
{
- return btempdir;
+ return btempdir_session[0] ? btempdir_session : BLI_temp_dir_base();
+}
+
+/**
+ * Path to persistent temporary directory (with trailing slash)
+ */
+const char *BLI_temp_dir_base(void)
+{
+ return btempdir_base;
}
/**
@@ -2404,7 +2445,17 @@ const char *BLI_temporary_dir(void)
*/
void BLI_system_temporary_dir(char *dir)
{
- BLI_where_is_temp(dir, FILE_MAX, NULL);
+ BLI_where_is_temp(dir, NULL, FILE_MAX, NULL);
+}
+
+/**
+ * Delete content of this instance's temp dir.
+ */
+void BLI_temp_dir_session_purge(void)
+{
+ if (btempdir_session[0] && BLI_is_dir(btempdir_session)) {
+ BLI_delete(btempdir_session, true, true);
+ }
}
#ifdef WITH_ICONV
diff --git a/source/blender/blenlib/intern/polyfill2d.c b/source/blender/blenlib/intern/polyfill2d.c
index 6dff597c530..16cf7ff960b 100644
--- a/source/blender/blenlib/intern/polyfill2d.c
+++ b/source/blender/blenlib/intern/polyfill2d.c
@@ -53,9 +53,67 @@
/* avoid fan-fill topology */
#define USE_CLIP_EVEN
#define USE_CONVEX_SKIP
+/* sweep back-and-forth about convex ears (avoids lop-sided fans) */
+#define USE_CLIP_SWEEP
// #define USE_CONVEX_SKIP_TEST
+#ifdef USE_CONVEX_SKIP
+# define USE_KDTREE
+#endif
+
+// #define DEBUG_TIME
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
+
typedef signed char eSign;
+
+#ifdef USE_KDTREE
+/**
+ * This is a single purpose KDTree based on BLI_kdtree with some modifications
+ * to better suit polyfill2d.
+ *
+ *
+ * - #KDTreeNode2D is kept small (only 16 bytes),
+ * by not storing coords in the nodes and using index values rather then pointers
+ * to reference neg/pos values.
+ *
+ * - #kdtree2d_isect_tri is the only function currently used.
+ * This simply intersects a triangle with the kdtree points.
+ *
+ * - the KDTree is only built & used when the polygon is concave.
+ */
+
+typedef bool axis_t;
+
+/* use for sorting */
+typedef struct KDTreeNode2D_head {
+ unsigned int neg, pos;
+ unsigned int index;
+} KDTreeNode2D_head;
+
+typedef struct KDTreeNode2D {
+ unsigned int neg, pos;
+ unsigned int index;
+ axis_t axis; /* range is only (0-1) */
+ unsigned short flag;
+ unsigned int parent;
+} KDTreeNode2D;
+
+struct KDTree2D {
+ KDTreeNode2D *nodes;
+ const float (*coords)[2];
+ unsigned int root;
+ unsigned int totnode;
+ unsigned int *nodes_map; /* index -> node lookup */
+};
+
+struct KDRange2D {
+ float min, max;
+};
+#endif /* USE_KDTREE */
+
enum {
CONCAVE = -1,
TANGENTIAL = 0,
@@ -63,11 +121,10 @@ enum {
};
typedef struct PolyFill {
- unsigned int *indices; /* vertex aligned */
+ struct PolyIndex *indices; /* vertex aligned */
const float (*coords)[2];
unsigned int coords_tot;
- eSign *coords_sign;
#ifdef USE_CONVEX_SKIP
unsigned int coords_tot_concave;
#endif
@@ -75,22 +132,37 @@ typedef struct PolyFill {
/* A polygon with n vertices has a triangulation of n-2 triangles. */
unsigned int (*tris)[3];
unsigned int tris_tot;
+
+#ifdef USE_KDTREE
+ struct KDTree2D kdtree;
+#endif
} PolyFill;
+/* circular linklist */
+typedef struct PolyIndex {
+ struct PolyIndex *next, *prev;
+ unsigned int index;
+ eSign sign;
+} PolyIndex;
+
+
/* based on libgdx 2013-11-28, apache 2.0 licensed */
-static eSign pf_coord_sign_calc(PolyFill *pf, unsigned int index);
-static unsigned int pf_index_prev(const PolyFill *pf, const unsigned int index);
-static unsigned int pf_index_next(const PolyFill *pf, unsigned index);
+static void pf_coord_sign_calc(PolyFill *pf, PolyIndex *pi);
+static PolyIndex *pf_ear_tip_find(
+ PolyFill *pf
#ifdef USE_CLIP_EVEN
-static unsigned int pf_ear_tip_find(PolyFill *pf, const unsigned int index_offset);
-#else
-static unsigned int pf_ear_tip_find(PolyFill *pf);
+ , PolyIndex *pi_ear_init
#endif
-static bool pf_ear_tip_check(PolyFill *pf, const unsigned int index_ear_tip);
-static void pf_ear_tip_cut(PolyFill *pf, unsigned int index_ear_tip);
+#ifdef USE_CLIP_SWEEP
+ , bool reverse
+#endif
+ );
+
+static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip);
+static void pf_ear_tip_cut(PolyFill *pf, PolyIndex *pi_ear_tip);
BLI_INLINE eSign signum_i(float a)
@@ -122,122 +194,441 @@ static eSign span_tri_v2_sign(const float v1[2], const float v2[2], const float
return signum_i(area_tri_signed_v2_alt_2x(v3, v2, v1));
}
+
+#ifdef USE_KDTREE
+#define KDNODE_UNSET ((unsigned int)-1)
+
+enum {
+ KDNODE_FLAG_REMOVED = (1 << 0),
+};
+
+static void kdtree2d_new(
+ struct KDTree2D *tree,
+ unsigned int tot,
+ const float (*coords)[2])
+{
+ /* set by caller */
+ // tree->nodes = nodes;
+ tree->coords = coords;
+ tree->root = KDNODE_UNSET;
+ tree->totnode = tot;
+}
+
+/**
+ * no need for kdtree2d_insert, since we know the coords array.
+ */
+static void kdtree2d_init(
+ struct KDTree2D *tree,
+ const unsigned int coords_tot,
+ const PolyIndex *indices)
+{
+ KDTreeNode2D *node;
+ unsigned int i;
+
+ for (i = 0, node = tree->nodes; i < coords_tot; i++) {
+ if (indices[i].sign != CONVEX) {
+ node->neg = node->pos = KDNODE_UNSET;
+ node->index = indices[i].index;
+ node->axis = 0;
+ node->flag = 0;
+ node++;
+ }
+ }
+
+ BLI_assert(tree->totnode == (unsigned int)(node - tree->nodes));
+}
+
+static unsigned int kdtree2d_balance_recursive(
+ KDTreeNode2D *nodes, unsigned int totnode, axis_t axis,
+ const float (*coords)[2], const unsigned int ofs)
+{
+ KDTreeNode2D *node;
+ unsigned int neg, pos, median, i, j;
+
+ if (totnode <= 0) {
+ return KDNODE_UNSET;
+ }
+ else if (totnode == 1) {
+ return 0 + ofs;
+ }
+
+ /* quicksort style sorting around median */
+ neg = 0;
+ pos = totnode - 1;
+ median = totnode / 2;
+
+ while (pos > neg) {
+ const float co = coords[nodes[pos].index][axis];
+ i = neg - 1;
+ j = pos;
+
+ while (1) {
+ while (coords[nodes[++i].index][axis] < co) ;
+ while (coords[nodes[--j].index][axis] > co && j > neg) ;
+
+ if (i >= j) {
+ break;
+ }
+ SWAP(KDTreeNode2D_head, *(KDTreeNode2D_head *)&nodes[i], *(KDTreeNode2D_head *)&nodes[j]);
+ }
+
+ SWAP(KDTreeNode2D_head, *(KDTreeNode2D_head *)&nodes[i], *(KDTreeNode2D_head *)&nodes[pos]);
+ if (i >= median) {
+ pos = i - 1;
+ }
+ if (i <= median) {
+ neg = i + 1;
+ }
+ }
+
+ /* set node and sort subnodes */
+ node = &nodes[median];
+ node->axis = axis;
+ axis = !axis;
+ node->neg = kdtree2d_balance_recursive(nodes, median, axis, coords, ofs);
+ node->pos = kdtree2d_balance_recursive(&nodes[median + 1], (totnode - (median + 1)), axis, coords, (median + 1) + ofs);
+
+ return median + ofs;
+}
+
+static void kdtree2d_balance(
+ struct KDTree2D *tree)
+{
+ tree->root = kdtree2d_balance_recursive(tree->nodes, tree->totnode, 0, tree->coords, 0);
+}
+
+
+static void kdtree2d_init_mapping(
+ struct KDTree2D *tree)
+{
+ unsigned int i;
+ KDTreeNode2D *node;
+
+ for (i = 0, node = tree->nodes; i < tree->totnode; i++, node++) {
+ if (node->neg != KDNODE_UNSET) {
+ tree->nodes[node->neg].parent = i;
+ }
+ if (node->pos != KDNODE_UNSET) {
+ tree->nodes[node->pos].parent = i;
+ }
+
+ /* build map */
+ BLI_assert(tree->nodes_map[node->index] == KDNODE_UNSET);
+ tree->nodes_map[node->index] = i;
+ }
+
+ tree->nodes[tree->root].parent = KDNODE_UNSET;
+}
+
+static void kdtree2d_node_remove(
+ struct KDTree2D *tree,
+ unsigned int index)
+{
+ unsigned int node_index = tree->nodes_map[index];
+ KDTreeNode2D *node;
+
+ if (node_index == KDNODE_UNSET) {
+ return;
+ }
+ else {
+ tree->nodes_map[index] = KDNODE_UNSET;
+ }
+
+ node = &tree->nodes[node_index];
+ tree->totnode -= 1;
+
+ BLI_assert((node->flag & KDNODE_FLAG_REMOVED) == 0);
+ node->flag |= KDNODE_FLAG_REMOVED;
+
+ while ((node->neg == KDNODE_UNSET) &&
+ (node->pos == KDNODE_UNSET) &&
+ (node->parent != KDNODE_UNSET))
+ {
+ KDTreeNode2D *node_parent = &tree->nodes[node->parent];
+
+ BLI_assert((unsigned int)(node - tree->nodes) == node_index);
+ if (node_parent->neg == node_index) {
+ node_parent->neg = KDNODE_UNSET;
+ }
+ else {
+ BLI_assert(node_parent->pos == node_index);
+ node_parent->pos = KDNODE_UNSET;
+ }
+
+ if (node_parent->flag & KDNODE_FLAG_REMOVED) {
+ node_index = node->parent;
+ node = node_parent;
+ }
+ else {
+ break;
+ }
+ }
+}
+
+static bool kdtree2d_isect_tri_recursive(
+ const struct KDTree2D *tree,
+ const unsigned int tri_index[3],
+ const float *tri_coords[3],
+ const float tri_center[2],
+ const struct KDRange2D bounds[2],
+ const KDTreeNode2D *node)
+{
+ const float *co = tree->coords[node->index];
+
+ /* bounds then triangle intersect */
+ if ((node->flag & KDNODE_FLAG_REMOVED) == 0) {
+ /* bounding box test first */
+ if ((co[0] >= bounds[0].min) &&
+ (co[0] <= bounds[0].max) &&
+ (co[1] >= bounds[1].min) &&
+ (co[1] <= bounds[1].max))
+ {
+ if ((span_tri_v2_sign(tri_coords[0], tri_coords[1], co) != CONCAVE) &&
+ (span_tri_v2_sign(tri_coords[1], tri_coords[2], co) != CONCAVE) &&
+ (span_tri_v2_sign(tri_coords[2], tri_coords[0], co) != CONCAVE))
+ {
+ if (!ELEM(node->index, tri_index[0], tri_index[1], tri_index[2])) {
+ return true;
+ }
+ }
+ }
+ }
+
+#define KDTREE2D_ISECT_TRI_RECURSE_NEG \
+ (((node->neg != KDNODE_UNSET) && (co[node->axis] > bounds[node->axis].min)) && \
+ (kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \
+ &tree->nodes[node->neg])))
+#define KDTREE2D_ISECT_TRI_RECURSE_POS \
+ (((node->pos != KDNODE_UNSET) && (co[node->axis] < bounds[node->axis].max)) && \
+ (kdtree2d_isect_tri_recursive(tree, tri_index, tri_coords, tri_center, bounds, \
+ &tree->nodes[node->pos])))
+
+ if (tri_center[node->axis] > co[node->axis]) {
+ if (KDTREE2D_ISECT_TRI_RECURSE_POS) {
+ return true;
+ }
+ if (KDTREE2D_ISECT_TRI_RECURSE_NEG) {
+ return true;
+ }
+ }
+ else {
+ if (KDTREE2D_ISECT_TRI_RECURSE_NEG) {
+ return true;
+ }
+ if (KDTREE2D_ISECT_TRI_RECURSE_POS) {
+ return true;
+ }
+ }
+
+#undef KDTREE2D_ISECT_TRI_RECURSE_NEG
+#undef KDTREE2D_ISECT_TRI_RECURSE_POS
+
+ BLI_assert(node->index != KDNODE_UNSET);
+
+ return false;
+}
+
+static bool kdtree2d_isect_tri(
+ struct KDTree2D *tree,
+ const unsigned int ind[3])
+{
+ const float *vs[3];
+ unsigned int i;
+ struct KDRange2D bounds[2] = {
+ {FLT_MAX, -FLT_MAX},
+ {FLT_MAX, -FLT_MAX},
+ };
+ float tri_center[2] = {0.0f, 0.0f};
+
+ for (i = 0; i < 3; i++) {
+ vs[i] = tree->coords[ind[i]];
+
+ add_v2_v2(tri_center, vs[i]);
+
+ CLAMP_MAX(bounds[0].min, vs[i][0]);
+ CLAMP_MIN(bounds[0].max, vs[i][0]);
+ CLAMP_MAX(bounds[1].min, vs[i][1]);
+ CLAMP_MIN(bounds[1].max, vs[i][1]);
+ }
+
+ mul_v2_fl(tri_center, 1.0f / 3.0f);
+
+ return kdtree2d_isect_tri_recursive(tree, ind, vs, tri_center, bounds, &tree->nodes[tree->root]);
+}
+
+#endif /* USE_KDTREE */
+
+
static unsigned int *pf_tri_add(PolyFill *pf)
{
return pf->tris[pf->tris_tot++];
}
-static void pf_coord_remove(PolyFill *pf, const unsigned int index)
+static void pf_coord_remove(PolyFill *pf, PolyIndex *pi)
{
- ARRAY_DELETE(pf->indices, index, 1, pf->coords_tot);
- ARRAY_DELETE(pf->coords_sign, index, 1, pf->coords_tot);
+#ifdef USE_KDTREE
+ /* avoid double lookups, since convex coords are ignored when testing intersections */
+ if (pf->kdtree.totnode) {
+ kdtree2d_node_remove(&pf->kdtree, pi->index);
+ }
+#endif
+
+ pi->next->prev = pi->prev;
+ pi->prev->next = pi->next;
+
+ if (UNLIKELY(pf->indices == pi)) {
+ pf->indices = pi->next;
+ }
+#ifdef DEBUG
+ pi->index = (unsigned int)-1;
+ pi->next = pi->prev = NULL;
+#endif
+
pf->coords_tot -= 1;
}
static void pf_triangulate(PolyFill *pf)
{
/* localize */
- eSign *coords_sign = pf->coords_sign;
-
- unsigned int index_ear_tip = 0;
+ PolyIndex *pi_ear;
+#ifdef USE_CLIP_EVEN
+ PolyIndex *pi_ear_init = pf->indices;
+#endif
+#ifdef USE_CLIP_SWEEP
+ bool reverse = false;
+#endif
while (pf->coords_tot > 3) {
- unsigned int i_prev, i_next;
-
-#ifdef USE_CONVEX_SKIP
+ PolyIndex *pi_prev, *pi_next;
eSign sign_orig_prev, sign_orig_next;
-#endif
+ pi_ear = pf_ear_tip_find(
+ pf
+#ifdef USE_CLIP_EVEN
+ , pi_ear_init
+#endif
+#ifdef USE_CLIP_SWEEP
+ , reverse
+#endif
+ );
+#ifdef USE_CLIP_SWEEP
#ifdef USE_CLIP_EVEN
- index_ear_tip = pf_ear_tip_find(pf, index_ear_tip);
+ if (pi_ear != pi_ear_init) {
+ reverse = !reverse;
+ }
#else
- index_ear_tip = pf_ear_tip_find(pf);
+ if (pi_ear != pf->indices) {
+ reverse = !reverse;
+ }
+#endif
#endif
#ifdef USE_CONVEX_SKIP
- if (coords_sign[index_ear_tip] != CONVEX) {
+ if (pi_ear->sign != CONVEX) {
pf->coords_tot_concave -= 1;
}
#endif
- pf_ear_tip_cut(pf, index_ear_tip);
+ pi_prev = pi_ear->prev;
+ pi_next = pi_ear->next;
+
+ pf_ear_tip_cut(pf, pi_ear);
/* The type of the two vertices adjacent to the clipped vertex may have changed. */
- i_prev = pf_index_prev(pf, index_ear_tip);
- i_next = (index_ear_tip == pf->coords_tot) ? 0 : index_ear_tip;
+ sign_orig_prev = pi_prev->sign;
+ sign_orig_next = pi_next->sign;
+ /* check if any verts became convex the (else if)
+ * case is highly unlikely but may happen with degenerate polygons */
+ if (sign_orig_prev != CONVEX) {
+ pf_coord_sign_calc(pf, pi_prev);
#ifdef USE_CONVEX_SKIP
- sign_orig_prev = coords_sign[i_prev];
- sign_orig_next = coords_sign[i_next];
+ if (pi_prev->sign == CONVEX) {
+ pf->coords_tot_concave -= 1;
+#ifdef USE_KDTREE
+ kdtree2d_node_remove(&pf->kdtree, pi_prev->index);
#endif
-
- coords_sign[i_prev] = pf_coord_sign_calc(pf, i_prev);
- coords_sign[i_next] = pf_coord_sign_calc(pf, i_next);
-
+ }
+#endif
+ }
+ if (sign_orig_next != CONVEX) {
+ pf_coord_sign_calc(pf, pi_next);
#ifdef USE_CONVEX_SKIP
- /* check if any verts became convex the (else if)
- * case is highly unlikely but may happen with degenerate polygons */
- if ((sign_orig_prev != CONVEX) && (coords_sign[i_prev] == CONVEX)) pf->coords_tot_concave -= 1;
- else if (UNLIKELY((sign_orig_prev == CONVEX) && (coords_sign[i_prev] != CONVEX))) pf->coords_tot_concave += 1;
-
- if ((sign_orig_next != CONVEX) && (coords_sign[i_next] == CONVEX)) pf->coords_tot_concave -= 1;
- else if (UNLIKELY((sign_orig_next == CONVEX) && (coords_sign[i_next] != CONVEX))) pf->coords_tot_concave += 1;
+ if (pi_next->sign == CONVEX) {
+ pf->coords_tot_concave -= 1;
+#ifdef USE_KDTREE
+ kdtree2d_node_remove(&pf->kdtree, pi_next->index);
#endif
+ }
+#endif
+ }
#ifdef USE_CLIP_EVEN
- index_ear_tip = i_prev;
+#ifdef USE_CLIP_SWEEP
+ pi_ear_init = reverse ? pi_prev->prev : pi_next->next;
+#else
+ pi_ear_init = pi_next->next;
#endif
+#endif
+
}
if (pf->coords_tot == 3) {
unsigned int *tri = pf_tri_add(pf);
- tri[0] = pf->indices[0];
- tri[1] = pf->indices[1];
- tri[2] = pf->indices[2];
+ pi_ear = pf->indices;
+ tri[0] = pi_ear->index; pi_ear = pi_ear->next;
+ tri[1] = pi_ear->index; pi_ear = pi_ear->next;
+ tri[2] = pi_ear->index;
}
}
/**
* \return CONCAVE, TANGENTIAL or CONVEX
*/
-static eSign pf_coord_sign_calc(PolyFill *pf, unsigned int index)
+static void pf_coord_sign_calc(PolyFill *pf, PolyIndex *pi)
{
/* localize */
- unsigned int *indices = pf->indices;
const float (*coords)[2] = pf->coords;
- return span_tri_v2_sign(
- coords[indices[pf_index_prev(pf, index)]],
- coords[indices[index]],
- coords[indices[pf_index_next(pf, index)]]);
+ pi->sign = span_tri_v2_sign(
+ coords[pi->prev->index],
+ coords[pi->index],
+ coords[pi->next->index]);
}
+static PolyIndex *pf_ear_tip_find(
+ PolyFill *pf
#ifdef USE_CLIP_EVEN
-static unsigned int pf_ear_tip_find(PolyFill *pf, const unsigned int index_offset)
-#else
-static unsigned int pf_ear_tip_find(PolyFill *pf)
+ , PolyIndex *pi_ear_init
+#endif
+#ifdef USE_CLIP_SWEEP
+ , bool reverse
#endif
+ )
{
/* localize */
- const eSign *coords_sign = pf->coords_sign;
const unsigned int coords_tot = pf->coords_tot;
+ PolyIndex *pi_ear;
unsigned int i;
+#ifdef USE_CLIP_EVEN
+ pi_ear = pi_ear_init;
+#else
+ pi_ear = pf->indices;
+#endif
i = coords_tot;
while (i--) {
-#ifdef USE_CLIP_EVEN
- unsigned int j = (i + index_offset) % coords_tot;
- if (pf_ear_tip_check(pf, j)) {
- return j;
+ if (pf_ear_tip_check(pf, pi_ear)) {
+ return pi_ear;
}
+#ifdef USE_CLIP_SWEEP
+ pi_ear = reverse ? pi_ear->prev : pi_ear->next;
#else
- if (pf_ear_tip_check(pf, i)) {
- return i;
- }
+ pi_ear = pi_ear->next;
#endif
}
@@ -250,36 +641,35 @@ static unsigned int pf_ear_tip_find(PolyFill *pf)
* Return a convex or tangential vertex if one exists.
*/
- i = coords_tot;
- while (i--) {
#ifdef USE_CLIP_EVEN
- unsigned int j = (i + index_offset) % coords_tot;
- if (coords_sign[j] != CONCAVE) {
- return j;
- }
+ pi_ear = pi_ear_init;
#else
- if (coords_sign[i] != CONCAVE) {
- return i;
- }
+ pi_ear = pf->indices;
#endif
+
+ i = coords_tot;
+ while (i--) {
+ if (pi_ear->sign != CONCAVE) {
+ return pi_ear;
+ }
+ pi_ear = pi_ear->next;
}
/* If all vertices are concave, just return the last one. */
- return coords_tot - 1;
+ return pi_ear;
}
-static bool pf_ear_tip_check(PolyFill *pf, const unsigned int index_ear_tip)
+static bool pf_ear_tip_check(PolyFill *pf, PolyIndex *pi_ear_tip)
{
+#ifndef USE_KDTREE
/* localize */
- const unsigned int *indices = pf->indices;
const float (*coords)[2] = pf->coords;
- const eSign *coords_sign = pf->coords_sign;
-
- unsigned int i_prev, i_curr, i_next;
+ PolyIndex *pi_curr;
const float *v1, *v2, *v3;
+#endif
-#ifdef USE_CONVEX_SKIP
+#if defined(USE_CONVEX_SKIP) && !defined(USE_KDTREE)
unsigned int coords_tot_concave_checked = 0;
#endif
@@ -292,7 +682,7 @@ static bool pf_ear_tip_check(PolyFill *pf, const unsigned int index_ear_tip)
unsigned int coords_tot_concave_test = 0;
unsigned int i = pf->coords_tot;
while (i--) {
- if (coords_sign[i] != CONVEX) {
+ if (coords_sign[indices[i]] != CONVEX) {
coords_tot_concave_test += 1;
}
}
@@ -306,31 +696,44 @@ static bool pf_ear_tip_check(PolyFill *pf, const unsigned int index_ear_tip)
}
#endif
- if (UNLIKELY(coords_sign[index_ear_tip] == CONCAVE)) {
+ if (UNLIKELY(pi_ear_tip->sign == CONCAVE)) {
return false;
}
- i_prev = pf_index_prev(pf, index_ear_tip);
- i_next = pf_index_next(pf, index_ear_tip);
+#ifdef USE_KDTREE
+ {
+ const unsigned int ind[3] = {
+ pi_ear_tip->index,
+ pi_ear_tip->next->index,
+ pi_ear_tip->prev->index};
- v1 = coords[indices[i_prev]];
- v2 = coords[indices[index_ear_tip]];
- v3 = coords[indices[i_next]];
+ if (kdtree2d_isect_tri(&pf->kdtree, ind)) {
+ return false;
+ }
+ }
+#else
+
+ v1 = coords[pi_ear_tip->prev->index];
+ v2 = coords[pi_ear_tip->index];
+ v3 = coords[pi_ear_tip->next->index];
/* Check if any point is inside the triangle formed by previous, current and next vertices.
* Only consider vertices that are not part of this triangle, or else we'll always find one inside. */
- for (i_curr = pf_index_next(pf, i_next); i_curr != i_prev; i_curr = pf_index_next(pf, i_curr)) {
+ for (pi_curr = pi_ear_tip->next->next; pi_curr != pi_ear_tip->prev; pi_curr = pi_curr->next) {
/* Concave vertices can obviously be inside the candidate ear, but so can tangential vertices
* if they coincide with one of the triangle's vertices. */
- if (coords_sign[i_curr] != CONVEX) {
- const float *v = coords[indices[i_curr]];
+ if (pi_curr->sign != CONVEX) {
+ const float *v = coords[pi_curr->index];
/* Because the polygon has clockwise winding order,
* the area sign will be positive if the point is strictly inside.
* It will be 0 on the edge, which we want to include as well. */
- if ((span_tri_v2_sign(v1, v2, v) != CONCAVE) &&
- (span_tri_v2_sign(v2, v3, v) != CONCAVE) &&
- (span_tri_v2_sign(v3, v1, v) != CONCAVE))
+
+ /* note: check (v3, v1) first since it fails _far_ more often then the other 2 checks (those fail equally).
+ * It's logical - the chance is low that points exist on the same side as the ear we're clipping off. */
+ if ((span_tri_v2_sign(v3, v1, v) != CONCAVE) &&
+ (span_tri_v2_sign(v1, v2, v) != CONCAVE) &&
+ (span_tri_v2_sign(v2, v3, v) != CONCAVE))
{
return false;
}
@@ -343,122 +746,192 @@ static bool pf_ear_tip_check(PolyFill *pf, const unsigned int index_ear_tip)
#endif
}
}
+#endif /* USE_KDTREE */
+
return true;
}
-static void pf_ear_tip_cut(PolyFill *pf, unsigned int index_ear_tip)
+static void pf_ear_tip_cut(PolyFill *pf, PolyIndex *pi_ear_tip)
{
unsigned int *tri = pf_tri_add(pf);
- tri[0] = pf->indices[pf_index_prev(pf, index_ear_tip)];
- tri[1] = pf->indices[index_ear_tip];
- tri[2] = pf->indices[pf_index_next(pf, index_ear_tip)];
-
- pf_coord_remove(pf, index_ear_tip);
-}
-
-static unsigned int pf_index_prev(const PolyFill *pf, const unsigned int index)
-{
- return (index ? index : pf->coords_tot) - 1;
-}
+ tri[0] = pi_ear_tip->prev->index;
+ tri[1] = pi_ear_tip->index;
+ tri[2] = pi_ear_tip->next->index;
-static unsigned int pf_index_next(const PolyFill *pf, unsigned index)
-{
- return (index + 1) % pf->coords_tot;
+ pf_coord_remove(pf, pi_ear_tip);
}
/**
* Triangulates the given (convex or concave) simple polygon to a list of triangle vertices.
- * \param vertices pairs describing vertices of the polygon, in either clockwise or counterclockwise order.
+ *
+ * \param coords pairs describing vertices of the polygon, in either clockwise or counterclockwise order.
* \return triples of triangle indices in clockwise order.
* Note the returned array is reused for later calls to the same method.
*/
-void BLI_polyfill_calc_ex(
+static void polyfill_prepare(
+ PolyFill *pf,
const float (*coords)[2],
const unsigned int coords_tot,
+ int coords_sign,
unsigned int (*r_tris)[3],
-
- unsigned int *r_indices, eSign *r_coords_sign)
+ PolyIndex *r_indices)
{
- PolyFill pf;
-
/* localize */
- unsigned int *indices = r_indices;
- eSign *coords_sign = r_coords_sign;
+ PolyIndex *indices = r_indices;
unsigned int i;
/* assign all polyfill members here */
- pf.indices = r_indices;
- pf.coords = coords;
- pf.coords_tot = coords_tot;
- pf.coords_sign = r_coords_sign;
+ pf->indices = r_indices;
+ pf->coords = coords;
+ pf->coords_tot = coords_tot;
#ifdef USE_CONVEX_SKIP
- pf.coords_tot_concave = 0;
+ pf->coords_tot_concave = 0;
#endif
- pf.tris = r_tris;
- pf.tris_tot = 0;
+ pf->tris = r_tris;
+ pf->tris_tot = 0;
- if ((coords_tot < 3) ||
- cross_poly_v2(coords, coords_tot) > 0.0f)
- {
+ if (coords_sign == 0) {
+ coords_sign = (cross_poly_v2(coords, coords_tot) >= 0.0f) ? 1 : -1;
+ }
+ else {
+ /* chech we're passing in correcty args */
+#ifndef NDEBUG
+ if (coords_sign == 1) {
+ BLI_assert(cross_poly_v2(coords, coords_tot) >= 0.0f);
+ }
+ else {
+ BLI_assert(cross_poly_v2(coords, coords_tot) <= 0.0f);
+ }
+#endif
+ }
+
+ if (coords_sign == 1) {
for (i = 0; i < coords_tot; i++) {
- indices[i] = i;
+ indices[i].next = &indices[i + 1];
+ indices[i].prev = &indices[i - 1];
+ indices[i].index = i;
}
}
else {
/* reversed */
unsigned int n = coords_tot - 1;
for (i = 0; i < coords_tot; i++) {
- indices[i] = (n - i);
+ indices[i].next = &indices[i + 1];
+ indices[i].prev = &indices[i - 1];
+ indices[i].index = (n - i);
}
}
+ indices[0].prev = &indices[coords_tot - 1];
+ indices[coords_tot - 1].next = &indices[0];
for (i = 0; i < coords_tot; i++) {
- coords_sign[i] = pf_coord_sign_calc(&pf, i);
+ PolyIndex *pi = &indices[i];
+ pf_coord_sign_calc(pf, pi);
#ifdef USE_CONVEX_SKIP
- if (coords_sign[i] != CONVEX) {
- pf.coords_tot_concave += 1;
+ if (pi->sign != CONVEX) {
+ pf->coords_tot_concave += 1;
}
#endif
}
+}
- pf_triangulate(&pf);
+static void polyfill_calc(
+ PolyFill *pf)
+{
+#ifdef USE_KDTREE
+#ifdef USE_CONVEX_SKIP
+ if (pf->coords_tot_concave)
+#endif
+ {
+ kdtree2d_new(&pf->kdtree, pf->coords_tot_concave, pf->coords);
+ kdtree2d_init(&pf->kdtree, pf->coords_tot, pf->indices);
+ kdtree2d_balance(&pf->kdtree);
+ kdtree2d_init_mapping(&pf->kdtree);
+ }
+#endif
+
+ pf_triangulate(pf);
}
void BLI_polyfill_calc_arena(
const float (*coords)[2],
const unsigned int coords_tot,
+ const int coords_sign,
unsigned int (*r_tris)[3],
struct MemArena *arena)
{
- unsigned int *indices = BLI_memarena_alloc(arena, sizeof(*indices) * coords_tot);
- eSign *coords_sign = BLI_memarena_alloc(arena, sizeof(*coords_sign) * coords_tot);
+ PolyFill pf;
+ PolyIndex *indices = BLI_memarena_alloc(arena, sizeof(*indices) * coords_tot);
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(polyfill2d);
+#endif
- BLI_polyfill_calc_ex(
- coords, coords_tot,
+ polyfill_prepare(
+ &pf,
+ coords, coords_tot, coords_sign,
r_tris,
/* cache */
+ indices);
- indices, coords_sign);
+#ifdef USE_KDTREE
+ if (pf.coords_tot_concave) {
+ pf.kdtree.nodes = BLI_memarena_alloc(arena, sizeof(*pf.kdtree.nodes) * pf.coords_tot_concave);
+ pf.kdtree.nodes_map = memset(BLI_memarena_alloc(arena, sizeof(*pf.kdtree.nodes_map) * coords_tot),
+ 0xff, sizeof(*pf.kdtree.nodes_map) * coords_tot);
+ }
+ else {
+ pf.kdtree.totnode = 0;
+ }
+#endif
+
+ polyfill_calc(&pf);
- /* indices & coords_sign are no longer needed,
+ /* indices are no longer needed,
* caller can clear arena */
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(polyfill2d);
+#endif
}
void BLI_polyfill_calc(
const float (*coords)[2],
const unsigned int coords_tot,
+ const int coords_sign,
unsigned int (*r_tris)[3])
{
- unsigned int *indices = BLI_array_alloca(indices, coords_tot);
- eSign *coords_sign = BLI_array_alloca(coords_sign, coords_tot);
+ PolyFill pf;
+ PolyIndex *indices = BLI_array_alloca(indices, coords_tot);
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(polyfill2d);
+#endif
- BLI_polyfill_calc_ex(
- coords, coords_tot,
+ polyfill_prepare(
+ &pf,
+ coords, coords_tot, coords_sign,
r_tris,
/* cache */
+ indices);
- indices, coords_sign);
+#ifdef USE_KDTREE
+ if (pf.coords_tot_concave) {
+ pf.kdtree.nodes = BLI_array_alloca(pf.kdtree.nodes, pf.coords_tot_concave);
+ pf.kdtree.nodes_map = memset(BLI_array_alloca(pf.kdtree.nodes_map, coords_tot),
+ 0xff, sizeof(*pf.kdtree.nodes_map) * coords_tot);
+ }
+ else {
+ pf.kdtree.totnode = 0;
+ }
+#endif
+
+ polyfill_calc(&pf);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(polyfill2d);
+#endif
}
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index 5d78608e70c..59ccf381f29 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -36,8 +36,6 @@
#include "MEM_guardedalloc.h"
-#include "PIL_time.h"
-
#include "BLI_threads.h"
#include "BLI_rand.h"
#include "BLI_math.h"
@@ -97,15 +95,20 @@ void BLI_rng_srandom(RNG *rng, unsigned int seed)
BLI_rng_seed(rng, seed + hash[seed & 255]);
}
-int BLI_rng_get_int(RNG *rng)
+BLI_INLINE void rng_step(RNG *rng)
{
rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK;
+}
+
+int BLI_rng_get_int(RNG *rng)
+{
+ rng_step(rng);
return (int) (rng->X >> 17);
}
unsigned int BLI_rng_get_uint(RNG *rng)
{
- rng->X = (MULTIPLIER * rng->X + ADDEND) & MASK;
+ rng_step(rng);
return (unsigned int) (rng->X >> 17);
}
@@ -119,6 +122,13 @@ float BLI_rng_get_float(RNG *rng)
return (float) BLI_rng_get_int(rng) / 0x80000000;
}
+void BLI_rng_get_float_unit_v2(RNG *rng, float v[2])
+{
+ float a = (float)(M_PI * 2.0) * BLI_rng_get_float(rng);
+ v[0] = cosf(a);
+ v[1] = sinf(a);
+}
+
void BLI_rng_get_float_unit_v3(RNG *rng, float v[3])
{
float r;
@@ -162,10 +172,9 @@ void BLI_rng_shuffle_array(RNG *rng, void *data, unsigned int elem_size_i, unsig
void BLI_rng_skip(RNG *rng, int n)
{
- int i;
-
- for (i = 0; i < n; i++)
- BLI_rng_get_int(rng);
+ while (n--) {
+ rng_step(rng);
+ }
}
/***/
@@ -236,3 +245,29 @@ float BLI_thread_frand(int thread)
return BLI_rng_get_float(&rng_tab[thread]);
}
+struct RNG_THREAD_ARRAY {
+ RNG rng_tab[BLENDER_MAX_THREADS];
+};
+
+RNG_THREAD_ARRAY *BLI_rng_threaded_new(void)
+{
+ unsigned int i;
+ RNG_THREAD_ARRAY *rngarr = MEM_mallocN(sizeof(RNG_THREAD_ARRAY), "random_array");
+
+ for (i = 0; i < BLENDER_MAX_THREADS; i++) {
+ BLI_rng_srandom(&rngarr->rng_tab[i], (unsigned int)clock());
+ }
+
+ return rngarr;
+}
+
+void BLI_rng_threaded_free(struct RNG_THREAD_ARRAY *rngarr)
+{
+ MEM_freeN(rngarr);
+}
+
+int BLI_rng_thread_rand(RNG_THREAD_ARRAY *rngarr, int thread)
+{
+ return BLI_rng_get_int(&rngarr->rng_tab[thread]);
+}
+
diff --git a/source/blender/blenlib/intern/scanfill.c b/source/blender/blenlib/intern/scanfill.c
index 05e4984d9a3..cf0d8cff870 100644
--- a/source/blender/blenlib/intern/scanfill.c
+++ b/source/blender/blenlib/intern/scanfill.c
@@ -865,6 +865,9 @@ unsigned int BLI_scanfill_calc_ex(ScanFillContext *sf_ctx, const int flag, const
/* Newell's Method */
/* Similar code used elsewhere, but this checks for double ups
* which historically this function supports so better not change */
+
+ /* warning: this only gives stable direction with single polygons,
+ * ideally we'd calculate connectivity and each polys normal, see T41047 */
const float *v_prev;
zero_v3(n);
diff --git a/source/blender/blenlib/intern/scanfill_utils.c b/source/blender/blenlib/intern/scanfill_utils.c
index 828cb3a580b..9fc1db1f1e4 100644
--- a/source/blender/blenlib/intern/scanfill_utils.c
+++ b/source/blender/blenlib/intern/scanfill_utils.c
@@ -132,12 +132,12 @@ static ListBase *edge_isect_ls_add(GHash *isect_hash, ScanFillEdge *eed, ScanFil
return e_ls;
}
-static int edge_isect_ls_sort_cb(void *thunk, void *def_a_ptr, void *def_b_ptr)
+static int edge_isect_ls_sort_cb(void *thunk, const void *def_a_ptr, const void *def_b_ptr)
{
const float *co = thunk;
- ScanFillIsect *i_a = (ScanFillIsect *)(((LinkData *)def_a_ptr)->data);
- ScanFillIsect *i_b = (ScanFillIsect *)(((LinkData *)def_b_ptr)->data);
+ const ScanFillIsect *i_a = ((LinkData *)def_a_ptr)->data;
+ const ScanFillIsect *i_b = ((LinkData *)def_b_ptr)->data;
const float a = len_squared_v2v2(co, i_a->co);
const float b = len_squared_v2v2(co, i_b->co);
diff --git a/source/blender/blenlib/intern/smallhash.c b/source/blender/blenlib/intern/smallhash.c
index d6b2383bd47..0cf9f69b9ae 100644
--- a/source/blender/blenlib/intern/smallhash.c
+++ b/source/blender/blenlib/intern/smallhash.c
@@ -44,8 +44,6 @@
*
* Note that the values and keys are often pointers or index values,
* use the maximum values to avoid real pointers colliding with magic numbers.
- *
- * \note these have the SMHASH prefix because we may want to make them public.
*/
#include <string.h>
@@ -86,6 +84,11 @@ BLI_INLINE bool smallhash_val_is_used(const void *val)
extern const unsigned int hashsizes[];
+BLI_INLINE unsigned int smallhash_key(const uintptr_t key)
+{
+ return (unsigned int)key;
+}
+
/**
* Check if the number of items in the smallhash is large enough to require more buckets.
*/
@@ -118,7 +121,7 @@ BLI_INLINE void smallhash_buckets_reserve(SmallHash *sh, const unsigned int nent
BLI_INLINE SmallHashEntry *smallhash_lookup(SmallHash *sh, const uintptr_t key)
{
SmallHashEntry *e;
- unsigned int h = (unsigned int)key;
+ unsigned int h = smallhash_key(key);
unsigned int hoff = 1;
BLI_assert(key != SMHASH_KEY_UNUSED);
@@ -142,7 +145,7 @@ BLI_INLINE SmallHashEntry *smallhash_lookup(SmallHash *sh, const uintptr_t key)
BLI_INLINE SmallHashEntry *smallhash_lookup_first_free(SmallHash *sh, const uintptr_t key)
{
SmallHashEntry *e;
- unsigned int h = (unsigned int)key;
+ unsigned int h = smallhash_key(key);
unsigned int hoff = 1;
for (e = &sh->buckets[h % sh->nbuckets];
@@ -312,6 +315,9 @@ void *BLI_smallhash_iternew(SmallHash *sh, SmallHashIter *iter, uintptr_t *key)
return BLI_smallhash_iternext(iter, key);
}
+/** \name Debugging & Introspection
+ * \{ */
+
/* note, this was called _print_smhash in knifetool.c
* it may not be intended for general use - campbell */
#if 0
@@ -345,3 +351,41 @@ void BLI_smallhash_print(SmallHash *sh)
fflush(stdout);
}
#endif
+
+#ifdef DEBUG
+/**
+ * Measure how well the hash function performs
+ * (1.0 is perfect - no stepping needed).
+ *
+ * Smaller is better!
+ */
+double BLI_smallhash_calc_quality(SmallHash *sh)
+{
+ uint64_t sum = 0;
+ unsigned int i;
+
+ if (sh->nentries == 0)
+ return -1.0;
+
+ for (i = 0; i < sh->nbuckets; i++) {
+ if (sh->buckets[i].key != SMHASH_KEY_UNUSED) {
+ uint64_t count = 0;
+ SmallHashEntry *e, *e_final = &sh->buckets[i];
+ unsigned int h = smallhash_key(e_final->key);
+ unsigned int hoff = 1;
+
+ for (e = &sh->buckets[h % sh->nbuckets];
+ e != e_final;
+ h = SMHASH_NEXT(h, hoff), e = &sh->buckets[h % sh->nbuckets])
+ {
+ count += 1;
+ }
+
+ sum += count;
+ }
+ }
+ return ((double)(sh->nentries + sum) / (double)sh->nentries);
+}
+#endif
+
+/** \} */
diff --git a/source/blender/blenlib/intern/sort.c b/source/blender/blenlib/intern/sort.c
index a1b7296feb6..c5922feb0ed 100644
--- a/source/blender/blenlib/intern/sort.c
+++ b/source/blender/blenlib/intern/sort.c
@@ -32,10 +32,15 @@
#include <stdlib.h>
+#if defined(__GLIBC__) && (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8))
+/* do nothing! */
+#else
+
#include "BLI_utildefines.h"
#include "BLI_sort.h"
+/* note: modified to use glibc arg order for callback */
/* **** qsort based on FreeBSD source (libkern\qsort.c) **** */
BLI_INLINE char *med3(char *, char *, char *, BLI_sort_cmp_t, void *);
BLI_INLINE void swapfunc(char *, char *, int, int);
@@ -72,7 +77,7 @@ BLI_INLINE void swapfunc(char *a, char *b, int n, int swaptype)
swapfunc(a, b, es, swaptype)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
-#define CMP(t, x, y) (cmp((t), (x), (y)))
+#define CMP(t, x, y) (cmp((x), (y), (t)))
BLI_INLINE char *med3(char *a, char *b, char *c, BLI_sort_cmp_t cmp, void *thunk)
{
@@ -86,7 +91,7 @@ BLI_INLINE char *med3(char *a, char *b, char *c, BLI_sort_cmp_t cmp, void *thunk
*
* \note Follows BSD arg order (incompatible with glibc).
*/
-void BLI_qsort_r(void *a, size_t n, size_t es, void *thunk, BLI_sort_cmp_t cmp)
+void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk)
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
@@ -163,7 +168,7 @@ loop:
r = min(pd - pc, pn - pd - es);
vecswap(pb, pn - r, r);
if ((r = pb - pa) > es)
- BLI_qsort_r(a, r / es, es, thunk, cmp);
+ BLI_qsort_r(a, r / es, es, cmp, thunk);
if ((r = pd - pc) > es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
@@ -171,3 +176,5 @@ loop:
goto loop;
}
}
+
+#endif /* __GLIBC__ */
diff --git a/source/blender/blenlib/intern/stack.c b/source/blender/blenlib/intern/stack.c
index 5be2ed941a7..2d3a2f77a3e 100644
--- a/source/blender/blenlib/intern/stack.c
+++ b/source/blender/blenlib/intern/stack.c
@@ -28,83 +28,223 @@
#include <string.h>
#include <stdlib.h> /* abort() */
-#include "BLI_stack.h" /* own include */
-
#include "BLI_utildefines.h"
#include "MEM_guardedalloc.h"
-struct BLI_Stack {
- void *data;
+#include "BLI_stack.h" /* own include */
+
+#include "BLI_strict_flags.h"
+
+#define USE_TOTELEM
+
+#define CHUNK_EMPTY ((size_t)-1)
+/* target chunks size: 64kb */
+#define CHUNK_SIZE_DEFAULT (1 << 16)
+/* ensure we get at least this many elems per chunk */
+#define CHUNK_ELEM_MIN 32
+
+/* Gets the last element in the stack */
+#define CHUNK_LAST_ELEM(_stack) \
+ ((void)0, (((char *)(_stack)->chunk_curr->data) + \
+ ((_stack)->elem_size * (_stack)->chunk_index)))
- int totelem;
- int maxelem;
+struct StackChunk {
+ struct StackChunk *next;
+ char data[0];
+};
- int elem_size;
+struct BLI_Stack {
+ struct StackChunk *chunk_curr; /* currently active chunk */
+ struct StackChunk *chunk_free; /* free chunks */
+ size_t chunk_index; /* index into 'chunk_curr' */
+ size_t chunk_elem_max; /* number of elements per chunk */
+ size_t elem_size;
+#ifdef USE_TOTELEM
+ size_t totelem;
+#endif
};
-BLI_Stack *BLI_stack_new(int elem_size, const char *description)
+/**
+ * \return number of elements per chunk, optimized for slop-space.
+ */
+static size_t stack_chunk_elem_max_calc(const size_t elem_size, size_t chunk_size)
+{
+ /* get at least this number of elems per chunk */
+ const size_t elem_size_min = elem_size * CHUNK_ELEM_MIN;
+
+ BLI_assert((elem_size != 0) && (chunk_size != 0));
+
+ while (UNLIKELY(chunk_size <= elem_size_min)) {
+ chunk_size <<= 1;
+ }
+
+ /* account for slop-space */
+ chunk_size -= (sizeof(struct StackChunk) + MEM_SIZE_OVERHEAD);
+
+ return chunk_size / elem_size;
+}
+
+BLI_Stack *BLI_stack_new_ex(const size_t elem_size, const char *description,
+ const size_t chunk_size)
{
BLI_Stack *stack = MEM_callocN(sizeof(*stack), description);
+ stack->chunk_elem_max = stack_chunk_elem_max_calc(elem_size, chunk_size);
stack->elem_size = elem_size;
+ /* force init */
+ stack->chunk_index = stack->chunk_elem_max - 1;
return stack;
}
-void BLI_stack_free(BLI_Stack *stack)
+/**
+ * Create a new homogeneous stack with elements of 'elem_size' bytes.
+ */
+BLI_Stack *BLI_stack_new(const size_t elem_size, const char *description)
+{
+ return BLI_stack_new_ex(elem_size, description, CHUNK_SIZE_DEFAULT);
+}
+
+static void stack_free_chunks(struct StackChunk *data)
{
- if (stack) {
- if (stack->data)
- MEM_freeN(stack->data);
- MEM_freeN(stack);
+ while (data) {
+ struct StackChunk *data_next = data->next;
+ MEM_freeN(data);
+ data = data_next;
}
}
-/* Gets the last element in the stack */
-#define STACK_LAST_ELEM(stack__) \
- (((char *)(stack__)->data) + \
- ((stack__)->elem_size * ((stack__)->totelem - 1)))
+/**
+ * Free the stack's data and the stack itself
+ */
+void BLI_stack_free(BLI_Stack *stack)
+{
+ stack_free_chunks(stack->chunk_curr);
+ stack_free_chunks(stack->chunk_free);
+ MEM_freeN(stack);
+}
-void BLI_stack_push(BLI_Stack *stack, void *src)
+/**
+ * Copies the source value onto the stack (note that it copies
+ * elem_size bytes from 'src', the pointer itself is not stored)
+ */
+void *BLI_stack_push_r(BLI_Stack *stack)
{
- /* Ensure stack is large enough */
- if (stack->totelem == stack->maxelem) {
- if (stack->maxelem == 0) {
- /* Initialize stack with space for a small hardcoded
- * number of elements */
- stack->maxelem = 32;
- stack->data = MEM_mallocN((stack->elem_size *
- stack->maxelem), AT);
+ stack->chunk_index++;
+
+ if (UNLIKELY(stack->chunk_index == stack->chunk_elem_max)) {
+ struct StackChunk *chunk;
+ if (stack->chunk_free) {
+ chunk = stack->chunk_free;
+ stack->chunk_free = chunk->next;
}
else {
- /* Double stack size */
- int maxelem = stack->maxelem + stack->maxelem;
- /* Check for overflow */
- BLI_assert(maxelem > stack->maxelem);
- stack->data = MEM_reallocN(stack->data,
- (stack->elem_size *
- maxelem));
- stack->maxelem = maxelem;
+ chunk = MEM_mallocN(
+ sizeof(*chunk) + (stack->elem_size * stack->chunk_elem_max),
+ __func__);
}
+ chunk->next = stack->chunk_curr;
+ stack->chunk_curr = chunk;
+ stack->chunk_index = 0;
}
- BLI_assert(stack->totelem < stack->maxelem);
+ BLI_assert(stack->chunk_index < stack->chunk_elem_max);
- /* Copy source to end of stack */
+#ifdef USE_TOTELEM
stack->totelem++;
- memcpy(STACK_LAST_ELEM(stack), src, stack->elem_size);
+#endif
+
+ /* Return end of stack */
+ return CHUNK_LAST_ELEM(stack);
+}
+
+void BLI_stack_push(BLI_Stack *stack, const void *src)
+{
+ void *dst = BLI_stack_push_r(stack);
+ memcpy(dst, src, stack->elem_size);
}
+/**
+ * Retrieves and removes the top element from the stack.
+ * The value is copies to \a dst, which must be at least \a elem_size bytes.
+ *
+ * Does not reduce amount of allocated memory.
+ */
void BLI_stack_pop(BLI_Stack *stack, void *dst)
{
- BLI_assert(stack->totelem > 0);
- if (stack->totelem > 0) {
- memcpy(dst, STACK_LAST_ELEM(stack), stack->elem_size);
- stack->totelem--;
+ BLI_assert(BLI_stack_is_empty(stack) == false);
+
+ memcpy(dst, CHUNK_LAST_ELEM(stack), stack->elem_size);
+
+ BLI_stack_discard(stack);
+}
+
+void BLI_stack_pop_n(BLI_Stack *stack, void *dst, unsigned int n)
+{
+ BLI_assert(n <= BLI_stack_count(stack));
+
+ while (n--) {
+ BLI_stack_pop(stack, dst);
+ dst = (void *)((char *)dst + stack->elem_size);
}
}
-int BLI_stack_empty(const BLI_Stack *stack)
+void *BLI_stack_peek(BLI_Stack *stack)
+{
+ BLI_assert(BLI_stack_is_empty(stack) == false);
+
+ return CHUNK_LAST_ELEM(stack);
+}
+
+void BLI_stack_discard(BLI_Stack *stack)
+{
+ BLI_assert(BLI_stack_is_empty(stack) == false);
+
+#ifdef USE_TOTELEM
+ stack->totelem--;
+#endif
+ if (UNLIKELY(--stack->chunk_index == CHUNK_EMPTY)) {
+ struct StackChunk *chunk_free;
+
+ chunk_free = stack->chunk_curr;
+ stack->chunk_curr = stack->chunk_curr->next;
+
+ chunk_free->next = stack->chunk_free;
+ stack->chunk_free = chunk_free;
+
+ stack->chunk_index = stack->chunk_elem_max - 1;
+ }
+}
+
+size_t BLI_stack_count(const BLI_Stack *stack)
+{
+#ifdef USE_TOTELEM
+ return stack->totelem;
+#else
+ struct StackChunk *data = stack->chunk_curr;
+ size_t totelem = stack->chunk_index + 1;
+ size_t i;
+ if (totelem != stack->chunk_elem_max) {
+ data = data->next;
+ }
+ else {
+ totelem = 0;
+ }
+ for (i = 0; data; data = data->next) {
+ i++;
+ }
+ totelem += stack->chunk_elem_max * i;
+ return totelem;
+#endif
+}
+
+/**
+ * Returns true if the stack is empty, false otherwise
+ */
+bool BLI_stack_is_empty(const BLI_Stack *stack)
{
- return stack->totelem == 0;
+#ifdef USE_TOTELEM
+ BLI_assert((stack->chunk_curr == NULL) == (stack->totelem == 0));
+#endif
+ return (stack->chunk_curr == NULL);
}
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 2c6fc9f2058..f3ecc799e1e 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -255,22 +255,7 @@ static void bli_builddir(struct BuildDirCtx *dir_ctx, const char *dirname)
file->relname = dlink->name;
file->path = BLI_strdupcat(dirname, dlink->name);
BLI_join_dirfile(fullname, sizeof(fullname), dirname, dlink->name);
-// use 64 bit file size, only needed for WIN32 and WIN64.
-// Excluding other than current MSVC compiler until able to test
-#ifdef WIN32
- {
- wchar_t *name_16 = alloc_utf16_from_8(fullname, 0);
-#if defined(_MSC_VER) && (_MSC_VER >= 1500)
- _wstat64(name_16, &file->s);
-#elif defined(__MINGW32__)
- _stati64(fullname, &file->s);
-#endif
- free(name_16);
- }
-
-#else
- stat(fullname, &file->s);
-#endif
+ BLI_stat(fullname, &file->s);
file->type = file->s.st_mode;
file->flags = 0;
dir_ctx->nrfiles++;
@@ -460,7 +445,7 @@ size_t BLI_file_descriptor_size(int file)
*/
size_t BLI_file_size(const char *path)
{
- struct stat stats;
+ BLI_stat_t stats;
if (BLI_stat(path, &stats) == -1)
return -1;
return stats.st_size;
@@ -473,11 +458,7 @@ size_t BLI_file_size(const char *path)
int BLI_exists(const char *name)
{
#if defined(WIN32)
-#ifndef __MINGW32__
- struct _stat64i32 st;
-#else
- struct _stati64 st;
-#endif
+ BLI_stat_t st;
wchar_t *tmp_16 = alloc_utf16_from_8(name, 1);
int len, res;
unsigned int old_error_mode;
@@ -506,11 +487,7 @@ int BLI_exists(const char *name)
* when looking for a file on an empty CD/DVD drive */
old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
-#ifndef __MINGW32__
- res = _wstat(tmp_16, &st);
-#else
- res = _wstati64(tmp_16, &st);
-#endif
+ res = BLI_wstat(tmp_16, &st);
SetErrorMode(old_error_mode);
@@ -525,21 +502,27 @@ int BLI_exists(const char *name)
#ifdef WIN32
-int BLI_stat(const char *path, struct stat *buffer)
+int BLI_stat(const char *path, BLI_stat_t *buffer)
{
int r;
UTF16_ENCODE(path);
- /* workaround error in MinGW64 headers, normally, a wstat should work */
-#ifndef __MINGW64__
- r = _wstat(path_16, buffer);
-#else
- r = _wstati64(path_16, buffer);
-#endif
+ r = BLI_wstat(path_16, buffer);
UTF16_UN_ENCODE(path);
return r;
}
+
+int BLI_wstat(const wchar_t *path, BLI_stat_t *buffer)
+{
+#if defined(_MSC_VER) || defined(__MINGW64__)
+ return _wstat64(path, buffer);
+#elif defined(__MINGW32__)
+ return _wstati64(path, buffer);
+#else
+ return _wstat(path, buffer);
+#endif
+}
#else
int BLI_stat(const char *path, struct stat *buffer)
{
diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c
index 892bb16a543..eeafc1a9e8f 100644
--- a/source/blender/blenlib/intern/string.c
+++ b/source/blender/blenlib/intern/string.c
@@ -295,11 +295,21 @@ char *BLI_str_quoted_substrN(const char *__restrict str, const char *__restrict
startMatch = strstr(str, prefix) + prefixLen + 1;
if (startMatch) {
/* get the end point (i.e. where the next occurance of " is after the starting point) */
- endMatch = strchr(startMatch, '"'); /* " NOTE: this comment here is just so that my text editor still shows the functions ok... */
-
- if (endMatch)
+
+ endMatch = startMatch;
+ while ((endMatch = strchr(endMatch, '"'))) {
+ if (LIKELY(*(endMatch - 1) != '\\')) {
+ break;
+ }
+ else {
+ endMatch++;
+ }
+ }
+
+ if (endMatch) {
/* return the slice indicated */
return BLI_strdupn(startMatch, (size_t)(endMatch - startMatch));
+ }
}
return BLI_strdupn("", 0);
}
@@ -629,3 +639,140 @@ int BLI_str_rstrip_float_zero(char *str, const char pad)
return totstrip;
}
+
+/**
+ * Return index of a string in a string array.
+ *
+ * \param str The string to find.
+ * \param str_array Array of strings.
+ * \param str_array_len The length of the array, or -1 for a NULL-terminated array.
+ * \return The index of str in str_array or -1.
+ */
+int BLI_str_index_in_array_n(const char *__restrict str, const char **__restrict str_array, const int str_array_len)
+{
+ int index;
+ const char **str_iter = str_array;
+
+ for (index = 0; index < str_array_len; str_iter++, index++) {
+ if (STREQ(str, *str_iter)) {
+ return index;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Return index of a string in a string array.
+ *
+ * \param str The string to find.
+ * \param str_array Array of strings, (must be NULL-terminated).
+ * \return The index of str in str_array or -1.
+ */
+int BLI_str_index_in_array(const char *__restrict str, const char **__restrict str_array)
+{
+ int index;
+ const char **str_iter = str_array;
+
+ for (index = 0; *str_iter; str_iter++, index++) {
+ if (STREQ(str, *str_iter)) {
+ return index;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Find the first char matching one of the chars in \a delim, from left.
+ *
+ * \param str The string to search within.
+ * \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).
+ * \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)
+{
+ return BLI_str_partition_ex(str, delim, sep, suf, false);
+}
+
+/**
+ * Find the first char matching one of the chars in \a delim, from right.
+ *
+ * \param str The string to search within.
+ * \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).
+ * \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)
+{
+ return BLI_str_partition_ex(str, 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 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)
+{
+ const char *d;
+ char *(*func)(const char *str, int c) = from_right ? strrchr : strchr;
+
+ *sep = *suf = NULL;
+
+ for (d = delim; *d != '\0'; ++d) {
+ char *tmp = func(str, *d);
+
+ if (tmp && (from_right ? (*sep < tmp) : (!*sep || *sep > tmp))) {
+ *sep = tmp;
+ }
+ }
+
+ if (*sep) {
+ *suf = *sep + 1;
+ return (size_t)(*sep - str);
+ }
+
+ return strlen(str);
+}
+
+/**
+ * Format ints with decimal grouping.
+ * 1000 -> 1,000
+ *
+ * \param dst The resulting string
+ * \param num Number to format
+ * \return The length of \a dst
+ */
+size_t BLI_str_format_int_grouped(char dst[16], int num)
+{
+ char src[16];
+ char *p_src = src;
+ char *p_dst = dst;
+
+ const char separator = ',';
+ int num_len, commas;
+
+ num_len = sprintf(src, "%d", num);
+
+ if (*p_src == '-') {
+ *p_dst++ = *p_src++;
+ num_len--;
+ }
+
+ for (commas = 2 - num_len % 3; *p_src; commas = (commas + 1) % 3) {
+ *p_dst++ = *p_src++;
+ if (commas == 1) {
+ *p_dst++ = separator;
+ }
+ }
+ *--p_dst = '\0';
+
+ return (size_t)(p_dst - dst);
+}
diff --git a/source/blender/blenlib/intern/string_utf8.c b/source/blender/blenlib/intern/string_utf8.c
index 74e979a8579..9697fcf09e9 100644
--- a/source/blender/blenlib/intern/string_utf8.c
+++ b/source/blender/blenlib/intern/string_utf8.c
@@ -703,3 +703,49 @@ 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)
+{
+ return BLI_str_partition_ex_utf8(str, delim, sep, suf, false);
+}
+
+size_t BLI_str_rpartition_utf8(const char *str, const unsigned int delim[], char **sep, char **suf)
+{
+ return BLI_str_partition_ex_utf8(str, 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)
+{
+ const unsigned int *d;
+ const size_t str_len = strlen(str);
+ size_t index;
+
+ *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))
+ {
+ const unsigned int c = BLI_str_utf8_as_unicode_and_size(*sep, &index);
+
+ if (c == BLI_UTF8_ERR) {
+ *suf = *sep = NULL;
+ break;
+ }
+
+ for (d = delim; *d != '\0'; ++d) {
+ if (*d == c) {
+ /* *suf is already correct in case from_right is true. */
+ if (!from_right)
+ *suf = (char *)(str + index);
+ return (size_t)(*sep - str);
+ }
+ }
+
+ *suf = *sep; /* Useful in 'from_right' case! */
+ }
+
+ *suf = *sep = NULL;
+ return str_len;
+}
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 8d867b9f295..07c67f001f9 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -428,3 +428,115 @@ size_t BLI_task_pool_tasks_done(TaskPool *pool)
return pool->done;
}
+/* Parallel range routines */
+
+/**
+ *
+ * Main functions:
+ * - #BLI_task_parallel_range
+ *
+ * TODO:
+ * - #BLI_task_parallel_foreach_listbase (#ListBase - double linked list)
+ * - #BLI_task_parallel_foreach_link (#Link - single linked list)
+ * - #BLI_task_parallel_foreach_ghash/gset (#GHash/#GSet - hash & set)
+ * - #BLI_task_parallel_foreach_mempool (#BLI_mempool - iterate over mempools)
+ *
+ * Possible improvements:
+ *
+ * - Chunk iterations to reduce number of spin locks.
+ */
+
+typedef struct ParallelRangeState {
+ int start, stop;
+ void *userdata;
+ TaskParallelRangeFunc func;
+
+ int iter;
+ SpinLock lock;
+} ParallelRangeState;
+
+BLI_INLINE bool parallel_range_next_iter_get(
+ ParallelRangeState *state,
+ int *iter)
+{
+ bool result = false;
+ if (state->iter < state->stop) {
+ BLI_spin_lock(&state->lock);
+ if (state->iter < state->stop) {
+ *iter = state->iter++;
+ result = true;
+ }
+ BLI_spin_unlock(&state->lock);
+ }
+ return result;
+}
+
+static void parallel_range_func(
+ TaskPool *pool,
+ void *UNUSED(taskdata),
+ int UNUSED(threadid))
+{
+ ParallelRangeState *state = BLI_task_pool_userdata(pool);
+ int iter;
+ while (parallel_range_next_iter_get(state, &iter)) {
+ state->func(state->userdata, iter);
+ }
+}
+
+void BLI_task_parallel_range_ex(
+ int start, int stop,
+ void *userdata,
+ TaskParallelRangeFunc func,
+ const int range_threshold)
+{
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ ParallelRangeState state;
+ int i;
+
+ BLI_assert(start < stop);
+
+ /* If it's not enough data to be crunched, don't bother with tasks at all,
+ * do everything from the main thread.
+ */
+ if (stop - start < range_threshold) {
+ for (i = start; i < stop; ++i) {
+ func(userdata, i);
+ }
+ return;
+ }
+
+ BLI_spin_init(&state.lock);
+ state.start = start;
+ state.stop = stop;
+ state.userdata = userdata;
+ state.func = func;
+ state.iter = start;
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, &state);
+
+ /* The idea here is to prevent creating task for each of the loop iterations
+ * and instead have tasks which are evenly distributed across CPU cores and
+ * pull next iter to be crunched using the queue.
+ */
+ for (i = 0; i < 2 * BLI_task_scheduler_num_threads(task_scheduler); i++) {
+ BLI_task_pool_push(task_pool,
+ parallel_range_func,
+ NULL, false,
+ TASK_PRIORITY_HIGH);
+ }
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ BLI_spin_end(&state.lock);
+}
+
+void BLI_task_parallel_range(
+ int start, int stop,
+ void *userdata,
+ TaskParallelRangeFunc func)
+{
+ BLI_task_parallel_range_ex(start, stop, userdata, func, 64);
+}
diff --git a/source/blender/blenlib/intern/timecode.c b/source/blender/blenlib/intern/timecode.c
index 7b2ac9e112b..0c8834008b6 100644
--- a/source/blender/blenlib/intern/timecode.c
+++ b/source/blender/blenlib/intern/timecode.c
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/blendlib/intern/timecode.c
+/** \file blender/blenlib/intern/timecode.c
* \ingroup blendlib
*
* Time-Code string formatting
@@ -33,6 +33,7 @@
#include <stdio.h>
+#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "BLI_math.h"
diff --git a/source/blender/blenlib/intern/winstuff.c b/source/blender/blenlib/intern/winstuff.c
index 65ded37eb7b..a67e116969e 100644
--- a/source/blender/blenlib/intern/winstuff.c
+++ b/source/blender/blenlib/intern/winstuff.c
@@ -92,6 +92,7 @@ void RegisterBlendExtension(void)
const char *ThumbHandlerDLL;
char RegCmd[MAX_PATH * 2];
char MBox[256];
+ char *blender_app;
#ifndef WIN64
BOOL IsWOW64;
#endif
@@ -99,6 +100,12 @@ void RegisterBlendExtension(void)
printf("Registering file extension...");
GetModuleFileName(0, BlPath, MAX_PATH);
+ /* Replace the actual app name with the wrapper. */
+ blender_app = strstr(BlPath, "blender-app.exe");
+ if (blender_app != NULL) {
+ strcpy(blender_app, "blender.exe");
+ }
+
/* root is HKLM by default */
lresult = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Classes", 0, KEY_ALL_ACCESS, &root);
if (lresult != ERROR_SUCCESS) {
diff --git a/source/blender/blenlib/intern/winstuff_dir.c b/source/blender/blenlib/intern/winstuff_dir.c
index 90250de1683..3d669a869f9 100644
--- a/source/blender/blenlib/intern/winstuff_dir.c
+++ b/source/blender/blenlib/intern/winstuff_dir.c
@@ -28,7 +28,7 @@
* (opendir, readdir, closedir)
*/
-#if defined(WIN32) && !defined(FREE_WINDOWS)
+#ifdef WIN32
/* standalone for inclusion in binaries other then blender */
# ifdef USE_STANDALONE
@@ -44,6 +44,13 @@
#include "BLI_utildefines.h"
#include "utfconv.h"
+/* 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()
+* and related functions are used to properly support paths with non-ASCII
+* characters. (kjym3)
+*/
+
DIR *opendir(const char *path)
{
wchar_t *path_16 = alloc_utf16_from_8(path, 0);
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 4fb983c119b..4b7b9cecb17 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -275,7 +275,8 @@ void BLO_main_expander(void (*expand_doit_func)(void *, struct Main *, void *));
*/
void BLO_expand_main(void *fdhandle, struct Main *mainvar);
-/* Update defaults in startup.blend, without having to save and embed it */
+/* Update defaults in startup.blend & userprefs.blend, without having to save and embed it */
+void BLO_update_defaults_userpref_blend(void);
void BLO_update_defaults_startup_blend(struct Main *mainvar);
#ifdef __cplusplus
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 066c4ea67f1..d99500dae92 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -256,6 +256,12 @@ void blo_reportf_wrap(ReportList *reports, ReportType type, const char *format,
}
}
+/* for reporting linking messages */
+static const char *library_parent_filepath(Library *lib)
+{
+ return lib->parent ? lib->parent->filepath : "<direct>";
+}
+
static OldNewMap *oldnewmap_new(void)
{
OldNewMap *onm= MEM_callocN(sizeof(*onm), "OldNewMap");
@@ -434,8 +440,7 @@ void blo_join_main(ListBase *mainlist)
while ((tojoin = mainl->next)) {
add_main_to_main(mainl, tojoin);
BLI_remlink(mainlist, tojoin);
- MEM_freeN(tojoin->eval_ctx);
- MEM_freeN(tojoin);
+ BKE_main_free(tojoin);
}
}
@@ -1824,6 +1829,7 @@ static void lib_link_brush(FileData *fd, Main *main)
brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex);
brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex);
brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image);
+ brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve);
}
}
}
@@ -1834,6 +1840,8 @@ static void direct_link_brush(FileData *fd, Brush *brush)
/* fallof curve */
brush->curve = newdataadr(fd, brush->curve);
+ brush->gradient = newdataadr(fd, brush->gradient);
+
if (brush->curve)
direct_link_curvemapping(fd, brush->curve);
else
@@ -1843,6 +1851,44 @@ static void direct_link_brush(FileData *fd, Brush *brush)
brush->icon_imbuf = NULL;
}
+/* ************ READ Palette *************** */
+static void lib_link_palette(FileData *UNUSED(fd), Main *main)
+{
+ Palette *palette;
+
+ /* only link ID pointers */
+ for (palette = main->palettes.first; palette; palette = palette->id.next) {
+ if (palette->id.flag & LIB_NEED_LINK) {
+ palette->id.flag -= LIB_NEED_LINK;
+ }
+ }
+}
+
+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)
+{
+ PaintCurve *pc;
+
+ /* only link ID pointers */
+ for (pc = main->paintcurves.first; pc; pc = pc->id.next) {
+ if (pc->id.flag & LIB_NEED_LINK) {
+ pc->id.flag -= LIB_NEED_LINK;
+ }
+ }
+}
+
+static void direct_link_paint_curve(FileData *fd, PaintCurve *pc)
+{
+ pc->points = newdataadr(fd, pc->points);
+}
+
+
static void direct_link_script(FileData *UNUSED(fd), Script *script)
{
script->id.us = 1;
@@ -2664,9 +2710,9 @@ static void direct_link_nodetree(FileData *fd, bNodeTree *ntree)
}
}
else if (ntree->type==NTREE_COMPOSIT) {
- if (ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
+ if (ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
direct_link_curvemapping(fd, node->storage);
- else if (ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
+ else if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER))
((ImageUser *)node->storage)->ok = 1;
}
else if ( ntree->type==NTREE_TEXTURE) {
@@ -3265,7 +3311,7 @@ static void direct_link_image(FileData *fd, Image *ima)
{
/* for undo system, pointers could be restored */
if (fd->imamap)
- ima->cache = newmclipadr(fd, ima->cache);
+ ima->cache = newimaadr(fd, ima->cache);
else
ima->cache = NULL;
@@ -3516,7 +3562,8 @@ static void direct_link_material(FileData *fd, Material *ma)
for (a = 0; a < MAX_MTEX; a++) {
ma->mtex[a] = newdataadr(fd, ma->mtex[a]);
}
-
+ ma->texpaintslot = NULL;
+
ma->ramp_col = newdataadr(fd, ma->ramp_col);
ma->ramp_spec = newdataadr(fd, ma->ramp_spec);
@@ -4450,6 +4497,9 @@ static void lib_link_object(FileData *fd, Main *main)
steeringa->target = newlibadr(fd, ob->id.lib, steeringa->target);
steeringa->navmesh = newlibadr(fd, ob->id.lib, steeringa->navmesh);
}
+ else if(act->type == ACT_MOUSE) {
+ /* bMouseActuator *moa= act->data; */
+ }
}
{
@@ -5056,6 +5106,7 @@ static void link_paint(FileData *fd, Scene *sce, Paint *p)
{
if (p) {
p->brush = newlibadr_us(fd, sce->id.lib, p->brush);
+ p->palette = newlibadr_us(fd, sce->id.lib, p->palette);
p->paint_cursor = NULL;
}
}
@@ -5104,6 +5155,18 @@ static void lib_link_scene(FileData *fd, Main *main)
sce->toolsettings->sculpt->gravity_object =
newlibadr_us(fd, sce->id.lib, sce->toolsettings->sculpt->gravity_object);
+ if (sce->toolsettings->imapaint.stencil)
+ sce->toolsettings->imapaint.stencil =
+ newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.stencil);
+
+ if (sce->toolsettings->imapaint.clone)
+ sce->toolsettings->imapaint.clone =
+ newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.clone);
+
+ if (sce->toolsettings->imapaint.canvas)
+ sce->toolsettings->imapaint.canvas =
+ newlibadr_us(fd, sce->id.lib, sce->toolsettings->imapaint.canvas);
+
sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
for (base = sce->base.first; base; base = next) {
@@ -5308,6 +5371,8 @@ static void direct_link_scene(FileData *fd, Scene *sce)
sce->toolsettings->imapaint.paintcursor = NULL;
sce->toolsettings->particle.paintcursor = NULL;
+ sce->toolsettings->particle.scene = NULL;
+ sce->toolsettings->particle.object = NULL;
/* in rare cases this is needed, see [#33806] */
if (sce->toolsettings->vpaint) {
@@ -5352,7 +5417,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
if (seq->strip && seq->strip->done==0) {
seq->strip->done = true;
- if (ELEM4(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
+ if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
seq->strip->stripdata = newdataadr(fd, seq->strip->stripdata);
}
else {
@@ -5786,9 +5851,9 @@ static void lib_link_screen(FileData *fd, Main *main)
/* how to handle user count on pointer restore */
typedef enum ePointerUserMode {
- USER_IGNORE, /* ignore user count */
- USER_ONE, /* ensure at least one user (fake also counts) */
- USER_REAL /* ensure at least one real user (fake user ignored) */
+ USER_IGNORE = 0, /* ignore user count */
+ USER_ONE = 1, /* ensure at least one user (fake also counts) */
+ USER_REAL = 2, /* ensure at least one real user (fake user ignored) */
} ePointerUserMode;
static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user)
@@ -5813,9 +5878,9 @@ static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user)
* Only for undo files, or to restore a screen after reading without UI...
*
* user
- * - 0: no usercount change
- * - 1: ensure a user
- * - 2: ensure a real user (even if a fake one is set)
+ * - USER_IGNORE: no usercount change
+ * - USER_ONE: ensure a user
+ * - USER_REAL: ensure a real user (even if a fake one is set)
*/
static void *restore_pointer_by_name(Main *mainp, ID *id, ePointerUserMode user)
{
@@ -5912,8 +5977,12 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc
v3d->ob_centre = restore_pointer_by_name(newmain, (ID *)v3d->ob_centre, USER_ONE);
for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) {
- bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_ONE);
- bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_ONE);
+ if ((bgpic->ima = restore_pointer_by_name(newmain, (ID *)bgpic->ima, USER_IGNORE))) {
+ id_us_plus((ID *)bgpic->ima);
+ }
+ if ((bgpic->clip = restore_pointer_by_name(newmain, (ID *)bgpic->clip, USER_IGNORE))) {
+ id_us_plus((ID *)bgpic->clip);
+ }
}
if (v3d->localvd) {
/*Base *base;*/
@@ -6175,7 +6244,6 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
rv3d->depths = NULL;
rv3d->gpuoffscreen = NULL;
- rv3d->ri = NULL;
rv3d->render_engine = NULL;
rv3d->sms = NULL;
rv3d->smooth_timer = NULL;
@@ -6287,6 +6355,9 @@ static bool direct_link_screen(FileData *fd, bScreen *sc)
else if (sa->spacetype == SPACE_VIEW3D)
blo_do_versions_view3d_split_250(sa->spacedata.first, &sa->regionbase);
+ /* incase we set above */
+ sa->butspacetype = sa->spacetype;
+
for (sl = sa->spacedata.first; sl; sl = sl->next) {
link_list(fd, &(sl->regionbase));
@@ -7135,6 +7206,8 @@ static const char *dataname(short id_code)
case ID_NT: return "Data from NT";
case ID_BR: return "Data from BR";
case ID_PA: return "Data from PA";
+ case ID_PAL: return "Data from PAL";
+ case ID_PC: return "Data from PCRV";
case ID_GD: return "Data from GD";
case ID_WM: return "Data from WM";
case ID_MC: return "Data from MC";
@@ -7320,6 +7393,12 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, int flag, ID
case ID_LS:
direct_link_linestyle(fd, (FreestyleLineStyle *)id);
break;
+ case ID_PAL:
+ direct_link_palette(fd, (Palette *)id);
+ break;
+ case ID_PC:
+ direct_link_paint_curve(fd, (PaintCurve *)id);
+ break;
}
oldnewmap_free_unused(fd->datamap);
@@ -7484,8 +7563,9 @@ static void lib_link_all(FileData *fd, Main *main)
/* No load UI for undo memfiles */
if (fd->memfile == NULL) {
lib_link_windowmanager(fd, main);
- lib_link_screen(fd, main);
}
+ /* DO NOT skip screens here, 3Dview may contains pointers to other ID data (like bgpic)! See T41411. */
+ lib_link_screen(fd, main);
lib_link_scene(fd, main);
lib_link_object(fd, main);
lib_link_curve(fd, main);
@@ -7508,6 +7588,8 @@ static void lib_link_all(FileData *fd, Main *main)
lib_link_vfont(fd, main);
lib_link_nodetree(fd, main); /* has to be done after scene/materials, this will verify group nodes */
lib_link_brush(fd, main);
+ lib_link_palette(fd, main);
+ lib_link_paint_curve(fd, main);
lib_link_particlesettings(fd, main);
lib_link_movieclip(fd, main);
lib_link_mask(fd, main);
@@ -8047,6 +8129,7 @@ static void expand_brush(FileData *fd, Main *mainvar, Brush *brush)
expand_doit(fd, mainvar, brush->mtex.tex);
expand_doit(fd, mainvar, brush->mask_mtex.tex);
expand_doit(fd, mainvar, brush->clone.image);
+ expand_doit(fd, mainvar, brush->paint_curve);
}
static void expand_material(FileData *fd, Main *mainvar, Material *ma)
@@ -8918,13 +9001,13 @@ static ID *append_named_part_ex(const bContext *C, Main *mainl, FileData *fd, co
ob = (Object *)id;
- /* link at active layer (view3d->lay if in context, else scene->lay */
+ /* link at active layer (view3d if available in context, else scene one */
if ((flag & FILE_ACTIVELAY)) {
View3D *v3d = CTX_wm_view3d(C);
- ob->lay = v3d ? v3d->layact : scene->lay;
+ ob->lay = BKE_screen_view3d_layer_active(v3d, scene);
}
- ob->mode = 0;
+ ob->mode = OB_MODE_OBJECT;
base->lay = ob->lay;
base->object = ob;
ob->id.us++;
@@ -9142,8 +9225,10 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
if (mainptr->curlib->packedfile) {
PackedFile *pf = mainptr->curlib->packedfile;
- blo_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read packed library: '%s'"),
- mainptr->curlib->name);
+ blo_reportf_wrap(
+ basefd->reports, RPT_INFO, TIP_("Read packed library: '%s', parent '%s'"),
+ mainptr->curlib->name,
+ library_parent_filepath(mainptr->curlib));
fd = blo_openblendermemory(pf->data, pf->size, basefd->reports);
@@ -9151,8 +9236,11 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
BLI_strncpy(fd->relabase, mainptr->curlib->filepath, sizeof(fd->relabase));
}
else {
- blo_reportf_wrap(basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s'"),
- mainptr->curlib->filepath, mainptr->curlib->name);
+ blo_reportf_wrap(
+ basefd->reports, RPT_INFO, TIP_("Read library: '%s', '%s', parent '%s'"),
+ mainptr->curlib->filepath,
+ mainptr->curlib->name,
+ library_parent_filepath(mainptr->curlib));
fd = blo_openblenderfile(mainptr->curlib->filepath, basefd->reports);
}
/* allow typing in a new lib path */
@@ -9223,10 +9311,13 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
append_id_part(fd, mainptr, id, &realid);
if (!realid) {
- blo_reportf_wrap(fd->reports, RPT_WARNING,
- TIP_("LIB ERROR: %s: '%s' missing from '%s'"),
- BKE_idcode_to_name(GS(id->name)),
- id->name + 2, mainptr->curlib->filepath);
+ blo_reportf_wrap(
+ fd->reports, RPT_WARNING,
+ TIP_("LIB ERROR: %s: '%s' missing from '%s', parent '%s'"),
+ BKE_idcode_to_name(GS(id->name)),
+ id->name + 2,
+ mainptr->curlib->filepath,
+ library_parent_filepath(mainptr->curlib));
}
change_idid_adr(mainlist, basefd, id, realid);
@@ -9255,9 +9346,13 @@ static void read_libraries(FileData *basefd, ListBase *mainlist)
idn = id->next;
if (id->flag & LIB_READ) {
BLI_remlink(lbarray[a], id);
- blo_reportf_wrap(basefd->reports, RPT_WARNING,
- TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s'"),
- BKE_idcode_to_name(GS(id->name)), id->name + 2, mainptr->curlib->filepath);
+ blo_reportf_wrap(
+ basefd->reports, RPT_WARNING,
+ TIP_("LIB ERROR: %s: '%s' unread lib block missing from '%s', parent '%s'"),
+ BKE_idcode_to_name(GS(id->name)),
+ id->name + 2,
+ mainptr->curlib->filepath,
+ library_parent_filepath(mainptr->curlib));
change_idid_adr(mainlist, basefd, id, NULL);
MEM_freeN(id);
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 06d871c8db0..40b756a3f7c 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -89,9 +89,6 @@
#include "NOD_socket.h"
-//XXX #include "BIF_butspace.h" // badlevel, for do_versions, patching event codes
-//XXX #include "BIF_filelist.h" // badlevel too, where to move this? - elubie
-//XXX #include "BIF_previewrender.h" // bedlelvel, for struct RenderInfo
#include "BLO_readfile.h"
#include "BLO_undofile.h"
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index cf74ef068eb..7c6b6ec7249 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -829,7 +829,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
for (i = 0; i < 3; i++) {
if ( (ob->dsize[i] == 0.0f) || /* simple case, user never touched dsize */
(ob->size[i] == 0.0f)) /* cant scale the dsize to give a non zero result,
- so fallback to 1.0f */
+ * so fallback to 1.0f */
{
ob->dscale[i] = 1.0f;
}
@@ -2454,9 +2454,9 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
if (sl->spacetype == SPACE_OUTLINER) {
SpaceOops *so = (SpaceOops *)sl;
- if (!ELEM11(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE,
- SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS,
- SO_USERDEF))
+ if (!ELEM(so->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_SELECTED, SO_ACTIVE,
+ SO_SAME_TYPE, SO_GROUPS, SO_LIBRARIES, SO_SEQUENCE, SO_DATABLOCKS,
+ SO_USERDEF))
{
so->outlinevis = SO_ALL_SCENES;
}
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index ada32aadbe2..bd1b5f2c269 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -34,6 +34,8 @@
/* allow readfile to use deprecated functionality */
#define DNA_DEPRECATED_ALLOW
+#include "DNA_brush_types.h"
+#include "DNA_cloth_types.h"
#include "DNA_constraint_types.h"
#include "DNA_sdna_types.h"
#include "DNA_space_types.h"
@@ -41,7 +43,9 @@
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
#include "DNA_modifier_types.h"
+#include "DNA_particle_types.h"
#include "DNA_linestyle_types.h"
+#include "DNA_actuator_types.h"
#include "DNA_genfile.h"
@@ -110,6 +114,19 @@ static void do_version_constraints_radians_degrees_270_5(ListBase *lb)
}
}
+static void do_version_constraints_stretch_to_limits(ListBase *lb)
+{
+ bConstraint *con;
+
+ for (con = lb->first; con; con = con->next) {
+ if (con->type == CONSTRAINT_TYPE_STRETCHTO) {
+ bStretchToConstraint *data = (bStretchToConstraint *)con->data;
+ data->bulge_min = 1.0f;
+ data->bulge_max = 1.0f;
+ }
+ }
+}
+
void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
{
if (!MAIN_VERSION_ATLEAST(main, 270, 0)) {
@@ -251,32 +268,171 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
- if (!DNA_struct_elem_find(fd->filesdna, "Material", "int", "mode2")) {
- Material *ma;
+ if (!MAIN_VERSION_ATLEAST(main, 271, 0)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Material", "int", "mode2")) {
+ Material *ma;
- for (ma = main->mat.first; ma; ma = ma->id.next)
- ma->mode2 = MA_CASTSHADOW;
+ for (ma = main->mat.first; ma; ma = ma->id.next)
+ ma->mode2 = MA_CASTSHADOW;
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "BakeData", "bake")) {
+ Scene *sce;
+
+ for (sce = main->scene.first; sce; sce = sce->id.next) {
+ sce->r.bake.flag = R_BAKE_CLEAR;
+ sce->r.bake.width = 512;
+ sce->r.bake.height = 512;
+ sce->r.bake.margin = 16;
+ sce->r.bake.normal_space = R_BAKE_SPACE_TANGENT;
+ sce->r.bake.normal_swizzle[0] = R_BAKE_POSX;
+ sce->r.bake.normal_swizzle[1] = R_BAKE_POSY;
+ sce->r.bake.normal_swizzle[2] = R_BAKE_POSZ;
+ BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
+
+ sce->r.bake.im_format.planes = R_IMF_PLANES_RGBA;
+ sce->r.bake.im_format.imtype = R_IMF_IMTYPE_PNG;
+ sce->r.bake.im_format.depth = R_IMF_CHAN_DEPTH_8;
+ sce->r.bake.im_format.quality = 90;
+ sce->r.bake.im_format.compress = 15;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "FreestyleLineStyle", "float", "texstep")) {
+ FreestyleLineStyle *linestyle;
+
+ for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) {
+ linestyle->flag |= LS_TEXTURE;
+ linestyle->texstep = 1.0;
+ }
+ }
+
+ {
+ Scene *scene;
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ int num_layers = BLI_countlist(&scene->r.layers);
+ scene->r.actlay = min_ff(scene->r.actlay, num_layers - 1);
+ }
+ }
}
- if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "BakeData", "bake")) {
- Scene *sce;
+ if (!MAIN_VERSION_ATLEAST(main, 271, 1)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Material", "float", "line_col[4]")) {
+ Material *mat;
- for (sce = main->scene.first; sce; sce = sce->id.next) {
- sce->r.bake.flag = R_BAKE_CLEAR;
- sce->r.bake.width = 512;
- sce->r.bake.height = 512;
- sce->r.bake.margin = 16;
- sce->r.bake.normal_space = R_BAKE_SPACE_TANGENT;
- sce->r.bake.normal_swizzle[0] = R_BAKE_POSX;
- sce->r.bake.normal_swizzle[1] = R_BAKE_POSY;
- sce->r.bake.normal_swizzle[2] = R_BAKE_POSZ;
- BLI_strncpy(sce->r.bake.filepath, U.renderdir, sizeof(sce->r.bake.filepath));
-
- sce->r.bake.im_format.planes = R_IMF_PLANES_RGBA;
- sce->r.bake.im_format.imtype = R_IMF_IMTYPE_PNG;
- sce->r.bake.im_format.depth = R_IMF_CHAN_DEPTH_8;
- sce->r.bake.im_format.quality = 90;
- sce->r.bake.im_format.compress = 15;
+ for (mat = main->mat.first; mat; mat = mat->id.next) {
+ mat->line_col[0] = mat->line_col[1] = mat->line_col[2] = 0.0f;
+ mat->line_col[3] = mat->alpha;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) {
+ Scene *scene;
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ scene->r.preview_start_resolution = 64;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 271, 2)) {
+ /* init up & track axis property of trackto actuators */
+ Object *ob;
+
+ 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_EDIT_OBJECT) {
+ bEditObjectActuator *eoact = act->data;
+ eoact->trackflag = ob->trackflag;
+ /* if trackflag is pointing +-Z axis then upflag should point Y axis.
+ * Rest of trackflag cases, upflag should be point z axis */
+ if ((ob->trackflag == OB_POSZ) || (ob->trackflag == OB_NEGZ)) {
+ eoact->upflag = 1;
+ }
+ else {
+ eoact->upflag = 2;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 271, 3)) {
+ Brush *br;
+
+ for (br = main->brush.first; br; br = br->id.next) {
+ br->fill_threshold = 0.2f;
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "BevelModifierData", "int", "mat")) {
+ 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_Bevel) {
+ BevelModifierData *bmd = (BevelModifierData *)md;
+ bmd->mat = -1;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 271, 6)) {
+ 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_ParticleSystem) {
+ ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
+ if (pmd->psys && pmd->psys->clmd) {
+ pmd->psys->clmd->sim_parms->vel_damping = 1.0f;
+ }
+ }
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 272, 0)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "RenderData", "int", "preview_start_resolution")) {
+ Scene *scene;
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ scene->r.preview_start_resolution = 64;
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 272, 1)) {
+ Brush *br;
+ for (br = main->brush.first; br; br = br->id.next) {
+ if ((br->ob_mode & OB_MODE_SCULPT) && ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK))
+ br->alpha = 1.0f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "Image", "float", "gen_color")) {
+ Image *image;
+ for (image = main->image.first; image != NULL; image = image->id.next) {
+ image->gen_color[3] = 1.0f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "bStretchToConstraint", "float", "bulge_min")) {
+ Object *ob;
+
+ /* Update Transform constraint (again :|). */
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ do_version_constraints_stretch_to_limits(&ob->constraints);
+
+ if (ob->pose) {
+ /* Bones constraints! */
+ bPoseChannel *pchan;
+ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ do_version_constraints_stretch_to_limits(&pchan->constraints);
+ }
+ }
}
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index 1e881eb11f9..1afcac313a2 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -26,8 +26,10 @@
*/
#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "DNA_brush_types.h"
#include "DNA_freestyle_types.h"
#include "DNA_linestyle_types.h"
#include "DNA_scene_types.h"
@@ -35,21 +37,43 @@
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_material_types.h"
+#include "DNA_object_types.h"
+#include "BKE_brush.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BLO_readfile.h"
-/* Update defaults in startup.blend, without having to save and embed the file.
+
+/**
+ * Override values in in-memory startup.blend, avoids resaving for small changes.
+ */
+void BLO_update_defaults_userpref_blend(void)
+{
+ /* defaults from T37518 */
+
+ U.uiflag |= USER_ZBUF_CURSOR;
+ U.uiflag |= USER_QUIT_PROMPT;
+ U.uiflag |= USER_CONTINUOUS_MOUSE;
+
+ U.versions = 1;
+ U.savetime = 2;
+}
+
+/**
+ * Update defaults in startup.blend, without having to save and embed the file.
* This function can be emptied each time the startup.blend is updated. */
-void BLO_update_defaults_startup_blend(Main *main)
+void BLO_update_defaults_startup_blend(Main *bmain)
{
Scene *scene;
SceneRenderLayer *srl;
FreestyleLineStyle *linestyle;
Mesh *me;
+ Material *mat;
- for (scene = main->scene.first; scene; scene = scene->id.next) {
+ for (scene = bmain->scene.first; scene; scene = scene->id.next) {
scene->r.im_format.planes = R_IMF_PLANES_RGBA;
scene->r.im_format.compress = 15;
@@ -57,34 +81,72 @@ void BLO_update_defaults_startup_blend(Main *main)
srl->freestyleConfig.sphere_radius = 0.1f;
srl->pass_alpha_threshold = 0.5f;
}
+
+ if (scene->toolsettings) {
+ ToolSettings *ts = scene->toolsettings;
+
+ if (ts->sculpt) {
+ Sculpt *sculpt = ts->sculpt;
+ sculpt->paint.symmetry_flags |= PAINT_SYMM_X;
+ sculpt->flags |= SCULPT_DYNTOPO_COLLAPSE;
+ sculpt->detail_size = 12;
+ }
+ }
}
- for (linestyle = main->linestyle.first; linestyle; linestyle = linestyle->id.next) {
+ for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
linestyle->flag = LS_SAME_OBJECT | LS_NO_SORTING | LS_TEXTURE;
linestyle->sort_key = LS_SORT_KEY_DISTANCE_FROM_CAMERA;
linestyle->integration_type = LS_INTEGRATION_MEAN;
linestyle->texstep = 1.0;
+ linestyle->chain_count = 10;
}
{
bScreen *screen;
- for (screen = main->screen.first; screen; screen = screen->id.next) {
+ for (screen = bmain->screen.first; screen; screen = screen->id.next) {
ScrArea *area;
for (area = screen->areabase.first; area; area = area->next) {
SpaceLink *space_link;
+ ARegion *ar;
+
for (space_link = area->spacedata.first; space_link; space_link = space_link->next) {
if (space_link->spacetype == SPACE_CLIP) {
SpaceClip *space_clip = (SpaceClip *) space_link;
space_clip->flag &= ~SC_MANUAL_CALIBRATION;
}
}
+
+ /* 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) {
+ BLI_freelistN(&ar->panels);
+ }
}
}
}
- for (me = main->mesh.first; me; me = me->id.next) {
+ for (me = bmain->mesh.first; me; me = me->id.next) {
me->smoothresh = DEG2RADF(180.0f);
+ me->flag &= ~ME_TWOSIDED;
+ }
+
+ for (mat = bmain->mat.first; mat; mat = mat->id.next) {
+ mat->line_col[0] = mat->line_col[1] = mat->line_col[2] = 0.0f;
+ mat->line_col[3] = 1.0f;
+ }
+
+ {
+ Brush *br;
+ br = BKE_brush_add(bmain, "Fill");
+ br->imagepaint_tool = PAINT_TOOL_FILL;
+ br->ob_mode = OB_MODE_TEXTURE_PAINT;
+
+ br = (Brush *)BKE_libblock_find_name_ex(bmain, ID_BR, "Mask");
+ if (br) {
+ br->imagepaint_tool = PAINT_TOOL_MASK;
+ br->ob_mode |= OB_MODE_TEXTURE_PAINT;
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 572c6d0a02d..557cc147f19 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -473,7 +473,7 @@ static void do_version_ntree_242_2(bNodeTree *ntree)
if (ntree->type == NTREE_COMPOSIT) {
for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM3(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
+ if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) {
/* only image had storage */
if (node->storage) {
NodeImageAnim *nia = node->storage;
@@ -2232,7 +2232,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
}
if (sce->r.mode & R_PANORAMA) {
- /* all these checks to ensure saved files with svn version keep working... */
+ /* all these checks to ensure saved files between released versions keep working... */
if (sce->r.xsch < sce->r.ysch) {
Object *obc = blo_do_versions_newlibadr(fd, lib, sce->camera);
if (obc && obc->type == OB_CAMERA) {
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 45139789f1e..59f12657703 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -183,6 +183,114 @@
#define MYWRITE_BUFFER_SIZE 100000
#define MYWRITE_MAX_CHUNK 32768
+
+
+/** \name Small API to handle compression.
+ * \{ */
+
+typedef enum {
+ WW_WRAP_NONE = 1,
+ WW_WRAP_ZLIB,
+} eWriteWrapType;
+
+typedef struct WriteWrap WriteWrap;
+struct WriteWrap {
+ /* callbacks */
+ bool (*open)(WriteWrap *ww, const char *filepath);
+ bool (*close)(WriteWrap *ww);
+ size_t (*write)(WriteWrap *ww, const char *data, size_t data_len);
+
+ /* internal */
+ union {
+ int file_handle;
+ gzFile gz_handle;
+ } _user_data;
+};
+
+/* none */
+#define FILE_HANDLE(ww) \
+ (ww)->_user_data.file_handle
+
+static bool ww_open_none(WriteWrap *ww, const char *filepath)
+{
+ int file;
+
+ file = BLI_open(filepath, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
+
+ if (file != -1) {
+ FILE_HANDLE(ww) = file;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+static bool ww_close_none(WriteWrap *ww)
+{
+ return (close(FILE_HANDLE(ww)) != -1);
+}
+static size_t ww_write_none(WriteWrap *ww, const char *buf, size_t buf_len)
+{
+ return write(FILE_HANDLE(ww), buf, buf_len);
+}
+#undef FILE_HANDLE
+
+/* zlib */
+#define FILE_HANDLE(ww) \
+ (ww)->_user_data.gz_handle
+
+static bool ww_open_zlib(WriteWrap *ww, const char *filepath)
+{
+ gzFile file;
+
+ file = BLI_gzopen(filepath, "wb1");
+
+ if (file != Z_NULL) {
+ FILE_HANDLE(ww) = file;
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+static bool ww_close_zlib(WriteWrap *ww)
+{
+ return (gzclose(FILE_HANDLE(ww)) == Z_OK);
+}
+static size_t ww_write_zlib(WriteWrap *ww, const char *buf, size_t buf_len)
+{
+ return gzwrite(FILE_HANDLE(ww), buf, buf_len);
+}
+#undef FILE_HANDLE
+
+/* --- end compression types --- */
+
+static void ww_handle_init(eWriteWrapType ww_type, WriteWrap *r_ww)
+{
+ memset(r_ww, 0, sizeof(*r_ww));
+
+ switch (ww_type) {
+ case WW_WRAP_ZLIB:
+ {
+ r_ww->open = ww_open_zlib;
+ r_ww->close = ww_close_zlib;
+ r_ww->write = ww_write_zlib;
+ break;
+ }
+ default:
+ {
+ r_ww->open = ww_open_none;
+ r_ww->close = ww_close_none;
+ r_ww->write = ww_write_none;
+ break;
+ }
+ }
+}
+
+/** \} */
+
+
+
typedef struct {
struct SDNA *sdna;
@@ -192,12 +300,17 @@ typedef struct {
int tot, count, error, memsize;
+ /* Wrap writing, so we can use zlib or
+ * other compression types later, see: G_FILE_COMPRESS
+ * Will be NULL for UNDO. */
+ WriteWrap *ww;
+
#ifdef USE_BMESH_SAVE_AS_COMPAT
char use_mesh_compat; /* option to save with older mesh format */
#endif
} WriteData;
-static WriteData *writedata_new(int file)
+static WriteData *writedata_new(WriteWrap *ww)
{
WriteData *wd= MEM_callocN(sizeof(*wd), "writedata");
@@ -209,7 +322,7 @@ static WriteData *writedata_new(int file)
wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false);
- wd->file= file;
+ wd->ww = ww;
wd->buf= MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf");
@@ -226,9 +339,9 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen)
add_memfilechunk(NULL, wd->current, mem, memlen);
}
else {
- if (write(wd->file, mem, memlen) != memlen)
- wd->error= 1;
-
+ if (wd->ww->write(wd->ww, mem, memlen) != memlen) {
+ wd->error = 1;
+ }
}
}
@@ -302,9 +415,9 @@ static void mywrite(WriteData *wd, const void *adr, int len)
* \param current The current memory file (can be NULL).
* \warning Talks to other functions with global parameters
*/
-static WriteData *bgnwrite(int file, MemFile *compare, MemFile *current)
+static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current)
{
- WriteData *wd= writedata_new(file);
+ WriteData *wd= writedata_new(ww);
if (wd == NULL) return NULL;
@@ -767,7 +880,7 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode);
writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage);
}
- else if (ntree->type==NTREE_COMPOSIT && ELEM4(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
+ else if (ntree->type==NTREE_COMPOSIT && ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT))
write_curvemapping(wd, node->storage);
else if (ntree->type==NTREE_TEXTURE && (node->type==TEX_NODE_CURVE_RGB || node->type==TEX_NODE_CURVE_TIME) )
write_curvemapping(wd, node->storage);
@@ -1237,6 +1350,9 @@ static void write_actuators(WriteData *wd, ListBase *lb)
case ACT_STEERING:
writestruct(wd, DATA, "bSteeringActuator", 1, act->data);
break;
+ case ACT_MOUSE:
+ writestruct(wd, DATA, "bMouseActuator", 1, act->data);
+ break;
default:
; /* error: don't know how to write this file */
}
@@ -2253,6 +2369,9 @@ static void write_scenes(WriteData *wd, ListBase *scebase)
case SEQ_TYPE_TRANSFORM:
writestruct(wd, DATA, "TransformVars", 1, seq->effectdata);
break;
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ writestruct(wd, DATA, "GaussianBlurVars", 1, seq->effectdata);
+ break;
}
}
@@ -2918,6 +3037,38 @@ static void write_brushes(WriteData *wd, ListBase *idbase)
if (brush->curve)
write_curvemapping(wd, brush->curve);
+ if (brush->curve)
+ writestruct(wd, DATA, "ColorBand", 1, brush->gradient);
+ }
+ }
+}
+
+static void write_palettes(WriteData *wd, ListBase *idbase)
+{
+ Palette *palette;
+
+ for (palette = idbase->first; palette; palette = palette->id.next) {
+ if (palette->id.us > 0 || wd->current) {
+ PaletteColor *color;
+ writestruct(wd, ID_PAL, "Palette", 1, palette);
+ if (palette->id.properties) IDP_WriteProperty(palette->id.properties, wd);
+
+ for (color = palette->colors.first; color; color= color->next)
+ writestruct(wd, DATA, "PaletteColor", 1, color);
+ }
+ }
+}
+
+static void write_paintcurves(WriteData *wd, ListBase *idbase)
+{
+ PaintCurve *pc;
+
+ for (pc = idbase->first; pc; pc = pc->id.next) {
+ if (pc->id.us > 0 || wd->current) {
+ writestruct(wd, ID_PC, "PaintCurve", 1, pc);
+
+ writestruct(wd, DATA, "PaintCurvePoint", pc->tot_points, pc->points);
+ if (pc->id.properties) IDP_WriteProperty(pc->id.properties, wd);
}
}
}
@@ -3331,8 +3482,11 @@ static void write_thumb(WriteData *wd, const int *img)
}
/* if MemFile * there's filesave to memory */
-static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFile *current,
- int write_user_block, int write_flags, const int *thumb)
+static int write_file_handle(
+ Main *mainvar,
+ WriteWrap *ww,
+ MemFile *compare, MemFile *current,
+ int write_user_block, int write_flags, const int *thumb)
{
BHead bhead;
ListBase mainlist;
@@ -3341,7 +3495,7 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil
blo_split_main(&mainlist, mainvar);
- wd= bgnwrite(handle, compare, current);
+ wd = bgnwrite(ww, compare, current);
#ifdef USE_BMESH_SAVE_AS_COMPAT
wd->use_mesh_compat = (write_flags & G_FILE_MESH_COMPAT) != 0;
@@ -3393,6 +3547,8 @@ static int write_file_handle(Main *mainvar, int handle, MemFile *compare, MemFil
write_particlesettings(wd, &mainvar->particle);
write_nodetrees(wd, &mainvar->nodetree);
write_brushes (wd, &mainvar->brush);
+ write_palettes (wd, &mainvar->palettes);
+ write_paintcurves (wd, &mainvar->paintcurves);
write_scripts (wd, &mainvar->script);
write_gpencils (wd, &mainvar->gpencil);
write_linestyles(wd, &mainvar->linestyle);
@@ -3465,7 +3621,9 @@ static bool do_history(const char *name, ReportList *reports)
int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const int *thumb)
{
char tempname[FILE_MAX+1];
- int file, err, write_user_block;
+ int err, write_user_block;
+ eWriteWrapType ww_type;
+ WriteWrap ww;
/* path backup/restore */
void *path_list_backup = NULL;
@@ -3474,8 +3632,16 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL
/* open temporary file, so we preserve the original in case we crash */
BLI_snprintf(tempname, sizeof(tempname), "%s@", filepath);
- file = BLI_open(tempname, O_BINARY+O_WRONLY+O_CREAT+O_TRUNC, 0666);
- if (file == -1) {
+ if (write_flags & G_FILE_COMPRESS) {
+ ww_type = WW_WRAP_ZLIB;
+ }
+ else {
+ ww_type = WW_WRAP_NONE;
+ }
+
+ ww_handle_init(ww_type, &ww);
+
+ if (ww.open(&ww, tempname) == false) {
BKE_reportf(reports, RPT_ERROR, "Cannot open file %s for writing: %s", tempname, strerror(errno));
return 0;
}
@@ -3516,8 +3682,9 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL
BKE_bpath_relative_convert(mainvar, filepath, NULL); /* note, making relative to something OTHER then G.main->name */
/* actual file writing */
- err= write_file_handle(mainvar, file, NULL, NULL, write_user_block, write_flags, thumb);
- close(file);
+ err = write_file_handle(mainvar, &ww, NULL, NULL, write_user_block, write_flags, thumb);
+
+ ww.close(&ww);
if (UNLIKELY(path_list_backup)) {
BKE_bpath_list_restore(mainvar, path_list_flag, path_list_backup);
@@ -3541,34 +3708,7 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL
}
}
- if (write_flags & G_FILE_COMPRESS) {
- /* compressed files have the same ending as regular files... only from 2.4!!! */
- char gzname[FILE_MAX+4];
- int ret;
-
- /* first write compressed to separate @.gz */
- BLI_snprintf(gzname, sizeof(gzname), "%s@.gz", filepath);
- ret = BLI_file_gzip(tempname, gzname);
-
- if (0==ret) {
- /* now rename to real file name, and delete temp @ file too */
- if (BLI_rename(gzname, filepath) != 0) {
- BKE_report(reports, RPT_ERROR, "Cannot change old file (file saved with @)");
- return 0;
- }
-
- BLI_delete(tempname, false, false);
- }
- else if (-1==ret) {
- BKE_report(reports, RPT_ERROR, "Failed opening .gz file");
- return 0;
- }
- else if (-2==ret) {
- BKE_report(reports, RPT_ERROR, "Failed opening .blend file for compression");
- return 0;
- }
- }
- else if (BLI_rename(tempname, filepath) != 0) {
+ if (BLI_rename(tempname, filepath) != 0) {
BKE_report(reports, RPT_ERROR, "Cannot change old file (file saved with @)");
return 0;
}
@@ -3581,7 +3721,7 @@ int BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int wr
{
int err;
- err= write_file_handle(mainvar, 0, compare, current, 0, write_flags, NULL);
+ err = write_file_handle(mainvar, NULL, compare, current, 0, write_flags, NULL);
if (err==0) return 1;
return 0;
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 2cd256e2346..50d3ac30ddc 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -136,8 +136,12 @@ set(SRC
tools/bmesh_edgenet.h
tools/bmesh_edgesplit.c
tools/bmesh_edgesplit.h
+ tools/bmesh_intersect.c
+ tools/bmesh_intersect.h
tools/bmesh_path.c
tools/bmesh_path.h
+ tools/bmesh_region_match.c
+ tools/bmesh_region_match.h
tools/bmesh_triangulate.c
tools/bmesh_triangulate.h
tools/bmesh_wireframe.c
diff --git a/source/blender/bmesh/bmesh.h b/source/blender/bmesh/bmesh.h
index 8b5250b7c1e..4efc6aa16f8 100644
--- a/source/blender/bmesh/bmesh.h
+++ b/source/blender/bmesh/bmesh.h
@@ -58,8 +58,8 @@
*
* \subsection bm_loop The Loop
*
- * Loops define the boundary loop of a face. Each loop logically corresponds to an edge,
- * which is defined by the loop and next loop's vertices.
+ * Each loop connects the face to one of its corner vertices,
+ * and also references an edge which connects this loop's vertex to the next loop's vertex.
*
* Loops store several handy pointers:
*
diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h
index 83b02764046..39359b97a4e 100644
--- a/source/blender/bmesh/bmesh_class.h
+++ b/source/blender/bmesh/bmesh_class.h
@@ -285,8 +285,8 @@ extern void bpy_bm_generic_invalidate(struct BPy_BMGeneric *self);
typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data);
/* defines */
-#define BM_ELEM_CD_SET_INT(ele, offset, f) \
- { assert(offset != -1); *((int *)((char *)(ele)->head.data + (offset))) = (f); } (void)0
+#define BM_ELEM_CD_SET_INT(ele, offset, f) { CHECK_TYPE_NONCONST(ele); \
+ assert(offset != -1); *((int *)((char *)(ele)->head.data + (offset))) = (f); } (void)0
#define BM_ELEM_CD_GET_INT(ele, offset) \
(assert(offset != -1), *((int *)((char *)(ele)->head.data + (offset))))
@@ -294,8 +294,8 @@ typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data);
#define BM_ELEM_CD_GET_VOID_P(ele, offset) \
(assert(offset != -1), (void *)((char *)(ele)->head.data + (offset)))
-#define BM_ELEM_CD_SET_FLOAT(ele, offset, f) \
- { assert(offset != -1); *((float *)((char *)(ele)->head.data + (offset))) = (f); } (void)0
+#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
#define BM_ELEM_CD_GET_FLOAT(ele, offset) \
(assert(offset != -1), *((float *)((char *)(ele)->head.data + (offset))))
@@ -311,6 +311,15 @@ typedef bool (*BMElemFilterFunc)(BMElem *, void *user_data);
# define BM_FACE_FIRST_LOOP(p) ((p)->l_first)
#endif
+#define BM_DISK_EDGE_NEXT(e, v) ( \
+ CHECK_TYPE_INLINE(e, BMEdge *), CHECK_TYPE_INLINE(v, BMVert *), \
+ BLI_assert(BM_vert_in_edge(e, v)), \
+ (((&e->v1_disk_link)[v == e->v2]).next))
+#define BM_DISK_EDGE_PREV(e, v) ( \
+ CHECK_TYPE_INLINE(e, BMEdge *), CHECK_TYPE_INLINE(v, BMVert *), \
+ BLI_assert(BM_vert_in_edge(e, v)), \
+ (((&e->v1_disk_link)[v == e->v2]).prev))
+
/**
* size to use for stack arrays when dealing with NGons,
* alloc after this limit is reached.
diff --git a/source/blender/bmesh/bmesh_tools.h b/source/blender/bmesh/bmesh_tools.h
index baffeb774b6..f7f767f91bf 100644
--- a/source/blender/bmesh/bmesh_tools.h
+++ b/source/blender/bmesh/bmesh_tools.h
@@ -41,6 +41,7 @@ extern "C" {
#include "tools/bmesh_edgenet.h"
#include "tools/bmesh_edgesplit.h"
#include "tools/bmesh_path.h"
+#include "tools/bmesh_region_match.h"
#include "tools/bmesh_triangulate.h"
#ifdef __cplusplus
diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c
index eef1e7bbb4f..e0348fea636 100644
--- a/source/blender/bmesh/intern/bmesh_construct.c
+++ b/source/blender/bmesh/intern/bmesh_construct.c
@@ -505,7 +505,7 @@ static void bm_vert_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
return;
}
copy_v3_v3(target_vertex->no, source_vertex->no);
- CustomData_bmesh_free_block_data(&target_mesh->vdata, &target_vertex->head.data);
+ CustomData_bmesh_free_block_data(&target_mesh->vdata, target_vertex->head.data);
CustomData_bmesh_copy_data(&source_mesh->vdata, &target_mesh->vdata,
source_vertex->head.data, &target_vertex->head.data);
}
@@ -517,7 +517,7 @@ static void bm_edge_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
BLI_assert(!"BMEdge: source and targer match");
return;
}
- CustomData_bmesh_free_block_data(&target_mesh->edata, &target_edge->head.data);
+ CustomData_bmesh_free_block_data(&target_mesh->edata, target_edge->head.data);
CustomData_bmesh_copy_data(&source_mesh->edata, &target_mesh->edata,
source_edge->head.data, &target_edge->head.data);
}
@@ -529,7 +529,7 @@ static void bm_loop_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
BLI_assert(!"BMLoop: source and targer match");
return;
}
- CustomData_bmesh_free_block_data(&target_mesh->ldata, &target_loop->head.data);
+ CustomData_bmesh_free_block_data(&target_mesh->ldata, target_loop->head.data);
CustomData_bmesh_copy_data(&source_mesh->ldata, &target_mesh->ldata,
source_loop->head.data, &target_loop->head.data);
}
@@ -542,7 +542,7 @@ static void bm_face_attrs_copy(BMesh *source_mesh, BMesh *target_mesh,
return;
}
copy_v3_v3(target_face->no, source_face->no);
- CustomData_bmesh_free_block_data(&target_mesh->pdata, &target_face->head.data);
+ CustomData_bmesh_free_block_data(&target_mesh->pdata, target_face->head.data);
CustomData_bmesh_copy_data(&source_mesh->pdata, &target_mesh->pdata,
source_face->head.data, &target_face->head.data);
target_face->mat_nr = source_face->mat_nr;
diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c
index 1f81b59badc..eb7b9f78ef4 100644
--- a/source/blender/bmesh/intern/bmesh_core.c
+++ b/source/blender/bmesh/intern/bmesh_core.c
@@ -32,6 +32,7 @@
#include "BLI_array.h"
#include "BLI_alloca.h"
#include "BLI_smallhash.h"
+#include "BLI_stackdefines.h"
#include "BLF_translation.h"
@@ -61,6 +62,8 @@ BMVert *BM_vert_create(BMesh *bm, const float co[3],
{
BMVert *v = BLI_mempool_alloc(bm->vpool);
+ BLI_assert((v_example == NULL) || (v_example->head.htype == BM_VERT));
+ BLI_assert(!(create_flag & 1));
/* --- assign all members --- */
v->head.data = NULL;
@@ -135,6 +138,8 @@ BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2,
BLI_assert(v1 != v2);
BLI_assert(v1->head.htype == BM_VERT && v2->head.htype == BM_VERT);
+ BLI_assert((e_example == NULL) || (e_example->head.htype == BM_EDGE));
+ BLI_assert(!(create_flag & 1));
if ((create_flag & BM_CREATE_NO_DOUBLE) && (e = BM_edge_exists(v1, v2)))
return e;
@@ -190,15 +195,24 @@ BMEdge *BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2,
}
static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
- const BMLoop *example, const eBMCreateFlag create_flag)
+ const BMLoop *l_example, const eBMCreateFlag create_flag)
{
BMLoop *l = NULL;
l = BLI_mempool_alloc(bm->lpool);
+ BLI_assert((l_example == NULL) || (l_example->head.htype == BM_LOOP));
+ BLI_assert(!(create_flag & 1));
+
/* --- assign all members --- */
l->head.data = NULL;
- BM_elem_index_set(l, 0); /* set_loop */
+
+#ifdef USE_DEBUG_INDEX_MEMCHECK
+ DEBUG_MEMCHECK_INDEX_INVALIDATE(l)
+#else
+ BM_elem_index_set(l, -1); /* set_ok_invalid */
+#endif
+
l->head.hflag = 0;
l->head.htype = BM_LOOP;
l->head.api_flag = 0;
@@ -219,8 +233,8 @@ static BMLoop *bm_loop_create(BMesh *bm, BMVert *v, BMEdge *e, BMFace *f,
bm->totloop++;
if (!(create_flag & BM_CREATE_SKIP_CD)) {
- if (example) {
- CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, example->head.data, &l->head.data);
+ if (l_example) {
+ CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, l_example->head.data, &l->head.data);
}
else {
CustomData_bmesh_set_default(&bm->ldata, &l->head.data);
@@ -381,7 +395,10 @@ BMFace *BM_face_create(BMesh *bm, BMVert **verts, BMEdge **edges, const int len,
BMFace *f = NULL;
BMLoop *l, *startl, *lastl;
int i;
-
+
+ BLI_assert((f_example == NULL) || (f_example->head.htype == BM_FACE));
+ BLI_assert(!(create_flag & 1));
+
if (len == 0) {
/* just return NULL for now */
return NULL;
@@ -931,6 +948,9 @@ static bool bm_loop_reverse_loop(BMesh *bm, BMFace *f
BM_CHECK_ELEMENT(f);
+ /* Loop indices are no more valid! */
+ bm->elem_index_dirty |= BM_LOOP;
+
return true;
}
@@ -946,54 +966,38 @@ bool bmesh_loop_reverse(BMesh *bm, BMFace *f)
#endif
}
-static void bm_elements_systag_enable(void *veles, int tot, int flag)
+static void bm_elements_systag_enable(void *veles, int tot, const char api_flag)
{
BMHeader **eles = veles;
int i;
for (i = 0; i < tot; i++) {
- BM_ELEM_API_FLAG_ENABLE((BMElemF *)eles[i], flag);
+ BM_ELEM_API_FLAG_ENABLE((BMElemF *)eles[i], api_flag);
}
}
-static void bm_elements_systag_disable(void *veles, int tot, int flag)
+static void bm_elements_systag_disable(void *veles, int tot, const char api_flag)
{
BMHeader **eles = veles;
int i;
for (i = 0; i < tot; i++) {
- BM_ELEM_API_FLAG_DISABLE((BMElemF *)eles[i], flag);
+ BM_ELEM_API_FLAG_DISABLE((BMElemF *)eles[i], api_flag);
}
}
-static int count_flagged_radial(BMesh *bm, BMLoop *l, int flag)
+static int bm_loop_systag_count_radial(BMLoop *l, const char api_flag)
{
- BMLoop *l2 = l;
- int i = 0, c = 0;
-
+ BMLoop *l_iter = l;
+ int i = 0;
do {
- if (UNLIKELY(!l2)) {
- BMESH_ASSERT(0);
- goto error;
- }
-
- i += BM_ELEM_API_FLAG_TEST(l2->f, flag) ? 1 : 0;
- l2 = l2->radial_next;
- if (UNLIKELY(c >= BM_LOOP_RADIAL_MAX)) {
- BMESH_ASSERT(0);
- goto error;
- }
- c++;
- } while (l2 != l);
+ i += BM_ELEM_API_FLAG_TEST(l_iter->f, api_flag) ? 1 : 0;
+ } while ((l_iter = l_iter->radial_next) != l);
return i;
-
-error:
- BMO_error_raise(bm, bm->currentop, BMERR_MESH_ERROR, NULL);
- return 0;
}
-static int UNUSED_FUNCTION(count_flagged_disk)(BMVert *v, int flag)
+static int UNUSED_FUNCTION(bm_vert_systag_count_disk)(BMVert *v, const char api_flag)
{
BMEdge *e = v->e;
int i = 0;
@@ -1002,13 +1006,13 @@ static int UNUSED_FUNCTION(count_flagged_disk)(BMVert *v, int flag)
return 0;
do {
- i += BM_ELEM_API_FLAG_TEST(e, flag) ? 1 : 0;
+ i += BM_ELEM_API_FLAG_TEST(e, api_flag) ? 1 : 0;
} while ((e = bmesh_disk_edge_next(e, v)) != v->e);
return i;
}
-static bool disk_is_flagged(BMVert *v, int flag)
+static bool disk_is_flagged(BMVert *v, const char api_flag)
{
BMEdge *e = v->e;
@@ -1026,7 +1030,7 @@ static bool disk_is_flagged(BMVert *v, int flag)
return false;
do {
- if (!BM_ELEM_API_FLAG_TEST(l->f, flag))
+ if (!BM_ELEM_API_FLAG_TEST(l->f, api_flag))
return false;
} while ((l = l->radial_next) != e->l);
} while ((e = bmesh_disk_edge_next(e, v)) != v->e);
@@ -1083,7 +1087,7 @@ BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface, const bool do_del)
f = faces[i];
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- int rlen = count_flagged_radial(bm, l_iter, _FLAG_JF);
+ int rlen = bm_loop_systag_count_radial(l_iter, _FLAG_JF);
if (rlen > 2) {
err = N_("Input faces do not form a contiguous manifold region");
@@ -1308,7 +1312,7 @@ BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2,
#ifdef USE_BMESH_HOLES
ListBase *holes,
#endif
- BMEdge *example,
+ BMEdge *e_example,
const bool no_double
)
{
@@ -1328,7 +1332,7 @@ BMFace *bmesh_sfme(BMesh *bm, BMFace *f, BMLoop *l_v1, BMLoop *l_v2,
BLI_assert(f == l_v1->f && f == l_v2->f);
/* allocate new edge between v1 and v2 */
- e = BM_edge_create(bm, v1, v2, example, no_double ? BM_CREATE_NO_DOUBLE : BM_CREATE_NOP);
+ e = BM_edge_create(bm, v1, v2, e_example, no_double ? BM_CREATE_NO_DOUBLE : BM_CREATE_NOP);
f2 = bm_face_create__sfme(bm, f);
l_f1 = bm_loop_create(bm, v2, e, f, l_v2, 0);
@@ -1469,8 +1473,10 @@ BMVert *bmesh_semv(BMesh *bm, BMVert *tv, BMEdge *e, BMEdge **r_e)
valence2 = bmesh_disk_count(tv);
#endif
+ /* order of 'e_new' verts should match 'e'
+ * (so extruded faces don't flip) */
v_new = BM_vert_create(bm, tv->co, tv, BM_CREATE_NOP);
- e_new = BM_edge_create(bm, v_new, tv, e, BM_CREATE_NOP);
+ e_new = BM_edge_create(bm, tv, v_new, e, BM_CREATE_NOP);
bmesh_disk_edge_remove(e_new, tv);
bmesh_disk_edge_remove(e_new, v_new);
@@ -1647,7 +1653,8 @@ 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 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;
@@ -1658,6 +1665,8 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool check_e
bool edok;
#endif
+ BLI_assert(BM_vert_in_edge(e_kill, v_kill));
+
if (BM_vert_in_edge(e_kill, v_kill) == 0) {
return NULL;
}
@@ -1735,8 +1744,7 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool check_e
l_kill = l_kill->radial_next;
}
for (i = 0; i < radlen; i++) {
- bm->totloop--;
- BLI_mempool_free(bm->lpool, loops[i]);
+ bm_kill_only_loop(bm, loops[i]);
}
}
#ifndef NDEBUG
@@ -1749,7 +1757,12 @@ BMEdge *bmesh_jekv(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, const bool check_e
bm_kill_only_edge(bm, e_kill);
/* deallocate vertex */
- bm_kill_only_vert(bm, v_kill);
+ if (do_del) {
+ bm_kill_only_vert(bm, v_kill);
+ }
+ else {
+ v_kill->e = NULL;
+ }
#ifndef NDEBUG
/* Validate disk cycle lengths of v_old, tv are unchanged */
@@ -1927,7 +1940,7 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
BLI_mempool_free(bm->fpool, f2);
bm->totface--;
/* account for both above */
- bm->elem_index_dirty |= BM_EDGE | BM_FACE;
+ bm->elem_index_dirty |= BM_EDGE | BM_LOOP | BM_FACE;
BM_CHECK_ELEMENT(f1);
@@ -1939,6 +1952,44 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
}
/**
+ * Check if splicing vertices would create any double edges.
+ *
+ * \note assume caller will handle case where verts share an edge.
+ */
+bool BM_vert_splice_check_double(BMVert *v_a, BMVert *v_b)
+{
+ bool is_double = false;
+
+ 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);
+
+ 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);
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_a)) != e_first);
+
+ 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)) {
+ is_double = true;
+ break;
+ }
+ } while ((e = BM_DISK_EDGE_NEXT(e, v_b)) != e_first);
+
+ BLI_smallhash_release(&visit);
+ }
+
+ return is_double;
+}
+
+/**
* \brief Splice Vert
*
* Merges two verts into one (\a v into \a vtarget).
@@ -1951,10 +2002,6 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
*/
bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target)
{
- void *loops_stack[BM_DEFAULT_ITER_STACK_SIZE];
- BMLoop **loops;
- int i, loops_tot;
-
BMEdge *e;
/* verts already spliced */
@@ -1962,21 +2009,25 @@ bool BM_vert_splice(BMesh *bm, BMVert *v, BMVert *v_target)
return false;
}
- /* we can't modify the vert while iterating so first allocate an array of loops */
- loops = BM_iter_as_arrayN(bm, BM_LOOPS_OF_VERT, v, &loops_tot,
- loops_stack, BM_DEFAULT_ITER_STACK_SIZE);
-
- if (LIKELY(loops != NULL)) {
- for (i = 0; i < loops_tot; i++) {
- loops[i]->v = v_target;
- }
- if (loops != (BMLoop **)loops_stack) {
- MEM_freeN(loops);
- }
- }
+ 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)) {
+
+ /* 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);
@@ -2020,7 +2071,7 @@ void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len
BLI_smallhash_init_ex(&visithash, v_edgetot);
- STACK_INIT(stack);
+ STACK_INIT(stack, v_edgetot);
maxindex = 0;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
@@ -2030,15 +2081,16 @@ void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len
/* 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));
do {
- BLI_smallhash_insert(&visithash, (uintptr_t)e, SET_INT_IN_POINTER(maxindex));
-
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);
}
} while ((l_iter = l_iter->radial_next) != l_first);
@@ -2091,7 +2143,7 @@ void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len
* 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);
+ STACK_INIT(stack, v_edgetot);
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
if (l->v == v) {
STACK_PUSH(stack, (BMEdge *)l);
@@ -2104,8 +2156,6 @@ void bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len
}
#endif
- STACK_FREE(stack);
-
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) {
diff --git a/source/blender/bmesh/intern/bmesh_core.h b/source/blender/bmesh/intern/bmesh_core.h
index 654698da3c6..ab847fc82eb 100644
--- a/source/blender/bmesh/intern/bmesh_core.h
+++ b/source/blender/bmesh/intern/bmesh_core.h
@@ -61,6 +61,7 @@ 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);
+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);
@@ -83,7 +84,8 @@ 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 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);
diff --git a/source/blender/bmesh/intern/bmesh_edgeloop.c b/source/blender/bmesh/intern/bmesh_edgeloop.c
index bbf4b661a1b..e83a1d5b00a 100644
--- a/source/blender/bmesh/intern/bmesh_edgeloop.c
+++ b/source/blender/bmesh/intern/bmesh_edgeloop.c
@@ -189,7 +189,7 @@ static void vs_add(BLI_mempool *vs_pool, ListBase *lb,
struct VertStep *vs_new = BLI_mempool_alloc(vs_pool);
vs_new->v = v;
- BM_elem_index_set(v, iter_tot);
+ BM_elem_index_set(v, iter_tot); /* set_dirty */
/* This edge stores a direct path back to the original vertex so we can
* backtrack without having to store an array of previous verts. */
@@ -248,6 +248,7 @@ static bool bm_loop_path_build_step(BLI_mempool *vs_pool, ListBase *lb, const in
BLI_mempool_free(vs_pool, vs);
}
+ /* bm->elem_index_dirty |= BM_VERT; */ /* Commented because used in a loop, and this flag has already been set. */
/* lb is now full of free'd items, overwrite */
*lb = lb_tmp;
@@ -303,6 +304,7 @@ bool BM_mesh_edgeloops_find_path(BMesh *bm, ListBase *r_eloops,
/* edge args are dummy */
vs_add(vs_pool, &lb_src, v_src, v_src->e, 1);
vs_add(vs_pool, &lb_dst, v_dst, v_dst->e, -1);
+ bm->elem_index_dirty |= BM_VERT;
do {
if ((bm_loop_path_build_step(vs_pool, &lb_src, 1, v_match) == false) || v_match[0]) {
@@ -655,7 +657,7 @@ bool BM_edgeloop_calc_normal_aligned(BMesh *UNUSED(bm), BMEdgeLoopStore *el_stor
void BM_edgeloop_flip(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store)
{
negate_v3(el_store->no);
- BLI_reverselist(&el_store->verts);
+ BLI_listbase_reverse(&el_store->verts);
}
void BM_edgeloop_expand(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, int el_store_len)
@@ -680,12 +682,12 @@ void BM_edgeloop_expand(BMesh *UNUSED(bm), BMEdgeLoopStore *el_store, int el_sto
LinkData *node_curr_init = node_curr;
LinkData *node_curr_copy;
int i = 0;
- LISTBASE_CIRCULAR_FORWARD_BEGIN (&el_store->verts, node_curr, node_curr_init) {
+ BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (&el_store->verts, node_curr, node_curr_init) {
if (i++ < step) {
break;
}
}
- LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init);
+ BLI_LISTBASE_CIRCULAR_FORWARD_END (&el_store->verts, node_curr, node_curr_init);
node_curr_copy = MEM_dupallocN(node_curr);
BLI_insertlinkafter(&el_store->verts, node_curr, node_curr_copy);
diff --git a/source/blender/bmesh/intern/bmesh_error.h b/source/blender/bmesh/intern/bmesh_error.h
index 0f23f87c143..6cd37011814 100644
--- a/source/blender/bmesh/intern/bmesh_error.h
+++ b/source/blender/bmesh/intern/bmesh_error.h
@@ -59,17 +59,20 @@ void BMO_error_clear(BMesh *bm);
/*------ error code defines -------*/
/*error messages*/
-#define BMERR_SELF_INTERSECTING 1
-#define BMERR_DISSOLVEDISK_FAILED 2
-#define BMERR_CONNECTVERT_FAILED 3
-#define BMERR_WALKER_FAILED 4
-#define BMERR_DISSOLVEFACES_FAILED 5
-#define BMERR_DISSOLVEVERTS_FAILED 6
-#define BMERR_TESSELLATION 7
-#define BMERR_NONMANIFOLD 8
-#define BMERR_INVALID_SELECTION 9
-#define BMERR_MESH_ERROR 10
-#define BMERR_CONVEX_HULL_FAILED 11
+enum {
+ BMERR_SELF_INTERSECTING = 1,
+ BMERR_DISSOLVEDISK_FAILED,
+ BMERR_CONNECTVERT_FAILED,
+ BMERR_WALKER_FAILED,
+ BMERR_DISSOLVEFACES_FAILED,
+ BMERR_TESSELLATION,
+ BMERR_NONMANIFOLD,
+ BMERR_INVALID_SELECTION,
+ BMERR_MESH_ERROR,
+ BMERR_CONVEX_HULL_FAILED,
+
+ BMERR_TOTAL,
+};
/* BMESH_ASSERT */
#ifdef WITH_ASSERT_ABORT
diff --git a/source/blender/bmesh/intern/bmesh_inline.h b/source/blender/bmesh/intern/bmesh_inline.h
index 5ac6d7da61b..96b2cd396a2 100644
--- a/source/blender/bmesh/intern/bmesh_inline.h
+++ b/source/blender/bmesh/intern/bmesh_inline.h
@@ -106,9 +106,6 @@ BLI_INLINE void _bm_elem_flag_merge_into(BMHeader *head, const BMHeader *head_a,
* adding new vert/edge/faces since they may be added at
* the end of the array.
*
- * - 'set_loop' -- currently loop index values are not used used much so
- * assume each case they are dirty.
- *
* - campbell */
#define BM_elem_index_get(ele) _bm_elem_index_get(&(ele)->head)
diff --git a/source/blender/bmesh/intern/bmesh_interp.c b/source/blender/bmesh/intern/bmesh_interp.c
index 2250b8135d7..a32f28169f6 100644
--- a/source/blender/bmesh/intern/bmesh_interp.c
+++ b/source/blender/bmesh/intern/bmesh_interp.c
@@ -54,7 +54,7 @@ static void bm_data_interp_from_elem(CustomData *data_layer, BMElem *ele1, BMEle
/* do nothing */
}
else {
- CustomData_bmesh_free_block_data(data_layer, &ele_dst->head.data);
+ CustomData_bmesh_free_block_data(data_layer, ele_dst->head.data);
CustomData_bmesh_copy_data(data_layer, data_layer, ele1->head.data, &ele_dst->head.data);
}
}
@@ -63,7 +63,7 @@ static void bm_data_interp_from_elem(CustomData *data_layer, BMElem *ele1, BMEle
/* do nothing */
}
else {
- CustomData_bmesh_free_block_data(data_layer, &ele_dst->head.data);
+ CustomData_bmesh_free_block_data(data_layer, ele_dst->head.data);
CustomData_bmesh_copy_data(data_layer, data_layer, ele2->head.data, &ele_dst->head.data);
}
}
@@ -397,8 +397,8 @@ 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(float source_axis_x[3], float source_axis_y[3],
- float target_axis_x[3], 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];
diff --git a/source/blender/bmesh/intern/bmesh_interp.h b/source/blender/bmesh/intern/bmesh_interp.h
index 2a3b5190ece..c605ad31ae7 100644
--- a/source/blender/bmesh/intern/bmesh_interp.h
+++ b/source/blender/bmesh/intern/bmesh_interp.h
@@ -33,9 +33,9 @@ void BM_vert_interp_from_face(BMesh *bm, BMVert *v, BMFace *source);
void BM_data_interp_from_verts(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, const float fac);
void BM_data_interp_from_edges(BMesh *bm, BMEdge *e1, BMEdge *e2, BMEdge *e, const float fac);
void BM_data_interp_face_vert_edge(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v, BMEdge *e1, const float fac);
-void BM_data_layer_add(BMesh *em, CustomData *data, int type);
+void BM_data_layer_add(BMesh *bm, CustomData *data, int type);
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name);
-void BM_data_layer_free(BMesh *em, CustomData *data, int type);
+void BM_data_layer_free(BMesh *bm, CustomData *data, int type);
void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n);
void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n);
diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c
index 91b9774634d..476878ad38c 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.c
+++ b/source/blender/bmesh/intern/bmesh_iterators.c
@@ -338,50 +338,18 @@ int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const
# define USE_IMMUTABLE_ASSERT
#endif
-void bmiter__vert_of_mesh_begin(struct BMIter__vert_of_mesh *iter)
+void bmiter__elem_of_mesh_begin(struct BMIter__elem_of_mesh *iter)
{
#ifdef USE_IMMUTABLE_ASSERT
- ((BMIter *)iter)->count = iter->bm->totvert;
+ ((BMIter *)iter)->count = BLI_mempool_count(iter->pooliter.pool);
#endif
- BLI_mempool_iternew(iter->bm->vpool, &iter->pooliter);
+ BLI_mempool_iternew(iter->pooliter.pool, &iter->pooliter);
}
-void *bmiter__vert_of_mesh_step(struct BMIter__vert_of_mesh *iter)
+void *bmiter__elem_of_mesh_step(struct BMIter__elem_of_mesh *iter)
{
#ifdef USE_IMMUTABLE_ASSERT
- BLI_assert(((BMIter *)iter)->count <= iter->bm->totvert);
-#endif
- return BLI_mempool_iterstep(&iter->pooliter);
-}
-
-void bmiter__edge_of_mesh_begin(struct BMIter__edge_of_mesh *iter)
-{
-#ifdef USE_IMMUTABLE_ASSERT
- ((BMIter *)iter)->count = iter->bm->totedge;
-#endif
- BLI_mempool_iternew(iter->bm->epool, &iter->pooliter);
-}
-
-void *bmiter__edge_of_mesh_step(struct BMIter__edge_of_mesh *iter)
-{
-#ifdef USE_IMMUTABLE_ASSERT
- BLI_assert(((BMIter *)iter)->count <= iter->bm->totedge);
-#endif
- return BLI_mempool_iterstep(&iter->pooliter);
-}
-
-void bmiter__face_of_mesh_begin(struct BMIter__face_of_mesh *iter)
-{
-#ifdef USE_IMMUTABLE_ASSERT
- ((BMIter *)iter)->count = iter->bm->totface;
-#endif
- BLI_mempool_iternew(iter->bm->fpool, &iter->pooliter);
-}
-
-void *bmiter__face_of_mesh_step(struct BMIter__face_of_mesh *iter)
-{
-#ifdef USE_IMMUTABLE_ASSERT
- BLI_assert(((BMIter *)iter)->count <= iter->bm->totface);
+ BLI_assert(((BMIter *)iter)->count <= BLI_mempool_count(iter->pooliter.pool));
#endif
return BLI_mempool_iterstep(&iter->pooliter);
}
diff --git a/source/blender/bmesh/intern/bmesh_iterators.h b/source/blender/bmesh/intern/bmesh_iterators.h
index fdf0f27f05f..44be7072e71 100644
--- a/source/blender/bmesh/intern/bmesh_iterators.h
+++ b/source/blender/bmesh/intern/bmesh_iterators.h
@@ -110,16 +110,7 @@ extern const char bm_iter_itype_htype_map[BM_ITYPE_MAX];
for (ele = BM_iter_new(iter, NULL, itype, data), indexvar = 0; ele; ele = BM_iter_step(iter), (indexvar)++)
/* iterator type structs */
-struct BMIter__vert_of_mesh {
- BMesh *bm;
- BLI_mempool_iter pooliter;
-};
-struct BMIter__edge_of_mesh {
- BMesh *bm;
- BLI_mempool_iter pooliter;
-};
-struct BMIter__face_of_mesh {
- BMesh *bm;
+struct BMIter__elem_of_mesh {
BLI_mempool_iter pooliter;
};
struct BMIter__edge_of_vert {
@@ -173,9 +164,7 @@ typedef void *(*BMIter__step_cb) (void *);
typedef struct BMIter {
/* keep union first */
union {
- struct BMIter__vert_of_mesh vert_of_mesh;
- struct BMIter__edge_of_mesh edge_of_mesh;
- struct BMIter__face_of_mesh face_of_mesh;
+ struct BMIter__elem_of_mesh elem_of_mesh;
struct BMIter__edge_of_vert edge_of_vert;
struct BMIter__face_of_vert face_of_vert;
@@ -219,9 +208,7 @@ int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, c
void bmiter__##name##_begin(struct BMIter__##name *iter); \
void *bmiter__##name##_step(struct BMIter__##name *iter)
-BMITER_CB_DEF(vert_of_mesh);
-BMITER_CB_DEF(edge_of_mesh);
-BMITER_CB_DEF(face_of_mesh);
+BMITER_CB_DEF(elem_of_mesh);
BMITER_CB_DEF(edge_of_vert);
BMITER_CB_DEF(face_of_vert);
BMITER_CB_DEF(loop_of_vert);
@@ -237,4 +224,12 @@ BMITER_CB_DEF(loop_of_face);
#include "intern/bmesh_iterators_inline.h"
+#define BM_ITER_CHECK_TYPE_DATA(data) \
+ CHECK_TYPE_ANY(data, void *, BMFace *, BMEdge *, BMVert *, BMLoop *, BMElem *)
+
+#define BM_iter_new(iter, bm, itype, data) \
+ (BM_ITER_CHECK_TYPE_DATA(data), BM_iter_new(iter, bm, itype, data))
+#define BM_iter_init(iter, bm, itype, data) \
+ (BM_ITER_CHECK_TYPE_DATA(data), BM_iter_init(iter, bm, itype, data))
+
#endif /* __BMESH_ITERATORS_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_iterators_inline.h b/source/blender/bmesh/intern/bmesh_iterators_inline.h
index 6a0eb0e0a30..d3e18b97acb 100644
--- a/source/blender/bmesh/intern/bmesh_iterators_inline.h
+++ b/source/blender/bmesh/intern/bmesh_iterators_inline.h
@@ -60,80 +60,90 @@ BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *da
case BM_VERTS_OF_MESH:
BLI_assert(bm != NULL);
BLI_assert(data == NULL);
- iter->begin = (BMIter__begin_cb)bmiter__vert_of_mesh_begin;
- iter->step = (BMIter__step_cb)bmiter__vert_of_mesh_step;
- iter->data.vert_of_mesh.bm = bm;
+ iter->begin = (BMIter__begin_cb)bmiter__elem_of_mesh_begin;
+ iter->step = (BMIter__step_cb)bmiter__elem_of_mesh_step;
+ iter->data.elem_of_mesh.pooliter.pool = bm->vpool;
break;
case BM_EDGES_OF_MESH:
BLI_assert(bm != NULL);
BLI_assert(data == NULL);
- iter->begin = (BMIter__begin_cb)bmiter__edge_of_mesh_begin;
- iter->step = (BMIter__step_cb)bmiter__edge_of_mesh_step;
- iter->data.edge_of_mesh.bm = bm;
+ iter->begin = (BMIter__begin_cb)bmiter__elem_of_mesh_begin;
+ iter->step = (BMIter__step_cb)bmiter__elem_of_mesh_step;
+ iter->data.elem_of_mesh.pooliter.pool = bm->epool;
break;
case BM_FACES_OF_MESH:
BLI_assert(bm != NULL);
BLI_assert(data == NULL);
- iter->begin = (BMIter__begin_cb)bmiter__face_of_mesh_begin;
- iter->step = (BMIter__step_cb)bmiter__face_of_mesh_step;
- iter->data.face_of_mesh.bm = bm;
+ iter->begin = (BMIter__begin_cb)bmiter__elem_of_mesh_begin;
+ iter->step = (BMIter__step_cb)bmiter__elem_of_mesh_step;
+ iter->data.elem_of_mesh.pooliter.pool = bm->fpool;
break;
case BM_EDGES_OF_VERT:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_VERT);
iter->begin = (BMIter__begin_cb)bmiter__edge_of_vert_begin;
iter->step = (BMIter__step_cb)bmiter__edge_of_vert_step;
iter->data.edge_of_vert.vdata = (BMVert *)data;
break;
case BM_FACES_OF_VERT:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_VERT);
iter->begin = (BMIter__begin_cb)bmiter__face_of_vert_begin;
iter->step = (BMIter__step_cb)bmiter__face_of_vert_step;
iter->data.face_of_vert.vdata = (BMVert *)data;
break;
case BM_LOOPS_OF_VERT:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_VERT);
iter->begin = (BMIter__begin_cb)bmiter__loop_of_vert_begin;
iter->step = (BMIter__step_cb)bmiter__loop_of_vert_step;
iter->data.loop_of_vert.vdata = (BMVert *)data;
break;
case BM_VERTS_OF_EDGE:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_EDGE);
iter->begin = (BMIter__begin_cb)bmiter__vert_of_edge_begin;
iter->step = (BMIter__step_cb)bmiter__vert_of_edge_step;
iter->data.vert_of_edge.edata = (BMEdge *)data;
break;
case BM_FACES_OF_EDGE:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_EDGE);
iter->begin = (BMIter__begin_cb)bmiter__face_of_edge_begin;
iter->step = (BMIter__step_cb)bmiter__face_of_edge_step;
iter->data.face_of_edge.edata = (BMEdge *)data;
break;
case BM_VERTS_OF_FACE:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_FACE);
iter->begin = (BMIter__begin_cb)bmiter__vert_of_face_begin;
iter->step = (BMIter__step_cb)bmiter__vert_of_face_step;
iter->data.vert_of_face.pdata = (BMFace *)data;
break;
case BM_EDGES_OF_FACE:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_FACE);
iter->begin = (BMIter__begin_cb)bmiter__edge_of_face_begin;
iter->step = (BMIter__step_cb)bmiter__edge_of_face_step;
iter->data.edge_of_face.pdata = (BMFace *)data;
break;
case BM_LOOPS_OF_FACE:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_FACE);
iter->begin = (BMIter__begin_cb)bmiter__loop_of_face_begin;
iter->step = (BMIter__step_cb)bmiter__loop_of_face_step;
iter->data.loop_of_face.pdata = (BMFace *)data;
break;
case BM_LOOPS_OF_LOOP:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_LOOP);
iter->begin = (BMIter__begin_cb)bmiter__loop_of_loop_begin;
iter->step = (BMIter__step_cb)bmiter__loop_of_loop_step;
iter->data.loop_of_loop.ldata = (BMLoop *)data;
break;
case BM_LOOPS_OF_EDGE:
BLI_assert(data != NULL);
+ BLI_assert(((BMElem *)data)->head.htype == BM_EDGE);
iter->begin = (BMIter__begin_cb)bmiter__loop_of_edge_begin;
iter->step = (BMIter__step_cb)bmiter__loop_of_edge_step;
iter->data.loop_of_edge.edata = (BMEdge *)data;
diff --git a/source/blender/bmesh/intern/bmesh_log.c b/source/blender/bmesh/intern/bmesh_log.c
index 7d3bc0e16b3..709a174731f 100644
--- a/source/blender/bmesh/intern/bmesh_log.c
+++ b/source/blender/bmesh/intern/bmesh_log.c
@@ -423,9 +423,7 @@ static void bm_log_id_ghash_retake(RangeTreeUInt *unused_ids, GHash *id_ghash)
void *key = BLI_ghashIterator_getKey(&gh_iter);
unsigned int id = GET_UINT_FROM_POINTER(key);
- if (range_tree_uint_has(unused_ids, id)) {
- range_tree_uint_take(unused_ids, id);
- }
+ range_tree_uint_retake(unused_ids, id);
}
}
@@ -489,6 +487,29 @@ BMLog *BM_log_create(BMesh *bm)
return log;
}
+void BM_log_cleanup_entry(BMLogEntry *entry)
+{
+ BMLog *log = entry->log;
+
+ if (log) {
+ /* Take all used IDs */
+ bm_log_id_ghash_retake(log->unused_ids, entry->deleted_verts);
+ bm_log_id_ghash_retake(log->unused_ids, entry->deleted_faces);
+ bm_log_id_ghash_retake(log->unused_ids, entry->added_verts);
+ bm_log_id_ghash_retake(log->unused_ids, entry->added_faces);
+ bm_log_id_ghash_retake(log->unused_ids, entry->modified_verts);
+ bm_log_id_ghash_retake(log->unused_ids, entry->modified_faces);
+
+ /* delete entries to avoid releasing ids in node cleanup */
+ BLI_ghash_clear(entry->deleted_verts, NULL, NULL);
+ BLI_ghash_clear(entry->deleted_faces, NULL, NULL);
+ BLI_ghash_clear(entry->added_verts, NULL, NULL);
+ BLI_ghash_clear(entry->added_faces, NULL, NULL);
+ BLI_ghash_clear(entry->modified_verts, NULL, NULL);
+ }
+}
+
+
/* Allocate and initialize a new BMLog using existing BMLogEntries
*
* The 'entry' should be the last entry in the BMLog. Its prev pointer
@@ -684,8 +705,27 @@ void BM_log_entry_drop(BMLogEntry *entry)
* entry. Since the entry is at the beginning of the undo
* stack, and it's being deleted, those elements can never be
* restored. Their IDs can go back into the pool. */
- bm_log_id_ghash_release(log, entry->deleted_faces);
- bm_log_id_ghash_release(log, entry->deleted_verts);
+
+ /* This would never happen usually since first entry of log is
+ * usually dyntopo enable, which, when reverted will free the log
+ * completely. However, it is possible have a stroke instead of
+ * dyntopo enable as first entry if nodes have been cleaned up
+ * after sculpting on a different object than A, B.
+ *
+ * The steps are:
+ * A dyntopo enable - sculpt
+ * B dyntopo enable - sculpt - undo (A objects operators get cleaned up)
+ * A sculpt (now A's log has a sculpt operator as first entry)
+ *
+ * Causing a cleanup at this point will call the code below, however
+ * this will invalidate the state of the log since the deleted vertices
+ * have been reclaimed already on step 2 (see BM_log_cleanup_entry)
+ *
+ * Also, design wise, a first entry should not have any deleted vertices since it
+ * should not have anything to delete them -from-
+ */
+ //bm_log_id_ghash_release(log, entry->deleted_faces);
+ //bm_log_id_ghash_release(log, entry->deleted_verts);
}
else if (!entry->next) {
/* Release IDs of elements that are added by this entry. Since
diff --git a/source/blender/bmesh/intern/bmesh_log.h b/source/blender/bmesh/intern/bmesh_log.h
index 7a26506439f..2147b5c64b4 100644
--- a/source/blender/bmesh/intern/bmesh_log.h
+++ b/source/blender/bmesh/intern/bmesh_log.h
@@ -51,6 +51,9 @@ void BM_log_mesh_elems_reorder(BMesh *bm, BMLog *log);
/* Start a new log entry and update the log entry list */
BMLogEntry *BM_log_entry_add(BMLog *log);
+/* Mark all used ids as unused for this node */
+void BM_log_cleanup_entry(BMLogEntry *entry);
+
/* Remove an entry from the log */
void BM_log_entry_drop(BMLogEntry *entry);
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index eff3cf220f3..ee35d8cd1d2 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -56,7 +56,7 @@ static void recount_totsels(BMesh *bm)
tots[1] = &bm->totedgesel;
tots[2] = &bm->totfacesel;
-#pragma omp parallel for schedule(dynamic)
+#pragma omp parallel for schedule(static) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
for (i = 0; i < 3; i++) {
BMIter iter;
BMElem *ele;
@@ -537,7 +537,7 @@ 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 short respecthide, const bool test_for_enabled)
+ const bool respecthide, const bool test_for_enabled)
{
BMElem *ele;
BMIter iter;
@@ -864,7 +864,9 @@ void BM_select_history_validate(BMesh *bm)
}
}
-/* utility function */
+/**
+ * Get the active mesh element (with active-face fallback).
+ */
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
{
BMEditSelection *ese_last = bm->selected.last;
@@ -887,7 +889,8 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
ese->htype = ese_last->htype;
}
}
- else if (efa) { /* no */
+ else if (efa) {
+ /* no edit-selection, fallback to active face */
ese->ele = (BMElem *)efa;
ese->htype = BM_FACE;
}
@@ -899,6 +902,27 @@ bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
return true;
}
+/**
+ * Return a map from BMVert/Edge/Face -> BMEditSelection
+ */
+GHash *BM_select_history_map_create(BMesh *bm)
+{
+ BMEditSelection *ese;
+ GHash *map;
+
+ if (BLI_listbase_is_empty(&bm->selected)) {
+ return NULL;
+ }
+
+ map = BLI_ghash_ptr_new(__func__);
+
+ for (ese = bm->selected.first; ese; ese = ese->next) {
+ BLI_ghash_insert(map, ese->ele, ese);
+ }
+
+ 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)
{
@@ -926,7 +950,7 @@ void BM_mesh_elem_hflag_disable_test(BMesh *bm, const char htype, const char hfl
/* fast path for deselect all, avoid topology loops
* since we know all will be de-selected anyway. */
-#pragma omp parallel for schedule(dynamic) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
+#pragma omp parallel for schedule(static) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
for (i = 0; i < 3; i++) {
BMIter iter;
BMElem *ele;
diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h
index 99456ea2c98..9e0c0923164 100644
--- a/source/blender/bmesh/intern/bmesh_marking.h
+++ b/source/blender/bmesh/intern/bmesh_marking.h
@@ -98,7 +98,14 @@ void _bm_select_history_store_after(BMesh *bm, BMEditSelection *ese_ref, BMHead
void _bm_select_history_store_after_notest(BMesh *bm, BMEditSelection *ese_ref, BMHeader *ele);
void BM_select_history_validate(BMesh *bm);
-void BM_select_history_clear(BMesh *em);
+void BM_select_history_clear(BMesh *bm);
bool BM_select_history_active_get(BMesh *bm, struct BMEditSelection *ese);
+struct GHash *BM_select_history_map_create(BMesh *bm);
+
+#define BM_SELECT_HISTORY_BACKUP(bm) { \
+ ListBase _bm_prev_selected = (bm)->selected; BLI_listbase_clear(&(bm)->selected)
+
+#define BM_SELECT_HISTORY_RESTORE(bm) \
+ (bm)->selected = _bm_prev_selected; } (void)0
#endif /* __BMESH_MARKING_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index e9d3c36eb1a..b16ea42304a 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -449,14 +449,14 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const flo
}
{
- char hflag = BM_LOOP;
+ char htype = BM_LOOP;
if (vnos) {
- hflag |= BM_VERT;
+ htype |= BM_VERT;
}
if (fnos) {
- hflag |= BM_FACE;
+ htype |= BM_FACE;
}
- BM_mesh_elem_index_ensure(bm, hflag);
+ BM_mesh_elem_index_ensure(bm, htype);
}
/* This first loop checks which edges are actually smooth, and pre-populate lnos with vnos (as if they were
@@ -477,11 +477,18 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const flo
is_angle_smooth = (dot_v3v3(no_a, no_b) >= split_angle);
}
- /* We only tag edges that are *really* smooth... */
+ /* We only tag edges that are *really* smooth:
+ * If the angle between both its polys' normals is below split_angle value,
+ * and it is tagged as such,
+ * and both its faces are smooth,
+ * and both its faces have compatible (non-flipped) normals, i.e. both loops on the same edge do not share
+ * the same vertex.
+ */
if (is_angle_smooth &&
BM_elem_flag_test_bool(e, BM_ELEM_SMOOTH) &&
BM_elem_flag_test_bool(l_a->f, BM_ELEM_SMOOTH) &&
- BM_elem_flag_test_bool(l_b->f, BM_ELEM_SMOOTH))
+ BM_elem_flag_test_bool(l_b->f, BM_ELEM_SMOOTH) &&
+ l_a->v != l_b->v)
{
const float *no;
BM_elem_flag_enable(e, BM_ELEM_TAG);
@@ -508,14 +515,14 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
BLI_SMALLSTACK_DECLARE(normal, float *);
{
- char hflag = BM_LOOP;
+ char htype = BM_LOOP;
if (vcos) {
- hflag |= BM_VERT;
+ htype |= BM_VERT;
}
if (fnos) {
- hflag |= BM_FACE;
+ htype |= BM_FACE;
}
- BM_mesh_elem_index_ensure(bm, hflag);
+ BM_mesh_elem_index_ensure(bm, htype);
}
/* We now know edges that can be smoothed (they are tagged), and edges that will be hard (they aren't).
@@ -542,6 +549,14 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
const float *no = fnos ? fnos[BM_elem_index_get(f_curr)] : f_curr->no;
copy_v3_v3(r_lnos[BM_elem_index_get(l_curr)], no);
}
+ /* We *do not need* to check/tag loops as already computed!
+ * Due to the fact a loop only links to one of its two edges, a same fan *will never be walked more than
+ * once!*
+ * Since we consider edges having neighbor faces with inverted (flipped) normals as sharp, we are sure that
+ * no fan will be skipped, even only considering the case (sharp curr_edge, smooth prev_edge), and not the
+ * alternative (smooth curr_edge, sharp prev_edge).
+ * All this due/thanks to link between normals and loop ordering.
+ */
else {
/* We have to fan around current vertex, until we find the other non-smooth edge,
* and accumulate face normals into the vertex!
@@ -626,11 +641,13 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
copy_v3_v3(nor, lnor);
}
}
+ else {
+ /* We still have to clear the stack! */
+ while (BLI_SMALLSTACK_POP(normal));
+ }
}
} while ((l_curr = l_curr->next) != l_first);
}
-
- BLI_SMALLSTACK_FREE(normal);
}
#if 0 /* Unused currently */
@@ -749,6 +766,8 @@ void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
*/
void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
{
+ ListBase select_history;
+
/* BMO_OPTYPE_FLAG_UNTAN_MULTIRES disabled for now, see comment above in bmesh_edit_begin. */
#ifdef BMOP_UNTAN_MULTIRES_ENABLED
/* switch multires data into tangent space */
@@ -767,22 +786,41 @@ void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
BM_mesh_normals_update(bm);
}
+
+ if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) {
+ select_history = bm->selected;
+ BLI_listbase_clear(&bm->selected);
+ }
+
if (type_flag & BMO_OPTYPE_FLAG_SELECT_FLUSH) {
BM_mesh_select_mode_flush(bm);
}
+
+ if ((type_flag & BMO_OPTYPE_FLAG_SELECT_VALIDATE) == 0) {
+ bm->selected = select_history;
+ }
}
-void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag)
+void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
{
+ const char htype_needed = bm->elem_index_dirty & htype;
+
#ifdef DEBUG
BM_ELEM_INDEX_VALIDATE(bm, "Should Never Fail!", __func__);
#endif
-#pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
+ if (htype_needed == 0) {
+ goto finally;
+ }
+
+ /* skip if we only need to operate on one element */
+#pragma omp parallel sections if ((!ELEM(htype_needed, BM_VERT, BM_EDGE, BM_FACE, BM_LOOP, BM_FACE | BM_LOOP)) && \
+ (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT))
{
#pragma omp section
+
{
- if (hflag & BM_VERT) {
+ if (htype & BM_VERT) {
if (bm->elem_index_dirty & BM_VERT) {
BMIter iter;
BMElem *ele;
@@ -801,7 +839,7 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag)
#pragma omp section
{
- if (hflag & BM_EDGE) {
+ if (htype & BM_EDGE) {
if (bm->elem_index_dirty & BM_EDGE) {
BMIter iter;
BMElem *ele;
@@ -820,13 +858,13 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag)
#pragma omp section
{
- if (hflag & (BM_FACE | BM_LOOP)) {
+ if (htype & (BM_FACE | BM_LOOP)) {
if (bm->elem_index_dirty & (BM_FACE | BM_LOOP)) {
BMIter iter;
BMElem *ele;
- const bool update_face = (hflag & BM_FACE) && (bm->elem_index_dirty & BM_FACE);
- const bool update_loop = (hflag & BM_LOOP) && (bm->elem_index_dirty & BM_LOOP);
+ const bool update_face = (htype & BM_FACE) && (bm->elem_index_dirty & BM_FACE);
+ const bool update_loop = (htype & BM_LOOP) && (bm->elem_index_dirty & BM_LOOP);
int index;
int index_loop = 0;
@@ -858,7 +896,9 @@ void BM_mesh_elem_index_ensure(BMesh *bm, const char hflag)
}
}
- bm->elem_index_dirty &= ~hflag;
+
+finally:
+ bm->elem_index_dirty &= ~htype;
}
@@ -989,6 +1029,10 @@ void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
/* in debug mode double check we didn't need to recalculate */
BLI_assert(BM_mesh_elem_table_check(bm) == true);
+ if (htype_needed == 0) {
+ goto finally;
+ }
+
if (htype_needed & BM_VERT) {
if (bm->vtable && bm->totvert <= bm->vtable_tot && bm->totvert * 2 >= bm->vtable_tot) {
/* pass (re-use the array) */
@@ -1023,7 +1067,9 @@ void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
}
}
-#pragma omp parallel sections if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
+ /* skip if we only need to operate on one element */
+#pragma omp parallel sections if ((!ELEM(htype_needed, BM_VERT, BM_EDGE, BM_FACE)) && \
+ (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT))
{
#pragma omp section
{
@@ -1045,19 +1091,12 @@ void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
}
}
+finally:
/* Only clear dirty flags when all the pointers and data are actually valid.
* This prevents possible threading issues when dirty flag check failed but
* data wasn't ready still.
*/
- if (htype_needed & BM_VERT) {
- bm->elem_table_dirty &= ~BM_VERT;
- }
- if (htype_needed & BM_EDGE) {
- bm->elem_table_dirty &= ~BM_EDGE;
- }
- if (htype_needed & BM_FACE) {
- bm->elem_table_dirty &= ~BM_FACE;
- }
+ bm->elem_table_dirty &= ~htype_needed;
}
/* use BM_mesh_elem_table_ensure where possible to avoid full rebuild */
@@ -1154,7 +1193,11 @@ int BM_mesh_elem_count(BMesh *bm, const char htype)
*
* WARNING: Be careful if you keep pointers to affected BM elements, or arrays, when using this func!
*/
-void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, unsigned int *face_idx)
+void BM_mesh_remap(
+ BMesh *bm,
+ const unsigned int *vert_idx,
+ const unsigned int *edge_idx,
+ const unsigned int *face_idx)
{
/* Mapping old to new pointers. */
GHash *vptr_map = NULL, *eptr_map = NULL, *fptr_map = NULL;
@@ -1167,18 +1210,23 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un
if (!(vert_idx || edge_idx || face_idx))
return;
+ BM_mesh_elem_table_ensure(
+ bm,
+ (vert_idx ? BM_VERT : 0) |
+ (edge_idx ? BM_EDGE : 0) |
+ (face_idx ? BM_FACE : 0));
+
/* Remap Verts */
if (vert_idx) {
BMVert **verts_pool, *verts_copy, **vep;
int i, totvert = bm->totvert;
- unsigned int *new_idx = NULL;
+ const unsigned int *new_idx;
/* Init the old-to-new vert pointers mapping */
vptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap vert pointers mapping", bm->totvert);
/* Make a copy of all vertices. */
- verts_pool = MEM_callocN(sizeof(BMVert *) * totvert, "BM_mesh_remap verts pool");
- BM_iter_as_array(bm, BM_VERTS_OF_MESH, NULL, (void **)verts_pool, totvert);
+ verts_pool = bm->vtable;
verts_copy = MEM_mallocN(sizeof(BMVert) * totvert, "BM_mesh_remap verts copy");
for (i = totvert, ve = verts_copy + totvert - 1, vep = verts_pool + totvert - 1; i--; ve--, vep--) {
*ve = **vep;
@@ -1196,8 +1244,8 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un
BLI_ghash_insert(vptr_map, (void *)*vep, (void *)new_vep);
}
bm->elem_index_dirty |= BM_VERT;
+ bm->elem_table_dirty |= BM_VERT;
- MEM_freeN(verts_pool);
MEM_freeN(verts_copy);
}
@@ -1205,14 +1253,13 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un
if (edge_idx) {
BMEdge **edges_pool, *edges_copy, **edp;
int i, totedge = bm->totedge;
- unsigned int *new_idx = NULL;
+ const unsigned int *new_idx;
/* Init the old-to-new vert pointers mapping */
eptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap edge pointers mapping", bm->totedge);
/* Make a copy of all vertices. */
- edges_pool = MEM_callocN(sizeof(BMEdge *) * totedge, "BM_mesh_remap edges pool");
- BM_iter_as_array(bm, BM_EDGES_OF_MESH, NULL, (void **)edges_pool, totedge);
+ edges_pool = bm->etable;
edges_copy = MEM_mallocN(sizeof(BMEdge) * totedge, "BM_mesh_remap edges copy");
for (i = totedge, ed = edges_copy + totedge - 1, edp = edges_pool + totedge - 1; i--; ed--, edp--) {
*ed = **edp;
@@ -1229,8 +1276,8 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un
/* 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;
+ bm->elem_table_dirty |= BM_EDGE;
- MEM_freeN(edges_pool);
MEM_freeN(edges_copy);
}
@@ -1238,14 +1285,13 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un
if (face_idx) {
BMFace **faces_pool, *faces_copy, **fap;
int i, totface = bm->totface;
- unsigned int *new_idx = NULL;
+ const unsigned int *new_idx;
/* Init the old-to-new vert pointers mapping */
fptr_map = BLI_ghash_ptr_new_ex("BM_mesh_remap face pointers mapping", bm->totface);
/* Make a copy of all vertices. */
- faces_pool = MEM_callocN(sizeof(BMFace *) * totface, "BM_mesh_remap faces pool");
- BM_iter_as_array(bm, BM_FACES_OF_MESH, NULL, (void **)faces_pool, totface);
+ faces_pool = bm->ftable;
faces_copy = MEM_mallocN(sizeof(BMFace) * totface, "BM_mesh_remap faces copy");
for (i = totface, fa = faces_copy + totface - 1, fap = faces_pool + totface - 1; i--; fa--, fap--) {
*fa = **fap;
@@ -1262,8 +1308,8 @@ void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, un
}
bm->elem_index_dirty |= BM_FACE | BM_LOOP;
+ bm->elem_table_dirty |= BM_FACE;
- MEM_freeN(faces_pool);
MEM_freeN(faces_copy);
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index 3923c2515a3..22e50502aee 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -50,7 +50,7 @@ void BM_mesh_elem_index_validate(BMesh *bm, const char *location, const char *fu
const char *msg_a, const char *msg_b);
#ifndef NDEBUG
-bool BM_mesh_elem_table_check(BMesh *em);
+bool BM_mesh_elem_table_check(BMesh *bm);
#endif
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype);
@@ -69,7 +69,11 @@ BMFace *BM_face_at_index_find(BMesh *bm, const int index);
int BM_mesh_elem_count(BMesh *bm, const char htype);
-void BM_mesh_remap(BMesh *bm, unsigned int *vert_idx, unsigned int *edge_idx, unsigned int *face_idx);
+void BM_mesh_remap(
+ BMesh *bm,
+ const unsigned int *vert_idx,
+ const unsigned int *edge_idx,
+ const unsigned int *face_idx);
typedef struct BMAllocTemplate {
int totvert, totedge, totloop, totface;
diff --git a/source/blender/bmesh/intern/bmesh_mesh_conv.c b/source/blender/bmesh/intern/bmesh_mesh_conv.c
index b7be0cc0ae2..05f3ff5b60b 100644
--- a/source/blender/bmesh/intern/bmesh_mesh_conv.c
+++ b/source/blender/bmesh/intern/bmesh_mesh_conv.c
@@ -233,7 +233,7 @@ void BM_mesh_bm_from_me(BMesh *bm, Mesh *me,
BMEdge *e, **etable = NULL;
BMFace *f;
float (*keyco)[3] = NULL;
- int totuv, i, j;
+ int totuv, totloops, i, j;
int cd_vert_bweight_offset;
int cd_edge_bweight_offset;
@@ -395,7 +395,7 @@ void BM_mesh_bm_from_me(BMesh *bm, Mesh *me,
mloop = me->mloop;
mp = me->mpoly;
- for (i = 0; i < me->totpoly; i++, mp++) {
+ for (i = 0, totloops = 0; i < me->totpoly; i++, mp++) {
BMLoop *l_iter;
BMLoop *l_first;
@@ -426,6 +426,9 @@ void BM_mesh_bm_from_me(BMesh *bm, Mesh *me,
j = mp->loopstart;
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
+ /* don't use 'j' since we may have skipped some faces, hence some loops. */
+ BM_elem_index_set(l_iter, totloops++); /* set_ok */
+
/* Save index of correspsonding MLoop */
CustomData_to_bmesh_block(&me->ldata, &bm->ldata, j++, &l_iter->head.data, true);
} while ((l_iter = l_iter->next) != l_first);
@@ -438,8 +441,7 @@ void BM_mesh_bm_from_me(BMesh *bm, Mesh *me,
}
}
- bm->elem_index_dirty &= ~BM_FACE; /* added in order, clear dirty flag */
- bm->elem_index_dirty |= BM_LOOP; /* did not set the loop indices */
+ bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); /* added in order, clear dirty flag */
if (me->mselect && me->totselect != 0) {
diff --git a/source/blender/bmesh/intern/bmesh_mods.c b/source/blender/bmesh/intern/bmesh_mods.c
index 60de592f964..72d25413f09 100644
--- a/source/blender/bmesh/intern/bmesh_mods.c
+++ b/source/blender/bmesh/intern/bmesh_mods.c
@@ -32,12 +32,19 @@
#include "BLI_math.h"
#include "BLI_array.h"
+#include "BLI_alloca.h"
+#include "BLI_stackdefines.h"
+#include "BLI_linklist_stack.h"
+#include "BLI_sort_utils.h"
#include "BKE_customdata.h"
#include "bmesh.h"
#include "intern/bmesh_private.h"
+// #define DEBUG_PRINT
+
+
/**
* \brief Dissolve Vert
*
@@ -78,7 +85,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
}
else if (!v->e->l) {
if (len == 2) {
- return (BM_vert_collapse_edge(bm, v->e, v, true) != NULL);
+ return (BM_vert_collapse_edge(bm, v->e, v, true, true) != NULL);
}
else {
/* used to kill the vertex here, but it may be connected to faces.
@@ -92,7 +99,7 @@ bool BM_vert_dissolve(BMesh *bm, BMVert *v)
}
else if (len == 2 && BM_vert_face_count(v) == 1) {
/* boundary vertex on a face */
- return (BM_vert_collapse_edge(bm, v->e, v, true) != NULL);
+ return (BM_vert_collapse_edge(bm, v->e, v, true, true) != NULL);
}
else {
return BM_disk_dissolve(bm, v);
@@ -144,7 +151,7 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
if (UNLIKELY(!BM_faces_join_pair(bm, e->l->f, e->l->radial_next->f, e, true))) {
return false;
}
- else if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, false, true))) {
+ else if (UNLIKELY(!BM_vert_collapse_faces(bm, v->e, v, 1.0, true, false, true))) {
return false;
}
#endif
@@ -152,7 +159,7 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
}
else if (keepedge == NULL && len == 2) {
/* collapse the vertex */
- e = BM_vert_collapse_faces(bm, v->e, v, 1.0, true, true);
+ e = BM_vert_collapse_faces(bm, v->e, v, 1.0, true, true, true);
if (!e) {
return false;
@@ -196,7 +203,7 @@ bool BM_disk_dissolve(BMesh *bm, BMVert *v)
/* collapse the vertex */
/* note, the baseedge can be a boundary of manifold, use this as join_faces arg */
- e = BM_vert_collapse_faces(bm, baseedge, v, 1.0, !BM_edge_is_boundary(baseedge), true);
+ e = BM_vert_collapse_faces(bm, baseedge, v, 1.0, true, !BM_edge_is_boundary(baseedge), true);
if (!e) {
return false;
@@ -258,7 +265,8 @@ BMFace *BM_faces_join_pair(BMesh *bm, BMFace *f_a, BMFace *f_b, BMEdge *e, const
*
* \param bm The bmesh
* \param f the original face
- * \param v1, v2 vertices which define the split edge, must be different
+ * \param l_a, l_b Loops of this face, their vertices define
+ * 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
@@ -341,7 +349,7 @@ BMFace *BM_face_split(BMesh *bm, BMFace *f,
* \param l_a, l_b vertices which define the split edge, must be different
* \param cos Array of coordinates for intermediate points
* \param n Length of \a cos (must be > 0)
- * \param r_l pointer which will receive the BMLoop for the first split edge (from \a v1) in the new face
+ * \param r_l pointer which will receive the BMLoop for the first split edge (from \a l_a) in the new face
* \param example Edge used for attributes of splitting edge, if non-NULL
*
* \return Pointer to the newly created face representing one side of the split
@@ -416,6 +424,547 @@ BMFace *BM_face_split_n(BMesh *bm, BMFace *f,
return f_new;
}
+
+/* -------------------------------------------------------------------- */
+/* Face Split Edge-Net */
+
+/** \name BM_face_split_edgenet and helper functions.
+ *
+ * \note Don't use #BM_edge_is_wire or #BM_edge_is_boundary
+ * since we need to take flagged faces into account.
+ * Also take care accessing e->l directly.
+ *
+ * \{ */
+
+/* Note: All these flags _must_ be cleared on exit */
+
+/* face is apart of the edge-net (including the original face we're splitting) */
+#define FACE_NET _FLAG_WALK
+/* edge is apart of the edge-net we're filling */
+#define EDGE_NET _FLAG_WALK
+/* tag verts we've visit */
+#define VERT_VISIT _FLAG_WALK
+
+struct VertOrder {
+ float angle;
+ BMVert *v;
+};
+
+static unsigned int bm_edge_flagged_radial_count(BMEdge *e)
+{
+ unsigned int count = 0;
+ BMLoop *l;
+
+ if ((l = e->l)) {
+ do {
+ if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) {
+ count++;
+ }
+ } while ((l = l->radial_next) != e->l);
+ }
+ return count;
+}
+
+static BMLoop *bm_edge_flagged_radial_first(BMEdge *e)
+{
+ BMLoop *l;
+
+ if ((l = e->l)) {
+ do {
+ if (BM_ELEM_API_FLAG_TEST(l->f, FACE_NET)) {
+ return l;
+ }
+ } while ((l = l->radial_next) != e->l);
+ }
+ return NULL;
+}
+
+static bool bm_face_split_edgenet_find_loop_pair(
+ BMVert *v_init, const float face_normal[3],
+ BMEdge *e_pair[2])
+{
+ /* Always find one boundary edge (to determine winding)
+ * and one wire (if available), otherwise another boundary.
+ */
+ BMIter iter;
+ BMEdge *e;
+
+ /* detect winding */
+ BMLoop *l_walk;
+ bool swap;
+
+ BLI_SMALLSTACK_DECLARE(edges_boundary, BMEdge *);
+ BLI_SMALLSTACK_DECLARE(edges_wire, BMEdge *);
+ int edges_boundary_len = 0;
+ int edges_wire_len = 0;
+
+ BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) {
+ if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) {
+ const unsigned int count = bm_edge_flagged_radial_count(e);
+ if (count == 1) {
+ BLI_SMALLSTACK_PUSH(edges_boundary, e);
+ edges_boundary_len++;
+ }
+ else if (count == 0) {
+ BLI_SMALLSTACK_PUSH(edges_wire, e);
+ edges_wire_len++;
+ }
+ }
+ }
+
+ /* first edge should always be boundary */
+ if (edges_boundary_len == 0) {
+ return false;
+ }
+ e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary);
+
+ /* attempt one boundary and one wire, or 2 boundary */
+ if (edges_wire_len == 0) {
+ if (edges_boundary_len >= 2) {
+ e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary);
+ }
+ else {
+ /* one boundary and no wire */
+ return false;
+ }
+ }
+ else {
+ e_pair[1] = BLI_SMALLSTACK_POP(edges_wire);
+
+ if (edges_wire_len > 1) {
+ BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init);
+ BMVert *v_next;
+ float angle_best;
+
+ v_next = BM_edge_other_vert(e_pair[1], v_init);
+ angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
+
+ while ((e = BLI_SMALLSTACK_POP(edges_wire))) {
+ float angle_test;
+ v_next = BM_edge_other_vert(e, v_init);
+ angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal);
+ if (angle_test < angle_best) {
+ angle_best = angle_test;
+ e_pair[1] = e;
+ }
+ }
+ }
+ }
+
+
+ /* flip based on winding */
+ l_walk = bm_edge_flagged_radial_first(e_pair[0]);
+ swap = false;
+ if (face_normal == l_walk->f->no) {
+ swap = !swap;
+ }
+ if (l_walk->v != v_init) {
+ swap = !swap;
+ }
+ if (swap) {
+ SWAP(BMEdge *, e_pair[0], e_pair[1]);
+ }
+
+ return true;
+}
+
+static bool bm_face_split_edgenet_find_loop_walk(
+ BMVert *v_init, const float face_normal[3],
+ /* cache to avoid realloc every time */
+ struct VertOrder *edge_order, const unsigned int edge_order_len,
+ BMEdge *e_pair[2])
+{
+ /* fast-path for the common case (avoid push-pop).
+ * Also avoids tagging as visited since we know we
+ * can't reach these verts some other way */
+#define USE_FASTPATH_NOFORK
+
+ BMVert *v;
+ BMVert *v_dst;
+ bool found = false;
+
+ struct VertOrder *eo;
+ STACK_DECLARE(edge_order);
+
+ /* store visited verts so we can clear the visit flag after execution */
+ BLI_SMALLSTACK_DECLARE(vert_visit, BMVert *);
+
+ /* likely this will stay very small
+ * all verts pushed into this stack _must_ have their previous edges set! */
+ BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *);
+ BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *);
+
+ STACK_INIT(edge_order, edge_order_len);
+
+ /* start stepping */
+ v = BM_edge_other_vert(e_pair[0], v_init);
+ v->e = e_pair[0];
+ BLI_SMALLSTACK_PUSH(vert_stack, v);
+
+ v_dst = BM_edge_other_vert(e_pair[1], v_init);
+
+#ifdef DEBUG_PRINT
+ printf("%s: vert (search) %d\n", __func__, BM_elem_index_get(v_init));
+#endif
+
+ /* This loop will keep stepping over the best possible edge,
+ * in most cases it finds the direct route to close the face.
+ *
+ * In cases where paths can't be closed,
+ * alternatives are stored in the 'vert_stack'.
+ */
+ while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) {
+ BMIter eiter;
+ BMEdge *e_next;
+
+#ifdef USE_FASTPATH_NOFORK
+walk_nofork:
+#else
+ BLI_SMALLSTACK_PUSH(vert_visit, v);
+ BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT);
+#endif
+
+ BLI_assert(STACK_SIZE(edge_order) == 0);
+
+ /* check if we're done! */
+ if (v == v_dst) {
+ found = true;
+ goto finally;
+ }
+
+ BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) {
+ if ((v->e != e_next) &&
+ (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) &&
+ (bm_edge_flagged_radial_count(e_next) < 2))
+ {
+ BMVert *v_next;
+
+ v_next = BM_edge_other_vert(e_next, v);
+
+#ifdef DEBUG_PRINT
+ /* indent and print */
+ {
+ BMVert *_v = v;
+ do {
+ printf(" ");
+ } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init);
+ printf("vert %d -> %d (add=%d)\n",
+ BM_elem_index_get(v), BM_elem_index_get(v_next),
+ BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0);
+ }
+#endif
+
+ if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) {
+ eo = STACK_PUSH_RET_PTR(edge_order);
+ eo->v = v_next;
+
+ v_next->e = e_next;
+ }
+ }
+ }
+
+#ifdef USE_FASTPATH_NOFORK
+ if (STACK_SIZE(edge_order) == 1) {
+ eo = STACK_POP_PTR(edge_order);
+ v = eo->v;
+
+ goto walk_nofork;
+ }
+#endif
+
+ /* sort by angle if needed */
+ if (STACK_SIZE(edge_order) > 1) {
+ unsigned int j;
+ BMVert *v_prev = BM_edge_other_vert(v->e, v);
+
+ for (j = 0; j < STACK_SIZE(edge_order); j++) {
+ edge_order[j].angle = angle_signed_on_axis_v3v3v3_v3(v_prev->co, v->co, edge_order[j].v->co, face_normal);
+ }
+ qsort(edge_order, STACK_SIZE(edge_order), sizeof(struct VertOrder), BLI_sortutil_cmp_float_reverse);
+
+#ifdef USE_FASTPATH_NOFORK
+ /* only tag forks */
+ BLI_SMALLSTACK_PUSH(vert_visit, v);
+ BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT);
+#endif
+ }
+
+ while ((eo = STACK_POP_PTR(edge_order))) {
+ BLI_SMALLSTACK_PUSH(vert_stack_next, eo->v);
+ }
+
+ if (!BLI_SMALLSTACK_IS_EMPTY(vert_stack_next)) {
+ BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next);
+ }
+ }
+
+
+finally:
+ /* clear flag for next execution */
+ while ((v = BLI_SMALLSTACK_POP(vert_visit))) {
+ BM_ELEM_API_FLAG_DISABLE(v, VERT_VISIT);
+ }
+
+ return found;
+
+#undef USE_FASTPATH_NOFORK
+}
+
+static bool bm_face_split_edgenet_find_loop(
+ BMVert *v_init, const float face_normal[3],
+ /* cache to avoid realloc every time */
+ struct VertOrder *edge_order, const unsigned int edge_order_len,
+ BMVert **r_face_verts, int *r_face_verts_len)
+{
+ BMEdge *e_pair[2];
+ BMVert *v;
+
+ if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) {
+ return false;
+ }
+
+ BLI_assert((bm_edge_flagged_radial_count(e_pair[0]) == 1) ||
+ (bm_edge_flagged_radial_count(e_pair[1]) == 1));
+
+ if (bm_face_split_edgenet_find_loop_walk(v_init, face_normal, edge_order, edge_order_len, e_pair)) {
+ unsigned int i = 0;
+
+ r_face_verts[i++] = v_init;
+ v = BM_edge_other_vert(e_pair[1], v_init);
+ do {
+ r_face_verts[i++] = v;
+ } while ((v = BM_edge_other_vert(v->e, v)) != v_init);
+ *r_face_verts_len = i;
+ return (i > 2) ? true : false;
+ }
+ else {
+ return false;
+ }
+}
+
+/**
+ * Splits a face into many smaller faces defined by an edge-net.
+ * handle customdata and degenerate cases.
+ *
+ * - isolated holes or unsupported face configurations, will be ignored.
+ * - customdata calculations aren't efficient
+ * (need to calculate weights for each vert).
+ */
+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)
+{
+ /* re-use for new face verts */
+ BMVert **face_verts;
+ int face_verts_len;
+
+ BMFace **face_arr = NULL;
+ BLI_array_declare(face_arr);
+
+ BMVert **vert_queue;
+ STACK_DECLARE(vert_queue);
+ int i;
+
+ struct VertOrder *edge_order;
+ const unsigned int edge_order_len = edge_net_len + 2;
+
+ BMVert *v;
+
+ BMLoop *l_iter, *l_first;
+
+
+ if (!edge_net_len) {
+ if (r_face_arr) {
+ *r_face_arr = NULL;
+ *r_face_arr_len = 0;
+ }
+ return false;
+ }
+
+ /* over-alloc (probably 2-4 is only used in most cases), for the biggest-fan */
+ edge_order = BLI_array_alloca(edge_order, edge_order_len);
+
+ /* use later */
+ face_verts = BLI_array_alloca(face_verts, edge_net_len + f->len);
+
+ vert_queue = BLI_array_alloca(vert_queue, edge_net_len + f->len);
+ STACK_INIT(vert_queue, f->len + edge_net_len);
+
+ BLI_assert(BM_ELEM_API_FLAG_TEST(f, FACE_NET) == 0);
+ BM_ELEM_API_FLAG_ENABLE(f, FACE_NET);
+
+#ifdef DEBUG
+ for (i = 0; i < edge_net_len; i++) {
+ BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET) == 0);
+ BLI_assert(BM_edge_in_face(edge_net[i], f) == false);
+ }
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BLI_assert(BM_ELEM_API_FLAG_TEST(l_iter->e, EDGE_NET) == 0);
+ } while ((l_iter = l_iter->next) != l_first);
+#endif
+
+
+ for (i = 0; i < edge_net_len; i++) {
+ BM_ELEM_API_FLAG_ENABLE(edge_net[i], EDGE_NET);
+ }
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET);
+ } while ((l_iter = l_iter->next) != l_first);
+
+
+ /* any vert can be used to begin with */
+ STACK_PUSH(vert_queue, l_first->v);
+
+ while ((v = STACK_POP(vert_queue))) {
+ if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) {
+ BMFace *f_new;
+
+ f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false);
+
+ for (i = 0; i < edge_net_len; i++) {
+ BLI_assert(BM_ELEM_API_FLAG_TEST(edge_net[i], EDGE_NET));
+ }
+
+ if (f_new) {
+ bool l_prev_is_boundary;
+ BLI_array_append(face_arr, f_new);
+ copy_v3_v3(f_new->no, f->no);
+
+ BM_ELEM_API_FLAG_ENABLE(f_new, FACE_NET);
+
+ /* add new verts to keep finding loops for
+ * (verts between boundary and manifold edges) */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f_new);
+ l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1);
+ do {
+ bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1);
+ if (l_prev_is_boundary != l_iter_is_boundary) {
+ STACK_PUSH(vert_queue, l_iter->v);
+ }
+ l_prev_is_boundary = l_iter_is_boundary;
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ }
+ }
+
+
+ if (CustomData_has_math(&bm->ldata)) {
+ /* reuse VERT_VISIT here to tag vert's already interpolated */
+ BMIter iter;
+ BMLoop *l_other;
+
+ /* see: #BM_loop_interp_from_face for similar logic */
+ void **blocks = BLI_array_alloca(blocks, f->len);
+ float (*cos_2d)[2] = BLI_array_alloca(cos_2d, f->len);
+ float *w = BLI_array_alloca(w, f->len);
+ float axis_mat[3][3];
+ float co[2];
+
+ /* interior loops */
+ axis_dominant_v3_to_m3(axis_mat, f->no);
+
+
+ /* first simply copy from existing face */
+ i = 0;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_ITER_ELEM (l_other, &iter, l_iter->v, BM_LOOPS_OF_VERT) {
+ if ((l_other->f != f) && BM_ELEM_API_FLAG_TEST(l_other->f, FACE_NET)) {
+ CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata,
+ l_iter->head.data, &l_other->head.data);
+ }
+ }
+ /* tag not to interpolate */
+ BM_ELEM_API_FLAG_ENABLE(l_iter->v, VERT_VISIT);
+
+
+ mul_v2_m3v3(cos_2d[i], axis_mat, l_iter->v->co);
+ blocks[i] = l_iter->head.data;
+
+ } while (i++, (l_iter = l_iter->next) != l_first);
+
+
+ for (i = 0; i < edge_net_len; i++) {
+ BM_ITER_ELEM (v, &iter, edge_net[i], BM_VERTS_OF_EDGE) {
+ if (!BM_ELEM_API_FLAG_TEST(v, VERT_VISIT)) {
+ BMIter liter;
+
+ BM_ELEM_API_FLAG_ENABLE(v, VERT_VISIT);
+
+ /* interpolate this loop, then copy to the rest */
+ l_first = NULL;
+
+ BM_ITER_ELEM (l_iter, &liter, v, BM_LOOPS_OF_VERT) {
+ if (BM_ELEM_API_FLAG_TEST(l_iter->f, FACE_NET)) {
+ if (l_first == NULL) {
+ mul_v2_m3v3(co, axis_mat, v->co);
+ interp_weights_poly_v2(w, cos_2d, f->len, co);
+ CustomData_bmesh_interp(&bm->ldata, blocks, w, NULL, f->len, l_iter->head.data);
+ l_first = l_iter;
+ }
+ else {
+ CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata,
+ l_first->head.data, &l_iter->head.data);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+
+ /* cleanup */
+ for (i = 0; i < edge_net_len; i++) {
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i], EDGE_NET);
+ /* from interp only */
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v1, VERT_VISIT);
+ BM_ELEM_API_FLAG_DISABLE(edge_net[i]->v2, VERT_VISIT);
+ }
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BM_ELEM_API_FLAG_DISABLE(l_iter->e, EDGE_NET);
+ /* from interp only */
+ BM_ELEM_API_FLAG_DISABLE(l_iter->v, VERT_VISIT);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (BLI_array_count(face_arr)) {
+ bmesh_face_swap_data(f, face_arr[0]);
+ BM_face_kill(bm, face_arr[0]);
+ face_arr[0] = f;
+ }
+ else {
+ BM_ELEM_API_FLAG_DISABLE(f, FACE_NET);
+ }
+
+ for (i = 0; i < BLI_array_count(face_arr); i++) {
+ BM_ELEM_API_FLAG_DISABLE(face_arr[i], FACE_NET);
+ }
+
+ if (r_face_arr) {
+ *r_face_arr = face_arr;
+ *r_face_arr_len = BLI_array_count(face_arr);
+ }
+ else {
+ if (face_arr) {
+ MEM_freeN(face_arr);
+ }
+ }
+
+ return true;
+}
+
+#undef FACE_NET
+#undef VERT_VISIT
+#undef EDGE_NET
+
+/** \} */
+
+
/**
* \brief Vert Collapse Faces
*
@@ -440,7 +989,7 @@ BMFace *BM_face_split_n(BMesh *bm, BMFace *f,
* \returns The New Edge
*/
BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float fac,
- const bool join_faces, const bool kill_degenerate_faces)
+ 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);
@@ -513,7 +1062,7 @@ BMEdge *BM_vert_collapse_faces(BMesh *bm, BMEdge *e_kill, BMVert *v_kill, float
/* single face or no faces */
/* same as BM_vert_collapse_edge() however we already
* have vars to perform this operation so don't call. */
- e_new = bmesh_jekv(bm, e_kill, v_kill, true);
+ e_new = bmesh_jekv(bm, e_kill, v_kill, do_del, true);
/* e_new = BM_edge_exists(tv, tv2); */ /* same as return above */
if (e_new && kill_degenerate_faces) {
@@ -553,7 +1102,7 @@ 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 kill_degenerate_faces)
+ const bool do_del, const bool kill_degenerate_faces)
{
/* nice example implementation but we want loops to have their customdata
* accounted for */
@@ -571,9 +1120,7 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
BMVert *tv2 = BM_edge_other_vert(e2, v_kill);
if (tv2) {
/* only action, other calls here only get the edge to return */
- e_new = bmesh_jekv(bm, e_kill, v_kill);
-
- /* e_new = BM_edge_exists(tv, tv2); */ /* same as return above */
+ e_new = bmesh_jekv(bm, e_kill, v_kill, do_del);
}
}
}
@@ -582,7 +1129,7 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
#else
/* with these args faces are never joined, same as above
* but account for loop customdata */
- return BM_vert_collapse_faces(bm, e_kill, v_kill, 1.0f, false, kill_degenerate_faces);
+ return BM_vert_collapse_faces(bm, e_kill, v_kill, 1.0f, do_del, false, kill_degenerate_faces);
#endif
}
@@ -591,22 +1138,32 @@ BMEdge *BM_vert_collapse_edge(BMesh *bm, BMEdge *e_kill, BMVert *v_kill,
/**
* \brief Edge Split
*
- * Splits an edge. \a v should be one of the vertices in \a e and defines
- * the "from" end of the splitting operation: the new vertex will be
- * \a percent of the way from \a v to the other end.
- * The newly created edge is attached to \a v and is returned in \a r_e.
- * The original edge \a e will be the other half of the split.
+ * <pre>
+ * Before: v
+ * +-----------------------------------+
+ * e
+ *
+ * After: v v_new (returned)
+ * +-----------------+-----------------+
+ * r_e e
+ * </pre>
*
- * \return The new vert
+ * \param e The edge to split.
+ * \param v One of the vertices in \a e and defines the the "from" end of the splitting operation,
+ * the new vertex will be \a fac of the way from \a v to the other end.
+ * \param r_e The newly created edge.
+ * \return The new vertex.
*/
-BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float percent)
+BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float fac)
{
- BMVert *v_new, *v2;
+ BMVert *v_new, *v_other;
BMFace **oldfaces = NULL;
BMEdge *e_dummy;
BLI_array_staticdeclare(oldfaces, 32);
const bool do_mdisp = (e->l && CustomData_has_layer(&bm->ldata, CD_MDISPS));
+ BLI_assert(BM_vert_in_edge(e, v) == true);
+
/* we need this for handling multi-res */
if (!r_e) {
r_e = &e_dummy;
@@ -631,22 +1188,22 @@ BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float perce
}
}
- v2 = BM_edge_other_vert(e, v);
+ v_other = BM_edge_other_vert(e, v);
v_new = bmesh_semv(bm, v, e, r_e);
BLI_assert(v_new != NULL);
+ BLI_assert(BM_vert_in_edge(*r_e, v) && BM_vert_in_edge(*r_e, v_new));
+ BLI_assert(BM_vert_in_edge(e, v_new) && BM_vert_in_edge(e, v_other));
- sub_v3_v3v3(v_new->co, v2->co, v->co);
- madd_v3_v3v3fl(v_new->co, v->co, v_new->co, percent);
+ sub_v3_v3v3(v_new->co, v_other->co, v->co);
+ madd_v3_v3v3fl(v_new->co, v->co, v_new->co, fac);
- if (r_e) {
- (*r_e)->head.hflag = e->head.hflag;
- BM_elem_attrs_copy(bm, bm, e, *r_e);
- }
+ (*r_e)->head.hflag = e->head.hflag;
+ BM_elem_attrs_copy(bm, bm, e, *r_e);
/* v->v_new->v2 */
- BM_data_interp_face_vert_edge(bm, v2, v, v_new, e, percent);
- BM_data_interp_from_verts(bm, v, v2, v_new, percent);
+ BM_data_interp_face_vert_edge(bm, v_other, v, v_new, e, fac);
+ BM_data_interp_from_verts(bm, v, v_other, v_new, fac);
if (do_mdisp) {
int i, j;
diff --git a/source/blender/bmesh/intern/bmesh_mods.h b/source/blender/bmesh/intern/bmesh_mods.h
index f3ed99230d7..59aee323bba 100644
--- a/source/blender/bmesh/intern/bmesh_mods.h
+++ b/source/blender/bmesh/intern/bmesh_mods.h
@@ -45,10 +45,14 @@ BMFace *BM_face_split_n(BMesh *bm, BMFace *f,
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 join_faces, const bool kill_degenerate_faces);
+ 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 kill_degenerate_faces);
+ const bool do_del, const bool kill_degenerate_faces);
BMVert *BM_edge_split(BMesh *bm, BMEdge *e, BMVert *v, BMEdge **r_e, float percent);
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index f8cca0a3707..aba805cccd7 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -104,6 +104,7 @@ static BMOpDefine bmo_smooth_vert_def = {
"smooth_vert",
/* slots_in */
{{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */
+ {"factor", BMO_OP_SLOT_FLT}, /* smoothing factor */
{"mirror_clip_x", BMO_OP_SLOT_BOOL}, /* set vertices close to the x axis before the operation to 0 */
{"mirror_clip_y", BMO_OP_SLOT_BOOL}, /* set vertices close to the y axis before the operation to 0 */
{"mirror_clip_z", BMO_OP_SLOT_BOOL}, /* set vertices close to the z axis before the operation to 0 */
@@ -115,7 +116,7 @@ static BMOpDefine bmo_smooth_vert_def = {
},
{{{'\0'}}}, /* no output */
bmo_smooth_vert_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -138,7 +139,7 @@ static BMOpDefine bmo_smooth_laplacian_vert_def = {
},
{{{'\0'}}}, /* no output */
bmo_smooth_laplacian_vert_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -154,7 +155,8 @@ static BMOpDefine bmo_recalc_face_normals_def = {
},
{{{'\0'}}}, /* no output */
bmo_recalc_face_normals_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -180,7 +182,8 @@ static BMOpDefine bmo_region_extend_def = {
{{'\0'}},
},
bmo_region_extend_exec,
- BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -201,7 +204,10 @@ static BMOpDefine bmo_rotate_edges_def = {
{{'\0'}},
},
bmo_rotate_edges_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -218,7 +224,8 @@ static BMOpDefine bmo_reverse_faces_def = {
},
{{{'\0'}}}, /* no output */
bmo_reverse_faces_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -240,7 +247,10 @@ static BMOpDefine bmo_bisect_edges_def = {
{{'\0'}},
},
bmo_bisect_edges_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -266,7 +276,9 @@ static BMOpDefine bmo_mirror_def = {
{{'\0'}},
},
bmo_mirror_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -291,7 +303,7 @@ static BMOpDefine bmo_find_doubles_def = {
{{'\0'}},
},
bmo_find_doubles_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -309,7 +321,10 @@ static BMOpDefine bmo_remove_doubles_def = {
},
{{{'\0'}}}, /* no output */
bmo_remove_doubles_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -328,7 +343,10 @@ static BMOpDefine bmo_automerge_def = {
},
{{{'\0'}}}, /* no output */
bmo_automerge_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -344,7 +362,10 @@ static BMOpDefine bmo_collapse_def = {
},
{{{'\0'}}}, /* no output */
bmo_collapse_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -361,7 +382,7 @@ static BMOpDefine bmo_pointmerge_facedata_def = {
},
{{{'\0'}}}, /* no output */
bmo_pointmerge_facedata_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -379,7 +400,7 @@ static BMOpDefine bmo_average_vert_facedata_def = {
},
{{{'\0'}}}, /* no output */
bmo_average_vert_facedata_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -396,7 +417,10 @@ static BMOpDefine bmo_pointmerge_def = {
},
{{{'\0'}}}, /* no output */
bmo_pointmerge_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -412,7 +436,7 @@ static BMOpDefine bmo_collapse_uvs_def = {
},
{{{'\0'}}}, /* no output */
bmo_collapse_uvs_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -431,7 +455,10 @@ static BMOpDefine bmo_weld_verts_def = {
},
{{{'\0'}}}, /* no output */
bmo_weld_verts_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -451,7 +478,7 @@ static BMOpDefine bmo_create_vert_def = {
{{'\0'}},
},
bmo_create_vert_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -476,7 +503,10 @@ static BMOpDefine bmo_join_triangles_def = {
{{'\0'}},
},
bmo_join_triangles_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -504,7 +534,10 @@ static BMOpDefine bmo_contextual_create_def = {
{{'\0'}},
},
bmo_contextual_create_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -527,7 +560,9 @@ static BMOpDefine bmo_bridge_loops_def = {
{{'\0'}},
},
bmo_bridge_loops_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -551,7 +586,8 @@ static BMOpDefine bmo_grid_fill_def = {
{{'\0'}},
},
bmo_grid_fill_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
@@ -573,7 +609,8 @@ static BMOpDefine bmo_holes_fill_def = {
{{'\0'}},
},
bmo_holes_fill_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
@@ -596,7 +633,7 @@ static BMOpDefine bmo_face_attribute_fill_def = {
{{'\0'}},
},
bmo_face_attribute_fill_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -619,7 +656,8 @@ static BMOpDefine bmo_edgeloop_fill_def = {
{{'\0'}},
},
bmo_edgeloop_fill_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
@@ -643,7 +681,8 @@ static BMOpDefine bmo_edgenet_fill_def = {
{{'\0'}},
},
bmo_edgenet_fill_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -667,7 +706,7 @@ static BMOpDefine bmo_edgenet_prepare_def = {
{{'\0'}},
},
bmo_edgenet_prepare_exec,
- BMO_OPTYPE_FLAG_NOP,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -686,7 +725,7 @@ static BMOpDefine bmo_rotate_def = {
},
{{{'\0'}}}, /* no output */
bmo_rotate_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -704,7 +743,7 @@ static BMOpDefine bmo_translate_def = {
},
{{{'\0'}}}, /* no output */
bmo_translate_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -722,7 +761,7 @@ static BMOpDefine bmo_scale_def = {
},
{{{'\0'}}}, /* no output */
bmo_scale_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
@@ -742,7 +781,7 @@ static BMOpDefine bmo_transform_def = {
},
{{{'\0'}}}, /* no output */
bmo_transform_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -760,7 +799,7 @@ static BMOpDefine bmo_object_load_bmesh_def = {
},
{{{'\0'}}}, /* no output */
bmo_object_load_bmesh_exec,
- BMO_OPTYPE_FLAG_NOP,
+ (BMO_OPTYPE_FLAG_NOP),
};
@@ -782,7 +821,7 @@ static BMOpDefine bmo_bmesh_to_mesh_def = {
},
{{{'\0'}}}, /* no output */
bmo_bmesh_to_mesh_exec,
- BMO_OPTYPE_FLAG_NOP,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -804,7 +843,7 @@ static BMOpDefine bmo_mesh_to_bmesh_def = {
},
{{{'\0'}}}, /* no output */
bmo_mesh_to_bmesh_exec,
- BMO_OPTYPE_FLAG_NOP,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -816,6 +855,7 @@ static BMOpDefine bmo_extrude_discrete_faces_def = {
"extrude_discrete_faces",
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
+ {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
},
/* slots_out */
@@ -823,7 +863,7 @@ static BMOpDefine bmo_extrude_discrete_faces_def = {
{{'\0'}},
},
bmo_extrude_discrete_faces_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -836,6 +876,7 @@ static BMOpDefine bmo_extrude_edge_only_def = {
"extrude_edge_only",
/* slots_in */
{{"edges", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}}, /* input vertices */
+ {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
},
/* slots_out */
@@ -843,7 +884,7 @@ static BMOpDefine bmo_extrude_edge_only_def = {
{{'\0'}},
},
bmo_extrude_edge_only_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -855,6 +896,7 @@ static BMOpDefine bmo_extrude_vert_indiv_def = {
"extrude_vert_indiv",
/* slots_in */
{{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}}, /* input vertices */
+ {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
},
/* slots_out */
@@ -863,7 +905,7 @@ static BMOpDefine bmo_extrude_vert_indiv_def = {
{{'\0'}},
},
bmo_extrude_vert_indiv_exec,
- BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -875,6 +917,7 @@ static BMOpDefine bmo_connect_verts_def = {
"connect_verts",
/* slots_in */
{{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}},
+ {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}},
{"check_degenerate", BMO_OP_SLOT_BOOL}, /* prevent splits with overlaps & intersections */
{{'\0'}},
},
@@ -883,7 +926,9 @@ static BMOpDefine bmo_connect_verts_def = {
{{'\0'}},
},
bmo_connect_verts_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -904,7 +949,9 @@ static BMOpDefine bmo_connect_verts_nonplanar_def = {
{{'\0'}},
},
bmo_connect_verts_nonplanar_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -916,6 +963,8 @@ static BMOpDefine bmo_connect_vert_pair_def = {
"connect_vert_pair",
/* slots_in */
{{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}},
+ {"verts_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}},
+ {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}},
{{'\0'}},
},
/* slots_out */
@@ -923,7 +972,9 @@ static BMOpDefine bmo_connect_vert_pair_def = {
{{'\0'}},
},
bmo_connect_vert_pair_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
@@ -938,6 +989,7 @@ static BMOpDefine bmo_extrude_face_region_def = {
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* edges and faces */
{"edges_exclude", BMO_OP_SLOT_MAPPING, {BMO_OP_SLOT_SUBTYPE_MAP_EMPTY}},
{"use_keep_orig", BMO_OP_SLOT_BOOL}, /* keep original geometry */
+ {"use_select_history", BMO_OP_SLOT_BOOL}, /* pass to duplicate */
{{'\0'}},
},
/* slots_out */
@@ -945,7 +997,7 @@ static BMOpDefine bmo_extrude_face_region_def = {
{{'\0'}},
},
bmo_extrude_face_region_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -956,11 +1008,15 @@ static BMOpDefine bmo_dissolve_verts_def = {
/* slots_in */
{{"verts", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT}},
{"use_face_split", BMO_OP_SLOT_BOOL},
+ {"use_boundary_tear", BMO_OP_SLOT_BOOL},
{{'\0'}},
},
{{{'\0'}}}, /* no output */
bmo_dissolve_verts_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -979,7 +1035,10 @@ static BMOpDefine bmo_dissolve_edges_def = {
{{'\0'}},
},
bmo_dissolve_edges_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -997,7 +1056,10 @@ static BMOpDefine bmo_dissolve_faces_def = {
{{'\0'}},
},
bmo_dissolve_faces_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1019,7 +1081,10 @@ static BMOpDefine bmo_dissolve_limit_def = {
{{"region.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}},
{{'\0'}}},
bmo_dissolve_limit_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1037,7 +1102,10 @@ static BMOpDefine bmo_dissolve_degenerate_def = {
/* slots_out */
{{{'\0'}}},
bmo_dissolve_degenerate_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1058,7 +1126,9 @@ static BMOpDefine bmo_triangulate_def = {
{{'\0'}},
},
bmo_triangulate_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1075,7 +1145,10 @@ static BMOpDefine bmo_unsubdivide_def = {
},
{{{'\0'}}}, /* no output */
bmo_unsubdivide_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1113,7 +1186,10 @@ static BMOpDefine bmo_subdivide_edges_def = {
{{'\0'}},
},
bmo_subdivide_edges_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1135,7 +1211,10 @@ static BMOpDefine bmo_subdivide_edgering_def = {
{{"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* output faces */
{{'\0'}}},
bmo_subdivide_edgering_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1159,7 +1238,10 @@ static BMOpDefine bmo_bisect_plane_def = {
{"geom.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}}, /* input and output geometry (result of cut) */
{{'\0'}}},
bmo_bisect_plane_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1176,7 +1258,9 @@ static BMOpDefine bmo_delete_def = {
},
{{{'\0'}}}, /* no output */
bmo_delete_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1191,6 +1275,7 @@ static BMOpDefine bmo_duplicate_def = {
{{"geom", BMO_OP_SLOT_ELEMENT_BUF, {BM_VERT | BM_EDGE | BM_FACE}},
/* destination bmesh, if NULL will use current on */
{"dest", BMO_OP_SLOT_PTR, {BMO_OP_SLOT_SUBTYPE_PTR_BMESH}},
+ {"use_select_history", BMO_OP_SLOT_BOOL},
{{'\0'}},
},
/* slots_out */
@@ -1206,7 +1291,8 @@ static BMOpDefine bmo_duplicate_def = {
{{'\0'}},
},
bmo_duplicate_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1231,7 +1317,8 @@ static BMOpDefine bmo_split_def = {
{{'\0'}},
},
bmo_split_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1258,7 +1345,8 @@ static BMOpDefine bmo_spin_def = {
{{'\0'}},
},
bmo_spin_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
@@ -1281,7 +1369,7 @@ static BMOpDefine bmo_similar_faces_def = {
{{'\0'}},
},
bmo_similar_faces_exec,
- BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1303,7 +1391,7 @@ static BMOpDefine bmo_similar_edges_def = {
{{'\0'}},
},
bmo_similar_edges_exec,
- BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1325,7 +1413,7 @@ static BMOpDefine bmo_similar_verts_def = {
{{'\0'}},
},
bmo_similar_verts_exec,
- BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1342,7 +1430,7 @@ static BMOpDefine bmo_rotate_uvs_def = {
},
{{{'\0'}}}, /* no output */
bmo_rotate_uvs_exec,
- BMO_OPTYPE_FLAG_NOP,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -1358,7 +1446,7 @@ static BMOpDefine bmo_reverse_uvs_def = {
},
{{{'\0'}}}, /* no output */
bmo_reverse_uvs_exec,
- BMO_OPTYPE_FLAG_NOP,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -1375,7 +1463,7 @@ static BMOpDefine bmo_rotate_colors_def = {
},
{{{'\0'}}}, /* no output */
bmo_rotate_colors_exec,
- BMO_OPTYPE_FLAG_NOP,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -1391,7 +1479,7 @@ static BMOpDefine bmo_reverse_colors_def = {
},
{{{'\0'}}}, /* no output */
bmo_reverse_colors_exec,
- BMO_OPTYPE_FLAG_NOP,
+ (BMO_OPTYPE_FLAG_NOP),
};
/*
@@ -1413,7 +1501,9 @@ static BMOpDefine bmo_split_edges_def = {
{{'\0'}},
},
bmo_split_edges_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1435,7 +1525,8 @@ static BMOpDefine bmo_create_grid_def = {
{{'\0'}},
},
bmo_create_grid_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1457,7 +1548,8 @@ static BMOpDefine bmo_create_uvsphere_def = {
{{'\0'}},
},
bmo_create_uvsphere_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1478,7 +1570,8 @@ static BMOpDefine bmo_create_icosphere_def = {
{{'\0'}},
},
bmo_create_icosphere_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1497,7 +1590,8 @@ static BMOpDefine bmo_create_monkey_def = {
{{'\0'}},
},
bmo_create_monkey_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1522,7 +1616,8 @@ static BMOpDefine bmo_create_cone_def = {
{{'\0'}},
},
bmo_create_cone_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1543,7 +1638,8 @@ static BMOpDefine bmo_create_circle_def = {
{{'\0'}},
},
bmo_create_circle_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1563,7 +1659,8 @@ static BMOpDefine bmo_create_cube_def = {
{{'\0'}},
},
bmo_create_cube_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1579,7 +1676,9 @@ static BMOpDefine bmo_bevel_def = {
{"offset_type", BMO_OP_SLOT_INT}, /* how to measure offset (enum) */
{"segments", BMO_OP_SLOT_INT}, /* number of segments in bevel */
{"profile", BMO_OP_SLOT_FLT}, /* profile shape, 0->1 (.5=>round) */
- {"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */
+ {"vertex_only", BMO_OP_SLOT_BOOL}, /* only bevel vertices, not edges */
+ {"clamp_overlap", BMO_OP_SLOT_BOOL}, /* do not allow beveled edges/vertices to overlap each other */
+ {"material", BMO_OP_SLOT_INT}, /* material for bevel faces, -1 means get from adjacent faces */
{{'\0'}},
},
/* slots_out */
@@ -1588,7 +1687,10 @@ static BMOpDefine bmo_bevel_def = {
},
bmo_bevel_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1610,7 +1712,10 @@ static BMOpDefine bmo_beautify_fill_def = {
{{'\0'}},
},
bmo_beautify_fill_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1632,7 +1737,9 @@ static BMOpDefine bmo_triangle_fill_def = {
{{'\0'}},
},
bmo_triangle_fill_exec,
- BMO_OPTYPE_FLAG_UNTAN_MULTIRES | BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1652,7 +1759,8 @@ static BMOpDefine bmo_solidify_def = {
{{'\0'}},
},
bmo_solidify_face_region_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1676,7 +1784,8 @@ static BMOpDefine bmo_inset_individual_def = {
{{'\0'}},
},
bmo_inset_individual_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC, /* caller needs to handle BMO_OPTYPE_FLAG_SELECT_FLUSH */
+ /* caller needs to handle BMO_OPTYPE_FLAG_SELECT_FLUSH */
+ (BMO_OPTYPE_FLAG_NORMALS_CALC),
};
/*
@@ -1688,6 +1797,7 @@ static BMOpDefine bmo_inset_region_def = {
"inset_region",
/* slots_in */
{{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}}, /* input faces */
+ {"faces_exclude", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}},
{"use_boundary", BMO_OP_SLOT_BOOL},
{"use_even_offset", BMO_OP_SLOT_BOOL},
{"use_interpolate", BMO_OP_SLOT_BOOL},
@@ -1703,7 +1813,8 @@ static BMOpDefine bmo_inset_region_def = {
{{'\0'}},
},
bmo_inset_region_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
};
/*
@@ -1732,7 +1843,9 @@ static BMOpDefine bmo_wireframe_def = {
{{'\0'}},
},
bmo_wireframe_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
/*
@@ -1755,7 +1868,9 @@ static BMOpDefine bmo_poke_def = {
{{'\0'}},
},
bmo_poke_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
#ifdef WITH_BULLET
@@ -1789,7 +1904,9 @@ static BMOpDefine bmo_convex_hull_def = {
{{'\0'}},
},
bmo_convex_hull_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
#endif
@@ -1816,7 +1933,9 @@ static BMOpDefine bmo_symmetrize_def = {
{{'\0'}},
},
bmo_symmetrize_exec,
- BMO_OPTYPE_FLAG_NORMALS_CALC | BMO_OPTYPE_FLAG_SELECT_FLUSH,
+ (BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH |
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE),
};
const BMOpDefine *bmo_opdefines[] = {
@@ -1904,4 +2023,4 @@ const BMOpDefine *bmo_opdefines[] = {
&bmo_wireframe_def,
};
-const int bmo_opdefines_total = (sizeof(bmo_opdefines) / sizeof(void *));
+const int bmo_opdefines_total = ARRAY_SIZE(bmo_opdefines);
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index 7fad3a8c20e..287aafc8f9f 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -182,8 +182,9 @@ typedef struct BMOpSlot {
typedef enum {
BMO_OPTYPE_FLAG_NOP = 0,
BMO_OPTYPE_FLAG_UNTAN_MULTIRES = (1 << 0), /* switch from multires tangent space to absolute coordinates */
- BMO_OPTYPE_FLAG_NORMALS_CALC = (1 << 1), /*switch from multires tangent space to absolute coordinates*/
- BMO_OPTYPE_FLAG_SELECT_FLUSH = (1 << 2) /*switch from multires tangent space to absolute coordinates*/
+ BMO_OPTYPE_FLAG_NORMALS_CALC = (1 << 1),
+ BMO_OPTYPE_FLAG_SELECT_FLUSH = (1 << 2),
+ BMO_OPTYPE_FLAG_SELECT_VALIDATE = (1 << 3),
} BMOpTypeFlag;
typedef struct BMOperator {
@@ -337,7 +338,8 @@ void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *op, const char htype, cons
void BMO_mesh_selected_remap(BMesh *bm,
BMOpSlot *slot_vert_map,
BMOpSlot *slot_edge_map,
- BMOpSlot *slot_face_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, \
diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c
index 2a6b4d70419..b041c010c22 100644
--- a/source/blender/bmesh/intern/bmesh_operators.c
+++ b/source/blender/bmesh/intern/bmesh_operators.c
@@ -54,13 +54,13 @@ static const char *bmo_error_messages[] = {
N_("Could not connect vertices"),
N_("Could not traverse mesh"),
N_("Could not dissolve faces"),
- N_("Could not dissolve vertices"),
N_("Tessellation error"),
N_("Cannot deal with non-manifold geometry"),
N_("Invalid selection"),
N_("Internal mesh error"),
};
+BLI_STATIC_ASSERT(ARRAY_SIZE(bmo_error_messages) + 1 == BMERR_TOTAL, "message mismatch");
/* operator slot type information - size of one element of the type given. */
const int BMO_OPSLOT_TYPEINFO[BMO_OP_SLOT_TOTAL_TYPES] = {
@@ -591,7 +591,7 @@ void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char hty
BMElemF *ele;
int i;
-#pragma omp parallel for schedule(dynamic) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
+#pragma omp parallel for schedule(static) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT)
for (i = 0; i < 3; i++) {
if (htype & flag_types[i]) {
BMIter iter;
@@ -605,7 +605,8 @@ 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)
+ BMOpSlot *slot_face_map,
+ const bool check_select)
{
if (bm->selected.first) {
BMEditSelection *ese, *ese_next;
@@ -623,7 +624,7 @@ void BMO_mesh_selected_remap(BMesh *bm,
ese->ele = BMO_slot_map_elem_get(slot_elem_map, ese->ele);
if (UNLIKELY((ese->ele == NULL) ||
- (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT) == false)))
+ (check_select && (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT) == false))))
{
BLI_remlink(&bm->selected, ese);
MEM_freeN(ese);
@@ -764,6 +765,9 @@ void BMO_slot_buffer_from_all(BMesh *bm, BMOperator *op, BMOpSlot slot_args[BMO_
BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
int totelement = 0, i = 0;
+ BLI_assert(output->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
+ BLI_assert(((output->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
+
if (htype & BM_VERT) totelement += bm->totvert;
if (htype & BM_EDGE) totelement += bm->totedge;
if (htype & BM_FACE) totelement += bm->totface;
@@ -811,7 +815,11 @@ static void bmo_slot_buffer_from_hflag(BMesh *bm, BMOperator *op, BMOpSlot slot_
{
BMOpSlot *output = BMO_slot_get(slot_args, slot_name);
int totelement = 0, i = 0;
- const int respecthide = (op->flag & BMO_FLAG_RESPECT_HIDE) != 0;
+ const bool respecthide = ((op->flag & BMO_FLAG_RESPECT_HIDE) != 0) && ((hflag & BM_ELEM_HIDDEN) == 0);
+
+ BLI_assert(output->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
+ BLI_assert(((output->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
+ BLI_assert((output->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0);
if (test_for_enabled)
totelement = BM_mesh_elem_hflag_count_enabled(bm, htype, hflag, respecthide);
@@ -951,14 +959,15 @@ static void bmo_slot_buffer_from_flag(BMesh *bm, BMOperator *op,
BLI_assert(op->slots_in == slot_args || op->slots_out == slot_args);
+ BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
+ BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
+ BLI_assert((slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0);
+
if (test_for_enabled)
totelement = BMO_mesh_enabled_flag_count(bm, htype, oflag);
else
totelement = BMO_mesh_disabled_flag_count(bm, htype, oflag);
- BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
- BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
-
if (totelement) {
BMIter iter;
BMHeader *ele;
@@ -1034,6 +1043,7 @@ void BMO_slot_buffer_hflag_enable(BMesh *bm,
BLI_assert(slot->slot_type == BMO_OP_SLOT_ELEMENT_BUF);
BLI_assert(((slot->slot_subtype.elem & BM_ALL_NOLOOP) & htype) == htype);
+ BLI_assert((slot->slot_subtype.elem & BMO_OP_SLOT_SUBTYPE_ELEM_IS_SINGLE) == 0);
for (i = 0; i < slot->len; i++, data++) {
if (!(htype & (*data)->head.htype))
@@ -1654,7 +1664,6 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt,
char slot_name[64] = {0};
int i, type;
bool noslot, state;
- char htype;
/* basic useful info to help find where bmop formatting strings fail */
@@ -1729,9 +1738,8 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt,
break;
case 'm':
{
- int size, c;
-
- c = NEXT_CHAR(fmt);
+ int size;
+ const char c = NEXT_CHAR(fmt);
fmt++;
if (c == '3') size = 3;
@@ -1800,22 +1808,23 @@ bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *_fmt,
BMO_slot_float_set(op->slots_in, slot_name, va_arg(vlist, double));
}
else {
- bool stop = false;
+ char htype = 0;
- htype = 0;
while (1) {
- switch (NEXT_CHAR(fmt)) {
- case 'f': htype |= BM_FACE; break;
- case 'e': htype |= BM_EDGE; break;
- case 'v': htype |= BM_VERT; break;
- default:
- stop = true;
- break;
- }
- if (stop) {
+ char htype_set;
+ const char c = NEXT_CHAR(fmt);
+ if (c == 'f') htype_set = BM_FACE;
+ else if (c == 'e') htype_set = BM_EDGE;
+ else if (c == 'v') htype_set = BM_VERT;
+ else {
break;
}
+ if (UNLIKELY(htype & htype_set)) {
+ GOTO_ERROR("htype duplicated");
+ }
+
+ htype |= htype_set;
fmt++;
}
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index 3422656b50c..a8e1acd9c71 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -73,7 +73,7 @@ static bool testedgesidef(const float v1[2], const float v2[2], const float v3[2
*
* Same as #normal_poly_v3 but operates directly on a bmesh face.
*/
-static void bm_face_calc_poly_normal(const BMFace *f, float n[3])
+static float bm_face_calc_poly_normal(const BMFace *f, float n[3])
{
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
BMLoop *l_iter = l_first;
@@ -92,9 +92,7 @@ static void bm_face_calc_poly_normal(const BMFace *f, float n[3])
} while (l_iter != l_first);
- if (UNLIKELY(normalize_v3(n) == 0.0f)) {
- n[2] = 1.0f;
- }
+ return normalize_v3(n);
}
/**
@@ -103,7 +101,7 @@ static void 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 void bm_face_calc_poly_normal_vertex_cos(BMFace *f, float r_no[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);
@@ -122,9 +120,7 @@ static void bm_face_calc_poly_normal_vertex_cos(BMFace *f, float r_no[3],
v_curr = vertexCos[BM_elem_index_get(l_iter->v)];
} while (l_iter != l_first);
- if (UNLIKELY(normalize_v3(r_no) == 0.0f)) {
- r_no[2] = 1.0f; /* other axis set to 0.0 */
- }
+ return normalize_v3(r_no);
}
/**
@@ -195,7 +191,7 @@ void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (
} while ((l_iter = l_iter->next) != l_first);
/* complete the loop */
- BLI_polyfill_calc((const float (*)[2])projverts, f->len, r_index);
+ BLI_polyfill_calc((const float (*)[2])projverts, f->len, -1, r_index);
}
}
@@ -243,6 +239,25 @@ float BM_face_calc_perimeter(BMFace *f)
return perimeter;
}
+void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3])
+{
+ float lens[3];
+ float difs[3];
+ int order[3] = {0, 1, 2};
+
+ lens[0] = len_v3v3(verts[0]->co, verts[1]->co);
+ lens[1] = len_v3v3(verts[1]->co, verts[2]->co);
+ lens[2] = len_v3v3(verts[2]->co, verts[0]->co);
+
+ /* find the shortest or the longest loop */
+ difs[0] = fabsf(lens[1] - lens[2]);
+ difs[1] = fabsf(lens[2] - lens[0]);
+ difs[2] = fabsf(lens[0] - lens[1]);
+
+ axis_sort_v3(difs, order);
+ sub_v3_v3v3(r_plane, verts[order[0]]->co, verts[(order[0] + 1) % 3]->co);
+}
+
/**
* Compute a meaningful direction along the face (use for manipulator axis).
* \note result isnt normalized.
@@ -251,23 +266,10 @@ void BM_face_calc_plane(BMFace *f, float r_plane[3])
{
if (f->len == 3) {
BMVert *verts[3];
- float lens[3];
- float difs[3];
- int order[3] = {0, 1, 2};
BM_face_as_array_vert_tri(f, verts);
- lens[0] = len_v3v3(verts[0]->co, verts[1]->co);
- lens[1] = len_v3v3(verts[1]->co, verts[2]->co);
- lens[2] = len_v3v3(verts[2]->co, verts[0]->co);
-
- /* find the shortest or the longest loop */
- difs[0] = fabsf(lens[1] - lens[2]);
- difs[1] = fabsf(lens[2] - lens[0]);
- difs[2] = fabsf(lens[0] - lens[1]);
-
- axis_sort_v3(difs, order);
- sub_v3_v3v3(r_plane, verts[order[0]]->co, verts[(order[0] + 1) % 3]->co);
+ BM_vert_tri_calc_plane(verts, r_plane);
}
else if (f->len == 4) {
BMVert *verts[4];
@@ -475,7 +477,7 @@ void BM_vert_normal_update_all(BMVert *v)
* is passed in as well.
*/
-void BM_face_calc_normal(const BMFace *f, float r_no[3])
+float BM_face_calc_normal(const BMFace *f, float r_no[3])
{
BMLoop *l;
@@ -488,8 +490,7 @@ void BM_face_calc_normal(const BMFace *f, float r_no[3])
const float *co3 = (l = l->next)->v->co;
const float *co4 = (l->next)->v->co;
- normal_quad_v3(r_no, co1, co2, co3, co4);
- break;
+ return normal_quad_v3(r_no, co1, co2, co3, co4);
}
case 3:
{
@@ -497,13 +498,11 @@ void BM_face_calc_normal(const BMFace *f, float r_no[3])
const float *co2 = (l = l->next)->v->co;
const float *co3 = (l->next)->v->co;
- normal_tri_v3(r_no, co1, co2, co3);
- break;
+ return normal_tri_v3(r_no, co1, co2, co3);
}
default:
{
- bm_face_calc_poly_normal(f, r_no);
- break;
+ return bm_face_calc_poly_normal(f, r_no);
}
}
}
@@ -513,8 +512,8 @@ void BM_face_normal_update(BMFace *f)
}
/* exact same as 'BM_face_calc_normal' but accepts vertex coords */
-void 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;
@@ -531,8 +530,7 @@ void BM_face_calc_normal_vcos(BMesh *bm, BMFace *f, float r_no[3],
const float *co3 = vertexCos[BM_elem_index_get((l = l->next)->v)];
const float *co4 = vertexCos[BM_elem_index_get((l->next)->v)];
- normal_quad_v3(r_no, co1, co2, co3, co4);
- break;
+ return normal_quad_v3(r_no, co1, co2, co3, co4);
}
case 3:
{
@@ -540,22 +538,38 @@ void BM_face_calc_normal_vcos(BMesh *bm, BMFace *f, float r_no[3],
const float *co2 = vertexCos[BM_elem_index_get((l = l->next)->v)];
const float *co3 = vertexCos[BM_elem_index_get((l->next)->v)];
- normal_tri_v3(r_no, co1, co2, co3);
- break;
- }
- case 0:
- {
- zero_v3(r_no);
- break;
+ return normal_tri_v3(r_no, co1, co2, co3);
}
default:
{
- bm_face_calc_poly_normal_vertex_cos(f, r_no, vertexCos);
- break;
+ return bm_face_calc_poly_normal_vertex_cos(f, r_no, vertexCos);
}
}
}
+/**
+ * Calculates the face subset normal.
+ */
+float BM_face_calc_normal_subset(BMLoop *l_first, BMLoop *l_last, float r_no[3])
+{
+ const float *v_prev, *v_curr;
+
+ /* Newell's Method */
+ BMLoop *l_iter = l_first;
+ BMLoop *l_term = l_last->next;
+
+ zero_v3(r_no);
+
+ v_prev = l_last->v->co;
+ do {
+ v_curr = l_iter->v->co;
+ add_newell_cross_v3_v3v3(r_no, v_prev, v_curr);
+ v_prev = v_curr;
+ } while ((l_iter = l_iter->next) != l_term);
+
+ return normalize_v3(r_no);
+}
+
/* 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])
@@ -652,49 +666,25 @@ static bool line_crosses_v2f(const float v1[2], const float v2[2], const float v
*/
bool BM_face_point_inside_test(BMFace *f, const float co[3])
{
- int ax, ay;
- float co2[2], cent[2] = {0.0f, 0.0f}, out[2] = {FLT_MAX * 0.5f, FLT_MAX * 0.5f};
+ float axis_mat[3][3];
+ float (*projverts)[2] = BLI_array_alloca(projverts, f->len);
+
+ float co_2d[2];
BMLoop *l_iter;
- BMLoop *l_first;
- int crosses = 0;
- float onepluseps = 1.0f + (float)FLT_EPSILON * 150.0f;
+ int i;
if (is_zero_v3(f->no))
BM_face_normal_update(f);
-
- /* find best projection of face XY, XZ or YZ: barycentric weights of
- * the 2d projected coords are the same and faster to compute
- *
- * this probably isn't all that accurate, but it has the advantage of
- * being fast (especially compared to projecting into the face orientation)
- */
- axis_dominant_v3(&ax, &ay, f->no);
-
- co2[0] = co[ax];
- co2[1] = co[ay];
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- cent[0] += l_iter->v->co[ax];
- cent[1] += l_iter->v->co[ay];
- } while ((l_iter = l_iter->next) != l_first);
-
- mul_v2_fl(cent, 1.0f / (float)f->len);
-
- l_iter = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- float v1[2], v2[2];
-
- v1[0] = (l_iter->prev->v->co[ax] - cent[0]) * onepluseps + cent[0];
- v1[1] = (l_iter->prev->v->co[ay] - cent[1]) * onepluseps + cent[1];
-
- v2[0] = (l_iter->v->co[ax] - cent[0]) * onepluseps + cent[0];
- v2[1] = (l_iter->v->co[ay] - cent[1]) * onepluseps + cent[1];
-
- crosses += line_crosses_v2f(v1, v2, co2, out) != 0;
- } while ((l_iter = l_iter->next) != l_first);
-
- return crosses % 2 != 0;
+
+ axis_dominant_v3_to_m3(axis_mat, f->no);
+
+ mul_v2_m3v3(co_2d, axis_mat, co);
+
+ for (i = 0, l_iter = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l_iter = l_iter->next) {
+ mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
+ }
+
+ return isect_point_poly_v2(co_2d, (const float (*)[2])projverts, f->len, false);
}
/**
@@ -825,7 +815,7 @@ void BM_face_triangulate(BMesh *bm, BMFace *f,
mul_v2_m3v3(projverts[i], axis_mat, l_iter->v->co);
}
- BLI_polyfill_calc_arena((const float (*)[2])projverts, f->len, tris,
+ BLI_polyfill_calc_arena((const float (*)[2])projverts, f->len, -1, tris,
sf_arena);
if (use_beauty) {
@@ -846,7 +836,7 @@ void BM_face_triangulate(BMesh *bm, BMFace *f,
l_tri[1]->v,
l_tri[2]->v};
- f_new = BM_face_create_verts(bm, v_tri, 3, f, false, true);
+ f_new = BM_face_create_verts(bm, v_tri, 3, f, BM_CREATE_NOP, true);
l_new = BM_FACE_FIRST_LOOP(f_new);
BLI_assert(v_tri[0] == l_new->v);
@@ -927,7 +917,7 @@ void BM_face_triangulate(BMesh *bm, BMFace *f,
#endif
if (FACE_USED_TEST(f_a) == false) {
- FACE_USED_SET(f_a);
+ FACE_USED_SET(f_a); /* set_dirty */
if (nf_i < edge_array_len) {
r_faces_new[nf_i++] = f_a;
@@ -939,7 +929,7 @@ void BM_face_triangulate(BMesh *bm, BMFace *f,
}
if (FACE_USED_TEST(f_b) == false) {
- FACE_USED_SET(f_b);
+ FACE_USED_SET(f_b); /* set_dirty */
if (nf_i < edge_array_len) {
r_faces_new[nf_i++] = f_b;
@@ -964,6 +954,7 @@ void BM_face_triangulate(BMesh *bm, BMFace *f,
}
}
}
+ bm->elem_index_dirty |= BM_FACE;
if (r_faces_new_tot) {
*r_faces_new_tot = nf_i;
@@ -978,7 +969,7 @@ void BM_face_triangulate(BMesh *bm, BMFace *f,
* intersecting splits, only the first of the set of intersecting
* splits survives
*/
-void BM_face_legal_splits(BMFace *f, BMLoop *(*loops)[2], int len)
+void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len)
{
const int len2 = len * 2;
BMLoop *l;
@@ -995,9 +986,10 @@ void BM_face_legal_splits(BMFace *f, BMLoop *(*loops)[2], int len)
axis_dominant_v3_to_m3(axis_mat, f->no);
for (i = 0, l = BM_FACE_FIRST_LOOP(f); i < f->len; i++, l = l->next) {
- BM_elem_index_set(l, i); /* set_loop */
+ BM_elem_index_set(l, i); /* set_dirty */
mul_v2_m3v3(projverts[i], axis_mat, l->v->co);
}
+ bm->elem_index_dirty |= BM_LOOP;
/* first test for completely convex face */
if (is_poly_convex_v2((const float (*)[2])projverts, f->len)) {
@@ -1096,6 +1088,21 @@ void BM_face_legal_splits(BMFace *f, BMLoop *(*loops)[2], int len)
}
}
+/**
+ * This simply checks that the verts don't connect faces which would have more optimal splits.
+ * but _not_ check for correctness.
+ */
+void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ BMLoop *l_a_dummy, *l_b_dummy;
+ if (f != BM_vert_pair_share_face_by_angle(loops[i][0]->v, loops[i][1]->v, &l_a_dummy, &l_b_dummy, false)) {
+ loops[i][0] = NULL;
+ }
+ }
+}
/**
* Small utility functions for fast access
@@ -1278,7 +1285,7 @@ void BM_bmesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptr
j++;
} while ((l_iter = l_iter->next) != l_first);
- BLI_polyfill_calc_arena((const float (*)[2])projverts, efa->len, tris, arena);
+ BLI_polyfill_calc_arena((const float (*)[2])projverts, efa->len, -1, tris, arena);
for (j = 0; j < totfilltri; j++) {
BMLoop **l_ptr = looptris[i++];
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index f408947f467..91e649edb16 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -32,9 +32,10 @@
void BM_bmesh_calc_tessellation(BMesh *bm, BMLoop *(*looptris)[3], int *r_looptris_tot);
void BM_face_calc_tessellation(const BMFace *f, BMLoop **r_loops, unsigned int (*r_index)[3]);
-void BM_face_calc_normal(const BMFace *f, float r_no[3]) ATTR_NONNULL();
-void BM_face_calc_normal_vcos(BMesh *bm, BMFace *f, float r_no[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_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();
@@ -61,7 +62,8 @@ void BM_face_triangulate(BMesh *bm, BMFace *f,
const int quad_method, const int ngon_method,
const bool use_tag) ATTR_NONNULL(1, 2);
-void BM_face_legal_splits(BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
+void BM_face_splits_check_legal(BMesh *bm, BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
+void BM_face_splits_check_optimal(BMFace *f, BMLoop *(*loops)[2], int len) ATTR_NONNULL();
void BM_face_as_array_vert_tri(BMFace *f, BMVert *r_verts[3]) ATTR_NONNULL();
void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL();
@@ -69,4 +71,6 @@ void BM_face_as_array_vert_quad(BMFace *f, BMVert *r_verts[4]) ATTR_NONNULL();
void BM_face_as_array_loop_tri(BMFace *f, BMLoop *r_loops[3]) ATTR_NONNULL();
void BM_face_as_array_loop_quad(BMFace *f, BMLoop *r_loops[4]) ATTR_NONNULL();
+void BM_vert_tri_calc_plane(BMVert *verts[3], float r_plane[3]);
+
#endif /* __BMESH_POLYGON_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h
index cac4713c8b2..102a677943b 100644
--- a/source/blender/bmesh/intern/bmesh_private.h
+++ b/source/blender/bmesh/intern/bmesh_private.h
@@ -64,13 +64,14 @@ enum {
_FLAG_JF = (1 << 0), /* join faces */
_FLAG_MF = (1 << 1), /* make face */
_FLAG_MV = (1 << 1), /* make face, vertex */
- _FLAG_OVERLAP = (1 << 2) /* general overlap flag */
+ _FLAG_OVERLAP = (1 << 2), /* general overlap flag */
+ _FLAG_WALK = (1 << 3), /* general walk flag (keep clean) */
};
-#define BM_ELEM_API_FLAG_ENABLE(element, f) ((element)->head.api_flag |= (f))
-#define BM_ELEM_API_FLAG_DISABLE(element, f) ((element)->head.api_flag &= ~(f))
-#define BM_ELEM_API_FLAG_TEST(element, f) ((element)->head.api_flag & (f))
-#define BM_ELEM_API_FLAG_CLEAR(element) ((element)->head.api_flag = 0)
+#define BM_ELEM_API_FLAG_ENABLE(element, f) { ((element)->head.api_flag |= (f)); } (void)0
+#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= ~(f)); } (void)0
+#define BM_ELEM_API_FLAG_TEST(element, f) ((element)->head.api_flag & (f))
+#define BM_ELEM_API_FLAG_CLEAR(element) { ((element)->head.api_flag = 0); } (void)0
void poly_rotate_plane(const float normal[3], float (*verts)[3], unsigned const int nverts);
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index 67f333215d9..40e0356e14c 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -36,6 +36,7 @@
#include "BLI_math.h"
#include "BLI_alloca.h"
#include "BLI_linklist.h"
+#include "BLI_stackdefines.h"
#include "bmesh.h"
#include "intern/bmesh_private.h"
@@ -182,10 +183,32 @@ BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v)
}
/**
+ * Check if verts share a face.
+ */
+bool BM_vert_pair_share_face_check(
+ BMVert *v_a, BMVert *v_b)
+{
+ if (v_a->e && v_b->e) {
+ BMIter iter;
+ BMFace *f;
+
+ BM_ITER_ELEM (f, &iter, v_a, BM_FACES_OF_VERT) {
+ if (BM_vert_in_face(f, v_b)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+/**
* Given 2 verts, find the smallest face they share and give back both loops.
*/
-BMFace *BM_vert_pair_share_face(BMVert *v_a, BMVert *v_b,
- BMLoop **r_l_a, BMLoop **r_l_b)
+BMFace *BM_vert_pair_share_face_by_len(
+ BMVert *v_a, BMVert *v_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;
@@ -197,21 +220,89 @@ BMFace *BM_vert_pair_share_face(BMVert *v_a, BMVert *v_b,
BM_ITER_ELEM (l_a, &iter, v_a, BM_LOOPS_OF_VERT) {
if ((f_cur == NULL) || (l_a->f->len < f_cur->len)) {
l_b = BM_face_vert_share_loop(l_a->f, v_b);
- if (l_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];
+
+ if ((BM_face_calc_normal_subset(l_a, l_b, no[0]) != 0.0f) &&
+ (BM_face_calc_normal_subset(l_b, l_a, no[1]) != 0.0f))
+ {
+ return dot_v3v3(no[0], no[1]);
+ }
+ else {
+ return -1.0f;
+ }
+}
+
+/**
+ * Given 2 verts, find a face they share that has the lowest angle across these verts and give back both loops.
+ *
+ * This can be better then #BM_vert_pair_share_face_by_len because concave splits are ranked lowest.
+ */
+BMFace *BM_vert_pair_share_face_by_angle(
+ BMVert *v_a, BMVert *v_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 (v_a->e && v_b->e) {
+ BMIter iter;
+ BMLoop *l_a, *l_b;
+ float dot_best = -1.0f;
+
+ BM_ITER_ELEM (l_a, &iter, v_a, BM_LOOPS_OF_VERT) {
+ l_b = BM_face_vert_share_loop(l_a->f, v_b);
+ if (l_b && (allow_adjacent || !BM_loop_is_adjacent(l_a, l_b))) {
+
+ if (f_cur == NULL) {
f_cur = l_a->f;
l_cur_a = l_a;
l_cur_b = l_b;
}
+ else {
+ /* avoid expensive calculations if we only ever find one face */
+ float dot;
+ if (dot_best == -1.0f) {
+ dot_best = bm_face_calc_split_dot(l_cur_a, l_cur_b);
+ }
+
+ dot = bm_face_calc_split_dot(l_a, l_b);
+ if (dot > dot_best) {
+ dot_best = dot;
+
+ f_cur = l_a->f;
+ l_cur_a = l_a;
+ l_cur_b = l_b;
+ }
+ }
}
}
}
- if (r_l_a) *r_l_a = l_cur_a;
- if (r_l_b) *r_l_b = l_cur_b;
+ *r_l_a = l_cur_a;
+ *r_l_b = l_cur_b;
return f_cur;
}
+
/**
* Get the first loop of a vert. Uses the same initialization code for the first loop of the
* iterator API
@@ -220,7 +311,7 @@ BMLoop *BM_vert_find_first_loop(BMVert *v)
{
BMEdge *e;
- if (!v || !v->e)
+ if (!v->e)
return NULL;
e = bmesh_disk_faceedge_find_first(v->e, v);
@@ -588,6 +679,19 @@ bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
}
/**
+ * Fast alternative to ``(BM_vert_edge_count(v) == 2)``
+ */
+bool BM_vert_is_edge_pair(BMVert *v)
+{
+ BMEdge *e = v->e;
+ if (e) {
+ const BMDiskLink *dl = bmesh_disk_edge_link_from_vert(e, v);
+ return (dl->next == dl->prev);
+ }
+ return false;
+}
+
+/**
* Returns the number of edges around this vertex.
*/
int BM_vert_edge_count(BMVert *v)
@@ -1984,7 +2088,7 @@ int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde
BMFace *f;
int i;
- STACK_INIT(group_array);
+ STACK_INIT(group_array, bm->totface);
BLI_assert(((htype_step & ~(BM_VERT | BM_EDGE)) == 0) && (htype_step != 0));
@@ -2012,7 +2116,7 @@ int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde
BLI_assert(tot_touch < tot_faces);
- STACK_INIT(stack);
+ STACK_INIT(stack, tot_faces);
BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
if (BM_elem_flag_test(f, BM_ELEM_TAG) == false) {
@@ -2140,7 +2244,7 @@ int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde
BMEdge *e;
int i;
- STACK_INIT(group_array);
+ STACK_INIT(group_array, bm->totface);
/* init the array */
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
@@ -2166,7 +2270,7 @@ int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int (**r_group_inde
BLI_assert(tot_touch < tot_edges);
- STACK_INIT(stack);
+ STACK_INIT(stack, tot_edges);
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) {
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index 36e67a73f1f..0d47633dc73 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -27,119 +27,129 @@
* \ingroup bmesh
*/
-bool BM_vert_in_face(BMFace *f, BMVert *v);
-int BM_verts_in_face_count(BMFace *f, BMVert **varr, int len);
-bool BM_verts_in_face(BMFace *f, BMVert **varr, int len);
-
-bool BM_edge_in_face(BMEdge *e, BMFace *f);
-BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l);
-
-BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v);
-BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdge *e);
-
-float BM_edge_calc_length(BMEdge *e);
-float BM_edge_calc_length_squared(BMEdge *e);
-bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb);
-bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb);
-BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v);
-BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l);
-BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v);
-BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v);
-BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v);
-BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v);
-BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step);
-BMLoop *BM_vert_find_first_loop(BMVert *v);
-BMFace *BM_vert_pair_share_face(BMVert *v_a, BMVert *v_b,
- BMLoop **r_l_a, BMLoop **r_l_b);
-
-int BM_vert_edge_count_nonwire(BMVert *v);
-int BM_vert_edge_count(BMVert *v);
-int BM_edge_face_count(BMEdge *e);
-int BM_vert_face_count(BMVert *v);
-BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e);
-
-bool BM_vert_is_wire(const BMVert *v);
-BLI_INLINE bool BM_edge_is_wire(const BMEdge *e);
-
-bool BM_vert_is_manifold(const BMVert *v);
-BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e);
-bool BM_vert_is_boundary(const BMVert *v);
-BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e);
-BLI_INLINE bool BM_edge_is_contiguous(const BMEdge *e);
-bool BM_edge_is_convex(const BMEdge *e);
-
-bool BM_loop_is_convex(const BMLoop *l);
-BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b);
-
-float BM_loop_calc_face_angle(BMLoop *l);
-void BM_loop_calc_face_normal(BMLoop *l, float r_normal[3]);
+bool BM_vert_in_face(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BM_verts_in_face_count(BMFace *f, BMVert **varr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_verts_in_face(BMFace *f, BMVert **varr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
+bool BM_edge_in_face(BMEdge *e, 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();
+BLI_INLINE bool BM_verts_in_edge(const BMVert *v1, const BMVert *v2, const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
+float BM_edge_calc_length(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_edge_calc_length_squared(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb) ATTR_NONNULL();
+bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb) ATTR_NONNULL();
+BLI_INLINE BMVert *BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *BM_loop_other_edge_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *BM_vert_step_fan_loop(BMLoop *l, BMEdge **e_step) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *BM_vert_find_first_loop(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+
+bool BM_vert_pair_share_face_check(
+ BMVert *v_a, BMVert *v_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMFace *BM_vert_pair_share_face_by_len(
+ BMVert *v_a, BMVert *v_b,
+ BMLoop **r_l_a, BMLoop **r_l_b,
+ const bool allow_adjacent) ATTR_NONNULL();
+BMFace *BM_vert_pair_share_face_by_angle(
+ BMVert *v_a, BMVert *v_b,
+ BMLoop **r_l_a, BMLoop **r_l_b,
+ const bool allow_adjacent) ATTR_NONNULL();
+
+int BM_vert_edge_count_nonwire(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BM_vert_edge_count(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BM_edge_face_count(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BM_vert_face_count(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(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();
+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_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_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]);
-float BM_edge_calc_face_angle_ex(const BMEdge *e, const float fallback);
-float BM_edge_calc_face_angle(const BMEdge *e);
-float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback);
-float BM_edge_calc_face_angle_signed(const BMEdge *e);
-void BM_edge_calc_face_tangent(const BMEdge *e, const BMLoop *e_loop, 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();
+float BM_edge_calc_face_angle_signed_ex(const BMEdge *e, const float fallback) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+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);
-float BM_vert_calc_shell_factor(BMVert *v);
-float BM_vert_calc_shell_factor_ex(BMVert *v, const char hflag);
-float BM_vert_calc_mean_tagged_edge_length(BMVert *v);
+float BM_vert_calc_edge_angle(BMVert *v) 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 char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_vert_calc_mean_tagged_edge_length(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-BMLoop *BM_face_find_shortest_loop(BMFace *f);
-BMLoop *BM_face_find_longest_loop(BMFace *f);
+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();
-BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2);
-BMEdge *BM_edge_find_double(BMEdge *e);
+BMEdge *BM_edge_exists(BMVert *v1, BMVert *v2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMEdge *BM_edge_find_double(BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface);
+bool BM_face_exists(BMVert **varr, int len, BMFace **r_existface) ATTR_NONNULL(1);
-bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len);
-bool BM_face_exists_multi_edge(BMEdge **earr, int len);
+bool BM_face_exists_multi(BMVert **varr, BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_face_exists_multi_edge(BMEdge **earr, int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap);
-bool BM_face_exists_overlap_subset(BMVert **varr, const int len);
+bool BM_face_exists_overlap(BMVert **varr, const int len, BMFace **r_f_overlap) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
+bool BM_face_exists_overlap_subset(BMVert **varr, const int len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-int BM_face_share_face_count(BMFace *f_a, BMFace *f_b);
-int BM_face_share_edge_count(BMFace *f1, BMFace *f2);
+int BM_face_share_face_count(BMFace *f_a, BMFace *f_b) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+int BM_face_share_edge_count(BMFace *f1, BMFace *f2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_share_face_check(BMFace *f1, BMFace *f2);
-bool BM_face_share_edge_check(BMFace *f1, BMFace *f2);
-bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2);
-bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2);
-bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2);
+bool BM_face_share_face_check(BMFace *f1, BMFace *f2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_face_share_edge_check(BMFace *f1, BMFace *f2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_edge_share_face_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_edge_share_quad_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_edge_share_vert_check(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2);
-BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v);
-BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v);
-BMLoop *BM_face_edge_share_loop(BMFace *f, BMEdge *e);
+BMVert *BM_edge_share_vert(BMEdge *e1, BMEdge *e2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *BM_edge_vert_share_loop(BMLoop *l, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *BM_face_vert_share_loop(BMFace *f, BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+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);
+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);
+ const BMLoop *edge_loop) ATTR_NONNULL();
-bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide);
-bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide);
-bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide);
+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();
+bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag);
-bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag);
-bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag);
+bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_face_is_normal_valid(const BMFace *f);
+bool BM_face_is_normal_valid(const BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-float BM_mesh_calc_volume(BMesh *bm, bool is_signed);
+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);
+ 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);
+ 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);
+float bmesh_subd_falloff_calc(const int falloff, float val) ATTR_WARN_UNUSED_RESULT;
#include "bmesh_queries_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_queries_inline.h b/source/blender/bmesh/intern/bmesh_queries_inline.h
index a2a0a15faad..6162af46837 100644
--- a/source/blender/bmesh/intern/bmesh_queries_inline.h
+++ b/source/blender/bmesh/intern/bmesh_queries_inline.h
@@ -137,4 +137,16 @@ BLI_INLINE bool BM_loop_is_adjacent(const BMLoop *l_a, const BMLoop *l_b)
return (ELEM(l_b, l_a->next, l_a->prev));
}
+/**
+ * Check if we have a single wire edge user.
+ */
+BLI_INLINE bool BM_vert_is_wire_endpoint(const BMVert *v)
+{
+ const BMEdge *e = v->e;
+ if (e && e->l == NULL) {
+ return (BM_DISK_EDGE_NEXT(e, v) == e);
+ }
+ return false;
+}
+
#endif /* __BMESH_QUERIES_INLINE_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_structure.c b/source/blender/bmesh/intern/bmesh_structure.c
index afcafc8640d..3e8002c0192 100644
--- a/source/blender/bmesh/intern/bmesh_structure.c
+++ b/source/blender/bmesh/intern/bmesh_structure.c
@@ -108,6 +108,7 @@ bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new)
* - #bmesh_radial_append
* - #bmesh_radial_loop_remove
* - #bmesh_radial_facevert_count
+ * - #bmesh_radial_facevert_check
* - #bmesh_radial_faceloop_find_first
* - #bmesh_radial_faceloop_find_next
* - #bmesh_radial_validate
@@ -130,17 +131,6 @@ bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new)
* cycle order and all non-manifold conditions are represented trivially.
*/
-BLI_INLINE BMDiskLink *bmesh_disk_edge_link_from_vert(BMEdge *e, BMVert *v)
-{
- if (v == e->v1) {
- return &e->v1_disk_link;
- }
- else {
- BLI_assert(v == e->v2);
- return &e->v2_disk_link;
- }
-}
-
void bmesh_disk_edge_append(BMEdge *e, BMVert *v)
{
if (!v->e) {
@@ -205,28 +195,15 @@ BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2)
int bmesh_disk_count(const BMVert *v)
{
+ int count = 0;
if (v->e) {
BMEdge *e_first, *e_iter;
- int count = 0;
-
e_iter = e_first = v->e;
-
do {
- if (!e_iter) {
- return 0;
- }
-
- if (count >= (1 << 20)) {
- printf("bmesh error: infinite loop in disk cycle!\n");
- return 0;
- }
count++;
} while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
- return count;
- }
- else {
- return 0;
}
+ return count;
}
bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v)
@@ -289,7 +266,7 @@ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
{
const BMEdge *e_find = e;
do {
- if (e_find->l && bmesh_radial_facevert_count(e_find->l, v)) {
+ if (e_find->l && bmesh_radial_facevert_check(e_find->l, v)) {
return (BMEdge *)e_find;
}
} while ((e_find = bmesh_disk_edge_next(e_find, v)) != e);
@@ -299,10 +276,10 @@ BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v)
BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v)
{
- BMEdge *e_find = NULL;
+ BMEdge *e_find;
e_find = bmesh_disk_edge_next(e, v);
do {
- if (e_find->l && bmesh_radial_facevert_count(e_find->l, v)) {
+ if (e_find->l && bmesh_radial_facevert_check(e_find->l, v)) {
return e_find;
}
} while ((e_find = bmesh_disk_edge_next(e_find, v)) != e);
@@ -479,6 +456,24 @@ int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v)
return count;
}
+/**
+ * \brief RADIAL CHECK FACE VERT
+ *
+ * Quicker check for ``bmesh_radial_facevert_count(...) != 0``
+ */
+bool bmesh_radial_facevert_check(const BMLoop *l, const BMVert *v)
+{
+ const BMLoop *l_iter;
+ l_iter = l;
+ do {
+ if (l_iter->v == v) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != l);
+
+ return false;
+}
+
/*****loop cycle functions, e.g. loops surrounding a face**** */
bool bmesh_loop_validate(BMFace *f)
{
diff --git a/source/blender/bmesh/intern/bmesh_structure.h b/source/blender/bmesh/intern/bmesh_structure.h
index 5c87b5eb9b5..29868194bbf 100644
--- a/source/blender/bmesh/intern/bmesh_structure.h
+++ b/source/blender/bmesh/intern/bmesh_structure.h
@@ -39,37 +39,38 @@
* descriptive comments. but seriously, don't use this stuff.
*/
-struct ListBase;
-
/* LOOP CYCLE MANAGEMENT */
-bool bmesh_loop_validate(BMFace *f);
+bool bmesh_loop_validate(BMFace *f) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* DISK CYCLE MANAGMENT */
-void bmesh_disk_edge_append(BMEdge *e, BMVert *v);
-void bmesh_disk_edge_remove(BMEdge *e, BMVert *v);
-BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v);
-BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v);
-int bmesh_disk_facevert_count(const BMVert *v);
-BMEdge *bmesh_disk_faceedge_find_first(const BMEdge *e, const BMVert *v);
-BMEdge *bmesh_disk_faceedge_find_next(const BMEdge *e, const BMVert *v);
+void bmesh_disk_edge_append(BMEdge *e, BMVert *v) ATTR_NONNULL();
+void bmesh_disk_edge_remove(BMEdge *e, BMVert *v) ATTR_NONNULL();
+BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+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(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();
/* RADIAL CYCLE MANAGMENT */
-void bmesh_radial_append(BMEdge *e, BMLoop *l);
-void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e);
+void bmesh_radial_append(BMEdge *e, BMLoop *l) ATTR_NONNULL();
+void bmesh_radial_loop_remove(BMLoop *l, BMEdge *e) ATTR_NONNULL(1);
/* note:
* bmesh_radial_loop_next(BMLoop *l) / prev.
* just use member access l->radial_next, l->radial_prev now */
-int bmesh_radial_facevert_count(const BMLoop *l, const BMVert *v);
-BMLoop *bmesh_radial_faceloop_find_first(const BMLoop *l, const BMVert *v);
-BMLoop *bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v);
-BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v);
-bool bmesh_radial_validate(int radlen, BMLoop *l);
+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();
+BMLoop *bmesh_radial_faceloop_find_next(const BMLoop *l, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+BMLoop *bmesh_radial_faceloop_find_vert(const BMFace *f, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool bmesh_radial_validate(int radlen, BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
/* EDGE UTILITIES */
-bool bmesh_edge_swapverts(BMEdge *e, BMVert *orig, BMVert *newv); /* relink edge */
-BMEdge *bmesh_disk_edge_exists(const BMVert *v1, const BMVert *v2);
-bool bmesh_disk_validate(int len, BMEdge *e, BMVert *v);
+bool bmesh_edge_swapverts(BMEdge *e, BMVert *v_orig, BMVert *v_new) 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();
#include "intern/bmesh_structure_inline.h"
diff --git a/source/blender/bmesh/intern/bmesh_structure_inline.h b/source/blender/bmesh/intern/bmesh_structure_inline.h
index c29acaa724c..5b7e890f5ea 100644
--- a/source/blender/bmesh/intern/bmesh_structure_inline.h
+++ b/source/blender/bmesh/intern/bmesh_structure_inline.h
@@ -27,6 +27,12 @@
#ifndef __BMESH_STRUCTURE_INLINE_H__
#define __BMESH_STRUCTURE_INLINE_H__
+BLI_INLINE BMDiskLink *bmesh_disk_edge_link_from_vert(const BMEdge *e, const BMVert *v)
+{
+ BLI_assert(BM_vert_in_edge(e, v));
+ return (BMDiskLink *)&(&e->v1_disk_link)[v == e->v2];
+}
+
/**
* \brief Next Disk Edge
*
@@ -34,7 +40,7 @@
*
* \return Pointer to the next edge in the disk cycle for the vertex v.
*/
-BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v)
+BLI_INLINE BMEdge *bmesh_disk_edge_next_safe(const BMEdge *e, const BMVert *v)
{
if (v == e->v1)
return e->v1_disk_link.next;
@@ -43,7 +49,7 @@ BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v)
return NULL;
}
-BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v)
+BLI_INLINE BMEdge *bmesh_disk_edge_prev_safe(const BMEdge *e, const BMVert *v)
{
if (v == e->v1)
return e->v1_disk_link.prev;
@@ -52,4 +58,14 @@ BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v)
return NULL;
}
+BLI_INLINE BMEdge *bmesh_disk_edge_next(const BMEdge *e, const BMVert *v)
+{
+ return BM_DISK_EDGE_NEXT(e, v);
+}
+
+BLI_INLINE BMEdge *bmesh_disk_edge_prev(const BMEdge *e, const BMVert *v)
+{
+ return BM_DISK_EDGE_PREV(e, v);
+}
+
#endif /* __BMESH_STRUCTURE_INLINE_H__ */
diff --git a/source/blender/bmesh/intern/bmesh_walkers.c b/source/blender/bmesh/intern/bmesh_walkers.c
index 75513a48d98..6a5efbe70ac 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.c
+++ b/source/blender/bmesh/intern/bmesh_walkers.c
@@ -47,7 +47,7 @@
*
* basic design pattern: the walker step function goes through it's
* list of possible choices for recursion, and recurses (by pushing a new state)
- * using the first non-visited one. this choise is the flagged as visited using
+ * using the first non-visited one. This choice is the flagged as visited using
* the ghash. each step may push multiple new states onto the worklist at once.
*
* - Walkers use tool flags, not header flags.
@@ -60,6 +60,8 @@
void *BMW_begin(BMWalker *walker, void *start)
{
+ BLI_assert(((BMHeader *)start)->htype & walker->begin_htype);
+
walker->begin(walker, start);
return BMW_current_state(walker) ? walker->step(walker) : NULL;
@@ -100,6 +102,7 @@ void BMW_init(BMWalker *walker, BMesh *bm, int type,
}
if (type != BMW_CUSTOM) {
+ walker->begin_htype = bm_walker_types[type]->begin_htype;
walker->begin = bm_walker_types[type]->begin;
walker->yield = bm_walker_types[type]->yield;
walker->step = bm_walker_types[type]->step;
diff --git a/source/blender/bmesh/intern/bmesh_walkers.h b/source/blender/bmesh/intern/bmesh_walkers.h
index 9b0c200adc5..d551ea9fba9 100644
--- a/source/blender/bmesh/intern/bmesh_walkers.h
+++ b/source/blender/bmesh/intern/bmesh_walkers.h
@@ -27,8 +27,6 @@
* \ingroup bmesh
*/
-#include "BLI_ghash.h"
-
/*
* NOTE: do NOT modify topology while walking a mesh!
*/
@@ -45,6 +43,7 @@ typedef enum {
/*Walkers*/
typedef struct BMWalker {
+ char begin_htype; /* only for validating input */
void (*begin) (struct BMWalker *walker, void *start);
void *(*step) (struct BMWalker *walker);
void *(*yield) (struct BMWalker *walker);
@@ -67,8 +66,8 @@ typedef struct BMWalker {
BMWFlag flag;
- GSet *visit_set;
- GSet *visit_set_alt;
+ struct GSet *visit_set;
+ struct GSet *visit_set_alt;
int depth;
} BMWalker;
@@ -108,34 +107,16 @@ void BMW_reset(BMWalker *walker);
*/
enum {
- /* walk over connected geometry. can restrict to a search flag,
- * or not, it's optional.
- *
- * takes a vert as an argument, and spits out edges, restrict flag acts
- * on the edges as well. */
- BMW_SHELL,
- /*walk over an edge loop. search flag doesn't do anything.*/
+ BMW_VERT_SHELL,
+ BMW_FACE_SHELL,
BMW_LOOP,
BMW_FACELOOP,
BMW_EDGERING,
BMW_EDGEBOUNDARY,
- /* #define BMW_RING 2 */
- /* walk over uv islands; takes a loop as input. restrict flag
- * restricts the walking to loops whose vert has restrict flag set as a
- * tool flag.
- *
- * the flag parameter to BMW_init maps to a loop customdata layer index.
- */
+ /* BMW_RING, */
BMW_LOOPDATA_ISLAND,
- /* walk over an island of flagged faces. note, that this doesn't work on
- * non-manifold geometry. it might be better to rewrite this to extract
- * boundary info from the island walker, rather then directly walking
- * over the boundary. raises an error if it encounters nonmanifold
- * geometry. */
BMW_ISLANDBOUND,
- /* walk over all faces in an island of tool flagged faces. */
BMW_ISLAND,
- /* walk from a vertex to all connected vertices. */
BMW_CONNECTED_VERTEX,
/* end of array index enum vals */
diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c
index 70b90238f96..406dd412d6d 100644
--- a/source/blender/bmesh/intern/bmesh_walkers_impl.c
+++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c
@@ -93,9 +93,12 @@ static bool bmw_mask_check_face(BMWalker *walker, BMFace *f)
* Starts at a vertex on the mesh and walks over the 'shell' it belongs
* to via visiting connected edges.
*
+ * takes an edge or vertex as an argument, and spits out edges,
+ * restrict flag acts on the edges as well.
+ *
* \todo Add restriction flag/callback for wire edges.
*/
-static void bmw_ShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
+static void bmw_VertShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
{
BMwShellWalker *shellWalk = NULL;
@@ -112,7 +115,7 @@ static void bmw_ShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
BLI_gset_insert(walker->visit_set, e);
}
-static void bmw_ShellWalker_begin(BMWalker *walker, void *data)
+static void bmw_VertShellWalker_begin(BMWalker *walker, void *data)
{
BMIter eiter;
BMHeader *h = data;
@@ -130,7 +133,7 @@ static void bmw_ShellWalker_begin(BMWalker *walker, void *data)
* to the worklist */
v = (BMVert *)h;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- bmw_ShellWalker_visitEdge(walker, e);
+ bmw_VertShellWalker_visitEdge(walker, e);
}
break;
}
@@ -140,19 +143,21 @@ static void bmw_ShellWalker_begin(BMWalker *walker, void *data)
/* starting the walk at an edge, add the single edge
* to the worklist */
e = (BMEdge *)h;
- bmw_ShellWalker_visitEdge(walker, e);
+ bmw_VertShellWalker_visitEdge(walker, e);
break;
}
+ default:
+ BLI_assert(0);
}
}
-static void *bmw_ShellWalker_yield(BMWalker *walker)
+static void *bmw_VertShellWalker_yield(BMWalker *walker)
{
BMwShellWalker *shellWalk = BMW_current_state(walker);
return shellWalk->curedge;
}
-static void *bmw_ShellWalker_step(BMWalker *walker)
+static void *bmw_VertShellWalker_step(BMWalker *walker)
{
BMwShellWalker *swalk, owalk;
BMEdge *e, *e2;
@@ -168,7 +173,7 @@ static void *bmw_ShellWalker_step(BMWalker *walker)
for (i = 0; i < 2; i++) {
v = i ? e->v2 : e->v1;
BM_ITER_ELEM (e2, &iter, v, BM_EDGES_OF_VERT) {
- bmw_ShellWalker_visitEdge(walker, e2);
+ bmw_VertShellWalker_visitEdge(walker, e2);
}
}
@@ -176,7 +181,7 @@ static void *bmw_ShellWalker_step(BMWalker *walker)
}
#if 0
-static void *bmw_ShellWalker_step(BMWalker *walker)
+static void *bmw_VertShellWalker_step(BMWalker *walker)
{
BMEdge *curedge, *next = NULL;
BMVert *v_old = NULL;
@@ -220,10 +225,77 @@ static void *bmw_ShellWalker_step(BMWalker *walker)
/** \} */
+/** \name FaceShell Walker
+ * \{
+ *
+ * Starts at an edge on the mesh and walks over the 'shell' it belongs
+ * to via visiting connected faces.
+ */
+static void bmw_FaceShellWalker_visitEdge(BMWalker *walker, BMEdge *e)
+{
+ BMwShellWalker *shellWalk = NULL;
+
+ if (BLI_gset_haskey(walker->visit_set, e)) {
+ return;
+ }
+
+ if (!bmw_mask_check_edge(walker, e)) {
+ return;
+ }
+
+ shellWalk = BMW_state_add(walker);
+ shellWalk->curedge = e;
+ BLI_gset_insert(walker->visit_set, e);
+}
+
+static void bmw_FaceShellWalker_begin(BMWalker *walker, void *data)
+{
+ BMEdge *e = data;
+ bmw_FaceShellWalker_visitEdge(walker, e);
+}
+
+static void *bmw_FaceShellWalker_yield(BMWalker *walker)
+{
+ BMwShellWalker *shellWalk = BMW_current_state(walker);
+ return shellWalk->curedge;
+}
+
+static void *bmw_FaceShellWalker_step(BMWalker *walker)
+{
+ BMwShellWalker *swalk, owalk;
+ BMEdge *e, *e2;
+ BMIter iter;
+
+ BMW_state_remove_r(walker, &owalk);
+ swalk = &owalk;
+
+ e = swalk->curedge;
+
+ if (e->l) {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = e->l;
+ do {
+ BM_ITER_ELEM (e2, &iter, l_iter->f, BM_EDGES_OF_FACE) {
+ if (e2 != e) {
+ bmw_FaceShellWalker_visitEdge(walker, e2);
+ }
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+
+ return e;
+}
+/** \} */
+
+
/** \name Connected Vertex Walker
* \{
*
* Similar to shell walker, but visits vertices instead of edges.
+ *
+ * Walk from a vertex to all connected vertices.
+ *
*/
static void bmw_ConnectedVertexWalker_visitVertex(BMWalker *walker, BMVert *v)
{
@@ -286,6 +358,11 @@ static void *bmw_ConnectedVertexWalker_step(BMWalker *walker)
*
* Starts at a edge on the mesh and walks over the boundary of an island it belongs to.
*
+ * \note that this doesn't work on non-manifold geometry.
+ * it might be better to rewrite this to extract
+ * boundary info from the island walker, rather then directly walking
+ * over the boundary. raises an error if it encounters nonmanifold geometry.
+ *
* \todo Add restriction flag/callback for wire edges.
*/
static void bmw_IslandboundWalker_begin(BMWalker *walker, void *data)
@@ -456,6 +533,7 @@ static void *bmw_IslandWalker_step(BMWalker *walker)
* \{
*
* Starts at a tool-flagged edge and walks over the edge loop
+ *
*/
/* utility function to see if an edge is apart of an ngon boundary */
@@ -841,8 +919,8 @@ static void *bmw_FaceLoopWalker_step(BMWalker *walker)
}
/* both may already exist */
- BLI_gset_reinsert(walker->visit_set_alt, l->e, NULL);
- BLI_gset_reinsert(walker->visit_set, l->f, NULL);
+ BLI_gset_add(walker->visit_set_alt, l->e);
+ BLI_gset_add(walker->visit_set, l->f);
}
return f;
@@ -1066,6 +1144,13 @@ static void *bmw_EdgeboundaryWalker_step(BMWalker *walker)
/** \name UV Edge Walker
+ *
+ * walk over uv islands; takes a loop as input. restrict flag
+ * restricts the walking to loops whose vert has restrict flag set as a
+ * tool flag.
+ *
+ * the flag parameter to BMW_init maps to a loop customdata layer index.
+ *
* \{ */
static void bmw_UVEdgeWalker_begin(BMWalker *walker, void *data)
@@ -1154,16 +1239,28 @@ static void *bmw_UVEdgeWalker_step(BMWalker *walker)
/** \} */
-static BMWalker bmw_ShellWalker_Type = {
- bmw_ShellWalker_begin,
- bmw_ShellWalker_step,
- bmw_ShellWalker_yield,
+static BMWalker bmw_VertShellWalker_Type = {
+ BM_VERT | BM_EDGE,
+ bmw_VertShellWalker_begin,
+ bmw_VertShellWalker_step,
+ bmw_VertShellWalker_yield,
+ sizeof(BMwShellWalker),
+ BMW_BREADTH_FIRST,
+ BM_EDGE, /* valid restrict masks */
+};
+
+static BMWalker bmw_FaceShellWalker_Type = {
+ BM_EDGE,
+ bmw_FaceShellWalker_begin,
+ bmw_FaceShellWalker_step,
+ bmw_FaceShellWalker_yield,
sizeof(BMwShellWalker),
BMW_BREADTH_FIRST,
BM_EDGE, /* valid restrict masks */
};
static BMWalker bmw_IslandboundWalker_Type = {
+ BM_LOOP,
bmw_IslandboundWalker_begin,
bmw_IslandboundWalker_step,
bmw_IslandboundWalker_yield,
@@ -1173,6 +1270,7 @@ static BMWalker bmw_IslandboundWalker_Type = {
};
static BMWalker bmw_IslandWalker_Type = {
+ BM_FACE,
bmw_IslandWalker_begin,
bmw_IslandWalker_step,
bmw_IslandWalker_yield,
@@ -1182,6 +1280,7 @@ static BMWalker bmw_IslandWalker_Type = {
};
static BMWalker bmw_LoopWalker_Type = {
+ BM_EDGE,
bmw_LoopWalker_begin,
bmw_LoopWalker_step,
bmw_LoopWalker_yield,
@@ -1191,6 +1290,7 @@ static BMWalker bmw_LoopWalker_Type = {
};
static BMWalker bmw_FaceLoopWalker_Type = {
+ BM_EDGE,
bmw_FaceLoopWalker_begin,
bmw_FaceLoopWalker_step,
bmw_FaceLoopWalker_yield,
@@ -1200,6 +1300,7 @@ static BMWalker bmw_FaceLoopWalker_Type = {
};
static BMWalker bmw_EdgeringWalker_Type = {
+ BM_EDGE,
bmw_EdgeringWalker_begin,
bmw_EdgeringWalker_step,
bmw_EdgeringWalker_yield,
@@ -1209,6 +1310,7 @@ static BMWalker bmw_EdgeringWalker_Type = {
};
static BMWalker bmw_EdgeboundaryWalker_Type = {
+ BM_EDGE,
bmw_EdgeboundaryWalker_begin,
bmw_EdgeboundaryWalker_step,
bmw_EdgeboundaryWalker_yield,
@@ -1218,6 +1320,7 @@ static BMWalker bmw_EdgeboundaryWalker_Type = {
};
static BMWalker bmw_UVEdgeWalker_Type = {
+ BM_LOOP,
bmw_UVEdgeWalker_begin,
bmw_UVEdgeWalker_step,
bmw_UVEdgeWalker_yield,
@@ -1227,6 +1330,7 @@ static BMWalker bmw_UVEdgeWalker_Type = {
};
static BMWalker bmw_ConnectedVertexWalker_Type = {
+ BM_VERT,
bmw_ConnectedVertexWalker_begin,
bmw_ConnectedVertexWalker_step,
bmw_ConnectedVertexWalker_yield,
@@ -1236,7 +1340,8 @@ static BMWalker bmw_ConnectedVertexWalker_Type = {
};
BMWalker *bm_walker_types[] = {
- &bmw_ShellWalker_Type, /* BMW_SHELL */
+ &bmw_VertShellWalker_Type, /* BMW_VERT_SHELL */
+ &bmw_FaceShellWalker_Type, /* BMW_FACE_SHELL */
&bmw_LoopWalker_Type, /* BMW_LOOP */
&bmw_FaceLoopWalker_Type, /* BMW_FACELOOP */
&bmw_EdgeringWalker_Type, /* BMW_EDGERING */
@@ -1247,4 +1352,4 @@ BMWalker *bm_walker_types[] = {
&bmw_ConnectedVertexWalker_Type, /* BMW_CONNECTED_VERTEX */
};
-const int bm_totwalkers = sizeof(bm_walker_types) / sizeof(*bm_walker_types);
+const int bm_totwalkers = ARRAY_SIZE(bm_walker_types);
diff --git a/source/blender/bmesh/operators/bmo_bevel.c b/source/blender/bmesh/operators/bmo_bevel.c
index 07a2e674863..864c4dada6d 100644
--- a/source/blender/bmesh/operators/bmo_bevel.c
+++ b/source/blender/bmesh/operators/bmo_bevel.c
@@ -35,11 +35,13 @@
void bmo_bevel_exec(BMesh *bm, BMOperator *op)
{
- const float offset = BMO_slot_float_get(op->slots_in, "offset");
- const int offset_type = BMO_slot_int_get(op->slots_in, "offset_type");
- const int seg = BMO_slot_int_get(op->slots_in, "segments");
- const bool vonly = BMO_slot_bool_get(op->slots_in, "vertex_only");
- const float profile = BMO_slot_float_get(op->slots_in, "profile");
+ const float offset = BMO_slot_float_get(op->slots_in, "offset");
+ const int offset_type = BMO_slot_int_get(op->slots_in, "offset_type");
+ const int seg = BMO_slot_int_get(op->slots_in, "segments");
+ const bool vonly = BMO_slot_bool_get(op->slots_in, "vertex_only");
+ const float profile = BMO_slot_float_get(op->slots_in, "profile");
+ const bool clamp_overlap = BMO_slot_bool_get(op->slots_in, "clamp_overlap");
+ const int material = BMO_slot_int_get(op->slots_in, "material");
if (offset > 0) {
BMOIter siter;
@@ -60,7 +62,7 @@ void bmo_bevel_exec(BMesh *bm, BMOperator *op)
}
}
- BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, false, NULL, -1);
+ BM_mesh_bevel(bm, offset, offset_type, seg, profile, vonly, false, clamp_overlap, NULL, -1, material);
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
}
diff --git a/source/blender/bmesh/operators/bmo_bisect_plane.c b/source/blender/bmesh/operators/bmo_bisect_plane.c
index 74cb9d67e88..bed1ea5cb94 100644
--- a/source/blender/bmesh/operators/bmo_bisect_plane.c
+++ b/source/blender/bmesh/operators/bmo_bisect_plane.c
@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_stackdefines.h"
#include "BLI_math.h"
#include "bmesh.h"
@@ -89,7 +90,7 @@ void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op)
plane_outer[3] = plane[3] - dist;
plane_inner[3] = plane[3] + dist;
- STACK_INIT(vert_arr);
+ STACK_INIT(vert_arr, vert_arr_max);
BMO_ITER (v, &siter, op->slots_in, "geom", BM_VERT) {
if ((clear_outer && plane_point_side_v3(plane_outer, v->co) > 0.0f) ||
@@ -103,7 +104,6 @@ void bmo_bisect_plane_exec(BMesh *bm, BMOperator *op)
BM_vert_kill(bm, v);
}
- STACK_FREE(vert_arr);
MEM_freeN(vert_arr);
}
diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c
index 9e9cd0d66e2..e4417477e76 100644
--- a/source/blender/bmesh/operators/bmo_bridge.c
+++ b/source/blender/bmesh/operators/bmo_bridge.c
@@ -119,7 +119,7 @@ static void bm_bridge_best_rotation(struct BMEdgeLoopStore *el_store_a, struct B
}
if (el_b_best) {
- BLI_rotatelist_first(lb_b, el_b_best);
+ BLI_listbase_rotate_first(lb_b, el_b_best);
}
}
@@ -272,7 +272,7 @@ static void bridge_loop_pair(BMesh *bm,
const int len_b = BM_edgeloop_length_get(el_store_b);
ListBase *lb_b = BM_edgeloop_verts_get(el_store_b);
LinkData *el_b = BLI_rfindlink(lb_b, mod_i(twist_offset, len_b));
- BLI_rotatelist_first(lb_b, el_b);
+ BLI_listbase_rotate_first(lb_b, el_b);
}
}
diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c
index 2e45cb9fec1..0213329118c 100644
--- a/source/blender/bmesh/operators/bmo_connect.c
+++ b/source/blender/bmesh/operators/bmo_connect.c
@@ -27,6 +27,7 @@
*/
#include "BLI_utildefines.h"
+#include "BLI_stackdefines.h"
#include "BLI_alloca.h"
#include "BLI_linklist_stack.h"
@@ -35,54 +36,75 @@
#include "intern/bmesh_operators_private.h" /* own include */
#define VERT_INPUT 1
+
#define EDGE_OUT 1
-#define FACE_TAG 2
+/* Edge spans 2 VERT_INPUT's, its a nop,
+ * but include in "edges.out" */
+#define EDGE_OUT_ADJ 2
+
+#define FACE_TAG 2
+#define FACE_EXCLUDE 4
static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenerate)
{
- BMLoop *(*loops_split)[2] = BLI_array_alloca(loops_split, f->len);
+ const unsigned pair_split_max = f->len / 2;
+ BMLoop *(*loops_split)[2] = BLI_array_alloca(loops_split, pair_split_max);
STACK_DECLARE(loops_split);
- BMVert *(*verts_pair)[2] = BLI_array_alloca(verts_pair, f->len);
+ BMVert *(*verts_pair)[2] = BLI_array_alloca(verts_pair, pair_split_max);
STACK_DECLARE(verts_pair);
- BMIter liter;
- BMFace *f_new;
- BMLoop *l;
- BMLoop *l_last;
+ BMLoop *l_tag_prev = NULL, *l_tag_first = NULL;
+ BMLoop *l_iter, *l_first;
unsigned int i;
- STACK_INIT(loops_split);
- STACK_INIT(verts_pair);
+ STACK_INIT(loops_split, pair_split_max);
+ STACK_INIT(verts_pair, pair_split_max);
- l_last = NULL;
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (BMO_elem_flag_test(bm, l->v, VERT_INPUT)) {
- if (!l_last) {
- l_last = l;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BMO_elem_flag_test(bm, l_iter->v, VERT_INPUT) &&
+ /* ensure this vertex isnt part of a contiguous group */
+ ((BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) ||
+ (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0)))
+ {
+ if (!l_tag_prev) {
+ l_tag_prev = l_tag_first = l_iter;
continue;
}
- if (!BM_loop_is_adjacent(l_last, l)) {
- BMLoop **l_pair = STACK_PUSH_RET(loops_split);
- l_pair[0] = l_last;
- l_pair[1] = l;
+ if (!BM_loop_is_adjacent(l_tag_prev, l_iter)) {
+ BMEdge *e;
+ e = BM_edge_exists(l_tag_prev->v, l_iter->v);
+ if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_OUT)) {
+ BMLoop **l_pair = STACK_PUSH_RET(loops_split);
+ l_pair[0] = l_tag_prev;
+ l_pair[1] = l_iter;
+ }
}
- l_last = l;
+
+ l_tag_prev = l_iter;
}
- }
+ } while ((l_iter = l_iter->next) != l_first);
if (STACK_SIZE(loops_split) == 0) {
return 0;
}
- if (STACK_SIZE(loops_split) > 1) {
+ if (!BM_loop_is_adjacent(l_tag_first, l_tag_prev) &&
+ /* ensure we don't add the same pair twice */
+ (((loops_split[0][0] == l_tag_first) &&
+ (loops_split[0][1] == l_tag_prev)) == 0))
+ {
BMLoop **l_pair = STACK_PUSH_RET(loops_split);
- l_pair[0] = loops_split[STACK_SIZE(loops_split) - 2][1];
- l_pair[1] = loops_split[0][0];
+ l_pair[0] = l_tag_first;
+ l_pair[1] = l_tag_prev;
}
if (check_degenerate) {
- BM_face_legal_splits(f, loops_split, STACK_SIZE(loops_split));
+ BM_face_splits_check_legal(bm, f, loops_split, STACK_SIZE(loops_split));
+ }
+ else {
+ BM_face_splits_check_optimal(f, loops_split, STACK_SIZE(loops_split));
}
for (i = 0; i < STACK_SIZE(loops_split); i++) {
@@ -97,6 +119,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
}
for (i = 0; i < STACK_SIZE(verts_pair); i++) {
+ BMFace *f_new;
BMLoop *l_new;
BMLoop *l_a, *l_b;
@@ -126,7 +149,6 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera
void bmo_connect_verts_exec(BMesh *bm, BMOperator *op)
{
BMOIter siter;
- BMIter iter;
BMVert *v;
BMFace *f;
const bool check_degenerate = BMO_slot_bool_get(op->slots_in, "check_degenerate");
@@ -134,16 +156,35 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op)
BLI_LINKSTACK_INIT(faces);
+ /* tag so we won't touch ever (typically hidden faces) */
+ BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE);
+
/* add all faces connected to verts */
BMO_ITER (v, &siter, op->slots_in, "verts", BM_VERT) {
+ BMIter iter;
+ BMLoop *l_iter;
+
BMO_elem_flag_enable(bm, v, VERT_INPUT);
- BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
- if (!BMO_elem_flag_test(bm, f, FACE_TAG)) {
- BMO_elem_flag_enable(bm, f, FACE_TAG);
- if (f->len > 3) {
- BLI_LINKSTACK_PUSH(faces, f);
+ BM_ITER_ELEM (l_iter, &iter, v, BM_LOOPS_OF_VERT) {
+ f = l_iter->f;
+ if (!BMO_elem_flag_test(bm, f, FACE_EXCLUDE)) {
+ if (!BMO_elem_flag_test(bm, f, FACE_TAG)) {
+ BMO_elem_flag_enable(bm, f, FACE_TAG);
+ if (f->len > 3) {
+ BLI_LINKSTACK_PUSH(faces, f);
+ }
}
}
+
+ /* flag edges even if these are not newly created
+ * this way cut-pairs that include co-linear edges will get
+ * predictable output. */
+ if (BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT)) {
+ BMO_elem_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ);
+ }
+ if (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT)) {
+ BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ);
+ }
}
}
@@ -156,5 +197,5 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op)
BLI_LINKSTACK_FREE(faces);
- BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT);
+ BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, EDGE_OUT | EDGE_OUT_ADJ);
}
diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
index 15447c97b5f..6859ce2060c 100644
--- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c
+++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
@@ -39,29 +39,6 @@
#define FACE_OUT (1 << 1)
/**
- * Calculates the face subset normal.
- */
-static bool bm_face_subset_calc_normal(BMLoop *l_first, BMLoop *l_last, float r_no[3])
-{
- const float *v_prev, *v_curr;
-
- /* Newell's Method */
- BMLoop *l_iter = l_first;
- BMLoop *l_term = l_last->next;
-
- zero_v3(r_no);
-
- v_prev = l_last->v->co;
- do {
- v_curr = l_iter->v->co;
- add_newell_cross_v3_v3v3(r_no, v_prev, v_curr);
- v_prev = v_curr;
- } while ((l_iter = l_iter->next) != l_term);
-
- return (normalize_v3(r_no) != 0.0f);
-}
-
-/**
* Calculates how non-planar the face subset is.
*/
static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const float no[3])
@@ -86,7 +63,7 @@ static float bm_face_subset_calc_planar(BMLoop *l_first, BMLoop *l_last, const f
return delta_z;
}
-static bool bm_face_split_find(BMFace *f, BMLoop *l_pair[2], float *r_angle)
+static bool bm_face_split_find(BMesh *bm, BMFace *f, BMLoop *l_pair[2], float *r_angle)
{
BMLoop *l_iter, *l_first;
BMLoop **l_arr = BLI_array_alloca(l_arr, f->len);
@@ -115,8 +92,8 @@ static bool bm_face_split_find(BMFace *f, BMLoop *l_pair[2], float *r_angle)
/* first calculate normals */
float no_a[3], no_b[3];
- if (bm_face_subset_calc_normal(l_a, l_b, no_a) &&
- bm_face_subset_calc_normal(l_b, l_a, no_b))
+ if (BM_face_calc_normal_subset(l_a, l_b, no_a) != 0.0f &&
+ BM_face_calc_normal_subset(l_b, l_a, no_b) != 0.0f)
{
const float err_a = bm_face_subset_calc_planar(l_a, l_b, no_a);
const float err_b = bm_face_subset_calc_planar(l_b, l_a, no_b);
@@ -125,7 +102,7 @@ static bool bm_face_split_find(BMFace *f, BMLoop *l_pair[2], float *r_angle)
if (err_test < err_best) {
/* check we're legal (we could batch this) */
BMLoop *l_split[2] = {l_a, l_b};
- BM_face_legal_splits(f, &l_split, 1);
+ BM_face_splits_check_legal(bm, f, &l_split, 1);
if (l_split[0]) {
err_best = err_test;
l_pair[0] = l_a;
@@ -152,7 +129,7 @@ static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], co
BMLoop *l_pair[2];
float angle;
- if (bm_face_split_find(f, l_pair, &angle) && (angle > angle_limit)) {
+ if (bm_face_split_find(bm, f, l_pair, &angle) && (angle > angle_limit)) {
BMFace *f_new;
BMLoop *l_new;
diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c
index b497ab2f693..a0acf6ed2c5 100644
--- a/source/blender/bmesh/operators/bmo_connect_pair.c
+++ b/source/blender/bmesh/operators/bmo_connect_pair.c
@@ -51,6 +51,15 @@
#define CONNECT_EPS 0.0001f
#define VERT_OUT 1
+#define VERT_EXCLUDE 2
+
+/* typically hidden faces */
+#define FACE_EXCLUDE 2
+
+#define FACE_WALK_TEST(f) (CHECK_TYPE_INLINE(f, BMFace *), \
+ BMO_elem_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0)
+#define VERT_WALK_TEST(v) (CHECK_TYPE_INLINE(v, BMVert *), \
+ BMO_elem_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0)
// #define DEBUG_PRINT
@@ -59,6 +68,9 @@ typedef struct PathContext {
float matrix[3][3];
float axis_sep;
+ /* only to access BMO flags */
+ BMesh *bm_bmoflag;
+
BMVert *v_a, *v_b;
BLI_mempool *link_pool;
@@ -134,7 +146,7 @@ static void state_calc_co_pair(const PathContext *pc,
static bool state_link_find(PathLinkState *state, BMElem *ele)
{
PathLink *link = state->link_last;
- BLI_assert(ELEM3(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE));
+ BLI_assert(ELEM(ele->head.htype, BM_VERT, BM_EDGE, BM_FACE));
if (link) {
do {
if (link->ele == ele) {
@@ -204,8 +216,9 @@ static void state_link_add(PathContext *pc, PathLinkState *state,
state->link_last = step_new;
}
-static PathLinkState *state_dupe_add(PathContext *pc,
- PathLinkState *state, const PathLinkState *state_orig)
+static PathLinkState *state_dupe_add(
+ PathContext *pc,
+ PathLinkState *state, const PathLinkState *state_orig)
{
state = MEM_mallocN(sizeof(*state), __func__);
*state = *state_orig;
@@ -214,16 +227,19 @@ static PathLinkState *state_dupe_add(PathContext *pc,
}
/* walk around the face edges */
-static PathLinkState *state_step__face_edges(PathContext *pc,
- PathLinkState *state, const PathLinkState *state_orig,
- BMLoop *l_iter, BMLoop *l_last)
+static PathLinkState *state_step__face_edges(
+ PathContext *pc,
+ PathLinkState *state, const PathLinkState *state_orig,
+ BMLoop *l_iter, BMLoop *l_last)
{
do {
if (state_isect_co_pair(pc, l_iter->v->co, l_iter->next->v->co)) {
BMElem *ele_next = (BMElem *)l_iter->e;
BMElem *ele_next_from = (BMElem *)l_iter->f;
- if (state_link_find(state, ele_next) == false) {
+ if (FACE_WALK_TEST((BMFace *)ele_next_from) &&
+ (state_link_find(state, ele_next) == false))
+ {
if (state_orig->link_last != state->link_last) {
state = state_dupe_add(pc, state, state_orig);
}
@@ -235,16 +251,19 @@ static PathLinkState *state_step__face_edges(PathContext *pc,
}
/* walk around the face verts */
-static PathLinkState *state_step__face_verts(PathContext *pc,
- PathLinkState *state, const PathLinkState *state_orig,
- BMLoop *l_iter, BMLoop *l_last)
+static PathLinkState *state_step__face_verts(
+ PathContext *pc,
+ PathLinkState *state, const PathLinkState *state_orig,
+ BMLoop *l_iter, BMLoop *l_last)
{
do {
if (state_isect_co_exact(pc, l_iter->v->co)) {
BMElem *ele_next = (BMElem *)l_iter->v;
BMElem *ele_next_from = (BMElem *)l_iter->f;
- if (state_link_find(state, ele_next) == false) {
+ if (FACE_WALK_TEST((BMFace *)ele_next_from) &&
+ state_link_find(state, ele_next) == false)
+ {
if (state_orig->link_last != state->link_last) {
state = state_dupe_add(pc, state, state_orig);
}
@@ -268,7 +287,9 @@ static bool state_step(PathContext *pc, PathLinkState *state)
BMLoop *l_start;
BM_ITER_ELEM (l_start, &liter, e, BM_LOOPS_OF_EDGE) {
- if (l_start->f != ele_from) {
+ if ((l_start->f != ele_from) &&
+ FACE_WALK_TEST(l_start->f))
+ {
/* very similar to block below */
if (BM_vert_in_face(l_start->f, pc->v_b)) {
if (state_orig.link_last != state->link_last) {
@@ -295,7 +316,9 @@ static bool state_step(PathContext *pc, PathLinkState *state)
BMLoop *l_start;
BM_ITER_ELEM (l_start, &liter, v, BM_LOOPS_OF_VERT) {
- if (l_start->f != ele_from) {
+ if ((l_start->f != ele_from) &&
+ FACE_WALK_TEST(l_start->f))
+ {
/* very similar to block above */
if (BM_vert_in_face(l_start->f, pc->v_b)) {
BMElem *ele_next = (BMElem *)pc->v_b;
@@ -324,8 +347,10 @@ static bool state_step(PathContext *pc, PathLinkState *state)
BMIter eiter;
BMEdge *e;
BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if ((BMElem *)e != ele_from) {
- BMVert *v_other = BM_edge_other_vert(e, v);
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ if (((BMElem *)e != ele_from) &&
+ VERT_WALK_TEST(v_other))
+ {
if (v_other == pc->v_b) {
BMElem *ele_next = (BMElem *)pc->v_b;
BMElem *ele_next_from = (BMElem *)e;
@@ -371,6 +396,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
return;
}
+ pc.bm_bmoflag = bm;
pc.v_a = ((BMVert **)op_verts_slot->data.p)[0];
pc.v_b = ((BMVert **)op_verts_slot->data.p)[1];
@@ -384,6 +410,10 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
printf("%s: v_b: %d\n", __func__, BM_elem_index_get(pc.v_b));
#endif
+ /* tag so we won't touch ever (typically hidden faces) */
+ BMO_slot_buffer_flag_enable(bm, op->slots_in, "faces_exclude", BM_FACE, FACE_EXCLUDE);
+ BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts_exclude", BM_VERT, VERT_EXCLUDE);
+
/* setup context */
{
BLI_listbase_clear(&pc.state_lb);
@@ -468,9 +498,7 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
BLI_remlink(&pc.state_lb, state);
MEM_freeN(state);
}
- else {
- found_all = false;
- }
+ found_all = false;
}
else {
/* didn't reach the end, remove it,
@@ -481,6 +509,11 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
}
if (found_all) {
+#ifdef DEBUG
+ for (state = pc.state_lb.first; state; state = state->next) {
+ BLI_assert(state->link_last->ele == (BMElem *)pc.v_b);
+ }
+#endif
break;
}
}
@@ -533,7 +566,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op)
* always connect even when resulting faces are degenerate [#39418] */
BMOperator op_sub;
BMO_op_initf(bm, &op_sub, 0,
- "connect_verts verts=%fv", VERT_OUT);
+ "connect_verts verts=%fv faces_exclude=%s",
+ VERT_OUT, op, "faces_exclude");
BMO_op_exec(bm, &op_sub);
BMO_slot_copy(&op_sub, slots_out, "edges.out",
op, slots_out, "edges.out");
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 334242f3100..8cd9ee14bcb 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -29,6 +29,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_array.h"
+#include "BLI_stack.h"
#include "BLI_math.h"
#include "bmesh.h"
@@ -48,8 +49,10 @@
#define EDGE_ISGC 8
#define VERT_MARK 1
+#define VERT_MARK_PAIR 4
#define VERT_TAG 2
#define VERT_ISGC 8
+#define VERT_MARK_TEAR 16
@@ -84,15 +87,20 @@ static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f)
return true;
}
-static void bm_face_split(BMesh *bm, const short oflag)
+static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete)
{
+ BLI_Stack *edge_delete_verts;
BMIter iter;
BMVert *v;
- BMIter liter;
+ if (use_edge_delete) {
+ edge_delete_verts = BLI_stack_new(sizeof(BMVert *), __func__);
+ }
+
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BMO_elem_flag_test(bm, v, oflag)) {
- if (BM_vert_edge_count(v) > 2) {
+ if (BM_vert_is_edge_pair(v) == false) {
+ BMIter liter;
BMLoop *l;
BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
if (l->f->len > 3) {
@@ -103,8 +111,23 @@ static void bm_face_split(BMesh *bm, const short oflag)
}
}
}
+
+ if (use_edge_delete) {
+ BLI_stack_push(edge_delete_verts, &v);
+ }
+ }
+ }
+ }
+
+ if (use_edge_delete) {
+ while (!BLI_stack_is_empty(edge_delete_verts)) {
+ /* remove surrounding edges & faces */
+ BLI_stack_pop(edge_delete_verts, &v);
+ while (v->e) {
+ BM_edge_kill(bm, v->e);
}
}
+ BLI_stack_free(edge_delete_verts);
}
}
@@ -129,7 +152,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
BMVert *v;
BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
- BMO_elem_flag_set(bm, v, VERT_MARK, (BM_vert_edge_count(v) != 2));
+ BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
}
}
@@ -211,12 +234,12 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op)
if (use_verts) {
BMIter viter;
- BMVert *v;
+ BMVert *v, *v_next;
- BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) {
if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
- if (BM_vert_edge_count(v) == 2) {
- BM_vert_collapse_edge(bm, v->e, v, true);
+ if (BM_vert_is_edge_pair(v)) {
+ BM_vert_collapse_edge(bm, v->e, v, true, true);
}
}
}
@@ -267,12 +290,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
}
}
- bm_face_split(bm, VERT_TAG);
+ bm_face_split(bm, VERT_TAG, false);
}
if (use_verts) {
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- BMO_elem_flag_set(bm, v, VERT_MARK, (BM_vert_edge_count(v) != 2));
+ BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v));
}
}
@@ -327,134 +350,124 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op)
if (use_verts) {
BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
- if (BM_vert_edge_count(v) == 2) {
- BM_vert_collapse_edge(bm, v->e, v, true);
+ if (BM_vert_is_edge_pair(v)) {
+ BM_vert_collapse_edge(bm, v->e, v, true, true);
}
}
}
}
}
-static bool test_extra_verts(BMesh *bm, BMVert *v)
+void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
{
- BMIter fiter, liter, eiter, fiter_sub;
- BMFace *f;
- BMLoop *l;
- BMEdge *e;
+ BMOIter oiter;
+ BMIter iter;
+ BMVert *v, *v_next;
+ BMEdge *e, *e_next;
+ BMFace *act_face = bm->act_face;
+
+ const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split");
+ const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear");
+
+ BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
+ BMO_elem_flag_enable(bm, v, VERT_MARK | VERT_ISGC);
+ }
+
+ if (use_face_split) {
+ bm_face_split(bm, VERT_MARK, false);
+ }
- /* test faces around verts for verts that would be wrongly killed
- * by dissolve faces. */
- BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) {
- /* if an edge around a vert is a boundary edge,
- * then dissolve faces won't destroy it.
- * also if it forms a boundary with one
- * of the face region */
- bool found = false;
- BM_ITER_ELEM (e, &eiter, l->v, BM_EDGES_OF_VERT) {
- BMFace *f_iter;
+ if (use_boundary_tear) {
+ BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
+ if (!BM_vert_is_edge_pair(v)) {
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
if (BM_edge_is_boundary(e)) {
- found = true;
- }
- else {
- BM_ITER_ELEM (f_iter, &fiter_sub, e, BM_FACES_OF_EDGE) {
- if (!BMO_elem_flag_test(bm, f_iter, FACE_MARK)) {
- found = true;
- break;
- }
- }
- }
- if (found == true) {
+ BMO_elem_flag_enable(bm, v, VERT_MARK_TEAR);
break;
}
}
- if (found == false) {
- return false;
- }
}
}
+
+ bm_face_split(bm, VERT_MARK_TEAR, true);
}
- return true;
-}
-void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op)
-{
- BMIter iter, fiter;
- BMVert *v, *v_next;
- BMFace *f;
+ BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
+ BMIter itersub;
+ BMLoop *l_first;
+ BMEdge *e_first = NULL;
+ BM_ITER_ELEM (l_first, &itersub, v, BM_LOOPS_OF_VERT) {
+ BMLoop *l_iter;
+ l_iter = l_first;
+ do {
+ BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC);
+ BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC);
+ } while ((l_iter = l_iter->next) != l_first);
- const bool use_face_split = BMO_slot_bool_get(op->slots_in, "use_face_split");
+ e_first = l_first->e;
+ }
+ /* important e_first won't be deleted */
+ if (e_first) {
+ e = e_first;
+ do {
+ e_next = BM_DISK_EDGE_NEXT(e, v);
+ if (BM_edge_is_wire(e)) {
+ BM_edge_kill(bm, e);
+ }
+ } while ((e = e_next) != e_first);
+ }
+ }
- BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts", BM_VERT, VERT_MARK);
-
- if (use_face_split) {
- bm_face_split(bm, VERT_MARK);
+ BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
+ /* tag here so we avoid feedback loop (checking topology as we edit) */
+ if (BM_vert_is_edge_pair(v)) {
+ BMO_elem_flag_enable(bm, v, VERT_MARK_PAIR);
+ }
}
- BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
- /* check if it's a two-valence ver */
- if (BM_vert_edge_count(v) == 2) {
-
- /* collapse the ver */
- /* previously the faces were joined, but collapsing between 2 edges
- * gives some advantage/difference in using vertex-dissolve over edge-dissolve */
-#if 0
- BM_vert_collapse_faces(bm, v->e, v, 1.0f, true, true);
-#else
- BM_vert_collapse_edge(bm, v->e, v, true);
-#endif
-
- continue;
- }
+ BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
+ BMIter itersub;
- BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- BMO_elem_flag_enable(bm, f, FACE_MARK | FACE_ORIG);
- }
-
- /* check if our additions to the input to face dissolve
- * will destroy nonmarked vertices. */
- if (!test_extra_verts(bm, v)) {
- BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- if (BMO_elem_flag_test(bm, f, FACE_ORIG)) {
- BMO_elem_flag_disable(bm, f, FACE_MARK | FACE_ORIG);
+ if (!BMO_elem_flag_test(bm, v, VERT_MARK_PAIR)) {
+ BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) {
+ BMFace *fa, *fb;
+ if (BM_edge_face_pair(e, &fa, &fb)) {
+ BMFace *f_new;
+
+ /* join faces */
+ f_new = BM_faces_join_pair(bm, fa, fb, e, false);
+
+ /* maintain active face */
+ if (act_face && bm->act_face == NULL) {
+ bm->act_face = f_new;
}
}
}
- else {
- BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
- BMO_elem_flag_disable(bm, f, FACE_ORIG);
- }
- }
}
}
- BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_MARK);
- if (BMO_error_occurred(bm)) {
- const char *msg;
-
- BMO_error_get(bm, &msg, NULL);
- BMO_error_clear(bm);
- BMO_error_raise(bm, op, BMERR_DISSOLVEVERTS_FAILED, msg);
+ /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on)
+ * so do this in a separate pass instead. */
+ BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) {
+ if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) {
+ BM_edge_kill(bm, e);
+ }
}
-
- /* clean up any remaining */
- /* note: don't use BM_ITER_MESH_MUTABLE here, even though vertices are removed (T37559) */
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BMO_elem_flag_test(bm, v, VERT_MARK)) {
- if (!BM_vert_dissolve(bm, v)) {
- BMO_error_raise(bm, op, BMERR_DISSOLVEVERTS_FAILED, NULL);
- return;
- }
-#ifdef DEBUG
- /* workaround debug assert */
- iter.count = bm->totvert;
-#endif
+
+ /* final cleanup */
+ BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) {
+ if (BM_vert_is_edge_pair(v)) {
+ BM_vert_collapse_edge(bm, v->e, v, false, true);
}
}
+ BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) {
+ if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) {
+ BM_vert_kill(bm, v);
+ }
+ }
+ /* done with cleanup */
}
/* Limited Dissolve */
diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c
index 794c688b26b..cd5592f08c9 100644
--- a/source/blender/bmesh/operators/bmo_dupe.c
+++ b/source/blender/bmesh/operators/bmo_dupe.c
@@ -183,6 +183,7 @@ static BMFace *bmo_face_copy(BMOperator *op,
*/
static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
{
+ const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
BMVert *v = NULL, *v2;
BMEdge *e = NULL;
@@ -285,6 +286,16 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src)
/* free pointer hashes */
BLI_ghash_free(vhash, NULL, NULL);
BLI_ghash_free(ehash, NULL, NULL);
+
+ if (use_select_history) {
+ BLI_assert(bm_src == bm_dst);
+ BMO_mesh_selected_remap(
+ bm_dst,
+ slot_vert_map_out,
+ slot_edge_map_out,
+ slot_face_map_out,
+ false);
+ }
}
/**
diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c
index 0c5de590ccf..4423123f65e 100644
--- a/source/blender/bmesh/operators/bmo_edgenet.c
+++ b/source/blender/bmesh/operators/bmo_edgenet.c
@@ -179,11 +179,11 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op)
if (!count) {
edges1 = edges;
- BLI_array_length_set(edges1, BLI_array_count(edges));
+ BLI_array_count_set(edges1, BLI_array_count(edges));
}
else {
edges2 = edges;
- BLI_array_length_set(edges2, BLI_array_count(edges));
+ BLI_array_count_set(edges2, BLI_array_count(edges));
}
BLI_array_empty(edges);
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index f924d478f1a..88b53b63abb 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -53,9 +53,16 @@ enum {
void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op)
{
+ const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
+ GHash *select_history_map = NULL;
+
BMOIter siter;
BMFace *f_org;
+ if (use_select_history) {
+ select_history_map = BM_select_history_map_create(bm);
+ }
+
BMO_ITER (f_org, &siter, op->slots_in, "faces", BM_FACE) {
BMFace *f_new;
BMLoop *l_org, *l_org_first;
@@ -66,6 +73,14 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op)
f_new = BM_face_copy(bm, bm, f_org, true, true);
BMO_elem_flag_enable(bm, f_new, EXT_KEEP);
+ if (select_history_map) {
+ BMEditSelection *ese;
+ ese = BLI_ghash_lookup(select_history_map, f_org);
+ if (ese) {
+ ese->ele = (BMElem *)f_new;
+ }
+ }
+
l_org = l_org_first = BM_FACE_FIRST_LOOP(f_org);
l_new = BM_FACE_FIRST_LOOP(f_new);
@@ -85,10 +100,28 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op)
BM_elem_attrs_copy(bm, bm, l_org->next, l_side_iter); l_side_iter = l_side_iter->next;
BM_elem_attrs_copy(bm, bm, l_org, l_side_iter); l_side_iter = l_side_iter->next;
BM_elem_attrs_copy(bm, bm, l_org, l_side_iter);
+
+ if (select_history_map) {
+ BMEditSelection *ese;
+
+ ese = BLI_ghash_lookup(select_history_map, l_org->v);
+ if (ese) {
+ ese->ele = (BMElem *)l_new->v;
+ }
+ ese = BLI_ghash_lookup(select_history_map, l_org->e);
+ if (ese) {
+ ese->ele = (BMElem *)l_new->e;
+ }
+ }
+
} while (((l_new = l_new->next),
(l_org = l_org->next)) != l_org_first);
}
+ if (select_history_map) {
+ BLI_ghash_free(select_history_map, NULL, NULL);
+ }
+
BMO_op_callf(bm, op->flag,
"delete geom=%ff context=%i",
EXT_DEL, DEL_ONLYFACES);
@@ -157,7 +190,11 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op)
BMO_elem_flag_enable(bm, e->v2, EXT_INPUT);
}
- BMO_op_initf(bm, &dupeop, op->flag, "duplicate geom=%fve", EXT_INPUT);
+ BMO_op_initf(
+ bm, &dupeop, op->flag,
+ "duplicate geom=%fve use_select_history=%b",
+ EXT_INPUT, BMO_slot_bool_get(op->slots_in, "use_select_history"));
+
BMO_op_exec(bm, &dupeop);
/* disable root flag on all new skin nodes */
@@ -205,20 +242,45 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op)
void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op)
{
+ const bool use_select_history = BMO_slot_bool_get(op->slots_in, "use_select_history");
BMOIter siter;
BMVert *v, *dupev;
BMEdge *e;
const bool has_vskin = CustomData_has_layer(&bm->vdata, CD_MVERT_SKIN);
+ GHash *select_history_map = NULL;
+
+ if (use_select_history) {
+ select_history_map = BM_select_history_map_create(bm);
+ }
for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) {
dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP);
+ BMO_elem_flag_enable(bm, dupev, EXT_KEEP);
+
if (has_vskin)
bm_extrude_disable_skin_root(bm, v);
- e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP);
+ if (select_history_map) {
+ BMEditSelection *ese;
+ ese = BLI_ghash_lookup(select_history_map, v);
+ if (ese) {
+ ese->ele = (BMElem *)dupev;
+ }
+ }
+ /* not essential, but ensures face normals from extruded edges are contiguous */
+ if (BM_vert_is_wire_endpoint(v)) {
+ if (v->e->v1 == v) {
+ SWAP(BMVert *, v, dupev);
+ }
+ }
+
+ e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, e, EXT_KEEP);
- BMO_elem_flag_enable(bm, dupev, EXT_KEEP);
+ }
+
+ if (select_history_map) {
+ BLI_ghash_free(select_history_map, NULL, NULL);
}
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, EXT_KEEP);
@@ -238,8 +300,11 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
BMOpSlot *slot_edges_exclude;
/* initialize our sub-operators */
- BMO_op_init(bm, &dupeop, op->flag, "duplicate");
-
+ BMO_op_initf(
+ bm, &dupeop, op->flag,
+ "duplicate use_select_history=%b",
+ BMO_slot_bool_get(op->slots_in, "use_select_history"));
+
BMO_slot_buffer_flag_enable(bm, op->slots_in, "geom", BM_EDGE | BM_FACE, EXT_INPUT);
/* if one flagged face is bordered by an un-flagged face, then we delete
@@ -408,7 +473,15 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op)
/* link isolated vert */
for (v = BMO_iter_new(&siter, dupeop.slots_out, "isovert_map.out", 0); v; v = BMO_iter_step(&siter)) {
BMVert *v2 = BMO_iter_map_value_ptr(&siter);
- BM_edge_create(bm, v, v2, v->e, BM_CREATE_NO_DOUBLE);
+
+ /* not essential, but ensures face normals from extruded edges are contiguous */
+ if (BM_vert_is_wire_endpoint(v)) {
+ if (v->e->v1 == v) {
+ SWAP(BMVert *, v, v2);
+ }
+ }
+
+ BM_edge_create(bm, v, v2, NULL, BM_CREATE_NO_DOUBLE);
}
/* cleanup */
diff --git a/source/blender/bmesh/operators/bmo_fill_attribute.c b/source/blender/bmesh/operators/bmo_fill_attribute.c
index fa77e6b509c..d9f50ac891c 100644
--- a/source/blender/bmesh/operators/bmo_fill_attribute.c
+++ b/source/blender/bmesh/operators/bmo_fill_attribute.c
@@ -154,7 +154,7 @@ static unsigned int bmesh_face_attribute_fill(BMesh *bm,
return face_tot;
}
-void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op)
+void bmo_face_attribute_fill_exec(BMesh *bm, BMOperator *op)
{
const bool use_normals = BMO_slot_bool_get(op->slots_in, "use_normals");
const bool use_data = BMO_slot_bool_get(op->slots_in, "use_data");
diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c
index 6a0fca425f8..40f6937245b 100644
--- a/source/blender/bmesh/operators/bmo_fill_grid.c
+++ b/source/blender/bmesh/operators/bmo_fill_grid.c
@@ -313,12 +313,12 @@ static void bm_grid_fill_array(BMesh *bm, BMVert **v_grid, const unsigned int xt
if (use_interp_simple == false) {
float co_a[3], co_b[3];
- barycentric_transform(
+ transform_point_by_tri_v3(
co_a,
v_grid[x]->co,
tri_t[0], tri_t[1], tri_t[2],
tri_a[0], tri_a[1], tri_a[2]);
- barycentric_transform(
+ transform_point_by_tri_v3(
co_b,
v_grid[(xtot * ytot) + (x - xtot)]->co,
tri_t[0], tri_t[1], tri_t[2],
diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c
index cb4255d337e..b7914e84c50 100644
--- a/source/blender/bmesh/operators/bmo_inset.c
+++ b/source/blender/bmesh/operators/bmo_inset.c
@@ -39,6 +39,9 @@
#include "intern/bmesh_operators_private.h" /* own include */
+/* Merge loop-data that diverges, see: T41445 */
+#define USE_LOOP_CUSTOMDATA_MERGE
+
#define ELE_NEW 1
@@ -90,8 +93,9 @@ static void bm_interp_face_store(InterpFace *iface, BMesh *bm, BMFace *f, MemAre
CustomData_bmesh_copy_data(&bm->vdata, &bm->vdata, l_iter->v->head.data, &blocks_v[i]);
/* use later for index lookups */
- BM_elem_index_set(l_iter, i); /* set_ok */
+ BM_elem_index_set(l_iter, i); /* set_dirty */
} while (i++, (l_iter = l_iter->next) != l_first);
+ bm->elem_index_dirty |= BM_LOOP;
}
static void bm_interp_face_free(InterpFace *iface, BMesh *bm)
{
@@ -105,6 +109,156 @@ static void bm_interp_face_free(InterpFace *iface, BMesh *bm)
}
}
+#ifdef USE_LOOP_CUSTOMDATA_MERGE
+/**
+ * This function merges loop customdata (UV's)
+ * where interpolating the values across the face causes values to diverge.
+ */
+static void bm_loop_customdata_merge(
+ BMesh *bm,
+ BMEdge *e_connect,
+ BMLoop *l_a_outer, BMLoop *l_b_outer,
+ BMLoop *l_a_inner, BMLoop *l_b_inner)
+{
+ /**
+ * Check for diverged values at the vert shared by
+ * \a l_a_inner & \a l_b_inner.
+ *
+ * <pre>
+ * -----------------------+
+ * l_a_outer--> /|<--l_b_outer
+ * / |
+ * (face a) / |
+ * / <--e_connect
+ * / |
+ * e_a l_a_inner--> / <--l_b_inner
+ * -----------------+ |
+ * /| |
+ * l_a/b_inner_inset| (face b)
+ * / | |
+ * / |e_b |
+ * (inset face(s)) | |
+ * / | |
+ * </pre>
+ */
+
+ const bool is_flip = (l_a_inner->next == l_a_outer);
+ BMLoop *l_a_inner_inset, *l_b_inner_inset;
+ BMEdge *e_a, *e_b;
+ int layer_n;
+
+ /* paranoid sanity checks */
+ BLI_assert(l_a_outer->v == l_b_outer->v);
+ BLI_assert(l_a_inner->v == l_b_inner->v);
+
+ BLI_assert(l_b_inner->f != l_a_inner->f);
+
+ BLI_assert(l_a_outer->f == l_a_inner->f);
+ BLI_assert(l_b_outer->f == l_b_inner->f);
+
+ (void) e_connect;
+ BLI_assert(BM_edge_in_face(e_connect, l_a_inner->f));
+ BLI_assert(BM_edge_in_face(e_connect, l_b_inner->f));
+
+ if (is_flip) {
+ e_a = l_a_inner->prev->e;
+ e_b = l_b_inner->e;
+ }
+ else {
+ e_a = l_a_inner->e;
+ e_b = l_b_inner->prev->e;
+ }
+
+ l_a_inner_inset = BM_edge_other_loop(e_a, l_a_inner);
+ l_b_inner_inset = BM_edge_other_loop(e_b, l_b_inner);
+ BLI_assert(l_a_inner_inset->v == l_b_inner_inset->v);
+
+ /* check if ther is no chance of diversion */
+ if (l_a_inner_inset->f == l_b_inner_inset->f) {
+ return;
+ }
+
+ for (layer_n = 0; layer_n < bm->ldata.totlayer; layer_n++) {
+ const int type = bm->ldata.layers[layer_n].type;
+ const int offset = bm->ldata.layers[layer_n].offset;
+ if (!CustomData_layer_has_math(&bm->ldata, layer_n))
+ continue;
+
+ /* check we begin with merged data */
+ if ((CustomData_data_equals(
+ type,
+ BM_ELEM_CD_GET_VOID_P(l_a_outer, offset),
+ BM_ELEM_CD_GET_VOID_P(l_b_outer, offset)) == true)
+
+ /* epsilon for comparing UV's is too big, gives noticable problems */
+#if 0
+ &&
+ /* check if the data ends up diverged */
+ (CustomData_data_equals(
+ type,
+ BM_ELEM_CD_GET_VOID_P(l_a_inner, offset),
+ BM_ELEM_CD_GET_VOID_P(l_b_inner, offset)) == false)
+#endif
+ )
+ {
+ /* no need to allocate a temp block:
+ * a = (a + b);
+ * a *= 0.5f;
+ * b = a;
+ */
+ const void *data_src;
+
+ CustomData_data_add(
+ type,
+ BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
+ BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset));
+ CustomData_data_multiply(
+ type,
+ BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
+ 0.5f);
+ CustomData_data_copy_value(
+ type,
+ BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset),
+ BM_ELEM_CD_GET_VOID_P(l_b_inner_inset, offset));
+
+ /* use this as a reference (could be 'l_b_inner_inset' too) */
+ data_src = BM_ELEM_CD_GET_VOID_P(l_a_inner_inset, offset);
+
+ /* check if the 2 faces share an edge */
+ if (is_flip ?
+ (l_b_inner_inset->e == l_a_inner_inset->prev->e) :
+ (l_a_inner_inset->e == l_b_inner_inset->prev->e))
+ {
+ /* simple case, we have all loops already */
+ }
+ else {
+ /* compare with (l_a_inner / l_b_inner) and assign the blended value if they match */
+ BMIter iter;
+ BMLoop *l_iter;
+ const void *data_cmp_a = BM_ELEM_CD_GET_VOID_P(l_b_inner, offset);
+ const void *data_cmp_b = BM_ELEM_CD_GET_VOID_P(l_a_inner, offset);
+ BM_ITER_ELEM (l_iter, &iter, l_a_inner_inset->v, BM_LOOPS_OF_VERT) {
+ if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
+ if (!ELEM(l_iter, l_a_inner, l_b_inner, l_a_inner_inset, l_b_inner_inset)) {
+ void *data_dst = BM_ELEM_CD_GET_VOID_P(l_iter, offset);
+
+ if (CustomData_data_equals(type, data_dst, data_cmp_a) ||
+ CustomData_data_equals(type, data_dst, data_cmp_b))
+ {
+ CustomData_data_copy_value(type, data_src, data_dst);
+ }
+ }
+ }
+ }
+ }
+
+ CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_b_inner, offset));
+ CustomData_data_copy_value(type, data_src, BM_ELEM_CD_GET_VOID_P(l_a_inner, offset));
+ }
+ }
+}
+#endif /* USE_LOOP_CUSTOMDATA_MERGE */
+
/* -------------------------------------------------------------------- */
/* Inset Individual */
@@ -388,12 +542,15 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
const bool use_outset = BMO_slot_bool_get(op->slots_in, "use_outset");
const bool use_boundary = BMO_slot_bool_get(op->slots_in, "use_boundary") && (use_outset == false);
const bool use_even_offset = BMO_slot_bool_get(op->slots_in, "use_even_offset");
- const bool use_even_boundry = use_even_offset; /* could make own option */
+ const bool use_even_boundary = use_even_offset; /* could make own option */
const bool use_relative_offset = BMO_slot_bool_get(op->slots_in, "use_relative_offset");
const bool use_edge_rail = BMO_slot_bool_get(op->slots_in, "use_edge_rail");
const bool use_interpolate = BMO_slot_bool_get(op->slots_in, "use_interpolate");
const float thickness = BMO_slot_float_get(op->slots_in, "thickness");
const float depth = BMO_slot_float_get(op->slots_in, "depth");
+#ifdef USE_LOOP_CUSTOMDATA_MERGE
+ const bool has_math_ldata = (use_interpolate && CustomData_has_math(&bm->ldata));
+#endif
int edge_info_len = 0;
@@ -431,6 +588,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
else {
BM_mesh_elem_hflag_enable_all(bm, BM_FACE, BM_ELEM_TAG, false);
BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces", BM_FACE, BM_ELEM_TAG, false);
+ BMO_slot_buffer_hflag_disable(bm, op->slots_in, "faces_exclude", BM_FACE, BM_ELEM_TAG, false);
}
/* first count all inset edges we will split */
@@ -715,7 +873,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
else if (vert_edge_tag_tot == 1) { /* 1 edge user - boundary vert, not so common */
const float *e_no_a = edge_info[vecpair[0]].no;
- if (use_even_boundry) {
+ if (use_even_boundary) {
/* This case where only one edge attached to v_split
* is used - ei - the face to inset is on a boundary.
@@ -902,10 +1060,34 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
BM_elem_attrs_copy(bm, bm, l_a_other, l_a);
BM_elem_attrs_copy(bm, bm, l_b_other, l_b);
+ BLI_assert(l_a->f != l_a_other->f);
+ BLI_assert(l_b->f != l_b_other->f);
+
/* step around to the opposite side of the quad - warning, this may have no other edges! */
l_a = l_a->next->next;
l_b = l_a->next;
+ /**
+ * Loops vars from newly created face (face_a/b)
+ * <pre>
+ * l_a->e & l_b->prev->e
+ * +------------------------------------+
+ * |\ l_a l_b /|
+ * | \ l_a->prev->e l_b->e / |
+ * | \ l_a->prev l_b->next / |
+ * | +----------------------------+ |
+ * | |l_a_other ^ l_b_other| |
+ * | | l_b->next->e &... | |
+ * | | l_a->prev->prev->e | |
+ * | | (inset face) | |
+ * | +----------------------------+ |
+ * | / \ |
+ * | / \ |
+ * |/ \|
+ * +------------------------------------+
+ * </pre>
+ */
+
/* swap a<->b intentionally */
if (use_interpolate) {
InterpFace *iface = iface_array[BM_elem_index_get(es->l->f)];
@@ -913,6 +1095,31 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
const int i_b = BM_elem_index_get(l_b_other);
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_a], &l_b->head.data);
CustomData_bmesh_copy_data(&bm->ldata, &bm->ldata, iface->blocks_l[i_b], &l_a->head.data);
+
+#ifdef USE_LOOP_CUSTOMDATA_MERGE
+ if (has_math_ldata) {
+ BMEdge *e_connect;
+
+ /* connecting edge 'a' */
+ e_connect = l_a->prev->e;
+ if (BM_edge_is_manifold(e_connect)) {
+ bm_loop_customdata_merge(
+ bm, e_connect,
+ l_a, BM_edge_other_loop(e_connect, l_a),
+ l_a->prev, BM_edge_other_loop(e_connect, l_a->prev));
+ }
+
+ /* connecting edge 'b' */
+ e_connect = l_b->e;
+ if (BM_edge_is_manifold(e_connect)) {
+ /* swap arg order to maintain winding */
+ bm_loop_customdata_merge(
+ bm, e_connect,
+ l_b, BM_edge_other_loop(e_connect, l_b),
+ l_b->next, BM_edge_other_loop(e_connect, l_b->next));
+ }
+ }
+#endif /* USE_LOOP_CUSTOMDATA_MERGE */
}
else {
BM_elem_attrs_copy(bm, bm, l_a_other, l_b);
@@ -983,7 +1190,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op)
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
const float fac = (depth *
(use_relative_offset ? bm_edge_info_average_length(v, edge_info) : 1.0f) *
- (use_even_boundry ? BM_vert_calc_shell_factor(v) : 1.0f));
+ (use_even_boundary ? BM_vert_calc_shell_factor(v) : 1.0f));
madd_v3_v3v3fl(varr_co[i], v->co, v->no, fac);
}
}
diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c
index 0856beeeb12..d0f08871400 100644
--- a/source/blender/bmesh/operators/bmo_normals.c
+++ b/source/blender/bmesh/operators/bmo_normals.c
@@ -81,6 +81,8 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f
}
f_len_best_sq = -FLT_MAX;
+ /* used in degenerate cases only */
+ f_start_index = 0;
for (i = 0; i < faces_len; i++) {
float f_len_test_sq;
diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c
index 26f20656478..363e395e082 100644
--- a/source/blender/bmesh/operators/bmo_poke.c
+++ b/source/blender/bmesh/operators/bmo_poke.c
@@ -101,7 +101,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op)
do {
BMLoop *l_new;
- f_new = BM_face_create_quad_tri(bm, l_iter->v, l_iter->next->v, v_center, NULL, f, false);
+ f_new = BM_face_create_quad_tri(bm, l_iter->v, l_iter->next->v, v_center, NULL, f, BM_CREATE_NOP);
l_new = BM_FACE_FIRST_LOOP(f_new);
if (i == 0) {
diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c
index f0e31b78ca0..e69dcca6342 100644
--- a/source/blender/bmesh/operators/bmo_primitive.c
+++ b/source/blender/bmesh/operators/bmo_primitive.c
@@ -405,7 +405,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op)
v2 = eva[icoface[a][1]];
v3 = eva[icoface[a][2]];
- eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, false);
+ eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP);
BM_ITER_ELEM (l, &liter, eftemp, BM_LOOPS_OF_FACE) {
BMO_elem_flag_enable(bm, l->e, EDGE_MARK);
@@ -476,14 +476,14 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op)
tv[monkeyf[i][1] + i - monkeyo],
tv[monkeyf[i][2] + i - monkeyo],
(monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeyf[i][3] + i - monkeyo] : NULL,
- NULL, false);
+ NULL, BM_CREATE_NOP);
BM_face_create_quad_tri(bm,
tv[monkeynv + monkeyf[i][2] + i - monkeyo],
tv[monkeynv + monkeyf[i][1] + i - monkeyo],
tv[monkeynv + monkeyf[i][0] + i - monkeyo],
(monkeyf[i][3] != monkeyf[i][2]) ? tv[monkeynv + monkeyf[i][3] + i - monkeyo] : NULL,
- NULL, false);
+ NULL, BM_CREATE_NOP);
}
MEM_freeN(tv);
@@ -535,7 +535,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
if (a && cap_ends) {
BMFace *f;
- f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, false);
+ f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, f, FACE_NEW);
}
@@ -553,7 +553,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op)
if (cap_ends) {
BMFace *f;
- f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false);
+ f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, f, FACE_NEW);
}
@@ -622,12 +622,12 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
if (cap_ends) {
BMFace *f;
- f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, false);
+ f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, f, FACE_NEW);
- f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, false);
+ f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, f, FACE_NEW);
}
- BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, false);
+ BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP);
}
else {
firstv1 = v1;
@@ -644,9 +644,9 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
if (cap_ends) {
BMFace *f;
- f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, false);
+ f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, f, FACE_NEW);
- f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, false);
+ f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP);
BMO_elem_flag_enable(bm, f, FACE_NEW);
}
@@ -654,7 +654,7 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op)
BMO_op_callf(bm, op->flag, "dissolve_faces faces=%ff", FACE_NEW);
}
- BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, false);
+ BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP);
BMO_op_callf(bm, op->flag, "remove_doubles verts=%fv dist=%f", VERT_MARK, 0.000001);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
@@ -726,14 +726,14 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op)
BMO_elem_flag_enable(bm, v8, VERT_MARK);
/* the four sides */
- BM_face_create_quad_tri(bm, v5, v6, v2, v1, NULL, false);
- BM_face_create_quad_tri(bm, v6, v7, v3, v2, NULL, false);
- BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, false);
- BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, false);
+ BM_face_create_quad_tri(bm, v5, v6, v2, v1, NULL, BM_CREATE_NOP);
+ BM_face_create_quad_tri(bm, v6, v7, v3, v2, NULL, BM_CREATE_NOP);
+ BM_face_create_quad_tri(bm, v7, v8, v4, v3, NULL, BM_CREATE_NOP);
+ BM_face_create_quad_tri(bm, v8, v5, v1, v4, NULL, BM_CREATE_NOP);
/* top/bottom */
- BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, false);
- BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, false);
+ BM_face_create_quad_tri(bm, v1, v2, v3, v4, NULL, BM_CREATE_NOP);
+ BM_face_create_quad_tri(bm, v8, v7, v6, v5, NULL, BM_CREATE_NOP);
BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "verts.out", BM_VERT, VERT_MARK);
}
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 216d3410de8..75f9feef413 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -31,6 +31,7 @@
#include "BLI_math.h"
#include "BLI_array.h"
#include "BLI_alloca.h"
+#include "BLI_stackdefines.h"
#include "BKE_customdata.h"
@@ -91,8 +92,8 @@ static void remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_targetmap
STACK_DECLARE(edges);
STACK_DECLARE(loops);
- STACK_INIT(edges);
- STACK_INIT(loops);
+ STACK_INIT(edges, f->len);
+ STACK_INIT(loops, f->len);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
BMVert *v1 = l->v;
@@ -151,9 +152,6 @@ static void remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_targetmap
}
}
}
-
- STACK_FREE(edges);
- STACK_FREE(loops);
}
/**
@@ -389,7 +387,7 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, EDGE_MARK);
- BMW_init(&walker, bm, BMW_SHELL,
+ BMW_init(&walker, bm, BMW_VERT_SHELL,
BMW_MASK_NOP, EDGE_MARK, BMW_MASK_NOP,
BMW_FLAG_NOP, /* no need to use BMW_FLAG_TEST_HIDDEN, already marked data */
BMW_NIL_LAY);
@@ -530,7 +528,8 @@ static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op,
int i, j, keepvert = 0;
const float dist = BMO_slot_float_get(op->slots_in, "dist");
- const float dist3 = dist * 3.0f;
+ const float dist_sq = dist * dist;
+ const float dist3 = (M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
/* Test whether keep_verts arg exists and is non-empty */
if (BMO_slot_exists(op->slots_in, "keep_verts")) {
@@ -578,7 +577,7 @@ static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op,
continue;
}
- if (compare_len_v3v3(v_check->co, v_other->co, dist)) {
+ if (compare_len_squared_v3v3(v_check->co, v_other->co, dist_sq)) {
/* If one vert is marked as keep, make sure it will be the target */
if (BMO_elem_flag_test(bm, v_other, VERT_KEEP)) {
diff --git a/source/blender/bmesh/operators/bmo_smooth_laplacian.c b/source/blender/bmesh/operators/bmo_smooth_laplacian.c
index af5f35f2a75..a250c716c16 100644
--- a/source/blender/bmesh/operators/bmo_smooth_laplacian.c
+++ b/source/blender/bmesh/operators/bmo_smooth_laplacian.c
@@ -156,7 +156,7 @@ static LaplacianSystem *init_laplacian_system(int a_numEdges, int a_numFaces, in
return sys;
}
-/* Compute weigth between vertice v_i and all your neighbors
+/* Compute weight between vertice v_i and all your neighbors
* weight between v_i and v_neighbor
* Wij = cot(alpha) + cot(beta) / (4.0 * total area of all faces * sum all weight)
* v_i *
diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c
index e0c86564db4..0d9ce4b2731 100644
--- a/source/blender/bmesh/operators/bmo_subdivide.c
+++ b/source/blender/bmesh/operators/bmo_subdivide.c
@@ -32,6 +32,7 @@
#include "BLI_rand.h"
#include "BLI_array.h"
#include "BLI_noise.h"
+#include "BLI_stack.h"
#include "BKE_customdata.h"
@@ -140,13 +141,19 @@ static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace
/* this isn't the best thing in the world. it doesn't handle cases where there's
* multiple faces yet. that might require a convexity test to figure out which
- * face is "best" and who knows what for non-manifold conditions. */
- f = BM_vert_pair_share_face(v_a, v_b, &l_a, &l_b);
+ * face is "best" and who knows what for non-manifold conditions.
+ *
+ * note: we allow adjacent here, since theres no chance this happens.
+ */
+ f = BM_vert_pair_share_face_by_len(v_a, v_b, &l_a, &l_b, true);
+
if (f) {
BMFace *f_new;
BMLoop *l_new;
+ BLI_assert(!BM_loop_is_adjacent(l_a, l_b));
+
f_new = BM_face_split(bm, f, l_a, l_b, &l_new, NULL, false);
if (r_f_new) *r_f_new = f_new;
@@ -159,14 +166,11 @@ static BMEdge *connect_smallest_face(BMesh *bm, BMVert *v_a, BMVert *v_b, BMFace
static void alter_co(BMVert *v, BMEdge *UNUSED(origed), const SubDParams *params, float perc,
BMVert *vsta, BMVert *vend)
{
- float tvec[3], prev_co[3], fac;
+ float tvec[3], fac;
float *co = BM_ELEM_CD_GET_VOID_P(v, params->shape_info.cd_vert_shape_offset_tmp);
int i;
-
- BM_vert_normal_update_all(v);
copy_v3_v3(co, v->co);
- copy_v3_v3(prev_co, co);
if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */
normalize_v3(co);
@@ -230,7 +234,7 @@ 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, prev_co, co);
+ sub_v3_v3v3(tvec, v->co, co);
if (params->shape_info.totlayer > 1) {
/* skip the last layer since its the temp */
@@ -749,7 +753,7 @@ static const SubDPattern *patterns[] = {
NULL,
};
-#define PATTERNS_TOT (sizeof(patterns) / sizeof(void *))
+#define PATTERNS_TOT ARRAY_SIZE(patterns)
typedef struct SubDFaceData {
BMVert *start;
@@ -763,8 +767,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
BMOpSlot *einput;
const SubDPattern *pat;
SubDParams params;
- SubDFaceData *facedata = NULL;
- BLI_array_declare(facedata);
+ BLI_Stack *facedata;
BMIter viter, fiter, liter;
BMVert *v, **verts = NULL;
BMEdge *edge;
@@ -779,7 +782,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
BLI_array_declare(verts);
float smooth, fractal, along_normal;
bool use_sphere, use_single_edge, use_grid_fill, use_only_quads;
- int cornertype, seed, i, j, matched, a, b, numcuts, totesel, smooth_falloff;
+ int cornertype, seed, i, j, a, b, numcuts, totesel, smooth_falloff;
BMO_slot_buffer_flag_enable(bm, op->slots_in, "edges", BM_EDGE, SUBD_SPLIT);
@@ -872,9 +875,12 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
BM_EDGE, EDGE_PERCENT);
+ facedata = BLI_stack_new(sizeof(SubDFaceData), __func__);
+
BM_ITER_MESH (face, &fiter, bm, BM_FACES_OF_MESH) {
BMEdge *e1 = NULL, *e2 = NULL;
float vec1[3], vec2[3];
+ bool matched = false;
/* skip non-quads if requested */
if (use_only_quads && face->len != 4)
@@ -888,8 +894,6 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
BLI_array_grow_items(edges, face->len);
BLI_array_grow_items(verts, face->len);
- matched = 0;
-
totesel = 0;
BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, i) {
edges[i] = l_new->e;
@@ -927,12 +931,13 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
}
}
if (matched) {
- BLI_array_grow_one(facedata);
- b = BLI_array_count(facedata) - 1;
- facedata[b].pat = pat;
- facedata[b].start = verts[i];
- facedata[b].face = face;
- facedata[b].totedgesel = totesel;
+ SubDFaceData *fd;
+
+ fd = BLI_stack_push_r(facedata);
+ fd->pat = pat;
+ fd->start = verts[i];
+ fd->face = face;
+ fd->totedgesel = totesel;
BMO_elem_flag_enable(bm, face, SUBD_SPLIT);
break;
}
@@ -963,15 +968,15 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
}
}
if (matched) {
- BLI_array_grow_one(facedata);
- j = BLI_array_count(facedata) - 1;
+ SubDFaceData *fd;
BMO_elem_flag_enable(bm, face, SUBD_SPLIT);
- facedata[j].pat = pat;
- facedata[j].start = verts[a];
- facedata[j].face = face;
- facedata[j].totedgesel = totesel;
+ fd = BLI_stack_push_r(facedata);
+ fd->pat = pat;
+ fd->start = verts[a];
+ fd->face = face;
+ fd->totedgesel = totesel;
break;
}
}
@@ -979,16 +984,16 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
}
if (!matched && totesel) {
- BLI_array_grow_one(facedata);
- j = BLI_array_count(facedata) - 1;
+ SubDFaceData *fd;
BMO_elem_flag_enable(bm, face, SUBD_SPLIT);
/* must initialize all members here */
- facedata[j].start = NULL;
- facedata[j].pat = NULL;
- facedata[j].totedgesel = totesel;
- facedata[j].face = face;
+ fd = BLI_stack_push_r(facedata);
+ fd->start = NULL;
+ fd->pat = NULL;
+ fd->totedgesel = totesel;
+ fd->face = face;
}
}
@@ -1006,16 +1011,17 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
copy_v3_v3(v->co, co);
}
- i = 0;
- for (i = 0; i < BLI_array_count(facedata); i++) {
- face = facedata[i].face;
+ for (; !BLI_stack_is_empty(facedata); BLI_stack_discard(facedata)) {
+ SubDFaceData *fd = BLI_stack_peek(facedata);
+
+ face = fd->face;
/* figure out which pattern to use */
BLI_array_empty(verts);
- pat = facedata[i].pat;
+ pat = fd->pat;
- if (!pat && facedata[i].totedgesel == 2) {
+ if (!pat && fd->totedgesel == 2) {
int vlen;
/* ok, no pattern. we still may be able to do something */
@@ -1107,7 +1113,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
* - concave corner of an ngon.
* - 2 edges being used in 2+ ngons.
*/
-// BM_face_legal_splits(face, loops_split, BLI_array_count(loops_split));
+// BM_face_splits_check_legal(bm, face, loops_split, BLI_array_count(loops_split));
for (j = 0; j < BLI_array_count(loops_split); j++) {
if (loops_split[j][0]) {
@@ -1128,7 +1134,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
a = 0;
BM_ITER_ELEM_INDEX (l_new, &liter, face, BM_LOOPS_OF_FACE, j) {
- if (l_new->v == facedata[i].start) {
+ if (l_new->v == fd->start) {
a = j + 1;
break;
}
@@ -1153,7 +1159,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op)
BM_data_layer_free_n(bm, &bm->vdata, CD_SHAPEKEY, params.shape_info.tmpkey);
- if (facedata) BLI_array_free(facedata);
+ BLI_stack_free(facedata);
if (edges) BLI_array_free(edges);
if (verts) BLI_array_free(verts);
BLI_array_free(loops_split);
diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
index 182bf0518ef..c01ad10d716 100644
--- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c
+++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c
@@ -40,6 +40,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_stackdefines.h"
#include "BLI_alloca.h"
#include "BLI_math.h"
#include "BLI_listbase.h"
@@ -726,8 +727,8 @@ static void bm_edgering_pair_interpolate(BMesh *bm, LoopPairStore *lpair,
tri_tmp = tri_array[i];
- barycentric_transform(co_a, v_a->co, UNPACK3(tri_tmp), UNPACK3(tri_sta));
- barycentric_transform(co_b, v_b->co, UNPACK3(tri_tmp), UNPACK3(tri_end));
+ transform_point_by_tri_v3(co_a, v_a->co, UNPACK3(tri_tmp), UNPACK3(tri_sta));
+ transform_point_by_tri_v3(co_b, v_b->co, UNPACK3(tri_tmp), UNPACK3(tri_end));
interp_v3_v3v3(((BMVert *)v_iter->data)->co, co_a, co_b, (float)i / (float)(resolu - 1));
}
@@ -919,13 +920,13 @@ static void bm_edgering_pair_order(BMesh *bm,
}
BLI_assert(node != NULL);
- BLI_rotatelist_first(lb_b, node);
+ BLI_listbase_rotate_first(lb_b, node);
/* now check we are winding the same way */
if (bm_edgering_pair_order_is_flipped(bm, el_store_a, el_store_b)) {
BM_edgeloop_flip(bm, el_store_b);
/* re-ensure the first node */
- BLI_rotatelist_first(lb_b, node);
+ BLI_listbase_rotate_first(lb_b, node);
}
/* sanity checks that we are aligned & winding now */
@@ -969,8 +970,8 @@ static void bm_edgering_pair_subdiv(BMesh *bm,
BMEdge *e;
BMFace *f;
- STACK_INIT(edges_ring_arr);
- STACK_INIT(faces_ring_arr);
+ STACK_INIT(edges_ring_arr, stack_max);
+ STACK_INIT(faces_ring_arr, stack_max);
bm_edgeloop_vert_tag(el_store_a, false);
bm_edgeloop_vert_tag(el_store_b, true);
diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c
index 8e254b2e499..986583cc21b 100644
--- a/source/blender/bmesh/operators/bmo_triangulate.c
+++ b/source/blender/bmesh/operators/bmo_triangulate.c
@@ -26,10 +26,12 @@
* Triangulate faces, also defines triangle fill.
*/
+#include "MEM_guardedalloc.h"
+
#include "DNA_listBase.h"
#include "BLI_math.h"
-#include "BLI_smallhash.h"
+#include "BLI_sort_utils.h"
#include "BLI_scanfill.h"
#include "bmesh.h"
@@ -56,6 +58,10 @@ void bmo_triangulate_exec(BMesh *bm, BMOperator *op)
BMO_slot_buffer_from_enabled_hflag(bm, op, op->slots_out, "faces.out", BM_FACE, BM_ELEM_TAG);
}
+struct SortNormal {
+ float value; /* keep first */
+ float no[3];
+};
void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
{
@@ -65,54 +71,153 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
BMEdge *e;
ScanFillContext sf_ctx;
/* ScanFillEdge *sf_edge; */ /* UNUSED */
- ScanFillVert *sf_vert_1, *sf_vert_2;
ScanFillFace *sf_tri;
- SmallHash hash;
- float normal[3], *normal_pt;
+ GHash *sf_vert_map;
+ float normal[3];
const int scanfill_flag = BLI_SCANFILL_CALC_HOLES | BLI_SCANFILL_CALC_POLYS | BLI_SCANFILL_CALC_LOOSE;
+ bool calc_winding = false;
- BLI_smallhash_init_ex(&hash, BMO_slot_buffer_count(op->slots_in, "edges"));
+ sf_vert_map = BLI_ghash_ptr_new_ex(__func__, BMO_slot_buffer_count(op->slots_in, "edges"));
BMO_slot_vec_get(op->slots_in, "normal", normal);
BLI_scanfill_begin(&sf_ctx);
BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) {
+ ScanFillVert *sf_verts[2];
+ BMVert **e_verts = &e->v1;
+ unsigned int i;
+
BMO_elem_flag_enable(bm, e, EDGE_MARK);
-
- if ((sf_vert_1 = BLI_smallhash_lookup(&hash, (uintptr_t)e->v1)) == NULL) {
- sf_vert_1 = BLI_scanfill_vert_add(&sf_ctx, e->v1->co);
- sf_vert_1->tmp.p = e->v1;
- BLI_smallhash_insert(&hash, (uintptr_t)e->v1, sf_vert_1);
- }
-
- if ((sf_vert_2 = BLI_smallhash_lookup(&hash, (uintptr_t)e->v2)) == NULL) {
- sf_vert_2 = BLI_scanfill_vert_add(&sf_ctx, e->v2->co);
- sf_vert_2->tmp.p = e->v2;
- BLI_smallhash_insert(&hash, (uintptr_t)e->v2, sf_vert_2);
+
+ calc_winding = (calc_winding || BM_edge_is_boundary(e));
+
+ for (i = 0; i < 2; i++) {
+ if ((sf_verts[i] = BLI_ghash_lookup(sf_vert_map, e_verts[i])) == NULL) {
+ sf_verts[i] = BLI_scanfill_vert_add(&sf_ctx, e_verts[i]->co);
+ sf_verts[i]->tmp.p = e_verts[i];
+ BLI_ghash_insert(sf_vert_map, e_verts[i], sf_verts[i]);
+ }
}
-
- /* sf_edge = */ BLI_scanfill_edge_add(&sf_ctx, sf_vert_1, sf_vert_2);
+ /* sf_edge = */ BLI_scanfill_edge_add(&sf_ctx, UNPACK2(sf_verts));
/* sf_edge->tmp.p = e; */ /* UNUSED */
}
+ BLI_ghash_free(sf_vert_map, NULL, NULL);
+
if (is_zero_v3(normal)) {
- normal_pt = NULL;
+ /* calculate the normal from the cross product of vert-edge pairs.
+ * Since we don't know winding, just accumulate */
+ ScanFillVert *sf_vert;
+ struct SortNormal *nors;
+ const unsigned int nors_tot = BLI_ghash_size(sf_vert_map);
+ unsigned int i;
+ bool is_degenerate = true;
+
+ nors = MEM_mallocN(sizeof(*nors) * nors_tot, __func__);
+
+ for (sf_vert = sf_ctx.fillvertbase.first, i = 0; sf_vert; sf_vert = sf_vert->next, i++) {
+ BMVert *v = sf_vert->tmp.p;
+ BMIter eiter;
+ BMEdge *e, *e_pair[2];
+ unsigned int e_index = 0;
+
+ nors[i].value = -1.0f;
+
+ /* only use if 'is_degenerate' stays true */
+ add_v3_v3(normal, v->no);
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ if (e_index == 2) {
+ e_index = 0;
+ break;
+ }
+ e_pair[e_index++] = e;
+ }
+ }
+
+ if (e_index == 2) {
+ float dir_a[3], dir_b[3];
+
+ is_degenerate = false;
+
+ sub_v3_v3v3(dir_a, v->co, BM_edge_other_vert(e_pair[0], v)->co);
+ sub_v3_v3v3(dir_b, v->co, BM_edge_other_vert(e_pair[1], v)->co);
+
+ cross_v3_v3v3(nors[i].no, dir_a, dir_b);
+ nors[i].value = len_squared_v3(nors[i].no);
+
+ /* only to get deterministic behavior (for initial normal) */
+ if (len_squared_v3(dir_a) > len_squared_v3(dir_b)) {
+ negate_v3(nors[i].no);
+ }
+ }
+ }
+
+ if (UNLIKELY(is_degenerate)) {
+ /* no vertices have 2 edges?
+ * in this case fall back to the average vertex normals */
+ }
+ else {
+ qsort(nors, nors_tot, sizeof(*nors), BLI_sortutil_cmp_float_reverse);
+
+ copy_v3_v3(normal, nors[0].no);
+ for (i = 0; i < nors_tot; i++) {
+ if (UNLIKELY(nors[i].value == -1.0f)) {
+ break;
+ }
+ if (dot_v3v3(normal, nors[i].no) < 0.0f) {
+ negate_v3(nors[i].no);
+ }
+ add_v3_v3(normal, nors[i].no);
+ }
+ normalize_v3(normal);
+ }
+
+ MEM_freeN(nors);
}
else {
- normalize_v3(normal);
- normal_pt = normal;
+ calc_winding = false;
}
- BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal_pt);
-
+ normalize_v3(normal);
+
+ BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal);
+
+
+ /* if we have existing faces, base winding on those */
+ if (calc_winding) {
+ int winding_votes = 0;
+ for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
+ BMVert *v_tri[3] = {sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p};
+ unsigned int i, i_prev;
+
+ for (i = 0, i_prev = 2; i < 3; i_prev = i++) {
+ e = BM_edge_exists(v_tri[i], v_tri[i_prev]);
+ if (e && BM_edge_is_boundary(e) && BMO_elem_flag_test(bm, e, EDGE_MARK)) {
+ winding_votes += (e->l->v == v_tri[i]) ? 1 : -1;
+ }
+ }
+ }
+
+ if (winding_votes < 0) {
+ for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
+ SWAP(struct ScanFillVert *, sf_tri->v2, sf_tri->v3);
+ }
+ }
+ }
+
+
for (sf_tri = sf_ctx.fillfacebase.first; sf_tri; sf_tri = sf_tri->next) {
- BMFace *f = BM_face_create_quad_tri(bm,
- sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL,
- NULL, true);
+ BMFace *f;
BMLoop *l;
BMIter liter;
+
+ f = BM_face_create_quad_tri(bm,
+ sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL,
+ NULL, BM_CREATE_NO_DOUBLE);
BMO_elem_flag_enable(bm, f, ELE_NEW);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
@@ -123,7 +228,6 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op)
}
BLI_scanfill_end(&sf_ctx);
- BLI_smallhash_release(&hash);
if (use_beauty) {
BMOperator bmop;
diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c
index 600386893dd..a06d40c8c0f 100644
--- a/source/blender/bmesh/operators/bmo_utils.c
+++ b/source/blender/bmesh/operators/bmo_utils.c
@@ -63,7 +63,7 @@ void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op)
if (!is_zero_m4(mat_space)) {
invert_m4_m4(imat_space, mat_space);
- mul_serie_m4(mat, imat_space, mat, mat_space, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(mat, imat_space, mat, mat_space);
}
BMO_ITER (v, &iter, op->slots_in, "verts", BM_VERT) {
@@ -291,6 +291,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
BMEdge *e;
float (*cos)[3] = MEM_mallocN(sizeof(*cos) * BMO_slot_buffer_count(op->slots_in, "verts"), __func__);
float *co, *co2, clip_dist = BMO_slot_float_get(op->slots_in, "clip_dist");
+ const float fac = BMO_slot_float_get(op->slots_in, "factor");
int i, j, clipx, clipy, clipz;
int xaxis, yaxis, zaxis;
@@ -322,7 +323,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op)
}
mul_v3_fl(co, 1.0f / (float)j);
- mid_v3_v3v3(co, co, v->co);
+ interp_v3_v3v3(co, v->co, co, fac);
if (clipx && fabsf(v->co[0]) <= clip_dist)
co[0] = 0.0f;
diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c
index 90d26a775d3..6639e767e77 100644
--- a/source/blender/bmesh/tools/bmesh_beautify.c
+++ b/source/blender/bmesh/tools/bmesh_beautify.c
@@ -67,6 +67,7 @@ static unsigned int erot_gsetutil_hash(const void *ptr)
return BLI_ghashutil_inthash_v4(&e_state->v1);
}
#endif
+#if 0
static int erot_gsetutil_cmp(const void *a, const void *b)
{
const EdRotState *e_state_a = (const EdRotState *)a;
@@ -81,10 +82,10 @@ static int erot_gsetutil_cmp(const void *a, const void *b)
else if (e_state_a->f2 > e_state_b->f2) return 1;
else return 0;
}
-
+#endif
static GSet *erot_gset_new(void)
{
- return BLI_gset_new(BLI_ghashutil_inthash_v4_p, erot_gsetutil_cmp, __func__);
+ return BLI_gset_new(BLI_ghashutil_inthash_v4_p, BLI_ghashutil_inthash_v4_cmp, __func__);
}
/* ensure v0 is smaller */
@@ -142,10 +143,10 @@ static float bm_edge_calc_rotate_beauty__area(
float axis_mat[3][3];
// printf("%p %p %p %p - %p %p\n", v1, v2, v3, v4, e->l->f, e->l->radial_next->f);
- BLI_assert((ELEM3(v1, v2, v3, v4) == false) &&
- (ELEM3(v2, v1, v3, v4) == false) &&
- (ELEM3(v3, v1, v2, v4) == false) &&
- (ELEM3(v4, v1, v2, v3) == false));
+ BLI_assert((ELEM(v1, v2, v3, v4) == false) &&
+ (ELEM(v2, v1, v3, v4) == false) &&
+ (ELEM(v3, v1, v2, v4) == false) &&
+ (ELEM(v4, v1, v2, v3) == false));
is_zero_a = (normal_tri_v3(no_a, v2, v3, v4) <= FLT_EPSILON);
is_zero_b = (normal_tri_v3(no_b, v2, v4, v1) <= FLT_EPSILON);
diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c
index 33ba4b9550e..34317866b39 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.c
+++ b/source/blender/bmesh/tools/bmesh_bevel.c
@@ -52,6 +52,7 @@
#define BEVEL_EPSILON_D 1e-6
#define BEVEL_EPSILON 1e-6f
#define BEVEL_EPSILON_SQ 1e-12f
+#define BEVEL_EPSILON_BIG 1e-4f
/* happens far too often, uncomment for development */
// #define BEVEL_ASSERT_PROJECT
@@ -136,7 +137,7 @@ typedef struct BoundVert {
Profile profile; /* edge profile between this and next BoundVert */
bool any_seam; /* are any of the edges attached here seams? */
// int _pad;
-} BoundVert;
+} BoundVert;
/* Mesh structure replacing a vertex */
typedef struct VMesh {
@@ -157,12 +158,14 @@ typedef struct VMesh {
/* Data for a vertex involved in a bevel */
typedef struct BevVert {
BMVert *v; /* original mesh vertex */
- int edgecount; /* total number of edges around the vertex */
+ int edgecount; /* total number of edges around the vertex (excluding wire edges if edge beveling) */
int selcount; /* number of selected edges around the vertex */
+ int wirecount; /* count of wire edges */
float offset; /* offset for this vertex, if vertex_only bevel */
bool any_seam; /* any seams on attached edges? */
bool visited; /* used in graph traversal */
EdgeHalf *edges; /* array of size edgecount; CCW order from vertex normal side */
+ BMEdge **wire_edges; /* array of size wirecount of wire edges */
VMesh *vmesh; /* mesh structure for replacing vertex */
} BevVert;
@@ -184,6 +187,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 */
} BevelParams;
// #pragma GCC diagnostic ignored "-Wpadded"
@@ -353,11 +357,12 @@ static BMFace *boundvert_rep_face(BoundVert *v)
* Make ngon from verts alone.
* Make sure to properly copy face attributes and do custom data interpolation from
* corresponding elements of face_arr, if that is non-NULL, else from facerep.
+ * If mat_nr >= 0 then the material of the face is set to that.
*
* \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, bool do_interp)
+ BMFace **face_arr, BMFace *facerep, int mat_nr, bool do_interp)
{
BMIter iter;
BMLoop *l;
@@ -392,22 +397,24 @@ static BMFace *bev_create_ngon(BMesh *bm, BMVert **vert_arr, const int totv,
BM_elem_flag_enable(f, BM_ELEM_TAG);
}
+ if (mat_nr >= 0)
+ f->mat_nr = mat_nr;
return f;
}
static BMFace *bev_create_quad_tri(BMesh *bm, BMVert *v1, BMVert *v2, BMVert *v3, BMVert *v4,
- BMFace *facerep, bool do_interp)
+ 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, do_interp);
+ 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)
+ 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};
- return bev_create_ngon(bm, varr, v4 ? 4 : 3, farr, f1, true);
+ return bev_create_ngon(bm, varr, v4 ? 4 : 3, farr, f1, mat_nr, true);
}
@@ -487,13 +494,13 @@ static bool contig_ldata_across_edge(BMesh *bm, BMEdge *e, BMFace *f1, BMFace *f
* 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,
- BMFace *f1, BMFace *f2, bool is_seam)
+ BMFace *f1, BMFace *f2, int mat_nr, bool is_seam)
{
BMFace *f, *facerep;
BMLoop *l;
BMIter iter;
- f = bev_create_quad_tri(bm, v1, v2, v3, v4, f1, false);
+ f = bev_create_quad_tri(bm, v1, v2, v3, v4, f1, mat_nr, false);
if (!f)
return NULL;
@@ -552,13 +559,22 @@ static void slide_dist(EdgeHalf *e, BMVert *v, float d, float slideco[3])
madd_v3_v3fl(slideco, dir, -d);
}
-/* Is co not on the edge e? */
-static bool is_outside_edge(EdgeHalf *e, const float co[3])
+/* Is co not on the edge e? if not, return the closer end of e in ret_closer_v */
+static bool is_outside_edge(EdgeHalf *e, const float co[3], BMVert **ret_closer_v)
{
float d_squared;
d_squared = dist_squared_to_line_segment_v3(co, e->e->v1->co, e->e->v2->co);
- return d_squared > 10000.0f * BEVEL_EPSILON_SQ;
+ if (d_squared > BEVEL_EPSILON_BIG * BEVEL_EPSILON_BIG) {
+ if (len_squared_v3v3(co, e->e->v1->co) > len_squared_v3v3(co, e->e->v2->co))
+ *ret_closer_v = e->e->v2;
+ else
+ *ret_closer_v = e->e->v1;
+ return true;
+ }
+ else {
+ return false;
+ }
}
/*
@@ -577,16 +593,19 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
{
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;
+ BMVert *closer_v;
/* 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);
ang = angle_v3v3(dir1, dir2);
- if (ang < 100.0f * BEVEL_EPSILON) {
+ if (ang < BEVEL_EPSILON_BIG) {
/* special case: e1 and e2 are parallel; put offset point perp to both, from v.
* need to find a suitable plane.
- * if offsets are different, we're out of luck: just use e1->offset_r */
+ * if offsets are different, we're out of luck:
+ * use the max of the two (so get consistent looking results if the same situation
+ * arises elsewhere in the object but with opposite roles for e1 and e2 */
if (f)
copy_v3_v3(norm_v, f->no);
else
@@ -594,18 +613,24 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
cross_v3_v3v3(norm_perp1, dir1, norm_v);
normalize_v3(norm_perp1);
copy_v3_v3(off1a, v->co);
- madd_v3_v3fl(off1a, norm_perp1, e1->offset_r);
- if (e2->offset_l != e1->offset_r)
- e2->offset_l = e1->offset_r;
+ d = max_ff(e1->offset_r, e2->offset_l);
+ madd_v3_v3fl(off1a, norm_perp1, d);
+ if (e1->offset_r != d)
+ e1->offset_r = d;
+ else if (e2->offset_l != d)
+ e2->offset_l = d;
copy_v3_v3(meetco, off1a);
}
- else if (fabsf(ang - (float)M_PI) < 100.0f * BEVEL_EPSILON) {
+ else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_BIG) {
/* special case e1 and e2 are antiparallel, so bevel is into
* a zero-area face. Just make the offset point on the
* common line, at offset distance from v. */
- slide_dist(e2, v, e1->offset_r, meetco);
- if (e2->offset_l != e1->offset_r)
- e2->offset_l = e1->offset_r;
+ d = max_ff(e1->offset_r, e2->offset_l);
+ slide_dist(e2, v, d, meetco);
+ if (e1->offset_r != d)
+ e1->offset_r = d;
+ else if (e2->offset_l != d)
+ e2->offset_l = d;
}
else {
/* Get normal to plane where meet point should be,
@@ -646,14 +671,15 @@ static void offset_meet(EdgeHalf *e1, EdgeHalf *e2, BMVert *v, BMFace *f, float
/* The lines intersect, but is it at a reasonable place?
* One problem to check: if one of the offsets is 0, then don't
* want an intersection that is outside that edge itself.
- * This can happen if angle between them is > 180 degrees. */
- if (e1->offset_r == 0.0f && is_outside_edge(e1, meetco)) {
- copy_v3_v3(meetco, v->co);
- e2->offset_l = 0.0f;
+ * This can happen if angle between them is > 180 degrees,
+ * or if the offset amount is > the edge length*/
+ if (e1->offset_r == 0.0f && is_outside_edge(e1, meetco, &closer_v)) {
+ copy_v3_v3(meetco, closer_v->co);
+ e2->offset_l = len_v3v3(meetco, v->co);
}
- if (e2->offset_l == 0.0f && is_outside_edge(e2, meetco)) {
- copy_v3_v3(meetco, v->co);
- e1->offset_r = 0.0f;
+ if (e2->offset_l == 0.0f && is_outside_edge(e2, meetco, &closer_v)) {
+ copy_v3_v3(meetco, closer_v->co);
+ e1->offset_r = len_v3v3(meetco, v->co);
}
}
}
@@ -801,11 +827,11 @@ static void offset_in_two_planes(BevelParams *bp, EdgeHalf *e1, EdgeHalf *e2, Ed
add_v3_v3v3(off2b, off2a, dir2);
ang = angle_v3v3(dir1, dir2);
- if (ang < 100.0f * BEVEL_EPSILON) {
+ if (ang < BEVEL_EPSILON_BIG) {
/* lines are parallel; put intersection on emid */
offset_on_edge_between(bp, e1, e2, emid, v, meetco);
}
- else if (fabsf(ang - (float)M_PI) < 100.0f * BEVEL_EPSILON) {
+ else if (fabsf(ang - (float)M_PI) < BEVEL_EPSILON_BIG) {
slide_dist(e2, v, e2->offset_l, meetco);
d = dist_to_line_v3(meetco, v->co, BM_edge_other_vert(e1->e, v)->co);
if (fabsf(d - e1->offset_r) > BEVEL_EPSILON)
@@ -882,7 +908,7 @@ static void set_profile_params(BevelParams *bp, BoundVert *bndv)
{
EdgeHalf *e;
Profile *pro;
- float co1[3], co2[3], co3[3], d1[3], d2[3];
+ float co1[3], co2[3], co3[3], d1[3], d2[3], d3[3], l;
bool do_linear_interp;
copy_v3_v3(co1, bndv->nv.co);
@@ -895,6 +921,7 @@ static void set_profile_params(BevelParams *bp, BoundVert *bndv)
pro->super_r = bp->pro_super_r;
/* projection direction is direction of the edge */
sub_v3_v3v3(pro->proj_dir, e->e->v1->co, e->e->v2->co);
+ normalize_v3(pro->proj_dir);
project_to_edge(e->e, co1, co2, pro->midco);
/* put arc endpoints on plane with normal proj_dir, containing midco */
add_v3_v3v3(co3, co1, pro->proj_dir);
@@ -910,12 +937,18 @@ static void set_profile_params(BevelParams *bp, BoundVert *bndv)
/* default plane to project onto is the one with triangle co1 - midco - co2 in it */
sub_v3_v3v3(d1, pro->midco, co1);
sub_v3_v3v3(d2, pro->midco, co2);
+ normalize_v3(d1);
+ normalize_v3(d2);
cross_v3_v3v3(pro->plane_no, d1, d2);
- if (normalize_v3(pro->plane_no) < BEVEL_EPSILON) {
- /* co1 - midco -co2 are collinear - project onto that plane */
- cross_v3_v3v3(co3, d1, pro->proj_dir);
- cross_v3_v3v3(pro->plane_no, d1, co3);
- if (normalize_v3(pro->plane_no) < BEVEL_EPSILON) {
+ l = normalize_v3(pro->plane_no);
+ if (l <= BEVEL_EPSILON_BIG) {
+ /* co1 - midco -co2 are collinear - project plane that contains that line
+ * and is perpendicular to the plane containing it and the beveled edge */
+ cross_v3_v3v3(d3, d1, pro->proj_dir);
+ normalize_v3(d3);
+ cross_v3_v3v3(pro->plane_no, d1, d3);
+ l = normalize_v3(pro->plane_no);
+ if (l <= BEVEL_EPSILON_BIG) {
/* whole profile is collinear with edge: just interpolate */
do_linear_interp = true;
}
@@ -948,9 +981,9 @@ static void move_profile_plane(BoundVert *bndv, EdgeHalf *e1, EdgeHalf *e2)
sub_v3_v3v3(d2, e2->e->v1->co, e2->e->v2->co);
cross_v3_v3v3(no, d1, d2);
cross_v3_v3v3(no2, d1, bndv->profile.proj_dir);
- if (normalize_v3(no) > BEVEL_EPSILON && normalize_v3(no2) > BEVEL_EPSILON) {
+ if (normalize_v3(no) > BEVEL_EPSILON_BIG && normalize_v3(no2) > BEVEL_EPSILON_BIG) {
dot = fabsf(dot_v3v3(no, no2));
- if (fabsf(dot - 1.0f) > BEVEL_EPSILON)
+ if (fabsf(dot - 1.0f) > BEVEL_EPSILON_BIG)
copy_v3_v3(bndv->profile.plane_no, no);
}
}
@@ -962,7 +995,7 @@ static void move_profile_plane(BoundVert *bndv, EdgeHalf *e1, EdgeHalf *e2)
* The original vertex should form a third point of the desired plane. */
static void move_weld_profile_planes(BevVert *bv, BoundVert *bndv1, BoundVert *bndv2)
{
- float d1[3], d2[3], no[3], no2[3], no3[3], dot1, dot2;
+ float d1[3], d2[3], no[3], no2[3], no3[3], dot1, dot2, l1, l2, l3;
/* only do this if projecting, and d1, d2, and proj_dir are not coplanar */
if (is_zero_v3(bndv1->profile.proj_dir) || is_zero_v3(bndv2->profile.proj_dir))
@@ -970,22 +1003,20 @@ static void move_weld_profile_planes(BevVert *bv, BoundVert *bndv1, BoundVert *b
sub_v3_v3v3(d1, bv->v->co, bndv1->nv.co);
sub_v3_v3v3(d2, bv->v->co, bndv2->nv.co);
cross_v3_v3v3(no, d1, d2);
+ l1 = normalize_v3(no);
/* "no" is new normal projection plane, but don't move if
- * it is coplanar with one or the other of the projection dirs */
+ * it is coplanar with both of the projection dirs */
cross_v3_v3v3(no2, d1, bndv1->profile.proj_dir);
+ l2 = normalize_v3(no2);
cross_v3_v3v3(no3, d2, bndv2->profile.proj_dir);
- if (normalize_v3(no) > BEVEL_EPSILON &&
- normalize_v3(no2) > BEVEL_EPSILON &&
- normalize_v3(no3) > BEVEL_EPSILON)
- {
+ l3 = normalize_v3(no3);
+ if (l1 > BEVEL_EPSILON && (l2 > BEVEL_EPSILON || l3 > BEVEL_EPSILON)) {
dot1 = fabsf(dot_v3v3(no, no2));
dot2 = fabsf(dot_v3v3(no, no3));
- if (fabsf(dot1 - 1.0f) > BEVEL_EPSILON &&
- fabsf(dot2 - 1.0f) > BEVEL_EPSILON)
- {
+ if (fabsf(dot1 - 1.0f) > BEVEL_EPSILON)
copy_v3_v3(bndv1->profile.plane_no, no);
+ if (fabsf(dot2 - 1.0f) > BEVEL_EPSILON)
copy_v3_v3(bndv2->profile.plane_no, no);
- }
}
}
@@ -1547,8 +1578,8 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
calculate_profile(bp, v);
} while ((v = v->next) != vm->boundstart);
- if (bv->selcount == 1 && bv->edgecount == 3) {
- /* special case: snap profile to third face */
+ if (bv->selcount == 1 && 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);
@@ -1600,7 +1631,7 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct)
* corresponding ones that changed on the other end.
* The graph is dynamic in the sense that having an offset that
* doesn't meet the user spec can be added as the search proceeds.
- * We want this search to be deterministic (not dependendent
+ * We want this search to be deterministic (not dependent
* on order of processing through hash table), so as to avoid
* flicker to to different decisions made if search is different
* while dragging the offset number in the UI. So look for the
@@ -1623,7 +1654,7 @@ static void adjust_offsets(BevelParams *bp)
bv->visited = false;
}
- q = BLI_gsqueue_new((int)sizeof(BevVert *));
+ q = BLI_gsqueue_new(sizeof(BevVert *));
/* the following loop terminates because at least one node is visited each time */
for (;;) {
/* look for root of a connected component in search graph */
@@ -1692,7 +1723,7 @@ static BoundVert *pipe_test(BevVert *bv)
sub_v3_v3v3(dir3, BM_edge_other_vert(v3->ebev->e, bv->v)->co, bv->v->co);
normalize_v3(dir1);
normalize_v3(dir3);
- if (angle_v3v3(dir1, dir3) < 100.0f * BEVEL_EPSILON) {
+ if (angle_normalized_v3v3(dir1, dir3) < BEVEL_EPSILON_BIG) {
epipe = v1->ebev;
break;
}
@@ -1838,7 +1869,7 @@ static float sabin_gamma(int n)
k2 = k * k;
k4 = k2 * k2;
k6 = k4 * k2;
- y = pow(1.73205080756888 * sqrt(64.0 * k6 - 144.0 * k4 + 135.0 * k2 - 27.0) + 9.0 * k,
+ y = pow(M_SQRT3 * sqrt(64.0 * k6 - 144.0 * k4 + 135.0 * k2 - 27.0) + 9.0 * k,
1.0 / 3.0);
x = 0.480749856769136 * y - (0.231120424783545 * (12.0 * k2 - 9.0)) / y;
ans = (k * x + 2.0 * k2 - 1.0) / (x * x * (k * x + 1.0));
@@ -2231,7 +2262,7 @@ static VMesh *make_cube_corner_adj_vmesh(BevelParams *bp)
bndv = bndv->next;
}
/* center vertex */
- w = 0.57735027f; /* 1/sqrt(3) */
+ w = (float)(1.0 / M_SQRT3);
co[0] = w;
co[1] = w;
co[2] = w;
@@ -2473,6 +2504,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
BMVert *bmv1, *bmv2, *bmv3, *bmv4;
BMFace *f, *f2, *f23;
BoundVert *vpipe;
+ int mat_nr = bp->mat_nr;
n = bv->vmesh->count;
ns = bv->vmesh->seg;
@@ -2525,7 +2557,7 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
if (odd && k == ns2 && f2 && !v->any_seam)
f23 = f2;
bev_create_quad_tri_ex(bm, bmv1, bmv2, bmv3, bmv4,
- f, f23, f23, f);
+ f, f23, f23, f, mat_nr);
}
}
} while ((v = v->next) != vm->boundstart);
@@ -2562,13 +2594,13 @@ static void bevel_build_rings(BevelParams *bp, BMesh *bm, BevVert *bv)
BLI_array_append(vf, v->any_seam ? f : boundvert_rep_face(v));
} while ((v = v->next) != vm->boundstart);
f = boundvert_rep_face(vm->boundstart);
- bev_create_ngon(bm, vv, BLI_array_count(vv), vf, f, true);
+ bev_create_ngon(bm, vv, BLI_array_count(vv), vf, f, mat_nr, true);
BLI_array_free(vv);
}
}
-static BMFace *bevel_build_poly(BMesh *bm, BevVert *bv)
+static BMFace *bevel_build_poly(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
int n, k;
@@ -2598,7 +2630,7 @@ static BMFace *bevel_build_poly(BMesh *bm, BevVert *bv)
}
} while ((v = v->next) != vm->boundstart);
if (n > 2) {
- f = bev_create_ngon(bm, vv, n, vf, boundvert_rep_face(v), true);
+ f = bev_create_ngon(bm, vv, n, vf, boundvert_rep_face(v), bp->mat_nr, true);
}
else {
f = NULL;
@@ -2607,12 +2639,12 @@ static BMFace *bevel_build_poly(BMesh *bm, BevVert *bv)
return f;
}
-static void bevel_build_trifan(BMesh *bm, BevVert *bv)
+static void bevel_build_trifan(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
BLI_assert(next_bev(bv, NULL)->seg == 1 || bv->selcount == 1);
- f = bevel_build_poly(bm, bv);
+ f = bevel_build_poly(bp, bm, bv);
if (f) {
/* we have a polygon which we know starts at the previous vertex, make it into a fan */
@@ -2642,12 +2674,12 @@ static void bevel_build_trifan(BMesh *bm, BevVert *bv)
}
}
-static void bevel_build_quadstrip(BMesh *bm, BevVert *bv)
+static void bevel_build_quadstrip(BevelParams *bp, BMesh *bm, BevVert *bv)
{
BMFace *f;
BLI_assert(bv->selcount == 2);
- f = bevel_build_poly(bm, bv);
+ f = bevel_build_poly(bp, bm, bv);
if (f) {
/* we have a polygon which we know starts at this vertex, make it into strips */
@@ -2680,6 +2712,25 @@ static void bevel_build_quadstrip(BMesh *bm, BevVert *bv)
}
}
+/* Special case: there is no vmesh pattern because this has only two boundary verts,
+ * and there are no faces in the original mesh at the original vertex.
+ * Since there will be no rebuilt face to make the edge between the boundary verts,
+ * we have to make it here. */
+static void bevel_build_one_wire(BMesh *bm, BevVert *bv)
+{
+ VMesh *vm = bv->vmesh;
+ BMVert *v1, *v2;
+ BMEdge *e_eg;
+
+ BLI_assert(vm->count == 2);
+
+ v1 = mesh_vert(vm, 0, 0, 0)->v;
+ v2 = mesh_vert(vm, 1, 0, 0)->v;
+ e_eg = bv->edges[0].e;
+ BLI_assert(v1 != NULL && v2 != NULL && e_eg != NULL);
+ BM_edge_create(bm, v1, v2, e_eg, BM_CREATE_NO_DOUBLE);
+}
+
/* Given that the boundary is built, now make the actual BMVerts
* for the boundary and the interior of the vertex mesh. */
static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
@@ -2763,19 +2814,20 @@ static void build_vmesh(BevelParams *bp, BMesh *bm, BevVert *bv)
switch (vm->mesh_kind) {
case M_NONE:
- /* do nothing */
+ if (n == 2 && BM_vert_face_count(bv->v) == 0)
+ bevel_build_one_wire(bm, bv);
break;
case M_POLY:
- bevel_build_poly(bm, bv);
+ bevel_build_poly(bp, bm, bv);
break;
case M_ADJ:
bevel_build_rings(bp, bm, bv);
break;
case M_TRI_FAN:
- bevel_build_trifan(bm, bv);
+ bevel_build_trifan(bp, bm, bv);
break;
case M_QUAD_STRIP:
- bevel_build_quadstrip(bm, bv);
+ bevel_build_quadstrip(bp, bm, bv);
break;
}
}
@@ -2814,6 +2866,7 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
int i, found_shared_face, ccw_test_sum;
int nsel = 0;
int ntot = 0;
+ int nwire = 0;
int fcnt;
/* Gather input selected edges.
@@ -2821,13 +2874,14 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
* Want edges to be ordered so that they share faces.
* There may be one or more chains of shared faces broken by
* gaps where there are no faces.
- * TODO: Want to ignore wire edges completely for edge beveling.
+ * Want to ignore wire edges completely for edge beveling.
* TODO: make following work when more than one gap.
*/
first_bme = NULL;
BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
fcnt = BM_edge_face_count(bme);
+ BM_BEVEL_EDGE_TAG_DISABLE(bme);
if (BM_elem_flag_test(bme, BM_ELEM_TAG) && !bp->vertex_only) {
BLI_assert(fcnt == 2);
nsel++;
@@ -2838,8 +2892,15 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
/* good to start face chain from this edge */
first_bme = bme;
}
- ntot++;
- BM_BEVEL_EDGE_TAG_DISABLE(bme);
+ if (fcnt > 0 || bp->vertex_only)
+ ntot++;
+ if (BM_edge_is_wire(bme)) {
+ nwire++;
+ /* If edge beveling, exclude wire edges from edges array.
+ * Mark this edge as "chosen" so loop below won't choose it. */
+ if (!bp->vertex_only)
+ BM_BEVEL_EDGE_TAG_ENABLE(bme);
+ }
}
if (!first_bme)
first_bme = v->e;
@@ -2854,8 +2915,13 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
bv->v = v;
bv->edgecount = ntot;
bv->selcount = nsel;
+ bv->wirecount = nwire;
bv->offset = bp->offset;
bv->edges = (EdgeHalf *)BLI_memarena_alloc(bp->mem_arena, ntot * sizeof(EdgeHalf));
+ if (nwire)
+ bv->wire_edges = (BMEdge **)BLI_memarena_alloc(bp->mem_arena, nwire * sizeof(BMEdge *));
+ else
+ bv->wire_edges = NULL;
bv->vmesh = (VMesh *)BLI_memarena_alloc(bp->mem_arena, sizeof(VMesh));
bv->vmesh->seg = bp->seg;
@@ -2869,6 +2935,10 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
}
bv->offset *= weight;
}
+ else if (bp->use_weights) {
+ weight = BM_elem_float_data_get(&bm->vdata, v, CD_BWEIGHT);
+ bv->offset *= weight;
+ }
}
BLI_ghash_insert(bp->vert_hash, v, bv);
@@ -3023,6 +3093,17 @@ static BevVert *bevel_vert_construct(BMesh *bm, BevelParams *bp, BMVert *v)
e->is_seam = true;
}
+ if (nwire) {
+ i = 0;
+ BM_ITER_ELEM (bme, &iter, v, BM_EDGES_OF_VERT) {
+ if (BM_edge_is_wire(bme)) {
+ BLI_assert(i < bv->wirecount);
+ bv->wire_edges[i++] = bme;
+ }
+ }
+ BLI_assert(i == bv->wirecount);
+ }
+
return bv;
}
@@ -3035,19 +3116,24 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
BoundVert *v, *vstart, *vend;
EdgeHalf *e, *eprev;
VMesh *vm;
- int i, k;
+ int i, k, n;
bool do_rebuild = false;
BMVert *bmv;
+ BMEdge *bme, *bme_new, *bme_prev;
+ BMFace *f_new;
BMVert **vv = NULL;
BMVert **vv_fix = NULL;
+ BMEdge **ee = NULL;
BLI_array_staticdeclare(vv, BM_DEFAULT_NGON_STACK_SIZE);
BLI_array_staticdeclare(vv_fix, BM_DEFAULT_NGON_STACK_SIZE);
+ BLI_array_staticdeclare(ee, BM_DEFAULT_NGON_STACK_SIZE);
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) {
lprev = l->prev;
bv = find_bevvert(bp, l->v);
e = find_edge_half(bv, l->e);
+ bme = e->e;
eprev = find_edge_half(bv, lprev->e);
BLI_assert(e != NULL && eprev != NULL);
vstart = eprev->leftv;
@@ -3058,6 +3144,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
v = vstart;
vm = bv->vmesh;
BLI_array_append(vv, v->nv.v);
+ BLI_array_append(ee, bme);
while (v != vend) {
if (vm->mesh_kind == M_NONE && v->ebev && v->ebev->seg > 1 && v->ebev != e && v->ebev != eprev) {
/* case of 3rd face opposite a beveled edge, with no vmesh */
@@ -3066,6 +3153,7 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
for (k = 1; k < e->seg; k++) {
bmv = mesh_vert(vm, i, 0, k)->v;
BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme);
/* may want to merge UVs of these later */
if (!e->is_seam)
BLI_array_append(vv_fix, bmv);
@@ -3077,25 +3165,57 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
for (k = vm->seg - 1; k > 0; k--) {
bmv = mesh_vert(vm, i, 0, k)->v;
BLI_array_append(vv, bmv);
+ BLI_array_append(ee, bme);
}
}
v = v->prev;
BLI_array_append(vv, v->nv.v);
+ BLI_array_append(ee, bme);
}
do_rebuild = true;
}
else {
BLI_array_append(vv, l->v);
+ BLI_array_append(ee, l->e);
}
}
if (do_rebuild) {
- BMFace *f_new = bev_create_ngon(bm, vv, BLI_array_count(vv), NULL, f, true);
+ n = BLI_array_count(vv);
+ f_new = bev_create_ngon(bm, vv, n, NULL, f, -1, true);
for (k = 0; k < BLI_array_count(vv_fix); k++) {
bev_merge_uvs(bm, vv_fix[k]);
}
+ /* copy attributes from old edges */
+ BLI_assert(n == BLI_array_count(ee));
+ bme_prev = ee[n - 1];
+ for (k = 0; k < n; k++) {
+ bme_new = BM_edge_exists(vv[k], vv[(k + 1) % n]);
+ BLI_assert(ee[k] && bme_new);
+ if (ee[k] != bme_new) {
+ BM_elem_attrs_copy(bm, bm, ee[k], bme_new);
+ /* want to undo seam and smooth for corner segments
+ * if those attrs aren't contiguous around face */
+ if (k < n - 1 && ee[k] == ee[k + 1]) {
+ if (BM_elem_flag_test(ee[k], BM_ELEM_SEAM) &&
+ !BM_elem_flag_test(bme_prev, BM_ELEM_SEAM))
+ {
+ BM_elem_flag_disable(bme_new, BM_ELEM_SEAM);
+ }
+ /* actually want "sharp" to be contiguous, so reverse the test */
+ if (!BM_elem_flag_test(ee[k], BM_ELEM_SMOOTH) &&
+ BM_elem_flag_test(bme_prev, BM_ELEM_SMOOTH))
+ {
+ BM_elem_flag_enable(bme_new, BM_ELEM_SMOOTH);
+ }
+ }
+ else
+ bme_prev = ee[k];
+ }
+ }
+
/* don't select newly created boundary faces... */
if (f_new) {
BM_elem_flag_disable(f_new, BM_ELEM_TAG);
@@ -3103,6 +3223,8 @@ static bool bev_rebuild_polygon(BMesh *bm, BevelParams *bp, BMFace *f)
}
BLI_array_free(vv);
+ BLI_array_free(vv_fix);
+ BLI_array_free(ee);
return do_rebuild;
}
@@ -3128,6 +3250,61 @@ static void bevel_rebuild_existing_polygons(BMesh *bm, BevelParams *bp, BMVert *
}
}
+/* If there were any wire edges, they need to be reattached somewhere */
+static void bevel_reattach_wires(BMesh *bm, BevelParams *bp, BMVert *v)
+{
+ BMEdge *e;
+ BMVert *vclosest, *vother, *votherclosest;
+ BevVert *bv, *bvother;
+ BoundVert *bndv, *bndvother;
+ float d, dclosest;
+ int i;
+
+ bv = find_bevvert(bp, v);
+ if (!bv || bv->wirecount == 0 || !bv->vmesh)
+ return;
+
+ for (i = 0; i < bv->wirecount; i++) {
+ e = bv->wire_edges[i];
+ /* look for the new vertex closest to the other end of e */
+ vclosest = NULL;
+ dclosest = FLT_MAX;
+ votherclosest = NULL;
+ vother = BM_edge_other_vert(e, v);
+ bvother = NULL;
+ if (BM_elem_flag_test(vother, BM_ELEM_TAG)) {
+ bvother = find_bevvert(bp, vother);
+ if (!bvother || !bvother->vmesh)
+ return; /* shouldn't happen */
+ }
+ bndv = bv->vmesh->boundstart;
+ do {
+ if (bvother) {
+ bndvother = bvother->vmesh->boundstart;
+ do {
+ d = len_squared_v3v3(bndvother->nv.co, bndv->nv.co);
+ if (d < dclosest) {
+ vclosest = bndv->nv.v;
+ votherclosest = bndvother->nv.v;
+ dclosest = d;
+
+ }
+ } while ((bndvother = bndvother->next) != bvother->vmesh->boundstart);
+ }
+ else {
+ d = len_squared_v3v3(vother->co, bndv->nv.co);
+ if (d < dclosest) {
+ vclosest = bndv->nv.v;
+ votherclosest = vother;
+ dclosest = d;
+ }
+ }
+ } while ((bndv = bndv->next) != bv->vmesh->boundstart);
+ if (vclosest)
+ BM_edge_create(bm, vclosest, votherclosest, e, BM_CREATE_NO_DOUBLE);
+ }
+}
+
static void bev_merge_end_uvs(BMesh *bm, BevVert *bv, EdgeHalf *e)
{
VMesh *vm = bv->vmesh;
@@ -3141,6 +3318,70 @@ static void bev_merge_end_uvs(BMesh *bm, BevVert *bv, EdgeHalf *e)
}
/*
+ * Is this BevVert the special case of a weld (no vmesh) where there are
+ * four edges total, two are beveled, and the other two are on opposite sides?
+ */
+static bool bevvert_is_weld_cross(BevVert *bv)
+{
+ return (bv->edgecount == 4 && bv->selcount == 2 &&
+ ((bv->edges[0].is_bev && bv->edges[2].is_bev) ||
+ (bv->edges[1].is_bev && bv->edges[3].is_bev)));
+}
+
+/*
+ * Copy edge attribute data across the non-beveled crossing edges of a cross weld.
+ *
+ * Situation looks like this:
+ *
+ * e->next
+ * |
+ * -------3-------
+ * -------2-------
+ * -------1------- e
+ * -------0------
+ * |
+ * e->prev
+ *
+ * where e is the EdgeHalf of one of the beveled edges,
+ * e->next and e->prev are EdgeHalfs for the unbeveled edges of the cross
+ * and their attributes are to be copied to the edges 01, 12, 23.
+ * The vert i is mesh_vert(vm, vmindex, 0, i)->v
+ */
+static void weld_cross_attrs_copy(BMesh *bm, BevVert *bv, VMesh *vm, int vmindex, EdgeHalf *e)
+{
+ BMEdge *bme_prev, *bme_next, *bme;
+ int i, nseg;
+ bool disable_seam, enable_smooth;
+
+ bme_prev = bme_next = NULL;
+ for (i = 0; i < 4; i++) {
+ if (&bv->edges[i] == e) {
+ bme_prev = bv->edges[(i + 3) % 4].e;
+ bme_next = bv->edges[(i + 1) % 4].e;
+ break;
+ }
+ }
+ BLI_assert(bme_prev && bme_next);
+
+ /* want seams and sharp edges to cross only if that way on both sides */
+ disable_seam = BM_elem_flag_test(bme_prev, BM_ELEM_SEAM) != BM_elem_flag_test(bme_next, BM_ELEM_SEAM);
+ enable_smooth = BM_elem_flag_test(bme_prev, BM_ELEM_SMOOTH) != BM_elem_flag_test(bme_next, BM_ELEM_SMOOTH);
+
+ nseg = e->seg;
+ for (i = 0; i < nseg; i++) {
+ bme = BM_edge_exists(mesh_vert(vm, vmindex, 0, i)->v,
+ mesh_vert(vm, vmindex, 0, i + 1)->v);
+ BLI_assert(bme);
+ BM_elem_attrs_copy(bm, bm, bme_prev, bme);
+ if (disable_seam)
+ BM_elem_flag_disable(bme, BM_ELEM_SEAM);
+ if (enable_smooth)
+ BM_elem_flag_enable(bme, BM_ELEM_SMOOTH);
+ }
+}
+
+
+/*
* Build the polygons along the selected Edge
*/
static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
@@ -3152,6 +3393,7 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
BMEdge *bme1, *bme2;
BMFace *f1, *f2, *f;
int k, nseg, i1, i2, odd, mid;
+ int mat_nr = bp->mat_nr;
if (!BM_edge_is_manifold(bme))
return;
@@ -3184,15 +3426,15 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
f1 = e1->fprev;
f2 = e1->fnext;
+ i1 = e1->leftv->index;
+ i2 = e2->leftv->index;
+ vm1 = bv1->vmesh;
+ vm2 = bv2->vmesh;
if (nseg == 1) {
- bev_create_quad_straddle(bm, bmv1, bmv2, bmv3, bmv4, f1, f2, e1->is_seam);
+ bev_create_quad_straddle(bm, bmv1, bmv2, bmv3, bmv4, f1, f2, mat_nr, e1->is_seam);
}
else {
- i1 = e1->leftv->index;
- i2 = e2->leftv->index;
- vm1 = bv1->vmesh;
- vm2 = bv2->vmesh;
bmv1i = bmv1;
bmv2i = bmv2;
odd = nseg % 2;
@@ -3201,11 +3443,11 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
bmv4i = mesh_vert(vm1, i1, 0, k)->v;
bmv3i = mesh_vert(vm2, i2, 0, nseg - k)->v;
if (odd && k == mid + 1) {
- bev_create_quad_straddle(bm, bmv1i, bmv2i, bmv3i, bmv4i, f1, f2, e1->is_seam);
+ bev_create_quad_straddle(bm, bmv1i, bmv2i, bmv3i, bmv4i, f1, f2, mat_nr, e1->is_seam);
}
else {
f = (k <= mid) ? f1 : f2;
- bev_create_quad_tri(bm, bmv1i, bmv2i, bmv3i, bmv4i, f, true);
+ bev_create_quad_tri(bm, bmv1i, bmv2i, bmv3i, bmv4i, f, mat_nr, true);
}
bmv1i = bmv4i;
bmv2i = bmv3i;
@@ -3228,6 +3470,14 @@ static void bevel_build_edge_polygons(BMesh *bm, BevelParams *bp, BMEdge *bme)
BLI_assert(bme1 && bme2);
BM_elem_attrs_copy(bm, bm, bme, bme1);
BM_elem_attrs_copy(bm, bm, bme, bme2);
+
+ /* If either end is a "weld cross", want continuity of edge attributes across end edge(s) */
+ if (bevvert_is_weld_cross(bv1)) {
+ weld_cross_attrs_copy(bm, bv1, vm1, i1, e1);
+ }
+ if (bevvert_is_weld_cross(bv2)) {
+ weld_cross_attrs_copy(bm, bv2, vm2, i2, e2);
+ }
}
/* Returns the square of the length of the chord from parameter u0 to parameter u1
@@ -3436,7 +3686,7 @@ static float bevel_limit_offset(BMesh *bm, BevelParams *bp)
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 struct MDeformVert *dvert, const int vertex_group, const int mat)
{
BMIter iter;
BMVert *v, *v_next;
@@ -3454,6 +3704,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type,
bp.limit_offset = limit_offset;
bp.dvert = dvert;
bp.vertex_group = vertex_group;
+ bp.mat_nr = mat;
if (bp.pro_super_r < 0.60f)
bp.pro_super_r = 0.60f; /* TODO: implement 0 case properly */
@@ -3504,6 +3755,7 @@ void BM_mesh_bevel(BMesh *bm, const float offset, const int offset_type,
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
bevel_rebuild_existing_polygons(bm, &bp, v);
+ bevel_reattach_wires(bm, &bp, v);
}
}
diff --git a/source/blender/bmesh/tools/bmesh_bevel.h b/source/blender/bmesh/tools/bmesh_bevel.h
index 0c088ce0238..52d8faa5401 100644
--- a/source/blender/bmesh/tools/bmesh_bevel.h
+++ b/source/blender/bmesh/tools/bmesh_bevel.h
@@ -31,6 +31,7 @@ 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 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 f4318933deb..463304f27f7 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.c
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c
@@ -38,6 +38,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_stackdefines.h"
#include "BLI_alloca.h"
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
@@ -52,7 +53,7 @@
/* -------------------------------------------------------------------- */
/* Math utils */
-static int plane_point_test_v3(const float plane[4], const float co[3], const float eps, float *r_depth)
+static short plane_point_test_v3(const float plane[4], const float co[3], const float eps, float *r_depth)
{
const float f = plane_point_side_v3(plane, co);
*r_depth = f;
@@ -68,7 +69,8 @@ static int plane_point_test_v3(const float plane[4], const float co[3], const fl
* later we may want to move this into some hash lookup
* to a separate struct, but for now we can store in BMesh data */
-#define BM_VERT_DIR(v) ((v)->head.index) /* Direction -1/0/1 */
+#define BM_VERT_DIR(v) ((short *)(&(v)->head.index))[0] /* Direction -1/0/1 */
+#define BM_VERT_SKIP(v) ((short *)(&(v)->head.index))[1] /* Skip Vert 0/1 */
#define BM_VERT_DIST(v) ((v)->no[0]) /* Distance from the plane. */
#define BM_VERT_SORTVAL(v) ((v)->no[1]) /* Temp value for sorting. */
#define BM_VERT_LOOPINDEX(v) /* The verts index within a face (temp var) */ \
@@ -116,18 +118,24 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
STACK_DECLARE(vert_split_arr);
BMLoop *l_iter, *l_first;
bool use_dirs[3] = {false, false, false};
+ bool is_inside = false;
- STACK_INIT(vert_split_arr);
+ STACK_INIT(vert_split_arr, f_len_orig);
l_first = BM_FACE_FIRST_LOOP(f);
/* add plane-aligned verts to the stack
* and check we have verts from both sides in this face,
- * ... that the face doesn't only have boundry verts on the plane for eg. */
+ * ... that the face doesn't only have boundary verts on the plane for eg. */
l_iter = l_first;
do {
if (vert_is_center_test(l_iter->v)) {
BLI_assert(BM_VERT_DIR(l_iter->v) == 0);
+
+ /* if both are -1 or 1, or both are zero:
+ * don't flip 'inside' var while walking */
+ BM_VERT_SKIP(l_iter->v) = (((BM_VERT_DIR(l_iter->prev->v) ^ BM_VERT_DIR(l_iter->next->v))) == 0);
+
STACK_PUSH(vert_split_arr, l_iter->v);
}
use_dirs[BM_VERT_DIR(l_iter->v) + 1] = true;
@@ -223,21 +231,18 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
* while not all that nice, typically there are < 5 resulting faces,
* so its not _that_ bad. */
- STACK_INIT(face_split_arr);
+ STACK_INIT(face_split_arr, STACK_SIZE(vert_split_arr));
STACK_PUSH(face_split_arr, f);
for (i = 0; i < STACK_SIZE(vert_split_arr) - 1; i++) {
BMVert *v_a = vert_split_arr[i];
BMVert *v_b = vert_split_arr[i + 1];
- float co_mid[2];
- /* geometric test before doing face lookups,
- * find if the split spans a filled region of the polygon. */
- mid_v2_v2v2(co_mid,
- face_verts_proj_2d[BM_VERT_LOOPINDEX(v_a)],
- face_verts_proj_2d[BM_VERT_LOOPINDEX(v_b)]);
+ if (!BM_VERT_SKIP(v_a)) {
+ is_inside = !is_inside;
+ }
- if (isect_point_poly_v2(co_mid, (const float (*)[2])face_verts_proj_2d, f_len_orig, false)) {
+ if (is_inside) {
BMLoop *l_a, *l_b;
bool found = false;
unsigned int j;
@@ -253,7 +258,8 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
}
}
- BLI_assert(found == true);
+ /* ideally wont happen, but it can for self intersecting faces */
+ // BLI_assert(found == true);
/* in fact this simple test is good enough,
* test if the loops are adjacent */
@@ -275,22 +281,23 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con
}
}
-finally:
- STACK_FREE(vert_split_arr);
+finally:
+ (void)vert_split_arr;
}
/* -------------------------------------------------------------------- */
/* Main logic */
/**
+ * \param use_snap_center Snap verts onto the plane.
* \param use_tag Only bisect tagged edges and faces.
- * \param use_snap Snap verts onto the plane.
* \param oflag_center Operator flag, enabled for geometry on the axis (existing and created)
*/
-void BM_mesh_bisect_plane(BMesh *bm, float plane[4],
- const bool use_snap_center, const bool use_tag,
- const short oflag_center, const float eps)
+void BM_mesh_bisect_plane(
+ BMesh *bm, const float plane[4],
+ const bool use_snap_center, const bool use_tag,
+ const short oflag_center, const float eps)
{
unsigned int einput_len;
unsigned int i;
diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.h b/source/blender/bmesh/tools/bmesh_bisect_plane.h
index 15f902642c8..7f3a97c4c79 100644
--- a/source/blender/bmesh/tools/bmesh_bisect_plane.h
+++ b/source/blender/bmesh/tools/bmesh_bisect_plane.h
@@ -27,8 +27,9 @@
* \ingroup bmesh
*/
-void BM_mesh_bisect_plane(BMesh *bm, float plane[4],
- const bool use_snap_center, const bool use_tag,
- const short oflag_center, const float eps);
+void BM_mesh_bisect_plane(
+ BMesh *bm, const float plane[4],
+ const bool use_snap_center, const bool use_tag,
+ const short oflag_center, const float eps);
#endif /* __BMESH_BISECT_PLANE_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
index f614c43193a..ef1783cc693 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c
@@ -312,12 +312,14 @@ static bool bm_decim_triangulate_begin(BMesh *bm)
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
- BM_elem_index_set(l_iter, -1);
+ BM_elem_index_set(l_iter, -1); /* set_dirty */
} while ((l_iter = l_iter->next) != l_first);
// has_quad |= (f->len == 4)
}
+ bm->elem_index_dirty |= BM_LOOP;
+
/* adding new faces as we loop over faces
* is normally best avoided, however in this case its not so bad because any face touched twice
* will already be triangulated*/
@@ -366,8 +368,8 @@ static bool bm_decim_triangulate_begin(BMesh *bm)
/* since we just split theres only ever 2 loops */
BLI_assert(BM_edge_is_manifold(l_new->e));
- BM_elem_index_set(l_new, f_index);
- BM_elem_index_set(l_new->radial_next, f_index);
+ BM_elem_index_set(l_new, f_index); /* set_dirty */
+ BM_elem_index_set(l_new->radial_next, f_index); /* set_dirty */
BM_face_normal_update(f);
BM_face_normal_update(f_new);
@@ -412,10 +414,10 @@ static void bm_decim_triangulate_end(BMesh *bm)
BM_vert_in_edge(e, l_b->next->v) ? l_b->prev->v : l_b->next->v,
};
- BLI_assert(ELEM3(vquad[0], vquad[1], vquad[2], vquad[3]) == false);
- BLI_assert(ELEM3(vquad[1], vquad[0], vquad[2], vquad[3]) == false);
- BLI_assert(ELEM3(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
- BLI_assert(ELEM3(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
+ BLI_assert(ELEM(vquad[0], vquad[1], vquad[2], vquad[3]) == false);
+ BLI_assert(ELEM(vquad[1], vquad[0], vquad[2], vquad[3]) == false);
+ BLI_assert(ELEM(vquad[2], vquad[1], vquad[0], vquad[3]) == false);
+ BLI_assert(ELEM(vquad[3], vquad[1], vquad[2], vquad[0]) == false);
if (is_quad_convex_v3(vquad[0]->co, vquad[1]->co, vquad[2]->co, vquad[3]->co)) {
/* highly unlikely to fail, but prevents possible double-ups */
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index 96af37f4400..096349e8e9c 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -235,9 +235,9 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
for (i = 0; i < vinput_len; i++) {
BMVert *v = vinput_arr[i];
if (LIKELY(v != NULL) &&
- BM_vert_edge_count(v) == 2)
+ BM_vert_is_edge_pair(v))
{
- BM_vert_collapse_edge(bm, v->e, v, true); /* join edges */
+ BM_vert_collapse_edge(bm, v->e, v, true, true); /* join edges */
}
}
}
@@ -274,8 +274,8 @@ void BM_mesh_decimate_dissolve_ex(BMesh *bm, const float angle_limit, const bool
v = BLI_heap_node_ptr(vnode_top);
i = BM_elem_index_get(v);
- if (BM_vert_edge_count(v) == 2) {
- e_new = BM_vert_collapse_edge(bm, v->e, v, true); /* join edges */
+ if (BM_vert_is_edge_pair(v)) {
+ e_new = BM_vert_collapse_edge(bm, v->e, v, true, true); /* join edges */
if (e_new) {
diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
index ffc680817a7..db60b3e15e1 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c
@@ -119,7 +119,7 @@ static bool bm_vert_dissolve_fan(BMesh *bm, BMVert *v)
if (tot_edge == 2) {
/* check for 2 wire verts only */
if (tot_edge_wire == 2) {
- return (BM_vert_collapse_edge(bm, v->e, v, true) != NULL);
+ return (BM_vert_collapse_edge(bm, v->e, v, true, true) != NULL);
}
}
else if (tot_edge == 4) {
diff --git a/source/blender/bmesh/tools/bmesh_edgenet.c b/source/blender/bmesh/tools/bmesh_edgenet.c
index ddf43949258..1328b81b746 100644
--- a/source/blender/bmesh/tools/bmesh_edgenet.c
+++ b/source/blender/bmesh/tools/bmesh_edgenet.c
@@ -203,12 +203,18 @@ static BMEdge *bm_edgenet_path_step(
BMVert *v_curr, LinkNode **v_ls,
VertNetInfo *vnet_info, BLI_mempool *path_pool)
{
- const VertNetInfo *vn_curr = &vnet_info[BM_elem_index_get(v_curr)];
+ const VertNetInfo *vn_curr;
BMEdge *e;
BMIter iter;
- unsigned int tot = 0;
- unsigned int v_ls_tot = 0;
+ unsigned int tot;
+ unsigned int v_ls_tot;
+
+
+begin:
+ tot = 0;
+ v_ls_tot = 0;
+ vn_curr = &vnet_info[BM_elem_index_get(v_curr)];
BM_ITER_ELEM (e, &iter, v_curr, BM_EDGES_OF_VERT) {
BMVert *v_next = BM_edge_other_vert(e, v_curr);
@@ -256,7 +262,12 @@ static BMEdge *bm_edgenet_path_step(
/* trick to walk along wire-edge paths */
if (v_ls_tot == 1 && tot == 1) {
v_curr = BLI_linklist_pop_pool(v_ls, path_pool);
+ /* avoid recursion, can crash on very large nets */
+#if 0
bm_edgenet_path_step(v_curr, v_ls, vnet_info, path_pool);
+#else
+ goto begin;
+#endif
}
return NULL;
@@ -382,8 +393,8 @@ static LinkNode *bm_edgenet_path_calc_best(
if (path == NULL) {
return NULL;
}
- else if (path_cost <= 1) {
- /* any face that takes 1-2 iterations to find we consider valid */
+ else if (path_cost < 1) {
+ /* any face that takes 1 iteration to find we consider valid */
return path;
}
else {
@@ -454,7 +465,6 @@ void BM_mesh_edgenet(BMesh *bm,
if (use_edge_tag == false) {
BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_enable(e, BM_ELEM_TAG);
BM_elem_flag_set(e, BM_ELEM_TAG, bm_edge_step_ok(e));
}
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
new file mode 100644
index 00000000000..4d87c3e3551
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -0,0 +1,1302 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/tools/bmesh_intersect.c
+ * \ingroup bmesh
+ *
+ * Cut meshes along intersections.
+ *
+ * Boolean-like modeling operation (without calculating inside/outside).
+ *
+ * Supported:
+ * - Concave faces.
+ * - Non-planar faces.
+ * - Custom-data (UV's etc).
+ *
+ * Unsupported:
+ * - Intersecting between different meshes.
+ * - No support for holes (cutting a hole into a single face).
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_memarena.h"
+#include "BLI_alloca.h"
+#include "BLI_sort_utils.h"
+
+#include "BLI_linklist_stack.h"
+#include "BLI_stackdefines.h"
+#include "BLI_array.h"
+
+#include "BLI_kdopbvh.h"
+
+#include "bmesh.h"
+#include "bmesh_intersect.h" /* own include */
+
+#include "tools/bmesh_edgesplit.h"
+
+#include "BLI_strict_flags.h"
+
+/*
+ * Some of these depend on each other:
+ */
+
+/* splice verts into existing edges */
+#define USE_SPLICE
+/* split faces by intersecting edges */
+#define USE_NET
+/* split resulting edges */
+#define USE_SEPARATE
+/* remove verts created by intersecting triangles */
+#define USE_DISSOLVE
+
+/* strict asserts that may fail in practice (handy for debugging cases which should succeed) */
+// #define USE_PARANOID
+/* use accelerated overlap check */
+#define USE_BVH
+
+
+static void tri_v3_scale(
+ float v1[3], float v2[3], float v3[3],
+ const float t)
+{
+ float p[3];
+
+ mid_v3_v3v3v3(p, v1, v2, v3);
+
+ interp_v3_v3v3(v1, p, v1, t);
+ interp_v3_v3v3(v2, p, v2, t);
+ interp_v3_v3v3(v3, p, v3, t);
+}
+
+#ifdef USE_DISSOLVE
+/* other edge when a vert only has 2 edges */
+static BMEdge *bm_vert_other_edge(BMVert *v, BMEdge *e)
+{
+ BLI_assert(BM_vert_is_edge_pair(v));
+ BLI_assert(BM_vert_in_edge(e, v));
+
+ if (v->e != e) {
+ return v->e;
+ }
+ else {
+ return BM_DISK_EDGE_NEXT(v->e, v);
+ }
+}
+#endif
+
+enum ISectType {
+ IX_NONE = -1,
+ IX_EDGE_TRI_EDGE0,
+ IX_EDGE_TRI_EDGE1,
+ IX_EDGE_TRI_EDGE2,
+ IX_EDGE_TRI,
+ IX_TOT,
+};
+
+struct ISectEpsilon {
+ float eps, eps_sq;
+ float eps2x, eps2x_sq;
+ float eps_margin, eps_margin_sq;
+};
+
+struct ISectState {
+ BMesh *bm;
+ GHash *edgetri_cache; /* int[4]: BMVert */
+ GHash *edge_verts; /* BMEdge: LinkList(of verts), new and original edges */
+ GHash *face_edges; /* BMFace-index: LinkList(of edges), only original faces */
+ GSet *wire_edges; /* BMEdge (could use tags instead) */
+ LinkNode *vert_dissolve; /* BMVert's */
+
+ MemArena *mem_arena;
+
+ struct ISectEpsilon epsilon;
+};
+
+/**
+ * Store as value in GHash so we can get list-length without counting every time.
+ * Also means we don't need to update the GHash value each time.
+ */
+struct LinkBase {
+ LinkNode *list;
+ unsigned int list_len;
+};
+
+static bool ghash_insert_link(
+ GHash *gh, void *key, void *val, bool use_test,
+ MemArena *mem_arena)
+{
+ struct LinkBase *ls_base;
+ LinkNode *ls;
+
+ ls_base = BLI_ghash_lookup(gh, key);
+
+ if (ls_base) {
+ if (use_test && (BLI_linklist_index(ls_base->list, key) != -1)) {
+ return false;
+ }
+ }
+ else {
+ ls_base = BLI_memarena_alloc(mem_arena, sizeof(*ls_base));
+ ls_base->list = NULL;
+ ls_base->list_len = 0;
+ BLI_ghash_insert(gh, key, ls_base);
+ }
+
+ ls = BLI_memarena_alloc(mem_arena, sizeof(*ls));
+ ls->next = ls_base->list;
+ ls->link = val;
+ ls_base->list = ls;
+ ls_base->list_len += 1;
+
+ return true;
+}
+
+struct vert_sort_t {
+ float val;
+ BMVert *v;
+};
+
+#ifdef USE_SPLICE
+static void edge_verts_sort(const float co[3], struct LinkBase *v_ls_base)
+{
+ /* not optimal but list will be typically < 5 */
+ unsigned int i;
+ struct vert_sort_t *vert_sort = BLI_array_alloca(vert_sort, v_ls_base->list_len);
+ LinkNode *node;
+
+ BLI_assert(v_ls_base->list_len > 1);
+
+ for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
+ BMVert *v = node->link;
+ BLI_assert(v->head.htype == BM_VERT);
+ vert_sort[i].val = len_squared_v3v3(co, v->co);
+ vert_sort[i].v = v;
+ }
+
+ qsort(vert_sort, v_ls_base->list_len, sizeof(*vert_sort), BLI_sortutil_cmp_float);
+
+ for (i = 0, node = v_ls_base->list; i < v_ls_base->list_len; i++, node = node->next) {
+ node->link = vert_sort[i].v;
+ }
+}
+#endif
+
+static void edge_verts_add(
+ struct ISectState *s,
+ BMEdge *e,
+ BMVert *v,
+ const bool use_test
+ )
+{
+ BLI_assert(e->head.htype == BM_EDGE);
+ BLI_assert(v->head.htype == BM_VERT);
+ ghash_insert_link(s->edge_verts, (void *)e, v, use_test, s->mem_arena);
+}
+
+static void face_edges_add(
+ struct ISectState *s,
+ const int f_index,
+ BMEdge *e,
+ const bool use_test)
+{
+ void *f_index_key = SET_INT_IN_POINTER(f_index);
+ BLI_assert(e->head.htype == BM_EDGE);
+ BLI_assert(BM_edge_in_face(e, s->bm->ftable[f_index]) == false);
+ BLI_assert(BM_elem_index_get(s->bm->ftable[f_index]) == f_index);
+
+ ghash_insert_link(s->face_edges, f_index_key, e, use_test, s->mem_arena);
+}
+
+#ifdef USE_NET
+static void face_edges_split(
+ BMesh *bm,
+ BMFace *f,
+ struct LinkBase *e_ls_base)
+{
+ unsigned int i;
+ BMEdge **edge_arr = BLI_array_alloca(edge_arr, e_ls_base->list_len);
+ LinkNode *node;
+ BLI_assert(f->head.htype == BM_FACE);
+
+ for (i = 0, node = e_ls_base->list; i < e_ls_base->list_len; i++, node = node->next) {
+ edge_arr[i] = node->link;
+ }
+ BLI_assert(node == NULL);
+
+#ifdef USE_DUMP
+ printf("# %s: %d %u\n", __func__, BM_elem_index_get(f), e_ls_base->list_len);
+#endif
+
+ BM_face_split_edgenet(bm, f, edge_arr, (int)e_ls_base->list_len, NULL, NULL);
+}
+#endif
+
+#ifdef USE_DISSOLVE
+static void vert_dissolve_add(
+ struct ISectState *s,
+ BMVert *v)
+{
+ BLI_assert(v->head.htype == BM_VERT);
+ BLI_assert(!BM_elem_flag_test(v, BM_ELEM_TAG));
+ BLI_assert(BLI_linklist_index(s->vert_dissolve, v) == -1);
+
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+ BLI_linklist_prepend_arena(&s->vert_dissolve, v, s->mem_arena);
+}
+#endif
+
+static enum ISectType intersect_line_tri(
+ const float p0[3], const float p1[3],
+ const float *t_cos[3], const float t_nor[3],
+ float r_ix[3],
+ const struct ISectEpsilon *e)
+{
+ float p_dir[3];
+ unsigned int i_t0;
+ float fac;
+
+ sub_v3_v3v3(p_dir, p0, p1);
+ normalize_v3(p_dir);
+
+ for (i_t0 = 0; i_t0 < 3; i_t0++) {
+ const unsigned int i_t1 = (i_t0 + 1) % 3;
+ float te_dir[3];
+
+ sub_v3_v3v3(te_dir, t_cos[i_t0], t_cos[i_t1]);
+ normalize_v3(te_dir);
+ if (fabsf(dot_v3v3(p_dir, te_dir)) >= 1.0f - e->eps) {
+ /* co-linear */
+ }
+ else {
+ float ix_pair[2][3];
+ int ix_pair_type;
+
+ ix_pair_type = isect_line_line_epsilon_v3(p0, p1, t_cos[i_t0], t_cos[i_t1], ix_pair[0], ix_pair[1], 0.0f);
+
+ if (ix_pair_type != 0) {
+ if (ix_pair_type == 1) {
+ copy_v3_v3(ix_pair[1], ix_pair[0]);
+ }
+
+ if ((ix_pair_type == 1) ||
+ (len_squared_v3v3(ix_pair[0], ix_pair[1]) <= e->eps_margin_sq))
+ {
+ fac = line_point_factor_v3(ix_pair[1], t_cos[i_t0], t_cos[i_t1]);
+ if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
+ fac = line_point_factor_v3(ix_pair[0], p0, p1);
+ if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
+ copy_v3_v3(r_ix, ix_pair[0]);
+ return (IX_EDGE_TRI_EDGE0 + (enum ISectType)i_t0);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* check ray isn't planar with tri */
+ if (fabsf(dot_v3v3(p_dir, t_nor)) >= e->eps) {
+ if (isect_line_tri_epsilon_v3(p0, p1, t_cos[0], t_cos[1], t_cos[2], &fac, NULL, 0.0f)) {
+ if ((fac >= e->eps_margin) && (fac <= 1.0f - e->eps_margin)) {
+ interp_v3_v3v3(r_ix, p0, p1, fac);
+ if (min_fff(len_squared_v3v3(t_cos[0], r_ix),
+ len_squared_v3v3(t_cos[1], r_ix),
+ len_squared_v3v3(t_cos[2], r_ix)) >= e->eps_margin_sq)
+ {
+ return IX_EDGE_TRI;
+ }
+ }
+ }
+ }
+
+ /* r_ix may be unset */
+ return IX_NONE;
+}
+
+static BMVert *bm_isect_edge_tri(
+ struct ISectState *s,
+ BMVert *e_v0, BMVert *e_v1,
+ BMVert *t[3], const int t_index,
+ const float *t_cos[3], const float t_nor[3],
+ enum ISectType *r_side)
+{
+ BMesh *bm = s->bm;
+ int k_arr[IX_TOT][4];
+ unsigned int i;
+ const int ti[3] = {UNPACK3_EX(BM_elem_index_get, t, )};
+ float ix[3];
+
+ if (BM_elem_index_get(e_v0) > BM_elem_index_get(e_v1)) {
+ SWAP(BMVert *, e_v0, e_v1);
+ }
+
+#ifdef USE_PARANOID
+ BLI_assert(len_squared_v3v3(e_v0->co, t[0]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v0->co, t[1]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v0->co, t[2]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v1->co, t[0]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v1->co, t[1]->co) >= s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(e_v1->co, t[2]->co) >= s->epsilon.eps_sq);
+#endif
+
+#define KEY_SET(k, i0, i1, i2, i3) { \
+ (k)[0] = i0; \
+ (k)[1] = i1; \
+ (k)[2] = i2; \
+ (k)[3] = i3; \
+} (void)0
+
+ /* order tri, then order (1-2, 2-3)*/
+#define KEY_EDGE_TRI_ORDER(k) { \
+ if (k[2] > k[3]) { \
+ SWAP(int, k[2], k[3]); \
+ } \
+ if (k[0] > k[2]) { \
+ SWAP(int, k[0], k[2]); \
+ SWAP(int, k[1], k[3]); \
+ } \
+} (void)0
+
+ KEY_SET(k_arr[IX_EDGE_TRI], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), t_index, -1);
+ /* need to order here */
+ KEY_SET(k_arr[IX_EDGE_TRI_EDGE0], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[0], ti[1]);
+ KEY_SET(k_arr[IX_EDGE_TRI_EDGE1], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[1], ti[2]);
+ KEY_SET(k_arr[IX_EDGE_TRI_EDGE2], BM_elem_index_get(e_v0), BM_elem_index_get(e_v1), ti[2], ti[0]);
+
+ KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE0]);
+ KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE1]);
+ KEY_EDGE_TRI_ORDER(k_arr[IX_EDGE_TRI_EDGE2]);
+
+#undef KEY_SET
+#undef KEY_EDGE_TRI_ORDER
+
+
+
+ for (i = 0; i < ARRAY_SIZE(k_arr); i++) {
+ BMVert *iv;
+
+ iv = BLI_ghash_lookup(s->edgetri_cache, k_arr[i]);
+
+ if (iv) {
+#ifdef USE_DUMP
+ printf("# cache hit (%d, %d, %d, %d)\n", UNPACK4(k_arr[i]));
+#endif
+ *r_side = (enum ISectType)i;
+ return iv;
+ }
+ }
+
+ *r_side = intersect_line_tri(e_v0->co, e_v1->co, t_cos, t_nor, ix, &s->epsilon);
+ if (*r_side != IX_NONE) {
+ BMVert *iv;
+ BMEdge *e;
+#ifdef USE_DUMP
+ printf("# new vertex (%.6f, %.6f, %.6f) %d\n", UNPACK3(ix), *r_side);
+#endif
+
+#ifdef USE_PARANOID
+ BLI_assert(len_squared_v3v3(ix, e_v0->co) > s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(ix, e_v1->co) > s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(ix, t[0]->co) > s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(ix, t[1]->co) > s->epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(ix, t[2]->co) > s->epsilon.eps_sq);
+#endif
+ iv = BM_vert_create(bm, ix, NULL, 0);
+
+ e = BM_edge_exists(e_v0, e_v1);
+ if (e) {
+#ifdef USE_DUMP
+ printf("# adding to edge %d\n", BM_elem_index_get(e));
+#endif
+ edge_verts_add(s, e, iv, false);
+ }
+ else {
+#ifdef USE_DISSOLVE
+ vert_dissolve_add(s, iv);
+#endif
+ }
+
+ if ((*r_side >= IX_EDGE_TRI_EDGE0) && (*r_side <= IX_EDGE_TRI_EDGE2)) {
+ i = (unsigned int)(*r_side - IX_EDGE_TRI_EDGE0);
+ e = BM_edge_exists(t[i], t[(i + 1) % 3]);
+ if (e) {
+ edge_verts_add(s, e, iv, false);
+ }
+ }
+
+ {
+ int *k = BLI_memarena_alloc(s->mem_arena, sizeof(int[4]));
+ memcpy(k, k_arr[*r_side], sizeof(int[4]));
+ BLI_ghash_insert(s->edgetri_cache, k, iv);
+ }
+
+ return iv;
+
+ }
+
+ *r_side = IX_NONE;
+
+ return NULL;
+}
+
+/**
+ * Return true if we have any intersections.
+ */
+static void bm_isect_tri_tri(
+ struct ISectState *s,
+ int a_index, int b_index,
+ BMLoop **a, BMLoop **b)
+{
+ BMFace *f_a = (*a)->f;
+ BMFace *f_b = (*b)->f;
+ BMVert *fv_a[3] = {UNPACK3_EX(, a, ->v)};
+ BMVert *fv_b[3] = {UNPACK3_EX(, b, ->v)};
+ const float *f_a_cos[3] = {UNPACK3_EX(, fv_a, ->co)};
+ const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)};
+ float f_a_nor[3];
+ float f_b_nor[3];
+ int a_mask = 0;
+ int b_mask = 0;
+ unsigned int i;
+
+
+ /* should be enough but may need to bump */
+ BMVert *iv_ls_a[8];
+ BMVert *iv_ls_b[8];
+ STACK_DECLARE(iv_ls_a);
+ STACK_DECLARE(iv_ls_b);
+
+ if (UNLIKELY(ELEM(fv_a[0], UNPACK3(fv_b)) ||
+ ELEM(fv_a[1], UNPACK3(fv_b)) ||
+ ELEM(fv_a[2], UNPACK3(fv_b))))
+ {
+ return;
+ }
+
+ STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a));
+ STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b));
+
+ /* vert-vert
+ * --------- */
+ {
+ /* first check in any verts are touching
+ * (any case where we wont create new verts)
+ */
+ unsigned int i_a;
+ for (i_a = 0; i_a < 3; i_a++) {
+ unsigned int i_b;
+ for (i_b = 0; i_b < 3; i_b++) {
+ if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
+ if (!((1 << i_a) & a_mask)) {
+ STACK_PUSH(iv_ls_a, fv_a[i_a]);
+ a_mask |= (1 << i_a);
+#ifdef USE_DUMP
+ printf(" ('VERT-VERT-A') %d, %d),\n",
+ i_a, BM_elem_index_get(fv_a[i_a]));
+#endif
+ }
+ if (!((1 << i_b) & b_mask)) {
+ STACK_PUSH(iv_ls_b, fv_b[i_b]);
+ b_mask |= (1 << i_b);
+#ifdef USE_DUMP
+ printf(" ('VERT-VERT-B') %d, %d),\n",
+ i_b, BM_elem_index_get(fv_b[i_b]));
+#endif
+ }
+ }
+ }
+ }
+ }
+
+ /* vert-edge
+ * --------- */
+ {
+ unsigned int i_a;
+ for (i_a = 0; i_a < 3; i_a++) {
+ if (!((1 << i_a) & a_mask)) {
+ unsigned int i_b_e0;
+ for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) {
+ unsigned int i_b_e1 = (i_b_e0 + 1) % 3;
+ float fac;
+ if (((1 << i_b_e0) | (1 << i_b_e1)) & b_mask)
+ continue;
+ fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co);
+ if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0 + s->epsilon.eps)) {
+ float ix[3];
+ interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac);
+ if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
+ BMEdge *e;
+ STACK_PUSH(iv_ls_b, fv_a[i_a]);
+ // STACK_PUSH(iv_ls_a, fv_a[i_a]);
+ a_mask |= (1 << i_a);
+ e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]);
+#ifdef USE_DUMP
+ printf(" ('VERT-EDGE-A', %d, %d),\n",
+ BM_elem_index_get(fv_b[i_b_e0]), BM_elem_index_get(fv_b[i_b_e1]));
+#endif
+ if (e) {
+#ifdef USE_DUMP
+ printf("# adding to edge %d\n", BM_elem_index_get(e));
+#endif
+ edge_verts_add(s, e, fv_a[i_a], true);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ {
+ unsigned int i_b;
+ for (i_b = 0; i_b < 3; i_b++) {
+ if (!((1 << i_b) & b_mask)) {
+ unsigned int i_a_e0;
+ for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) {
+ unsigned int i_a_e1 = (i_a_e0 + 1) % 3;
+ float fac;
+ if (((1 << i_a_e0) | (1 << i_a_e1)) & a_mask)
+ continue;
+ fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co);
+ if ((fac > 0.0 - s->epsilon.eps) && (fac < 1.0 + s->epsilon.eps)) {
+ float ix[3];
+ interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac);
+ if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
+ BMEdge *e;
+ STACK_PUSH(iv_ls_a, fv_b[i_b]);
+ // STACK_PUSH(iv_ls_b, fv_b[i_b]);
+ b_mask |= (1 << i_b);
+ e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]);
+#ifdef USE_DUMP
+ printf(" ('VERT-EDGE-B', %d, %d),\n",
+ BM_elem_index_get(fv_a[i_a_e0]), BM_elem_index_get(fv_a[i_a_e1]));
+#endif
+ if (e) {
+#ifdef USE_DUMP
+ printf(" adding to edge %d\n", BM_elem_index_get(e));
+#endif
+ edge_verts_add(s, e, fv_b[i_b], true);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* vert-tri
+ * -------- */
+ {
+
+ float t_scale[3][3];
+ unsigned int i_a;
+
+ copy_v3_v3(t_scale[0], fv_b[0]->co);
+ copy_v3_v3(t_scale[1], fv_b[1]->co);
+ copy_v3_v3(t_scale[2], fv_b[2]->co);
+ tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
+
+ // second check for verts intersecting the triangle
+ for (i_a = 0; i_a < 3; i_a++) {
+ float ix[3];
+ if ((1 << i_a) & a_mask)
+ continue;
+ if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) {
+ if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
+ BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1);
+ BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1);
+
+ STACK_PUSH(iv_ls_a, fv_a[i_a]);
+ STACK_PUSH(iv_ls_b, fv_a[i_a]);
+ a_mask |= (1 << i_a);
+#ifdef USE_DUMP
+ printf(" 'VERT TRI-A',\n");
+#endif
+ }
+ }
+ }
+ }
+
+ {
+ float t_scale[3][3];
+ unsigned int i_b;
+
+ copy_v3_v3(t_scale[0], fv_a[0]->co);
+ copy_v3_v3(t_scale[1], fv_a[1]->co);
+ copy_v3_v3(t_scale[2], fv_a[2]->co);
+ tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x);
+
+ for (i_b = 0; i_b < 3; i_b++) {
+ float ix[3];
+ if ((1 << i_b) & b_mask)
+ continue;
+
+ if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) {
+ if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
+ BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1);
+ BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1);
+
+ STACK_PUSH(iv_ls_a, fv_b[i_b]);
+ STACK_PUSH(iv_ls_b, fv_b[i_b]);
+ b_mask |= (1 << i_b);
+#ifdef USE_DUMP
+ printf(" 'VERT TRI-B',\n");
+#endif
+ }
+ }
+ }
+ }
+
+ if ((STACK_SIZE(iv_ls_a) >= 3) &&
+ (STACK_SIZE(iv_ls_b) >= 3))
+ {
+#ifdef USE_DUMP
+ printf("# OVERLAP\n");
+#endif
+ return;
+ }
+
+ normal_tri_v3(f_a_nor, UNPACK3(f_a_cos));
+ normal_tri_v3(f_b_nor, UNPACK3(f_b_cos));
+
+ /* edge-tri & edge-edge
+ * -------------------- */
+ {
+ unsigned int i_e0;
+ for (i_e0 = 0; i_e0 < 3; i_e0++) {
+ unsigned int i_e1 = (i_e0 + 1) % 3;
+ enum ISectType side;
+ BMVert *iv;
+ if (((1 << i_e0) | (1 << i_e1)) & a_mask)
+ continue;
+ iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side);
+ if (iv) {
+ BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
+ BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
+ STACK_PUSH(iv_ls_a, iv);
+ STACK_PUSH(iv_ls_b, iv);
+#ifdef USE_DUMP
+ printf(" ('EDGE-TRI-A', %d),\n", side);
+#endif
+ }
+ }
+
+ for (i_e0 = 0; i_e0 < 3; i_e0++) {
+ unsigned int i_e1 = (i_e0 + 1) % 3;
+ enum ISectType side;
+ BMVert *iv;
+ if (((1 << i_e0) | (1 << i_e1)) & b_mask)
+ continue;
+ iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side);
+ if (iv) {
+ /* check this wasn't handled above */
+ if (!(side >= IX_EDGE_TRI_EDGE0 && side <= IX_EDGE_TRI_EDGE2)) {
+ BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1);
+ BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1);
+ STACK_PUSH(iv_ls_a, iv);
+ STACK_PUSH(iv_ls_b, iv);
+#ifdef USE_DUMP
+ printf(" ('EDGE-RAY-B', %d),\n", side);
+#endif
+ }
+ }
+ }
+ }
+
+ {
+ for (i = 0; i < 2; i++) {
+ BMVert **ie_vs;
+ BMFace *f;
+ bool ie_exists;
+ BMEdge *ie;
+
+ if (i == 0) {
+ if (STACK_SIZE(iv_ls_a) != 2)
+ continue;
+ ie_vs = iv_ls_a;
+ f = f_a;
+ }
+ else {
+ if (STACK_SIZE(iv_ls_b) != 2)
+ continue;
+ ie_vs = iv_ls_b;
+ f = f_b;
+ }
+
+ /* possible but unlikely we get this - for edge-edge intersection */
+ ie = BM_edge_exists(UNPACK2(ie_vs));
+ if (ie == NULL) {
+ ie_exists = false;
+ /* one of the verts must be new if we are making an edge
+ * ...no, we need this in case 2x quads intersect at either ends.
+ * if not (ie_vs[0].index == -1 or ie_vs[1].index == -1):
+ * continue */
+ ie = BM_edge_create(s->bm, UNPACK2(ie_vs), NULL, 0);
+ BLI_gset_insert(s->wire_edges, ie);
+ }
+ else {
+ ie_exists = true;
+ /* may already exist */
+ BLI_gset_add(s->wire_edges, ie);
+
+ if (BM_edge_in_face(ie, f)) {
+ continue;
+ }
+ }
+
+ face_edges_add(s, BM_elem_index_get(f), ie, ie_exists);
+ // BLI_assert(len(ie_vs) <= 2)
+ }
+ }
+}
+
+/**
+ * Intersect tessellated faces
+ * leaving the resulting edges tagged.
+ *
+ * \param test_fn Return value: -1: skip, 0: tree_a, 1: tree_b (use_self == false)
+ */
+bool BM_mesh_intersect(
+ BMesh *bm,
+ struct BMLoop *(*looptris)[3], const int looptris_tot,
+ int (*test_fn)(BMFace *f, void *user_data), void *user_data,
+ const bool use_self, const bool use_separate,
+ const float eps)
+{
+ struct ISectState s;
+ bool has_isect;
+ const int totface_orig = bm->totface;
+
+#ifdef USE_BVH
+ BVHTree *tree_a, *tree_b;
+ unsigned int tree_overlap_tot;
+ BVHTreeOverlap *overlap;
+#else
+ int i_a, i_b;
+#endif
+
+ s.bm = bm;
+
+ 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.wire_edges = BLI_gset_ptr_new(__func__);
+ s.vert_dissolve = NULL;
+
+ s.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+
+ /* setup epsilon from base */
+ s.epsilon.eps = eps;
+ s.epsilon.eps2x = eps * 2.0f;
+ s.epsilon.eps_margin = s.epsilon.eps2x * 10.0f;
+
+ s.epsilon.eps_sq = s.epsilon.eps * s.epsilon.eps;
+ s.epsilon.eps2x_sq = s.epsilon.eps2x * s.epsilon.eps2x;
+ s.epsilon.eps_margin_sq = s.epsilon.eps_margin * s.epsilon.eps_margin;
+
+ BM_mesh_elem_index_ensure(
+ bm,
+ BM_VERT |
+ BM_EDGE |
+#ifdef USE_NET
+ BM_FACE |
+#endif
+ 0);
+
+
+ BM_mesh_elem_table_ensure(
+ bm,
+#ifdef USE_SPLICE
+ BM_EDGE |
+#endif
+#ifdef USE_NET
+ BM_FACE |
+#endif
+ 0);
+
+#ifdef USE_DISSOLVE
+ BM_mesh_elem_hflag_disable_all(bm, BM_EDGE | BM_VERT, BM_ELEM_TAG, false);
+#endif
+
+#ifdef USE_DUMP
+ printf("data = [\n");
+#endif
+
+#ifdef USE_BVH
+ {
+ int i;
+ tree_a = BLI_bvhtree_new(looptris_tot, s.epsilon.eps_margin, 8, 8);
+ for (i = 0; i < looptris_tot; i++) {
+ if (test_fn(looptris[i][0]->f, user_data) == 0) {
+ const float t_cos[3][3] = {
+ {UNPACK3(looptris[i][0]->v->co)},
+ {UNPACK3(looptris[i][1]->v->co)},
+ {UNPACK3(looptris[i][2]->v->co)},
+ };
+
+ BLI_bvhtree_insert(tree_a, i, (float *)t_cos, 3);
+ }
+ }
+ BLI_bvhtree_balance(tree_a);
+ }
+
+ if (use_self == false) {
+ int i;
+ tree_b = BLI_bvhtree_new(looptris_tot, s.epsilon.eps_margin, 8, 8);
+ for (i = 0; i < looptris_tot; i++) {
+ if (test_fn(looptris[i][0]->f, user_data) == 1) {
+ const float t_cos[3][3] = {
+ {UNPACK3(looptris[i][0]->v->co)},
+ {UNPACK3(looptris[i][1]->v->co)},
+ {UNPACK3(looptris[i][2]->v->co)},
+ };
+
+ BLI_bvhtree_insert(tree_b, i, (float *)t_cos, 3);
+ }
+ }
+ BLI_bvhtree_balance(tree_b);
+ }
+ else {
+ tree_b = tree_a;
+ }
+
+ overlap = BLI_bvhtree_overlap(tree_b, tree_a, &tree_overlap_tot);
+
+ if (overlap) {
+ unsigned int i;
+
+ for (i = 0; i < tree_overlap_tot; i++) {
+#ifdef USE_DUMP
+ printf(" ((%d, %d), (\n",
+ overlap[i].indexA,
+ overlap[i].indexB);
+#endif
+ bm_isect_tri_tri(
+ &s,
+ overlap[i].indexA,
+ overlap[i].indexB,
+ looptris[overlap[i].indexA],
+ looptris[overlap[i].indexB]);
+#ifdef USE_DUMP
+ printf(")),\n");
+#endif
+ }
+ MEM_freeN(overlap);
+ }
+ BLI_bvhtree_free(tree_a);
+ if (tree_a != tree_b) {
+ BLI_bvhtree_free(tree_b);
+ }
+
+#else
+ {
+ for (i_a = 0; i_a < looptris_tot; i_a++) {
+ const int t_a = test_fn(looptris[i_a][0]->f, user_data);
+ for (i_b = i_a + 1; i_b < looptris_tot; i_b++) {
+ const int t_b = test_fn(looptris[i_b][0]->f, user_data);
+
+ if (use_self) {
+ if ((t_a != 0) || (t_b != 0)) {
+ continue;
+ }
+ }
+ else {
+ if ((t_a != t_b) && !ELEM(-1, t_a, t_b)) {
+ continue;
+ }
+ }
+
+#ifdef USE_DUMP
+ printf(" ((%d, %d), (",
+ i_a, i_b);
+#endif
+ bm_isect_tri_tri(
+ &s,
+ i_a,
+ i_b,
+ looptris[i_a],
+ looptris[i_b]);
+#ifdef USE_DUMP
+ printf(")),\n");
+#endif
+ }
+ }
+ }
+#endif /* USE_BVH */
+
+#ifdef USE_DUMP
+ printf("]\n");
+#endif
+
+ /* --------- */
+
+#ifdef USE_SPLICE
+ {
+ GHashIterator gh_iter;
+
+ GHASH_ITER (gh_iter, s.edge_verts) {
+ BMEdge *e = BLI_ghashIterator_getKey(&gh_iter);
+ struct LinkBase *v_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+
+ BMVert *v_start;
+ BMVert *v_end;
+ BMVert *v_prev;
+ bool is_wire;
+
+ LinkNode *node;
+
+ /* direction is arbitrary, could be swapped */
+ v_start = e->v1;
+ v_end = e->v2;
+
+ if (v_ls_base->list_len > 1) {
+ edge_verts_sort(v_start->co, v_ls_base);
+ }
+
+#ifdef USE_DUMP
+ printf("# SPLITTING EDGE: %d, %d\n", e_index, v_ls_base->list_len);
+#endif
+ /* intersect */
+ is_wire = BLI_gset_haskey(s.wire_edges, e);
+
+#ifdef USE_PARANOID
+ for (node = v_ls_base->list; node; node = node->next) {
+ BMVert *_v = node->link;
+ BLI_assert(len_squared_v3v3(_v->co, e->v1->co) > s.epsilon.eps_sq);
+ BLI_assert(len_squared_v3v3(_v->co, e->v2->co) > s.epsilon.eps_sq);
+ }
+#endif
+
+ v_prev = v_start;
+
+ for (node = v_ls_base->list; node; node = node->next) {
+ BMVert *vi = node->link;
+ const float fac = line_point_factor_v3(vi->co, e->v1->co, e->v2->co);
+
+ if (BM_vert_in_edge(e, v_prev)) {
+ v_prev = BM_edge_split(bm, e, v_prev, NULL, CLAMPIS(fac, 0.0f, 1.0f));
+ BLI_assert( BM_vert_in_edge(e, v_end));
+
+ if (!BM_edge_exists(v_prev, vi) &&
+ !BM_vert_splice_check_double(v_prev, vi) &&
+ !BM_vert_pair_share_face_check(v_prev, vi))
+ {
+ BM_vert_splice(bm, v_prev, vi);
+ }
+ else {
+ copy_v3_v3(v_prev->co, vi->co);
+ }
+ v_prev = vi;
+ if (is_wire) {
+ BLI_gset_insert(s.wire_edges, e);
+ }
+ }
+ }
+ }
+ }
+#endif
+
+
+ /* important to handle before edgenet */
+#ifdef USE_DISSOLVE
+ {
+ /* first pass */
+ BMVert *(*splice_ls)[2];
+ STACK_DECLARE(splice_ls);
+ LinkNode *node;
+
+
+ for (node = s.vert_dissolve; node; node = node->next) {
+ BMVert *v = node->link;
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ if (!BM_vert_is_edge_pair(v)) {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+ }
+ }
+
+ 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));
+
+ for (node = s.vert_dissolve; node; node = node->next) {
+ BMEdge *e_pair[2];
+ BMVert *v = node->link;
+ BMVert *v_a, *v_b;
+
+ if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ continue;
+ }
+
+ /* get chain */
+ e_pair[0] = v->e;
+ e_pair[1] = BM_DISK_EDGE_NEXT(v->e, v);
+
+ if (BM_elem_flag_test(e_pair[0], BM_ELEM_TAG) ||
+ BM_elem_flag_test(e_pair[1], BM_ELEM_TAG))
+ {
+ continue;
+ }
+
+ v_a = BM_edge_other_vert(e_pair[0], v);
+ v_b = BM_edge_other_vert(e_pair[1], v);
+
+ /* simple case */
+ if (BM_elem_flag_test(v_a, BM_ELEM_TAG) &&
+ BM_elem_flag_test(v_b, BM_ELEM_TAG))
+ {
+ /* only start on an edge-case */
+ /* pass */
+ }
+ else if ((!BM_elem_flag_test(v_a, BM_ELEM_TAG)) &&
+ (!BM_elem_flag_test(v_b, BM_ELEM_TAG)))
+ {
+ /* simple case, single edge spans face */
+ BMVert **splice_pair;
+ BM_elem_flag_enable(e_pair[1], BM_ELEM_TAG);
+ splice_pair = STACK_PUSH_RET(splice_ls);
+ splice_pair[0] = v;
+ splice_pair[1] = v_b;
+#ifdef USE_DUMP
+ printf("# Simple Case!\n");
+#endif
+ }
+ else {
+#ifdef USE_PARANOID
+ BMEdge *e_keep;
+#endif
+ BMEdge *e;
+ BMEdge *e_step;
+ BMVert *v_step;
+
+ /* walk the chain! */
+ if (BM_elem_flag_test(v_a, BM_ELEM_TAG)) {
+ e = e_pair[0];
+#ifdef USE_PARANOID
+ e_keep = e_pair[1];
+#endif
+ }
+ else {
+ SWAP(BMVert *, v_a, v_b);
+ e = e_pair[1];
+#ifdef USE_PARANOID
+ e_keep = e_pair[0];
+#endif
+ }
+
+ /* WALK */
+ v_step = v;
+ e_step = e;
+
+ while (true) {
+ BMEdge *e_next;
+ BMVert *v_next;
+
+ v_next = BM_edge_other_vert(e_step, v_step);
+ BM_elem_flag_enable(e_step, BM_ELEM_TAG);
+ if (!BM_elem_flag_test(v_next, BM_ELEM_TAG)) {
+ BMVert **splice_pair;
+#ifdef USE_PARANOID
+ BLI_assert(e_step != e_keep);
+#endif
+ splice_pair = STACK_PUSH_RET(splice_ls);
+ splice_pair[0] = v;
+ splice_pair[1] = v_next;
+ break;
+ }
+ else {
+ e_next = bm_vert_other_edge(v_next, e_step);
+ }
+
+ e_step = e_next;
+ v_step = v_next;
+ BM_elem_flag_enable(e_step, BM_ELEM_TAG);
+#ifdef USE_PARANOID
+ BLI_assert(e_step != e_keep);
+#endif
+#ifdef USE_DUMP
+ printf("# walk step %p %p\n", e_next, v_next);
+#endif
+ }
+#ifdef USE_PARANOID
+ BLI_assert(BM_elem_flag_test(e_keep, BM_ELEM_TAG) == 0);
+#endif
+ }
+ }
+
+ /* Remove edges! */
+ {
+ GHashIterator gh_iter;
+
+ GHASH_ITER (gh_iter, s.face_edges) {
+ struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+ LinkNode **node_prev_p;
+ unsigned int i;
+
+ node_prev_p = &e_ls_base->list;
+ for (i = 0, node = e_ls_base->list; node; i++, node = node->next) {
+ BMEdge *e = node->link;
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ /* allocated by arena, don't free */
+ *node_prev_p = node->next;
+ e_ls_base->list_len--;
+ }
+ else {
+ node_prev_p = &node->next;
+ }
+ }
+ }
+ }
+
+ {
+ BMIter eiter;
+ BMEdge *e, *e_next;
+
+ BM_ITER_MESH_MUTABLE (e, e_next, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+
+ /* in rare and annoying cases,
+ * there can be faces from 's.face_edges' removed by the edges.
+ * These are degenerate cases, so just make sure we don't reference the faces again. */
+ if (e->l) {
+ BMLoop *l_iter = e->l;
+ BMFace **faces;
+
+ faces = bm->ftable;
+
+ do {
+ const int f_index = BM_elem_index_get(l_iter->f);
+ if (f_index >= 0) {
+ BLI_assert(f_index < totface_orig);
+ /* we could check if these are in: 's.face_edges', but easier just to remove */
+ faces[f_index] = NULL;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+
+ BLI_gset_remove(s.wire_edges, e, NULL);
+ BM_edge_kill(bm, e);
+ }
+ }
+ }
+
+ /* Remove verts! */
+ {
+ GSet *verts_invalid = BLI_gset_ptr_new(__func__);
+
+ for (node = s.vert_dissolve; node; node = node->next) {
+ /* arena allocated, don't free */
+ BMVert *v = node->link;
+ if (BM_elem_flag_test(v, BM_ELEM_TAG)) {
+ if (!v->e) {
+ BLI_gset_add(verts_invalid, v);
+ BM_vert_kill(bm, v);
+ }
+ }
+ }
+
+ {
+ unsigned int i;
+ for (i = 0; i < STACK_SIZE(splice_ls); i++) {
+ if (!BLI_gset_haskey(verts_invalid, splice_ls[i][0]) &&
+ !BLI_gset_haskey(verts_invalid, splice_ls[i][1]))
+ {
+ 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]));
+ }
+ }
+ }
+ }
+
+ BLI_gset_free(verts_invalid, NULL);
+ }
+
+ MEM_freeN(splice_ls);
+ }
+#endif /* USE_DISSOLVE */
+
+
+ /* now split faces */
+#ifdef USE_NET
+ {
+ GHashIterator gh_iter;
+ BMFace **faces;
+
+ faces = bm->ftable;
+
+ GHASH_ITER (gh_iter, s.face_edges) {
+ const int f_index = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
+ BMFace *f;
+ struct LinkBase *e_ls_base = BLI_ghashIterator_getValue(&gh_iter);
+
+ BLI_assert(f_index >= 0 && f_index < totface_orig);
+
+ f = faces[f_index];
+ if (UNLIKELY(f == NULL)) {
+ continue;
+ }
+
+ BLI_assert(BM_elem_index_get(f) == f_index);
+
+ face_edges_split(bm, f, e_ls_base);
+ }
+ }
+#else
+ (void)totface_orig;
+#endif /* USE_NET */
+
+
+#ifdef USE_SEPARATE
+ if (use_separate) {
+ GSetIterator gs_iter;
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_EDGE, BM_ELEM_TAG, false);
+
+ GSET_ITER (gs_iter, s.wire_edges) {
+ BMEdge *e = BLI_gsetIterator_getKey(&gs_iter);
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+
+ BM_mesh_edgesplit(bm, false, true, false);
+ }
+#else
+ (void)use_separate;
+#endif /* USE_SEPARATE */
+
+ has_isect = (BLI_ghash_size(s.face_edges) != 0);
+
+ /* cleanup */
+ BLI_ghash_free(s.edgetri_cache, NULL, NULL);
+
+ BLI_ghash_free(s.edge_verts, NULL, NULL);
+ BLI_ghash_free(s.face_edges, NULL, NULL);
+ BLI_gset_free(s.wire_edges, NULL);
+
+ BLI_memarena_free(s.mem_arena);
+
+ return has_isect;
+}
diff --git a/source/blender/bmesh/tools/bmesh_intersect.h b/source/blender/bmesh/tools/bmesh_intersect.h
new file mode 100644
index 00000000000..af6e510a8f6
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_intersect.h
@@ -0,0 +1,35 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_INTERSECT_H__
+#define __BMESH_INTERSECT_H__
+
+/** \file blender/bmesh/tools/bmesh_intersect.h
+ * \ingroup bmesh
+ */
+
+bool BM_mesh_intersect(
+ BMesh *bm,
+ struct BMLoop *(*looptris)[3], const int looptris_tot,
+ int (*test_fn)(BMFace *f, void *user_data), void *user_data,
+ const bool use_self, const bool use_separate,
+ const float eps);
+
+#endif /* __BMESH_INTERSECT_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_region_match.c b/source/blender/bmesh/tools/bmesh_region_match.c
new file mode 100644
index 00000000000..050d5ae4808
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_region_match.c
@@ -0,0 +1,1511 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/tools/bmesh_region_match.c
+ * \ingroup bmesh
+ *
+ * Given a contiguous region of faces,
+ * find multiple matching regions (based on topology) and return them.
+ *
+ * Implementation:
+ *
+ * - Given a face region, find its topological center.
+ * - Compare this with other vertices surrounding geometry with this ones.
+ * (reduce the search space by creating a connectivity ID per vertex
+ * and only run comprehensive tests on those).
+ * - All hashes must be order independent so matching topology can be identified.
+ * - The term UUID here doesn't mean each ID is initially unique.
+ * (uniqueness is improved by re-hashing with connected data).
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+#include "BLI_listbase.h"
+#include "BLI_linklist.h"
+#include "BLI_alloca.h"
+#include "BLI_ghash.h"
+#include "BLI_mempool.h"
+#include "BLI_linklist_stack.h"
+
+#include "bmesh.h"
+
+#include "tools/bmesh_region_match.h" /* own incldue */
+
+/* avoid re-creating ghash and pools for each search */
+#define USE_WALKER_REUSE
+
+/* do a first-pass id of all vertices,
+ * this avoids expensive checks on every item later on
+ * (works fine without, just slower) */
+#define USE_PIVOT_FASTMATCH
+
+/* otherwise use active element as pivot, for quick tests only */
+#define USE_PIVOT_SEARCH
+
+// #define DEBUG_TIME
+// #define DEBUG_PRINT
+
+#ifdef DEBUG_TIME
+# include "PIL_time.h"
+# include "PIL_time_utildefines.h"
+#endif
+
+#include "BLI_strict_flags.h"
+
+
+/* -------------------------------------------------------------------- */
+/* UUID-Walk API */
+
+/** \name Internal UUIDWalk API
+ * \{ */
+
+#define PRIME_VERT_INIT 100003
+
+typedef uintptr_t UUID_Int;
+
+typedef struct UUIDWalk {
+
+ /* List of faces we can step onto (UUIDFaceStep's) */
+ ListBase faces_step;
+
+ /* Face & Vert UUID's */
+ GHash *verts_uuid;
+ GHash *faces_uuid;
+
+ /* memory pool for LinkNode's */
+ BLI_mempool *link_pool;
+
+ /* memory pool for LinkBase's */
+ BLI_mempool *lbase_pool;
+
+ /* memory pool for UUIDFaceStep's */
+ BLI_mempool *step_pool;
+ BLI_mempool *step_pool_items;
+
+ /* Optionaly use face-tag to isolate search */
+ bool use_face_isolate;
+
+ /* Increment for each pass added */
+ UUID_Int pass;
+
+ /* runtime vars, aviod re-creating each pass */
+ struct {
+ GHash *verts_uuid; /* BMVert -> UUID */
+ GSet *faces_step; /* BMFace */
+
+ GHash *faces_from_uuid; /* UUID -> UUIDFaceStepItem */
+
+ UUID_Int *rehash_store;
+ unsigned int rehash_store_len;
+ } cache;
+
+} UUIDWalk;
+
+/* stores a set of potential faces to step onto */
+typedef struct UUIDFaceStep {
+ struct UUIDFaceStep *next, *prev;
+
+ /* unsorted 'BMFace' */
+ LinkNode *faces;
+
+ /* faces sorted into 'UUIDFaceStepItem' */
+ ListBase items;
+} UUIDFaceStep;
+
+/* store face-lists with same uuid */
+typedef struct UUIDFaceStepItem {
+ struct UUIDFaceStepItem *next, *prev;
+ uintptr_t uuid;
+
+ LinkNode *list;
+ unsigned int list_len;
+} UUIDFaceStepItem;
+
+BLI_INLINE bool bm_uuidwalk_face_test(
+ UUIDWalk *uuidwalk, BMFace *f)
+{
+ if (uuidwalk->use_face_isolate) {
+ return BM_elem_flag_test_bool(f, BM_ELEM_TAG);
+ }
+ else {
+ return true;
+ }
+}
+
+BLI_INLINE bool bm_uuidwalk_vert_lookup(
+ UUIDWalk *uuidwalk, BMVert *v, UUID_Int *r_uuid)
+{
+ void **ret;
+ ret = BLI_ghash_lookup_p(uuidwalk->verts_uuid, v);
+ if (ret) {
+ *r_uuid = (UUID_Int)(*ret);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+BLI_INLINE bool bm_uuidwalk_face_lookup(
+ UUIDWalk *uuidwalk, BMFace *f, UUID_Int *r_uuid)
+{
+ void **ret;
+ ret = BLI_ghash_lookup_p(uuidwalk->faces_uuid, f);
+ if (ret) {
+ *r_uuid = (UUID_Int)(*ret);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+static unsigned int ghashutil_bmelem_indexhash(const void *key)
+{
+ const BMElem *ele = key;
+ return (unsigned int)BM_elem_index_get(ele);
+}
+
+static bool ghashutil_bmelem_indexcmp(const void *a, const void *b)
+{
+ BLI_assert((a != b) == (BM_elem_index_get((BMElem *)a) != BM_elem_index_get((BMElem *)b)));
+ return (a != b);
+}
+
+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);
+}
+
+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);
+}
+
+
+static GHash *ghash_bmelem_new(const char *info)
+{
+ return ghash_bmelem_new_ex(info, 0);
+}
+
+static GSet *gset_bmelem_new(const char *info)
+{
+ return gset_bmelem_new_ex(info, 0);
+}
+
+
+static void bm_uuidwalk_init(
+ UUIDWalk *uuidwalk,
+ const unsigned int faces_src_region_len,
+ const unsigned int verts_src_region_len)
+{
+ BLI_listbase_clear(&uuidwalk->faces_step);
+
+ uuidwalk->verts_uuid = ghash_bmelem_new_ex(__func__, verts_src_region_len);
+ uuidwalk->faces_uuid = ghash_bmelem_new_ex(__func__, faces_src_region_len);
+
+ uuidwalk->cache.verts_uuid = ghash_bmelem_new(__func__);
+ uuidwalk->cache.faces_step = gset_bmelem_new(__func__);
+
+ /* works because 'int' ghash works for intptr_t too */
+ uuidwalk->cache.faces_from_uuid = BLI_ghash_int_new(__func__);
+
+ uuidwalk->cache.rehash_store = NULL;
+ uuidwalk->cache.rehash_store_len = 0;
+
+ uuidwalk->use_face_isolate = false;
+
+ /* smaller pool's for faster clearing */
+ uuidwalk->link_pool = BLI_mempool_create(sizeof(LinkNode), 64, 64, BLI_MEMPOOL_NOP);
+ uuidwalk->step_pool = BLI_mempool_create(sizeof(UUIDFaceStep), 64, 64, BLI_MEMPOOL_NOP);
+ uuidwalk->step_pool_items = BLI_mempool_create(sizeof(UUIDFaceStepItem), 64, 64, BLI_MEMPOOL_NOP);
+
+ uuidwalk->pass = 1;
+}
+
+static void bm_uuidwalk_clear(
+ UUIDWalk *uuidwalk)
+{
+ BLI_listbase_clear(&uuidwalk->faces_step);
+
+ BLI_ghash_clear(uuidwalk->verts_uuid, NULL, NULL);
+ BLI_ghash_clear(uuidwalk->faces_uuid, NULL, NULL);
+
+ BLI_ghash_clear(uuidwalk->cache.verts_uuid, NULL, NULL);
+ BLI_gset_clear(uuidwalk->cache.faces_step, NULL);
+ BLI_ghash_clear(uuidwalk->cache.faces_from_uuid, NULL, NULL);
+
+ /* keep rehash_store as-is, for reuse */
+
+ uuidwalk->use_face_isolate = false;
+
+ BLI_mempool_clear(uuidwalk->link_pool);
+ BLI_mempool_clear(uuidwalk->step_pool);
+ BLI_mempool_clear(uuidwalk->step_pool_items);
+
+ uuidwalk->pass = 1;
+}
+
+static void bm_uuidwalk_free(
+ UUIDWalk *uuidwalk)
+{
+ /**
+ * Handled by pools
+ *
+ * - uuidwalk->faces_step
+ */
+
+ BLI_ghash_free(uuidwalk->verts_uuid, NULL, NULL);
+ BLI_ghash_free(uuidwalk->faces_uuid, NULL, NULL);
+
+ /* cache */
+ BLI_ghash_free(uuidwalk->cache.verts_uuid, NULL, NULL);
+ BLI_gset_free(uuidwalk->cache.faces_step, NULL);
+ BLI_ghash_free(uuidwalk->cache.faces_from_uuid, NULL, NULL);
+ MEM_SAFE_FREE(uuidwalk->cache.rehash_store);
+
+ BLI_mempool_destroy(uuidwalk->link_pool);
+ BLI_mempool_destroy(uuidwalk->step_pool);
+ BLI_mempool_destroy(uuidwalk->step_pool_items);
+}
+
+static UUID_Int bm_uuidwalk_calc_vert_uuid(
+ UUIDWalk *uuidwalk, BMVert *v)
+{
+#define PRIME_VERT_SMALL 7
+#define PRIME_VERT_MID 43
+#define PRIME_VERT_LARGE 1031
+
+#define PRIME_FACE_SMALL 13
+#define PRIME_FACE_MID 53
+
+ UUID_Int uuid;
+
+ uuid = uuidwalk->pass * PRIME_VERT_LARGE;
+
+ /* vert -> other */
+ {
+ unsigned int tot = 0;
+ BMIter eiter;
+ BMEdge *e;
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ UUID_Int uuid_other;
+ if (bm_uuidwalk_vert_lookup(uuidwalk, v_other, &uuid_other)) {
+ uuid ^= (uuid_other * PRIME_VERT_SMALL);
+ tot += 1;
+ }
+ }
+ uuid ^= (tot * PRIME_VERT_MID);
+ }
+
+ /* faces */
+ {
+ unsigned int tot = 0;
+ BMIter iter;
+ BMFace *f;
+
+ BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
+ UUID_Int uuid_other;
+ if (bm_uuidwalk_face_lookup(uuidwalk, f, &uuid_other)) {
+ uuid ^= (uuid_other * PRIME_FACE_SMALL);
+ tot += 1;
+ }
+ }
+ uuid ^= (tot * PRIME_FACE_MID);
+ }
+
+ return uuid;
+
+#undef PRIME_VERT_SMALL
+#undef PRIME_VERT_MID
+#undef PRIME_VERT_LARGE
+
+#undef PRIME_FACE_SMALL
+#undef PRIME_FACE_MID
+}
+
+static UUID_Int bm_uuidwalk_calc_face_uuid(
+ UUIDWalk *uuidwalk, BMFace *f)
+{
+#define PRIME_VERT_SMALL 11
+
+#define PRIME_FACE_SMALL 17
+#define PRIME_FACE_LARGE 1013
+
+ UUID_Int uuid;
+
+ uuid = uuidwalk->pass * (unsigned int)f->len * PRIME_FACE_LARGE;
+
+ /* face-verts */
+ {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ UUID_Int uuid_other;
+ if (bm_uuidwalk_vert_lookup(uuidwalk, l_iter->v, &uuid_other)) {
+ uuid ^= (uuid_other * PRIME_VERT_SMALL);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ /* face-faces (connected by edge) */
+ {
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (l_iter->radial_next != l_iter) {
+ BMLoop *l_iter_radial = l_iter->radial_next;
+ do {
+ UUID_Int uuid_other;
+ if (bm_uuidwalk_face_lookup(uuidwalk, l_iter_radial->f, &uuid_other)) {
+ uuid ^= (uuid_other * PRIME_FACE_SMALL);
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ return uuid;
+
+#undef PRIME_VERT_SMALL
+
+#undef PRIME_FACE_SMALL
+#undef PRIME_FACE_LARGE
+}
+
+static void bm_uuidwalk_rehash_reserve(
+ UUIDWalk *uuidwalk, unsigned int rehash_store_len_new)
+{
+ if (UNLIKELY(rehash_store_len_new > uuidwalk->cache.rehash_store_len)) {
+ /* avoid re-allocs */
+ rehash_store_len_new *= 2;
+ uuidwalk->cache.rehash_store =
+ MEM_reallocN(uuidwalk->cache.rehash_store,
+ rehash_store_len_new * sizeof(*uuidwalk->cache.rehash_store));
+ uuidwalk->cache.rehash_store_len = rehash_store_len_new;
+ }
+}
+
+/**
+ * Re-hash all elements, delay updating so as not to create feedback loop.
+ */
+static void bm_uuidwalk_rehash(
+ UUIDWalk *uuidwalk)
+{
+ GHashIterator gh_iter;
+ 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));
+
+ bm_uuidwalk_rehash_reserve(uuidwalk, rehash_store_len_new);
+ uuid_store = uuidwalk->cache.rehash_store;
+
+ /* verts */
+ i = 0;
+ GHASH_ITER (gh_iter, uuidwalk->verts_uuid) {
+ BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
+ uuid_store[i++] = bm_uuidwalk_calc_vert_uuid(uuidwalk, v);
+ }
+ i = 0;
+ GHASH_ITER (gh_iter, uuidwalk->verts_uuid) {
+ void **uuid_p = BLI_ghashIterator_getValue_p(&gh_iter);
+ *((UUID_Int *)uuid_p) = uuid_store[i++];
+ }
+
+ /* faces */
+ i = 0;
+ GHASH_ITER (gh_iter, uuidwalk->faces_uuid) {
+ BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+ uuid_store[i++] = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
+ }
+ i = 0;
+ GHASH_ITER (gh_iter, uuidwalk->faces_uuid) {
+ void **uuid_p = BLI_ghashIterator_getValue_p(&gh_iter);
+ *((UUID_Int *)uuid_p) = uuid_store[i++];
+ }
+}
+
+static void bm_uuidwalk_rehash_facelinks(
+ UUIDWalk *uuidwalk,
+ LinkNode *faces, const unsigned int faces_len,
+ const bool is_init)
+{
+ UUID_Int *uuid_store;
+ LinkNode *f_link;
+ unsigned int i;
+
+ bm_uuidwalk_rehash_reserve(uuidwalk, faces_len);
+ uuid_store = uuidwalk->cache.rehash_store;
+
+ i = 0;
+ for (f_link = faces; f_link; f_link = f_link->next) {
+ BMFace *f = f_link->link;
+ uuid_store[i++] = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
+ }
+
+ i = 0;
+ if (is_init) {
+ for (f_link = faces; f_link; f_link = f_link->next) {
+ BMFace *f = f_link->link;
+ BLI_ghash_insert(uuidwalk->faces_uuid, f, (void *)uuid_store[i++]);
+ }
+ }
+ else {
+ for (f_link = faces; f_link; f_link = f_link->next) {
+ BMFace *f = f_link->link;
+ void **uuid_p = BLI_ghash_lookup_p(uuidwalk->faces_uuid, f);
+ *((UUID_Int *)uuid_p) = uuid_store[i++];
+ }
+ }
+}
+
+static bool bm_vert_is_uuid_connect(
+ UUIDWalk *uuidwalk, BMVert *v)
+{
+ BMIter eiter;
+ BMEdge *e;
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ if (BLI_ghash_haskey(uuidwalk->verts_uuid, v_other)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static void bm_uuidwalk_pass_add(
+ UUIDWalk *uuidwalk, LinkNode *faces_pass, const unsigned int faces_pass_len)
+{
+ GHashIterator gh_iter;
+ GHash *verts_uuid_pass;
+ GSet *faces_step_next;
+ LinkNode *f_link;
+
+ UUIDFaceStep *fstep;
+
+ BLI_assert(faces_pass_len == (unsigned int)BLI_linklist_length(faces_pass));
+
+ /* rehash faces now all their verts have been added */
+ bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, true);
+
+ /* create verts_new */
+ verts_uuid_pass = uuidwalk->cache.verts_uuid;
+ faces_step_next = uuidwalk->cache.faces_step;
+
+ BLI_assert(BLI_ghash_size(verts_uuid_pass) == 0);
+ BLI_assert(BLI_gset_size(faces_step_next) == 0);
+
+ /* Add the face_step data from connected faces, creating new passes */
+ fstep = BLI_mempool_alloc(uuidwalk->step_pool);
+ BLI_addhead(&uuidwalk->faces_step, fstep);
+ fstep->faces = NULL;
+ BLI_listbase_clear(&fstep->items);
+
+ for (f_link = faces_pass; f_link; f_link = f_link->next) {
+ BMFace *f = f_link->link;
+ BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ /* fill verts_new */
+ if (!BLI_ghash_haskey(uuidwalk->verts_uuid, l_iter->v) &&
+ !BLI_ghash_haskey(verts_uuid_pass, l_iter->v) &&
+ (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);
+ }
+
+ /* fill faces_step_next */
+ if (l_iter->radial_next != l_iter) {
+ BMLoop *l_iter_radial = l_iter->radial_next;
+ do {
+ if (!BLI_ghash_haskey(uuidwalk->faces_uuid, l_iter_radial->f) &&
+ !BLI_gset_haskey(faces_step_next, l_iter_radial->f) &&
+ (bm_uuidwalk_face_test(uuidwalk, l_iter_radial->f)))
+ {
+ BLI_gset_insert(faces_step_next, l_iter_radial->f);
+
+ /* add to fstep */
+ BLI_linklist_prepend_pool(&fstep->faces, l_iter_radial->f, uuidwalk->link_pool);
+ }
+ } while ((l_iter_radial = l_iter_radial->radial_next) != l_iter);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ /* faces_uuid.update(verts_new) */
+ GHASH_ITER (gh_iter, verts_uuid_pass) {
+ BMVert *v = BLI_ghashIterator_getKey(&gh_iter);
+ void *uuid_p = BLI_ghashIterator_getValue(&gh_iter);
+ BLI_ghash_insert(uuidwalk->verts_uuid, v, uuid_p);
+ }
+
+ /* rehash faces now all their verts have been added */
+ bm_uuidwalk_rehash_facelinks(uuidwalk, faces_pass, faces_pass_len, false);
+
+ uuidwalk->pass += 1;
+
+ BLI_ghash_clear(uuidwalk->cache.verts_uuid, NULL, NULL);
+ BLI_gset_clear(uuidwalk->cache.faces_step, NULL);
+}
+
+static int bm_face_len_cmp(const void *v1, const void *v2)
+{
+ const BMFace *f1 = v1, *f2 = v2;
+
+ if (f1->len > f2->len) return 1;
+ else if (f1->len < f2->len) return -1;
+ else return 0;
+}
+
+static unsigned int bm_uuidwalk_init_from_edge(
+ UUIDWalk *uuidwalk, BMEdge *e)
+{
+ BMLoop *l_iter = e->l;
+ unsigned int f_arr_len = (unsigned int)BM_edge_face_count(e);
+ BMFace **f_arr = BLI_array_alloca(f_arr, f_arr_len);
+ unsigned int fstep_num = 0, i = 0;
+
+ do {
+ BMFace *f = l_iter->f;
+ if (bm_uuidwalk_face_test(uuidwalk, f)) {
+ f_arr[i++] = f;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ BLI_assert(i <= f_arr_len);
+ f_arr_len = i;
+
+ qsort(f_arr, f_arr_len, sizeof(*f_arr), bm_face_len_cmp);
+
+ /* start us off! */
+ {
+ const UUID_Int uuid = PRIME_VERT_INIT;
+ BLI_ghash_insert(uuidwalk->verts_uuid, e->v1, (void *)uuid);
+ BLI_ghash_insert(uuidwalk->verts_uuid, e->v2, (void *)uuid);
+ }
+
+ /* 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++) {
+ LinkNode *faces_pass = NULL;
+ 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);
+ BLI_linklist_free_pool(faces_pass, NULL, uuidwalk->link_pool);
+ fstep_num += 1;
+ }
+
+ return fstep_num;
+}
+
+#undef PRIME_VERT_INIT
+
+/** \} */
+
+
+/** \name Internal UUIDFaceStep API
+ * \{ */
+
+static int facestep_sort(const void *a, const void *b)
+{
+ const UUIDFaceStepItem *fstep_a = a;
+ const UUIDFaceStepItem *fstep_b = b;
+ return (fstep_a->uuid > fstep_b->uuid) ? 1 : 0;
+}
+
+/**
+ * Put faces in lists based on their uuid's,
+ * re-run for each pass since rehashing may differentiate face-groups.
+ */
+static bool bm_uuidwalk_facestep_begin(
+ UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
+{
+ LinkNode *f_link, *f_link_next, **f_link_prev_p;
+ bool ok = false;
+
+ BLI_assert(BLI_ghash_size(uuidwalk->cache.faces_from_uuid) == 0);
+ BLI_assert(BLI_countlist(&fstep->items) == 0);
+
+ f_link_prev_p = &fstep->faces;
+ for (f_link = fstep->faces; f_link; f_link = f_link_next) {
+ BMFace *f = f_link->link;
+ f_link_next = f_link->next;
+
+ /* possible another pass added this face already, free in that case */
+ if (!BLI_ghash_haskey(uuidwalk->faces_uuid, f)) {
+ const UUID_Int uuid = bm_uuidwalk_calc_face_uuid(uuidwalk, f);
+ UUIDFaceStepItem *fstep_item;
+
+ 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);
+
+ /* add to start, so its handled on the next round of passes */
+ BLI_addhead(&fstep->items, fstep_item);
+ fstep_item->uuid = uuid;
+ fstep_item->list = NULL;
+ fstep_item->list_len = 0;
+ }
+
+ BLI_linklist_prepend_pool(&fstep_item->list, f, uuidwalk->link_pool);
+ fstep_item->list_len += 1;
+
+ f_link_prev_p = &f_link->next;
+ }
+ else {
+ *f_link_prev_p = f_link->next;
+ BLI_mempool_free(uuidwalk->link_pool, f_link);
+ }
+ }
+
+ BLI_ghash_clear(uuidwalk->cache.faces_from_uuid, NULL, NULL);
+
+ BLI_sortlist(&fstep->items, facestep_sort);
+
+ return ok;
+}
+
+/**
+ * Cleans up temp data from #bm_uuidwalk_facestep_begin
+ */
+static void bm_uuidwalk_facestep_end(
+ UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
+{
+ UUIDFaceStepItem *fstep_item;
+
+ while ((fstep_item = BLI_pophead(&fstep->items))) {
+ BLI_mempool_free(uuidwalk->step_pool_items, fstep_item);
+ }
+}
+
+static void bm_uuidwalk_facestep_free(
+ UUIDWalk *uuidwalk, UUIDFaceStep *fstep)
+{
+ LinkNode *f_link, *f_link_next;
+
+ BLI_assert(BLI_listbase_is_empty(&fstep->items));
+
+ for (f_link = fstep->faces; f_link; f_link = f_link_next) {
+ f_link_next = f_link->next;
+ BLI_mempool_free(uuidwalk->link_pool, f_link);
+ }
+
+ BLI_remlink(&uuidwalk->faces_step, fstep);
+ BLI_mempool_free(uuidwalk->step_pool, fstep);
+}
+
+/** \} */
+
+
+/* -------------------------------------------------------------------- */
+/* Main Loop to match up regions */
+
+/**
+ * Given a face region and 2 candidate verts to begin mapping.
+ * return the matching region or NULL.
+ */
+static BMFace **bm_mesh_region_match_pair(
+#ifdef USE_WALKER_REUSE
+ UUIDWalk *w_src, UUIDWalk *w_dst,
+#endif
+ BMEdge *e_src, BMEdge *e_dst,
+ const unsigned int faces_src_region_len,
+ const unsigned int verts_src_region_len,
+ unsigned int *r_faces_result_len)
+{
+#ifndef USE_WALKER_REUSE
+ UUIDWalk w_src_, w_dst_;
+ UUIDWalk *w_src = &w_src_, *w_dst = &w_dst_;
+#endif
+ BMFace **faces_result = NULL;
+ bool found = false;
+
+ BLI_assert(e_src != e_dst);
+
+#ifndef USE_WALKER_REUSE
+ bm_uuidwalk_init(w_src, faces_src_region_len, verts_src_region_len);
+ bm_uuidwalk_init(w_dst, faces_src_region_len, verts_src_region_len);
+#endif
+
+ w_src->use_face_isolate = true;
+
+ /* setup the initial state */
+ if (UNLIKELY(bm_uuidwalk_init_from_edge(w_src, e_src) !=
+ bm_uuidwalk_init_from_edge(w_dst, e_dst)))
+ {
+ /* should never happen, if verts passed are compatible, but to be safe... */
+ goto finally;
+ }
+
+ bm_uuidwalk_rehash_reserve(w_src, MAX2(faces_src_region_len, verts_src_region_len));
+ bm_uuidwalk_rehash_reserve(w_dst, MAX2(faces_src_region_len, verts_src_region_len));
+
+ while (true) {
+ bool ok = false;
+
+ UUIDFaceStep *fstep_src = w_src->faces_step.first;
+ UUIDFaceStep *fstep_dst = w_dst->faces_step.first;
+
+ BLI_assert(BLI_countlist(&w_src->faces_step) == BLI_countlist(&w_dst->faces_step));
+
+ while (fstep_src) {
+
+ /* even if the destination has faces,
+ * it's not important, since the source doesn't, free and move-on. */
+ if (fstep_src->faces == NULL) {
+ UUIDFaceStep *fstep_src_next = fstep_src->next;
+ UUIDFaceStep *fstep_dst_next = fstep_dst->next;
+ bm_uuidwalk_facestep_free(w_src, fstep_src);
+ bm_uuidwalk_facestep_free(w_dst, fstep_dst);
+ fstep_src = fstep_src_next;
+ fstep_dst = fstep_dst_next;
+ continue;
+ }
+
+ if (bm_uuidwalk_facestep_begin(w_src, fstep_src) &&
+ bm_uuidwalk_facestep_begin(w_dst, fstep_dst))
+ {
+ /* Step over face-lists with matching UUID's
+ * both lists are sorted, so no need for lookups.
+ * The data is created on 'begin' and cleared on 'end' */
+ UUIDFaceStepItem *fstep_item_src;
+ UUIDFaceStepItem *fstep_item_dst;
+ for (fstep_item_src = fstep_src->items.first,
+ fstep_item_dst = fstep_dst->items.first;
+ fstep_item_src && fstep_item_dst;
+ fstep_item_src = fstep_item_src->next,
+ fstep_item_dst = fstep_item_dst->next)
+ {
+ while ((fstep_item_dst != NULL) &&
+ (fstep_item_dst->uuid < fstep_item_src->uuid))
+ {
+ fstep_item_dst = fstep_item_dst->next;
+ }
+
+ if ((fstep_item_dst == NULL) ||
+ (fstep_item_src->uuid != fstep_item_dst->uuid) ||
+ (fstep_item_src->list_len > fstep_item_dst->list_len))
+ {
+ /* if the target walker has less than the source
+ * then the islands don't match, bail early */
+ ok = false;
+ break;
+ }
+
+ if (fstep_item_src->list_len == fstep_item_dst->list_len) {
+ /* found a match */
+ bm_uuidwalk_pass_add(w_src, fstep_item_src->list, fstep_item_src->list_len);
+ bm_uuidwalk_pass_add(w_dst, fstep_item_dst->list, fstep_item_dst->list_len);
+
+ BLI_linklist_free_pool(fstep_item_src->list, NULL, w_src->link_pool);
+ BLI_linklist_free_pool(fstep_item_dst->list, NULL, w_dst->link_pool);
+
+ fstep_item_src->list = NULL;
+ fstep_item_src->list_len = 0;
+
+ fstep_item_dst->list = NULL;
+ fstep_item_dst->list_len = 0;
+
+ ok = true;
+ }
+ }
+ }
+
+ bm_uuidwalk_facestep_end(w_src, fstep_src);
+ bm_uuidwalk_facestep_end(w_dst, fstep_dst);
+
+ /* lock-step */
+ fstep_src = fstep_src->next;
+ fstep_dst = fstep_dst->next;
+ }
+
+ if (!ok) {
+ break;
+ }
+
+ found = ((unsigned int)BLI_ghash_size(w_dst->faces_uuid) == faces_src_region_len);
+ if (found) {
+ break;
+ }
+
+ /* Expensive! but some cases fails without.
+ * (also faster in other cases since it can rule-out invalid regions) */
+ bm_uuidwalk_rehash(w_src);
+ bm_uuidwalk_rehash(w_dst);
+ }
+
+ if (found) {
+ GHashIterator gh_iter;
+ const unsigned int faces_result_len = (unsigned int)BLI_ghash_size(w_dst->faces_uuid);
+ unsigned int i;
+
+ faces_result = MEM_mallocN(sizeof(faces_result) * (faces_result_len + 1), __func__);
+ GHASH_ITER_INDEX (gh_iter, w_dst->faces_uuid, i) {
+ BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
+ faces_result[i] = f;
+ }
+ faces_result[faces_result_len] = NULL;
+ *r_faces_result_len = faces_result_len;
+ }
+ else {
+ *r_faces_result_len = 0;
+ }
+
+finally:
+
+#ifdef USE_WALKER_REUSE
+ bm_uuidwalk_clear(w_src);
+ bm_uuidwalk_clear(w_dst);
+#else
+ bm_uuidwalk_free(w_src);
+ bm_uuidwalk_free(w_dst);
+#endif
+
+ return faces_result;
+}
+
+/**
+ * Tag as visited, avoid re-use.
+ */
+static void bm_face_array_visit(
+ BMFace **faces, const unsigned int faces_len,
+ unsigned int *r_verts_len,
+ bool visit_faces)
+{
+ unsigned int verts_len = 0;
+ unsigned int i;
+ for (i = 0; i < faces_len; i++) {
+ BMFace *f = faces[i];
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (r_verts_len) {
+ if (!BM_elem_flag_test(l_iter->v, BM_ELEM_TAG)) {
+ verts_len += 1;
+ }
+ }
+
+ BM_elem_flag_enable(l_iter->e, BM_ELEM_TAG);
+ BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
+ } while ((l_iter = l_iter->next) != l_first);
+
+ if (visit_faces) {
+ BM_elem_flag_enable(f, BM_ELEM_TAG);
+ }
+ }
+
+ if (r_verts_len) {
+ *r_verts_len = verts_len;
+ }
+}
+
+#ifdef USE_PIVOT_SEARCH
+
+/** \name Internal UUIDWalk API
+ * \{ */
+
+/* signed user id */
+typedef intptr_t SUID_Int;
+
+static bool bm_edge_is_region_boundary(BMEdge *e)
+{
+ if (e->l->radial_next != e->l) {
+ BMLoop *l_iter = e->l;
+ do {
+ if (!BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ return false;
+ }
+ else {
+ /* boundary */
+ return true;
+ }
+}
+
+static void bm_face_region_pivot_edge_use_best(
+ GHash *gh, BMEdge *e_test,
+ BMEdge **r_e_pivot_best,
+ SUID_Int e_pivot_best_id[2])
+{
+ SUID_Int e_pivot_test_id[2];
+
+ e_pivot_test_id[0] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v1);
+ e_pivot_test_id[1] = (SUID_Int)BLI_ghash_lookup(gh, e_test->v2);
+ if (e_pivot_test_id[0] > e_pivot_test_id[1]) {
+ SWAP(SUID_Int, e_pivot_test_id[0], e_pivot_test_id[1]);
+ }
+
+ if ((*r_e_pivot_best == NULL) ||
+ ((e_pivot_best_id[0] != e_pivot_test_id[0]) ?
+ (e_pivot_best_id[0] < e_pivot_test_id[0]) :
+ (e_pivot_best_id[1] < e_pivot_test_id[1])))
+ {
+ e_pivot_best_id[0] = e_pivot_test_id[0];
+ e_pivot_best_id[1] = e_pivot_test_id[1];
+
+ /* both verts are from the same pass, record this! */
+ *r_e_pivot_best = e_test;
+ }
+}
+
+/* quick id from a boundary vertex */
+static SUID_Int bm_face_region_vert_boundary_id(BMVert *v)
+{
+#define PRIME_VERT_SMALL_A 7
+#define PRIME_VERT_SMALL_B 13
+#define PRIME_VERT_MID_A 103
+#define PRIME_VERT_MID_B 131
+
+ int tot = 0;
+ BMIter iter;
+ BMLoop *l;
+ SUID_Int id = PRIME_VERT_MID_A;
+
+ BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
+ const bool is_boundary_vert = (bm_edge_is_region_boundary(l->e) || bm_edge_is_region_boundary(l->prev->e));
+ id ^= l->f->len * (is_boundary_vert ? PRIME_VERT_SMALL_A : PRIME_VERT_SMALL_B);
+ tot += 1;
+ }
+
+ id ^= (tot * PRIME_VERT_MID_B);
+
+ return id ? ABS(id) : 1;
+
+#undef PRIME_VERT_SMALL_A
+#undef PRIME_VERT_SMALL_B
+#undef PRIME_VERT_MID_A
+#undef PRIME_VERT_MID_B
+}
+
+/**
+ * Accumulate id's from a previous pass (swap sign each pass)
+ */
+static SUID_Int bm_face_region_vert_pass_id(GHash *gh, BMVert *v)
+{
+ BMIter eiter;
+ BMEdge *e;
+ SUID_Int tot = 0;
+ SUID_Int v_sum_face_len = 0;
+ SUID_Int v_sum_id = 0;
+ SUID_Int id;
+ SUID_Int id_min = INTPTR_MIN + 1;
+
+#define PRIME_VERT_MID_A 23
+#define PRIME_VERT_MID_B 31
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ 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)) {
+ /* non-zero values aren't allowed... so no need to check haskey */
+ SUID_Int v_other_id = (SUID_Int)BLI_ghash_lookup(gh, v_other);
+ if (v_other_id > 0) {
+ v_sum_id += v_other_id;
+ tot += 1;
+
+ /* face-count */
+ {
+ BMLoop *l_iter = e->l;
+ do {
+ if (BM_elem_flag_test(l_iter->f, BM_ELEM_TAG)) {
+ v_sum_face_len += l_iter->f->len;
+ }
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+ }
+ }
+ }
+ }
+
+ id = (tot * PRIME_VERT_MID_A);
+ id ^= (v_sum_face_len * PRIME_VERT_MID_B);
+ id ^= v_sum_id;
+
+ /* disallow 0 & min (since it can't be flipped) */
+ id = (UNLIKELY(id == 0) ? 1 : UNLIKELY(id < id_min) ? id_min : id);
+
+ return ABS(id);
+
+#undef PRIME_VERT_MID_A
+#undef PRIME_VERT_MID_B
+}
+
+/**
+ * Take a face region and find the inner-most vertex.
+ * also calculate the number of connections to the boundary,
+ * and the total number unique of verts used by this face region.
+ *
+ * This is only called once on the source region (no need to be highly optimized).
+ */
+static BMEdge *bm_face_region_pivot_edge_find(
+ BMFace **faces_region, unsigned int faces_region_len,
+ unsigned int verts_region_len,
+ unsigned int *r_depth)
+{
+ /* note, keep deterministic where possible (geometry order independent)
+ * this function assumed all visit faces & edges are tagged */
+
+ BLI_LINKSTACK_DECLARE(vert_queue_prev, BMVert *);
+ BLI_LINKSTACK_DECLARE(vert_queue_next, BMVert *);
+
+ GHash *gh = BLI_ghash_ptr_new(__func__);
+ unsigned int i;
+
+ BMEdge *e_pivot = NULL;
+ /* pick any non-boundary edge (not ideal) */
+ BMEdge *e_pivot_fallback = NULL;
+
+ SUID_Int pass = 0;
+
+ /* total verts in 'gs' we have visited - aka - not v_init_none */
+ unsigned int vert_queue_used = 0;
+
+ BLI_LINKSTACK_INIT(vert_queue_prev);
+ BLI_LINKSTACK_INIT(vert_queue_next);
+
+ /* face-verts */
+ for (i = 0; i < faces_region_len; i++) {
+ BMFace *f = faces_region[i];
+
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BMEdge *e = l_iter->e;
+ if (bm_edge_is_region_boundary(e)) {
+ unsigned int j;
+ for (j = 0; j < 2; j++) {
+ if (!BLI_ghash_haskey(gh, (&e->v1)[j])) {
+ SUID_Int v_id = bm_face_region_vert_boundary_id((&e->v1)[j]);
+ BLI_ghash_insert(gh, (&e->v1)[j], (void *)v_id);
+ BLI_LINKSTACK_PUSH(vert_queue_prev, (&e->v1)[j]);
+ vert_queue_used += 1;
+ }
+ }
+ }
+ else {
+ /* use incase (depth == 0), no interior verts */
+ e_pivot_fallback = e;
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+
+ while (BLI_LINKSTACK_SIZE(vert_queue_prev)) {
+ BMVert *v;
+ while ((v = BLI_LINKSTACK_POP(vert_queue_prev))) {
+ BMIter eiter;
+ BMEdge *e;
+ BLI_assert(BLI_ghash_haskey(gh, v));
+ BLI_assert((SUID_Int)BLI_ghash_lookup(gh, v) > 0);
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ 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)) {
+ /* 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);
+ BLI_LINKSTACK_PUSH(vert_queue_next, v_other);
+ vert_queue_used += 1;
+ }
+ }
+ }
+ }
+ }
+
+ /* flip all the newly added hashes to positive */
+ {
+ LinkNode *v_link;
+ for (v_link = vert_queue_next; v_link; v_link = v_link->next) {
+ SUID_Int *v_id_p = (SUID_Int *)BLI_ghash_lookup_p(gh, v_link->link);
+ *v_id_p = -(*v_id_p);
+ BLI_assert(*v_id_p > 0);
+ }
+ }
+
+ BLI_LINKSTACK_SWAP(vert_queue_prev, vert_queue_next);
+ pass += 1;
+
+ if (vert_queue_used == verts_region_len) {
+ break;
+ }
+ }
+
+ if (BLI_LINKSTACK_SIZE(vert_queue_prev) >= 2) {
+ /* common case - we managed to find some interior verts */
+ LinkNode *v_link;
+ BMEdge *e_pivot_best = NULL;
+ SUID_Int e_pivot_best_id[2] = {0, 0};
+
+ /* temp untag, so we can quickly know what other verts are in this last pass */
+ for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
+ BMVert *v = v_link->link;
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+
+ /* restore correct tagging */
+ for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
+ BMIter eiter;
+ BMEdge *e_test;
+
+ BMVert *v = v_link->link;
+ BM_elem_flag_enable(v, BM_ELEM_TAG);
+
+ BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
+ BMVert *v_other = BM_edge_other_vert(e_test, v);
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == false) {
+ bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
+ }
+ }
+ }
+ }
+
+ e_pivot = e_pivot_best;
+ }
+
+ if ((e_pivot == NULL) && BLI_LINKSTACK_SIZE(vert_queue_prev)) {
+ /* find the best single edge */
+ BMEdge *e_pivot_best = NULL;
+ SUID_Int e_pivot_best_id[2] = {0, 0};
+
+ LinkNode *v_link;
+
+ /* reduce a pass since we're having to step into a previous passes vert,
+ * and will be closer to the boundary */
+ BLI_assert(pass != 0);
+ pass -= 1;
+
+ for (v_link = vert_queue_prev; v_link; v_link = v_link->next) {
+ BMVert *v = v_link->link;
+
+ BMIter eiter;
+ BMEdge *e_test;
+ BM_ITER_ELEM (e_test, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e_test, BM_ELEM_TAG)) {
+ BMVert *v_other = BM_edge_other_vert(e_test, v);
+ if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) {
+ bm_face_region_pivot_edge_use_best(gh, e_test, &e_pivot_best, e_pivot_best_id);
+ }
+ }
+ }
+ }
+
+ e_pivot = e_pivot_best;
+ }
+
+ BLI_LINKSTACK_FREE(vert_queue_prev);
+ BLI_LINKSTACK_FREE(vert_queue_next);
+
+ BLI_ghash_free(gh, NULL, NULL);
+
+ if (e_pivot == NULL) {
+#ifdef DEBUG_PRINT
+ printf("%s: using fallback edge!\n", __func__);
+#endif
+ e_pivot = e_pivot_fallback;
+ pass = 0;
+ }
+
+ *r_depth = (unsigned int)pass;
+
+ return e_pivot;
+}
+/** \} */
+
+#endif /* USE_PIVOT_SEARCH */
+
+
+/* -------------------------------------------------------------------- */
+/* Quick UUID pass - identify candidates */
+
+#ifdef USE_PIVOT_FASTMATCH
+
+/** \name Fast Match
+ * \{ */
+
+typedef uintptr_t UUIDFashMatch;
+
+static UUIDFashMatch bm_vert_fasthash_single(BMVert *v)
+{
+ BMIter eiter;
+ BMEdge *e;
+ UUIDFashMatch e_num = 0, f_num = 0, l_num = 0;
+
+#define PRIME_EDGE 7
+#define PRIME_FACE 31
+#define PRIME_LOOP 61
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_edge_is_wire(e)) {
+ BMLoop *l_iter = e->l;
+ e_num += 1;
+ do {
+ f_num += 1;
+ l_num += (unsigned int)l_iter->f->len;
+ } while ((l_iter = l_iter->radial_next) != e->l);
+ }
+ }
+
+ return ((e_num * PRIME_EDGE) ^
+ (f_num * PRIME_FACE) *
+ (l_num * PRIME_LOOP));
+
+#undef PRIME_EDGE
+#undef PRIME_FACE
+#undef PRIME_LOOP
+}
+
+static UUIDFashMatch *bm_vert_fasthash_create(
+ BMesh *bm, const unsigned int depth)
+{
+ UUIDFashMatch *id_prev;
+ UUIDFashMatch *id_curr;
+ unsigned int pass, i;
+ BMVert *v;
+ BMIter iter;
+
+ id_prev = MEM_mallocN(sizeof(*id_prev) * (unsigned int)bm->totvert, __func__);
+ id_curr = MEM_mallocN(sizeof(*id_curr) * (unsigned int)bm->totvert, __func__);
+
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ id_prev[i] = bm_vert_fasthash_single(v);
+ }
+
+ for (pass = 0; pass < depth; pass++) {
+ BMEdge *e;
+
+ memcpy(id_curr, id_prev, sizeof(*id_prev) * (unsigned int)bm->totvert);
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_edge_is_wire(e) == false) {
+ const int i1 = BM_elem_index_get(e->v1);
+ const int i2 = BM_elem_index_get(e->v2);
+
+ id_curr[i1] += id_prev[i2];
+ id_curr[i2] += id_prev[i1];
+ }
+ }
+ }
+ MEM_freeN(id_prev);
+
+ return id_curr;
+}
+
+static void bm_vert_fasthash_edge_order(
+ UUIDFashMatch *fm, const BMEdge *e, UUIDFashMatch e_fm[2])
+{
+ e_fm[0] = fm[BM_elem_index_get(e->v1)];
+ e_fm[1] = fm[BM_elem_index_get(e->v2)];
+
+ if (e_fm[0] > e_fm[1]) {
+ SWAP(UUIDFashMatch, e_fm[0], e_fm[1]);
+ }
+}
+
+static bool bm_vert_fasthash_edge_is_match(
+ UUIDFashMatch *fm, const BMEdge *e_a, const BMEdge *e_b)
+{
+ UUIDFashMatch e_a_fm[2];
+ UUIDFashMatch e_b_fm[2];
+
+ bm_vert_fasthash_edge_order(fm, e_a, e_a_fm);
+ bm_vert_fasthash_edge_order(fm, e_b, e_b_fm);
+
+ return ((e_a_fm[0] == e_b_fm[0]) &&
+ (e_a_fm[1] == e_b_fm[1]));
+}
+
+static void bm_vert_fasthash_destroy(
+ UUIDFashMatch *fm)
+{
+ MEM_freeN(fm);
+}
+
+/** \} */
+
+#endif /* USE_PIVOT_FASTMATCH */
+
+
+/**
+ * Take a face-region and return a list of matching face-regions.
+ *
+ * \param faces_region A single, contiguous face-region.
+ * \return A list of matching null-terminated face-region arrays.
+ */
+int BM_mesh_region_match(
+ BMesh *bm,
+ BMFace **faces_region, unsigned int faces_region_len,
+ ListBase *r_face_regions)
+{
+ BMEdge *e_src;
+ BMEdge *e_dst;
+ BMIter iter;
+ unsigned int verts_region_len = 0;
+ unsigned int faces_result_len = 0;
+ /* number of steps from e_src to a boundary vert */
+ unsigned int depth;
+
+
+#ifdef USE_WALKER_REUSE
+ UUIDWalk w_src, w_dst;
+#endif
+
+#ifdef USE_PIVOT_FASTMATCH
+ UUIDFashMatch *fm;
+#endif
+
+#ifdef DEBUG_PRINT
+ int search_num = 0;
+#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(region_match);
+#endif
+
+ /* initialize visited verts */
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_TAG, false);
+ bm_face_array_visit(faces_region, faces_region_len, &verts_region_len, true);
+
+ /* needed for 'ghashutil_bmelem_indexhash' */
+ BM_mesh_elem_index_ensure(bm, BM_VERT | BM_FACE);
+
+#ifdef USE_PIVOT_SEARCH
+ e_src = bm_face_region_pivot_edge_find(
+ faces_region, faces_region_len,
+ verts_region_len, &depth);
+
+ /* see which edge is added */
+#if 0
+ BM_select_history_clear(bm);
+ if (e_src) {
+ BM_select_history_store(bm, e_src);
+ }
+#endif
+
+#else
+ /* quick test only! */
+ e_src = BM_mesh_active_edge_get(bm);
+#endif
+
+ if (e_src == NULL) {
+#ifdef DEBUG_PRINT
+ printf("Couldn't find 'e_src'");
+#endif
+ return 0;
+ }
+
+ BLI_listbase_clear(r_face_regions);
+
+#ifdef USE_PIVOT_FASTMATCH
+ if (depth > 0) {
+ fm = bm_vert_fasthash_create(bm, depth);
+ }
+ else {
+ fm = NULL;
+ }
+#endif
+
+#ifdef USE_WALKER_REUSE
+ bm_uuidwalk_init(&w_src, faces_region_len, verts_region_len);
+ bm_uuidwalk_init(&w_dst, faces_region_len, verts_region_len);
+#endif
+
+ BM_ITER_MESH (e_dst, &iter, bm, BM_EDGES_OF_MESH) {
+ BMFace **faces_result;
+ unsigned int faces_result_len_out;
+
+ if (BM_elem_flag_test(e_dst, BM_ELEM_TAG)) {
+ continue;
+ }
+
+#ifdef USE_PIVOT_FASTMATCH
+ if (fm && !bm_vert_fasthash_edge_is_match(fm, e_src, e_dst)) {
+ continue;
+ }
+#endif
+
+#ifdef DEBUG_PRINT
+ search_num += 1;
+#endif
+
+ faces_result = bm_mesh_region_match_pair(
+#ifdef USE_WALKER_REUSE
+ &w_src, &w_dst,
+#endif
+ e_src, e_dst,
+ faces_region_len,
+ verts_region_len,
+ &faces_result_len_out);
+
+ /* tag verts as visited */
+ if (faces_result) {
+ LinkData *link;
+
+ bm_face_array_visit(faces_result, faces_result_len_out, NULL, false);
+
+ link = BLI_genericNodeN(faces_result);
+ BLI_addtail(r_face_regions, link);
+ faces_result_len += 1;
+ }
+ }
+
+#ifdef USE_WALKER_REUSE
+ bm_uuidwalk_free(&w_src);
+ bm_uuidwalk_free(&w_dst);
+#else
+ (void)bm_uuidwalk_clear;
+#endif
+
+#ifdef USE_PIVOT_FASTMATCH
+ if (fm) {
+ bm_vert_fasthash_destroy(fm);
+ }
+#endif
+
+#ifdef DEBUG_PRINT
+ printf("%s: search: %d, found %d\n", __func__, search_num, faces_result_len);
+#endif
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(region_match);
+#endif
+
+ return (int)faces_result_len;
+}
diff --git a/source/blender/bmesh/tools/bmesh_region_match.h b/source/blender/bmesh/tools/bmesh_region_match.h
new file mode 100644
index 00000000000..edf8369b070
--- /dev/null
+++ b/source/blender/bmesh/tools/bmesh_region_match.h
@@ -0,0 +1,33 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BMESH_REGION_MATCH_H__
+#define __BMESH_REGION_MATCH_H__
+
+/** \file blender/bmesh/tools/bmesh_region_match.h
+ * \ingroup bmesh
+ */
+
+int BM_mesh_region_match(
+ BMesh *bm,
+ BMFace **faces_region, unsigned int faces_region_len,
+ ListBase *r_face_regions);
+
+#endif /* __BMESH_REGION_MATCH_H__ */
diff --git a/source/blender/bmesh/tools/bmesh_wireframe.c b/source/blender/bmesh/tools/bmesh_wireframe.c
index b7d7a595dc9..79fea3e5da1 100644
--- a/source/blender/bmesh/tools/bmesh_wireframe.c
+++ b/source/blender/bmesh/tools/bmesh_wireframe.c
@@ -20,7 +20,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/bmesh/operators/bmesh_wireframe.c
+/** \file blender/bmesh/tools/bmesh_wireframe.c
* \ingroup bmesh
*
* Creates a solid wireframe from connected faces.
@@ -334,7 +334,7 @@ void BM_mesh_wireframe(
}
BM_ITER_ELEM (l, &itersub, f_src, BM_LOOPS_OF_FACE) {
- BM_elem_index_set(l, verts_loop_tot); /* set_loop */
+ BM_elem_index_set(l, verts_loop_tot); /* set_dirty */ /* Because some faces might be skipped! */
BM_loop_calc_face_tangent(l, tvec);
@@ -407,6 +407,7 @@ void BM_mesh_wireframe(
verts_loop_tot++;
}
}
+ bm->elem_index_dirty |= BM_LOOP;
BM_ITER_MESH (f_src, &iter, bm, BM_FACES_OF_MESH) {
@@ -440,7 +441,7 @@ void BM_mesh_wireframe(
BMVert *v_pos1 = verts_pos[i_1];
BMVert *v_pos2 = verts_pos[i_2];
- f_new = BM_face_create_quad_tri(bm, v_l1, v_l2, v_neg2, v_neg1, f_src, false);
+ f_new = BM_face_create_quad_tri(bm, v_l1, v_l2, v_neg2, v_neg1, f_src, BM_CREATE_NOP);
if (mat_offset) f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
BM_elem_flag_enable(f_new, BM_ELEM_TAG);
l_new = BM_FACE_FIRST_LOOP(f_new);
@@ -450,7 +451,7 @@ void BM_mesh_wireframe(
BM_elem_attrs_copy(bm, bm, l_next, l_new->next);
BM_elem_attrs_copy(bm, bm, l_next, l_new->next->next);
- f_new = BM_face_create_quad_tri(bm, v_l2, v_l1, v_pos1, v_pos2, f_src, false);
+ f_new = BM_face_create_quad_tri(bm, v_l2, v_l1, v_pos1, v_pos2, f_src, BM_CREATE_NOP);
if (mat_offset) f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
BM_elem_flag_enable(f_new, BM_ELEM_TAG);
@@ -468,7 +469,7 @@ void BM_mesh_wireframe(
BMVert *v_b1 = verts_boundary[i_1];
BMVert *v_b2 = verts_boundary[i_2];
- f_new = BM_face_create_quad_tri(bm, v_b2, v_b1, v_neg1, v_neg2, f_src, false);
+ f_new = BM_face_create_quad_tri(bm, v_b2, v_b1, v_neg1, v_neg2, f_src, BM_CREATE_NOP);
if (mat_offset) f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
BM_elem_flag_enable(f_new, BM_ELEM_TAG);
l_new = BM_FACE_FIRST_LOOP(f_new);
@@ -478,7 +479,7 @@ void BM_mesh_wireframe(
BM_elem_attrs_copy(bm, bm, l, l_new->next);
BM_elem_attrs_copy(bm, bm, l, l_new->next->next);
- f_new = BM_face_create_quad_tri(bm, v_b1, v_b2, v_pos2, v_pos1, f_src, false);
+ f_new = BM_face_create_quad_tri(bm, v_b1, v_b2, v_pos2, v_pos1, f_src, BM_CREATE_NOP);
if (mat_offset) f_new->mat_nr = CLAMPIS(f_new->mat_nr + mat_offset, 0, mat_max);
BM_elem_flag_enable(f_new, BM_ELEM_TAG);
l_new = BM_FACE_FIRST_LOOP(f_new);
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index d27795b0ab2..6e2d337a32e 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -804,7 +804,7 @@ void AnimationImporter::apply_matrix_curves(Object *ob, std::vector<FCurve *>& a
// evaluate_joint_world_transform_at_frame(temp, NULL, node, fra);
// calc special matrix
- mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL);
+ mul_m4_series(mat, irest, temp, irest_dae, rest);
}
else {
copy_m4_m4(mat, matfra);
@@ -1210,7 +1210,7 @@ void AnimationImporter::add_bone_animation_sampled(Object *ob, std::vector<FCurv
// evaluate_joint_world_transform_at_frame(temp, NULL, node, fra);
// calc special matrix
- mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL);
+ mul_m4_series(mat, irest, temp, irest_dae, rest);
float rot[4], loc[3], scale[3];
@@ -1545,7 +1545,7 @@ Object *AnimationImporter::translate_animation_OLD(COLLADAFW::Node *node,
// evaluate_joint_world_transform_at_frame(temp, NULL, node, fra);
// calc special matrix
- mul_serie_m4(mat, irest, temp, irest_dae, rest, NULL, NULL, NULL, NULL);
+ mul_m4_series(mat, irest, temp, irest_dae, rest);
}
else {
copy_m4_m4(mat, matfra);
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index c5443828f60..bc1c4172f46 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -284,7 +284,7 @@ void ControllerExporter::export_skin_controller(Object *ob, Object *ob_arm)
}
if (oob_counter > 0) {
- fprintf(stderr, "Ignored %d Vertex weigths 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 %ld.\n", oob_counter, joint_index_by_def_index.size());
}
}
@@ -522,8 +522,6 @@ static float get_property(Bone *bone, const char *key, float def)
*/
static void create_restpose_mat(Bone *bone, float mat[4][4])
{
- const double PI = 3.1415926535897932384626433832795;
-
float loc[3] = {
get_property(bone, "restpose_loc_x", 0.0),
get_property(bone, "restpose_loc_y", 0.0),
@@ -531,9 +529,9 @@ static void create_restpose_mat(Bone *bone, float mat[4][4])
};
float rot[3] = {
- PI * get_property(bone, "restpose_rot_x", 0.0) / 180.0,
- PI * get_property(bone, "restpose_rot_y", 0.0) / 180.0,
- PI * get_property(bone, "restpose_rot_z", 0.0) / 180.0
+ DEG2RADF(get_property(bone, "restpose_rot_x", 0.0)),
+ DEG2RADF(get_property(bone, "restpose_rot_y", 0.0)),
+ DEG2RADF(get_property(bone, "restpose_rot_z", 0.0))
};
float scale[3] = {
diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp
index bbbbbf211c6..8101e579098 100644
--- a/source/blender/collada/DocumentImporter.cpp
+++ b/source/blender/collada/DocumentImporter.cpp
@@ -483,6 +483,17 @@ void DocumentImporter::create_constraints(ExtraTags *et, Object *ob)
}
}
+void DocumentImporter::report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type)
+{
+ std::string id = node.getOriginalId();
+ std::string name = node.getName();
+ fprintf(stderr,
+ "error: node id=\"%s\", name=\"%s\" refers to an undefined %s.\n",
+ id.c_str(),
+ name.c_str(),
+ object_type.c_str());
+}
+
std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLADAFW::Node *parent_node, Scene *sce, Object *par, bool is_library_node)
{
Object *ob = NULL;
@@ -538,10 +549,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
ob = mesh_importer.create_mesh_object(node, geom[geom_done], false, uid_material_map,
material_texture_mapping_map);
if (ob == NULL) {
- fprintf(stderr,
- "<node id=\"%s\", name=\"%s\" >...contains a reference to an unknown instance_mesh.\n",
- id.c_str(),
- name.c_str());
+ report_unknown_reference(*node, "instance_mesh");
}
else {
objects_done->push_back(ob);
@@ -554,9 +562,7 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
while (camera_done < camera.getCount()) {
ob = create_camera_object(camera[camera_done], sce);
if (ob == NULL) {
- std::string id = node->getOriginalId();
- std::string name = node->getName();
- fprintf(stderr, "<node id=\"%s\", name=\"%s\" >...contains a reference to an unknown instance_camera.\n", id.c_str(), name.c_str());
+ report_unknown_reference(*node, "instance_camera");
}
else {
objects_done->push_back(ob);
@@ -568,18 +574,28 @@ std::vector<Object *> *DocumentImporter::write_node(COLLADAFW::Node *node, COLLA
}
while (lamp_done < lamp.getCount()) {
ob = create_lamp_object(lamp[lamp_done], sce);
- objects_done->push_back(ob);
- if (parent_node == NULL) {
- root_objects->push_back(ob);
+ if (ob == NULL) {
+ report_unknown_reference(*node, "instance_lamp");
+ }
+ else {
+ objects_done->push_back(ob);
+ if (parent_node == NULL) {
+ root_objects->push_back(ob);
+ }
}
++lamp_done;
}
while (controller_done < controller.getCount()) {
COLLADAFW::InstanceGeometry *geom = (COLLADAFW::InstanceGeometry *)controller[controller_done];
ob = mesh_importer.create_mesh_object(node, geom, true, uid_material_map, material_texture_mapping_map);
- objects_done->push_back(ob);
- if (parent_node == NULL) {
- root_objects->push_back(ob);
+ if (ob == NULL) {
+ report_unknown_reference(*node, "instance_controller");
+ }
+ else {
+ objects_done->push_back(ob);
+ if (parent_node == NULL) {
+ root_objects->push_back(ob);
+ }
}
++controller_done;
}
@@ -805,10 +821,14 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia
// DIFFUSE
// color
if (ef->getDiffuse().isColor()) {
+ /* too high intensity can create artefacts (fireflies)
+ So here we take care that intensity is set to 0.8 wherever possible
+ */
col = ef->getDiffuse().getColor();
- ma->r = col.getRed();
- ma->g = col.getGreen();
- ma->b = col.getBlue();
+ ma->ref = max_ffff(col.getRed(), col.getGreen(), col.getBlue(), 0.8);
+ ma->r = col.getRed() / ma->ref;
+ ma->g = col.getGreen() / ma->ref;
+ ma->b = col.getBlue() / ma->ref;
}
// texture
else if (ef->getDiffuse().isTexture()) {
diff --git a/source/blender/collada/DocumentImporter.h b/source/blender/collada/DocumentImporter.h
index 96aa7eb4578..5a7df9a41cf 100644
--- a/source/blender/collada/DocumentImporter.h
+++ b/source/blender/collada/DocumentImporter.h
@@ -171,6 +171,8 @@ private:
std::map<COLLADAFW::UniqueId, const COLLADAFW::Object*> FW_object_map;
std::string import_from_version;
+
+ void report_unknown_reference(const COLLADAFW::Node &node, const std::string object_type);
};
#endif
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 6741e92cb5c..3c35618a4cd 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -310,12 +310,12 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
}
}
-
+ int active_uv_layer = -1;
std::set<Image *> uv_textures;
if (ob->type == OB_MESH && ob->totcol && this->export_settings->include_uv_textures) {
bool active_uv_only = this->export_settings->active_uv_only;
Mesh *me = (Mesh *) ob->data;
- int active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
+ active_uv_layer = CustomData_get_active_layer_index(&me->pdata, CD_MTEXPOLY);
BKE_mesh_tessface_ensure(me);
for (int i = 0; i < me->pdata.totlayer; i++) {
@@ -372,6 +372,10 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
MTex *t = ma->mtex[tex_indices[a]];
Image *ima = t->tex->ima;
+ if (!ima) {
+ continue;
+ }
+
std::string key(id_name(ima));
key = translate_id(key);
int i = im_samp_map[key];
@@ -381,13 +385,16 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
}
std::set<Image *>::iterator uv_t_iter;
- for (uv_t_iter = uv_textures.begin(); uv_t_iter != uv_textures.end(); uv_t_iter++ ) {
- Image *ima = *uv_t_iter;
- std::string key(id_name(ima));
- key = translate_id(key);
- int i = im_samp_map[key];
- COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i][0];
- ep.setDiffuse(createTexture(ima, active_uv, sampler), false, "diffuse");
+ int idx;
+ for (idx = 0, uv_t_iter = uv_textures.begin(); uv_t_iter != uv_textures.end(); uv_t_iter++, idx++ ) {
+ if(active_uv_layer>-1 && idx==active_uv_layer) {
+ Image *ima = *uv_t_iter;
+ std::string key(id_name(ima));
+ key = translate_id(key);
+ int i = im_samp_map[key];
+ COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i][0];
+ ep.setDiffuse(createTexture(ima, active_uv, sampler), false, "diffuse");
+ }
}
// performs the actual writing
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index 211c34ed325..a4bf1d28366 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -84,7 +84,7 @@ static const char *bc_primTypeToStr(COLLADAFW::MeshPrimitive::PrimitiveType type
case COLLADAFW::MeshPrimitive::TRIANGLE_FANS:
return "TRIANGLE_FANS";
case COLLADAFW::MeshPrimitive::TRIANGLE_STRIPS:
- return "TRIANGLE_FANS";
+ return "TRIANGLE_STRIPS";
case COLLADAFW::MeshPrimitive::POINTS:
return "POINTS";
case COLLADAFW::MeshPrimitive::UNDEFINED_PRIMITIVE_TYPE:
diff --git a/source/blender/collada/SkinInfo.cpp b/source/blender/collada/SkinInfo.cpp
index 7ae1750d2ca..75928f9d189 100644
--- a/source/blender/collada/SkinInfo.cpp
+++ b/source/blender/collada/SkinInfo.cpp
@@ -34,6 +34,10 @@
/* COLLADABU_ASSERT, may be able to remove later */
#include "COLLADABUPlatform.h"
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+#include "BLI_compiler_attrs.h"
+
#include "BKE_object.h"
#include "DNA_armature_types.h"
#include "DNA_modifier_types.h"
@@ -41,8 +45,6 @@
#include "ED_mesh.h"
#include "ED_object.h"
#include "BKE_action.h"
-#include "BLI_listbase.h"
-#include "BLI_math.h"
#include "SkinInfo.h"
#include "collada_utils.h"
diff --git a/source/blender/collada/TransformWriter.cpp b/source/blender/collada/TransformWriter.cpp
index c3665a33ca4..595787b44ac 100644
--- a/source/blender/collada/TransformWriter.cpp
+++ b/source/blender/collada/TransformWriter.cpp
@@ -77,7 +77,7 @@ void TransformWriter::add_node_transform_ob(COLLADASW::Node& node, Object *ob, B
BKE_object_to_mat4(ob, C);
copy_v3_v3(ob->size, scale);
- mul_serie_m4(tmat, ob->parent->obmat, ob->parentinv, C, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(tmat, ob->parent->obmat, ob->parentinv, C);
// calculate local mat
diff --git a/source/blender/collada/collada.cpp b/source/blender/collada/collada.cpp
index 223ab3eca2a..ffbbb8623ac 100644
--- a/source/blender/collada/collada.cpp
+++ b/source/blender/collada/collada.cpp
@@ -111,16 +111,28 @@ 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);
-
- if (export_settings.sort_by_name)
- bc_bubble_sort_by_Object_name(export_settings.export_set);
+ int export_count = BLI_linklist_length(export_settings.export_set);
+
+ if (export_count==0)
+ {
+ if (export_settings.selected) {
+ fprintf(stderr, "Collada: Found no objects to export.\nPlease ensure that all objects which shall be exported are also visible in the 3D Viewport.\n");
+ }
+ else{
+ fprintf(stderr, "Collada: Your scene seems to be empty. No Objects will be exported.\n");
+ }
+ }
+ else {
+ if (export_settings.sort_by_name)
+ bc_bubble_sort_by_Object_name(export_settings.export_set);
+ }
DocumentExporter exporter(&export_settings);
exporter.exportCurrentScene(sce);
BLI_linklist_free(export_settings.export_set, NULL);
- return 1;
+ return export_count;
}
/* end extern C */
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index a19433436f1..4bcdd4d9e34 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -39,7 +39,7 @@ set(INC
../nodes/intern
../render/extern/include
../render/intern/include
- ../../../intern/opencl
+ ../../../extern/clew/include
../../../intern/guardedalloc
)
@@ -175,6 +175,11 @@ set(SRC
nodes/COM_GlareNode.cpp
nodes/COM_GlareNode.h
+ nodes/COM_SunBeamsNode.cpp
+ nodes/COM_SunBeamsNode.h
+ operations/COM_SunBeamsOperation.cpp
+ operations/COM_SunBeamsOperation.h
+
nodes/COM_CornerPinNode.cpp
nodes/COM_CornerPinNode.h
nodes/COM_PlaneTrackDeformNode.cpp
@@ -535,4 +540,6 @@ list(APPEND INC
data_to_c(${CMAKE_CURRENT_SOURCE_DIR}/operations/COM_OpenCLKernels.cl
${CMAKE_CURRENT_BINARY_DIR}/operations/COM_OpenCLKernels.cl.h SRC)
+add_definitions(-DCL_USE_DEPRECATED_OPENCL_1_1_APIS)
+
blender_add_lib(bf_compositor "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h
index 2cf2c690d3e..9b22444cf7f 100644
--- a/source/blender/compositor/COM_compositor.h
+++ b/source/blender/compositor/COM_compositor.h
@@ -208,7 +208,7 @@ extern "C" {
*
* @see ExecutionGroup.execute Execute a complete ExecutionGroup. Halts until finished or breaked by user
* @see ExecutionGroup.scheduleChunkWhenPossible Tries to schedule a single chunk,
- * checks if all input data is available. Can trigger dependant chunks to be calculated
+ * checks if all input data is available. Can trigger dependent chunks to be calculated
* @see ExecutionGroup.scheduleAreaWhenPossible Tries to schedule an area. This can be multiple chunks
* (is called from [@ref ExecutionGroup.scheduleChunkWhenPossible])
* @see ExecutionGroup.scheduleChunk Schedule a chunk on the WorkScheduler
diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h
index d086f81d03c..b60fffc6a22 100644
--- a/source/blender/compositor/COM_defines.h
+++ b/source/blender/compositor/COM_defines.h
@@ -109,13 +109,4 @@ typedef enum OrderOfChunks {
#define COM_BLUR_BOKEH_PIXELS 512
-/**
- * The fast gaussien blur is not an accurate blur.
- * This setting can be used to increase/decrease the
- * amount of the input data. (dependent area of interest)
- *
- * Fix for: T39307
- */
-#define COM_FAST_GAUSSIAN_MULTIPLIER 3
-
#endif /* __COM_DEFINES_H__ */
diff --git a/source/blender/compositor/SConscript b/source/blender/compositor/SConscript
index 073b100e156..eab40873f64 100644
--- a/source/blender/compositor/SConscript
+++ b/source/blender/compositor/SConscript
@@ -26,7 +26,7 @@
# ***** END GPL LICENSE BLOCK *****
Import ('env')
-defs = ['GLEW_STATIC']
+defs = ['GLEW_STATIC', 'CL_USE_DEPRECATED_OPENCL_1_1_APIS']
sources_intern = env.Glob('intern/*.cpp')
sources_nodes = env.Glob('nodes/*.cpp')
@@ -37,7 +37,7 @@ incs = [
'intern',
'nodes',
'operations',
- '#/intern/opencl',
+ '#/extern/clew/include',
'../blenkernel',
'../blenlib',
'../imbuf',
diff --git a/source/blender/compositor/intern/COM_ChunkOrder.cpp b/source/blender/compositor/intern/COM_ChunkOrder.cpp
index 1b7c435ecea..3b094609a26 100644
--- a/source/blender/compositor/intern/COM_ChunkOrder.cpp
+++ b/source/blender/compositor/intern/COM_ChunkOrder.cpp
@@ -34,7 +34,7 @@ ChunkOrder::ChunkOrder()
void ChunkOrder::determineDistance(ChunkOrderHotspot **hotspots, unsigned int numberOfHotspots)
{
unsigned int index;
- double distance = MAXFLOAT;
+ double distance = FLT_MAX;
for (index = 0; index < numberOfHotspots; index++) {
ChunkOrderHotspot *hotspot = hotspots[index];
double ndistance = hotspot->determineDistance(this->m_x, this->m_y);
diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cpp
index 9251e161839..99f66bcb5b4 100644
--- a/source/blender/compositor/intern/COM_Converter.cpp
+++ b/source/blender/compositor/intern/COM_Converter.cpp
@@ -99,6 +99,7 @@ extern "C" {
#include "COM_SetValueOperation.h"
#include "COM_SplitViewerNode.h"
#include "COM_Stabilize2dNode.h"
+#include "COM_SunBeamsNode.h"
#include "COM_SwitchNode.h"
#include "COM_TextureNode.h"
#include "COM_TimeNode.h"
@@ -394,6 +395,9 @@ Node *Converter::convert(bNode *b_node)
case CMP_NODE_CORNERPIN:
node = new CornerPinNode(b_node);
break;
+ case CMP_NODE_SUNBEAMS:
+ node = new SunBeamsNode(b_node);
+ break;
}
return node;
}
diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cpp
index a453af5ad13..470f8fd2ef7 100644
--- a/source/blender/compositor/intern/COM_Debug.cpp
+++ b/source/blender/compositor/intern/COM_Debug.cpp
@@ -398,7 +398,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system)
char filename[FILE_MAX];
BLI_snprintf(basename, sizeof(basename), "compositor_%d.dot", m_file_index);
- BLI_join_dirfile(filename, sizeof(filename), BLI_temporary_dir(), basename);
+ BLI_join_dirfile(filename, sizeof(filename), BLI_temp_dir_session(), basename);
++m_file_index;
FILE *fp = BLI_fopen(filename, "wb");
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp
index 04828bfe3f8..c59ecced93c 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cpp
@@ -46,7 +46,7 @@ MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, r
BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
this->m_memoryProxy = memoryProxy;
this->m_chunkNumber = chunkNumber;
- this->m_buffer = (float *)MEM_mallocN(sizeof(float) * determineBufferSize() * COM_NUMBER_OF_CHANNELS, "COM_MemoryBuffer");
+ this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * COM_NUMBER_OF_CHANNELS, 16, "COM_MemoryBuffer");
this->m_state = COM_MB_ALLOCATED;
this->m_datatype = COM_DT_COLOR;
this->m_chunkWidth = this->m_rect.xmax - this->m_rect.xmin;
@@ -57,7 +57,7 @@ MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect)
BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
this->m_memoryProxy = memoryProxy;
this->m_chunkNumber = -1;
- this->m_buffer = (float *)MEM_mallocN(sizeof(float) * determineBufferSize() * COM_NUMBER_OF_CHANNELS, "COM_MemoryBuffer");
+ this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * COM_NUMBER_OF_CHANNELS, 16, "COM_MemoryBuffer");
this->m_state = COM_MB_TEMPORARILY;
this->m_datatype = COM_DT_COLOR;
this->m_chunkWidth = this->m_rect.xmax - this->m_rect.xmin;
@@ -178,162 +178,58 @@ void MemoryBuffer::addPixel(int x, int y, const float color[4])
}
}
-
-// table of (exp(ar) - exp(a)) / (1 - exp(a)) for r in range [0, 1] and a = -2
-// used instead of actual gaussian, otherwise at high texture magnifications circular artifacts are visible
-#define EWA_MAXIDX 255
-static const float EWA_WTS[EWA_MAXIDX + 1] = {
- 1.f, 0.990965f, 0.982f, 0.973105f, 0.96428f, 0.955524f, 0.946836f, 0.938216f, 0.929664f,
- 0.921178f, 0.912759f, 0.904405f, 0.896117f, 0.887893f, 0.879734f, 0.871638f, 0.863605f,
- 0.855636f, 0.847728f, 0.839883f, 0.832098f, 0.824375f, 0.816712f, 0.809108f, 0.801564f,
- 0.794079f, 0.786653f, 0.779284f, 0.771974f, 0.76472f, 0.757523f, 0.750382f, 0.743297f,
- 0.736267f, 0.729292f, 0.722372f, 0.715505f, 0.708693f, 0.701933f, 0.695227f, 0.688572f,
- 0.68197f, 0.67542f, 0.66892f, 0.662471f, 0.656073f, 0.649725f, 0.643426f, 0.637176f,
- 0.630976f, 0.624824f, 0.618719f, 0.612663f, 0.606654f, 0.600691f, 0.594776f, 0.588906f,
- 0.583083f, 0.577305f, 0.571572f, 0.565883f, 0.56024f, 0.55464f, 0.549084f, 0.543572f,
- 0.538102f, 0.532676f, 0.527291f, 0.521949f, 0.516649f, 0.511389f, 0.506171f, 0.500994f,
- 0.495857f, 0.490761f, 0.485704f, 0.480687f, 0.475709f, 0.470769f, 0.465869f, 0.461006f,
- 0.456182f, 0.451395f, 0.446646f, 0.441934f, 0.437258f, 0.432619f, 0.428017f, 0.42345f,
- 0.418919f, 0.414424f, 0.409963f, 0.405538f, 0.401147f, 0.39679f, 0.392467f, 0.388178f,
- 0.383923f, 0.379701f, 0.375511f, 0.371355f, 0.367231f, 0.363139f, 0.359079f, 0.355051f,
- 0.351055f, 0.347089f, 0.343155f, 0.339251f, 0.335378f, 0.331535f, 0.327722f, 0.323939f,
- 0.320186f, 0.316461f, 0.312766f, 0.3091f, 0.305462f, 0.301853f, 0.298272f, 0.294719f,
- 0.291194f, 0.287696f, 0.284226f, 0.280782f, 0.277366f, 0.273976f, 0.270613f, 0.267276f,
- 0.263965f, 0.26068f, 0.257421f, 0.254187f, 0.250979f, 0.247795f, 0.244636f, 0.241502f,
- 0.238393f, 0.235308f, 0.232246f, 0.229209f, 0.226196f, 0.223206f, 0.220239f, 0.217296f,
- 0.214375f, 0.211478f, 0.208603f, 0.20575f, 0.20292f, 0.200112f, 0.197326f, 0.194562f,
- 0.191819f, 0.189097f, 0.186397f, 0.183718f, 0.18106f, 0.178423f, 0.175806f, 0.17321f,
- 0.170634f, 0.168078f, 0.165542f, 0.163026f, 0.16053f, 0.158053f, 0.155595f, 0.153157f,
- 0.150738f, 0.148337f, 0.145955f, 0.143592f, 0.141248f, 0.138921f, 0.136613f, 0.134323f,
- 0.132051f, 0.129797f, 0.12756f, 0.125341f, 0.123139f, 0.120954f, 0.118786f, 0.116635f,
- 0.114501f, 0.112384f, 0.110283f, 0.108199f, 0.106131f, 0.104079f, 0.102043f, 0.100023f,
- 0.0980186f, 0.09603f, 0.094057f, 0.0920994f, 0.0901571f, 0.08823f, 0.0863179f, 0.0844208f,
- 0.0825384f, 0.0806708f, 0.0788178f, 0.0769792f, 0.0751551f, 0.0733451f, 0.0715493f, 0.0697676f,
- 0.0679997f, 0.0662457f, 0.0645054f, 0.0627786f, 0.0610654f, 0.0593655f, 0.0576789f, 0.0560055f,
- 0.0543452f, 0.0526979f, 0.0510634f, 0.0494416f, 0.0478326f, 0.0462361f, 0.0446521f, 0.0430805f,
- 0.0415211f, 0.039974f, 0.0384389f, 0.0369158f, 0.0354046f, 0.0339052f, 0.0324175f, 0.0309415f,
- 0.029477f, 0.0280239f, 0.0265822f, 0.0251517f, 0.0237324f, 0.0223242f, 0.020927f, 0.0195408f,
- 0.0181653f, 0.0168006f, 0.0154466f, 0.0141031f, 0.0127701f, 0.0114476f, 0.0101354f, 0.00883339f,
- 0.00754159f, 0.00625989f, 0.00498819f, 0.00372644f, 0.00247454f, 0.00123242f, 0.f
-};
-
-static void ellipse_bounds(float A, float B, float C, float F, float &xmax, float &ymax)
-{
- float denom = 4.0f * A * C - B * B;
- if (denom > 0.0f && A != 0.0f && C != 0.0f) {
- xmax = sqrtf(F) / (2.0f * A) * (sqrtf(F * (4.0f * A - B * B / C)) + B * B * sqrtf(F / (C * denom)));
- ymax = sqrtf(F) / (2.0f * C) * (sqrtf(F * (4.0f * C - B * B / A)) + B * B * sqrtf(F / (A * denom)));
+typedef struct ReadEWAData {
+ MemoryBuffer *buffer;
+ PixelSampler sampler;
+ float ufac, vfac;
+} ReadEWAData;
+
+static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4])
+{
+ ReadEWAData *data = (ReadEWAData *) userdata;
+ switch (data->sampler) {
+ case COM_PS_NEAREST:
+ data->buffer->read(result, x, y);
+ break;
+ case COM_PS_BILINEAR:
+ data->buffer->readBilinear(result,
+ (float)x + data->ufac,
+ (float)y + data->vfac);
+ break;
+ case COM_PS_BICUBIC:
+ /* TOOD(sergey): no readBicubic method yet */
+ data->buffer->readBilinear(result,
+ (float)x + data->ufac,
+ (float)y + data->vfac);
+ break;
+ default:
+ zero_v4(result);
+ break;
}
- else {
- xmax = 0.0f;
- ymax = 0.0f;
- }
-}
-
-static void ellipse_params(float Ux, float Uy, float Vx, float Vy,
- float &A, float &B, float &C, float &F, float &umax, float &vmax)
-{
- A = Vx * Vx + Vy * Vy;
- B = -2.0f * (Ux * Vx + Uy * Vy);
- C = Ux * Ux + Uy * Uy;
- F = A * C - B * B * 0.25f;
-
- float factor = (F != 0.0f ? (float)(EWA_MAXIDX + 1) / F : 0.0f);
- A *= factor;
- B *= factor;
- C *= factor;
- F = (float)(EWA_MAXIDX + 1);
-
- ellipse_bounds(A, B, C, sqrtf(F), umax, vmax);
}
-/**
- * Filtering method based on
- * "Creating raster omnimax images from multiple perspective views using the elliptical weighted average filter"
- * by Ned Greene and Paul S. Heckbert (1986)
- */
void MemoryBuffer::readEWA(float result[4], const float uv[2], const float derivatives[2][2], PixelSampler sampler)
{
- zero_v4(result);
- int width = this->getWidth(), height = this->getHeight();
- if (width == 0 || height == 0)
- return;
-
- float u = uv[0], v = uv[1];
- float Ux = derivatives[0][0], Vx = derivatives[1][0], Uy = derivatives[0][1], Vy = derivatives[1][1];
- float A, B, C, F, ue, ve;
- ellipse_params(Ux, Uy, Vx, Vy, A, B, C, F, ue, ve);
+ ReadEWAData data;
+ data.buffer = this;
+ data.sampler = sampler;
+ data.ufac = uv[0] - floorf(uv[0]);
+ data.vfac = uv[1] - floorf(uv[1]);
- /* Note: highly eccentric ellipses can lead to large texture space areas to filter!
- * This is limited somewhat by the EWA_WTS size in the loop, but a nicer approach
- * could be the one found in
- * "High Quality Elliptical Texture Filtering on GPU"
- * by Pavlos Mavridis and Georgios Papaioannou
- * in which the eccentricity of the ellipse is clamped.
- */
-
- int U0 = (int)u;
- int V0 = (int)v;
- /* pixel offset for interpolation */
- float ufac = u - floorf(u), vfac = v - floorf(v);
- /* filter size */
- int u1 = (int)(u - ue);
- int u2 = (int)(u + ue);
- int v1 = (int)(v - ve);
- int v2 = (int)(v + ve);
-
- /* sane clamping to avoid unnecessarily huge loops */
- /* note: if eccentricity gets clamped (see above),
- * the ue/ve limits can also be lowered accordingly
+ int width = this->getWidth(), height = this->getHeight();
+ /* TODO(sergey): Render pipeline uses normalized coordinates and derivatives,
+ * but compositor uses pixel space. For now let's just divide the values and
+ * switch compositor to normalized space for EWA later.
*/
- if (U0 - u1 > EWA_MAXIDX) u1 = U0 - EWA_MAXIDX;
- if (u2 - U0 > EWA_MAXIDX) u2 = U0 + EWA_MAXIDX;
- if (V0 - v1 > EWA_MAXIDX) v1 = V0 - EWA_MAXIDX;
- if (v2 - V0 > EWA_MAXIDX) v2 = V0 + EWA_MAXIDX;
-
- /* Early output check for cases the whole region is outside of the buffer. */
- if ((u2 < m_rect.xmin || u1 >= m_rect.xmax) ||
- (v2 < m_rect.ymin || v1 >= m_rect.ymax))
- {
- zero_v4(result);
- return;
- }
-
- /* Clamp sampling rectagle to the buffer dimensions. */
- u1 = max_ii(u1, m_rect.xmin);
- u2 = min_ii(u2, m_rect.xmax);
- v1 = max_ii(v1, m_rect.ymin);
- v2 = min_ii(v2, m_rect.ymax);
-
- float DDQ = 2.0f * A;
- float U = u1 - U0;
- float ac1 = A * (2.0f * U + 1.0f);
- float ac2 = A * U * U;
- float BU = B * U;
-
- float sum = 0.0f;
- for (int v = v1; v <= v2; ++v) {
- float V = v - V0;
-
- float DQ = ac1 + B * V;
- float Q = (C * V + BU) * V + ac2;
- for (int u = u1; u <= u2; ++u) {
- if (Q < F) {
- float tc[4];
- const float wt = EWA_WTS[CLAMPIS((int)Q, 0, EWA_MAXIDX)];
- switch (sampler) {
- case COM_PS_NEAREST: read(tc, u, v); break;
- case COM_PS_BILINEAR: readBilinear(tc, (float)u + ufac, (float)v + vfac); break;
- case COM_PS_BICUBIC: readBilinear(tc, (float)u + ufac, (float)v + vfac); break; /* XXX no readBicubic method yet */
- default: zero_v4(tc); break;
- }
- madd_v4_v4fl(result, tc, wt);
- sum += wt;
- }
- Q += DQ;
- DQ += DDQ;
- }
- }
-
- mul_v4_fl(result, (sum != 0.0f ? 1.0f / sum : 0.0f));
+ float uv_normal[2] = {uv[0] / width, uv[1] / height};
+ float du_normal[2] = {derivatives[0][0] / width, derivatives[0][1] / height};
+ float dv_normal[2] = {derivatives[1][0] / width, derivatives[1][1] / height};
+
+ BLI_ewa_filter(this->getWidth(), this->getHeight(),
+ false,
+ true,
+ uv_normal, du_normal, dv_normal,
+ read_ewa_pixel_sampled,
+ &data,
+ result);
}
diff --git a/source/blender/compositor/intern/COM_NodeConverter.cpp b/source/blender/compositor/intern/COM_NodeConverter.cpp
index 5965eade389..208a3db812f 100644
--- a/source/blender/compositor/intern/COM_NodeConverter.cpp
+++ b/source/blender/compositor/intern/COM_NodeConverter.cpp
@@ -83,9 +83,9 @@ NodeOperation *NodeConverter::setInvalidOutput(NodeOutput *output)
return operation;
}
-NodeOperationOutput *NodeConverter::addInputProxy(NodeInput *input)
+NodeOperationOutput *NodeConverter::addInputProxy(NodeInput *input, bool use_conversion)
{
- SocketProxyOperation *proxy = new SocketProxyOperation(input->getDataType());
+ SocketProxyOperation *proxy = new SocketProxyOperation(input->getDataType(), use_conversion);
m_builder->addOperation(proxy);
m_builder->mapInputSocket(input, proxy->getInputSocket(0));
@@ -93,9 +93,9 @@ NodeOperationOutput *NodeConverter::addInputProxy(NodeInput *input)
return proxy->getOutputSocket();
}
-NodeOperationInput *NodeConverter::addOutputProxy(NodeOutput *output)
+NodeOperationInput *NodeConverter::addOutputProxy(NodeOutput *output, bool use_conversion)
{
- SocketProxyOperation *proxy = new SocketProxyOperation(output->getDataType());
+ SocketProxyOperation *proxy = new SocketProxyOperation(output->getDataType(), use_conversion);
m_builder->addOperation(proxy);
m_builder->mapOutputSocket(output, proxy->getOutputSocket());
@@ -156,3 +156,13 @@ void NodeConverter::addOutputVector(NodeOutput *output, const float value[3])
m_builder->addOperation(operation);
m_builder->mapOutputSocket(output, operation->getOutputSocket());
}
+
+void NodeConverter::registerViewer(ViewerOperation *viewer)
+{
+ m_builder->registerViewer(viewer);
+}
+
+ViewerOperation *NodeConverter::active_viewer() const
+{
+ return m_builder->active_viewer();
+}
diff --git a/source/blender/compositor/intern/COM_NodeConverter.h b/source/blender/compositor/intern/COM_NodeConverter.h
index cad8408a2bf..414b4f1ee95 100644
--- a/source/blender/compositor/intern/COM_NodeConverter.h
+++ b/source/blender/compositor/intern/COM_NodeConverter.h
@@ -34,6 +34,8 @@ class NodeOperationInput;
class NodeOperationOutput;
class NodeOperationBuilder;
+class ViewerOperation;
+
/** Interface type for converting a \a Node into \a NodeOperation.
* This is passed to \a Node::convertToOperation methods and allows them
* to register any number of operations, create links between them,
@@ -68,12 +70,12 @@ public:
* This operation will be removed later and replaced
* by direct links between the connected operations.
*/
- NodeOperationOutput *addInputProxy(NodeInput *input);
+ NodeOperationOutput *addInputProxy(NodeInput *input, bool use_conversion);
/** Create a proxy operation for a node output.
* This operation will be removed later and replaced
* by direct links between the connected operations.
*/
- NodeOperationInput *addOutputProxy(NodeOutput *output);
+ NodeOperationInput *addOutputProxy(NodeOutput *output, bool use_conversion);
/** Define a constant input value. */
void addInputValue(NodeOperationInput *input, float value);
@@ -102,6 +104,11 @@ public:
*/
NodeOperation *setInvalidOutput(NodeOutput *output);
+ /** Define a viewer operation as the active output, if possible */
+ void registerViewer(ViewerOperation *viewer);
+ /** The currently active viewer output operation */
+ ViewerOperation *active_viewer() const;
+
private:
/** The internal builder for storing the results of the graph construction. */
NodeOperationBuilder *m_builder;
diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cpp
index 5c3de84f13c..2dcf419d81b 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.cpp
+++ b/source/blender/compositor/intern/COM_NodeGraph.cpp
@@ -101,8 +101,7 @@ void NodeGraph::add_bNodeTree(const CompositorContext &context, int nodes_start,
const bNodeTree *basetree = context.getbNodeTree();
/* update viewers in the active edittree as well the base tree (for backdrop) */
- bool is_active_group = ((parent_key.value == basetree->active_viewer_key.value) ||
- (tree == basetree));
+ bool is_active_group = (parent_key.value == basetree->active_viewer_key.value);
/* add all nodes of the tree to the node list */
for (bNode *node = (bNode *)tree->nodes.first; node; node = node->next) {
@@ -146,17 +145,19 @@ void NodeGraph::add_bNode(const CompositorContext &context, bNodeTree *b_ntree,
}
}
-NodeInput *NodeGraph::find_input(const NodeRange &node_range, bNodeSocket *b_socket)
+NodeGraph::NodeInputs NodeGraph::find_inputs(const NodeRange &node_range, bNodeSocket *b_socket)
{
+ NodeInputs result;
for (NodeGraph::NodeIterator it = node_range.first; it != node_range.second; ++it) {
Node *node = *it;
for (int index = 0; index < node->getNumberOfInputSockets(); index++) {
NodeInput *input = node->getInputSocket(index);
- if (input->getbNodeSocket() == b_socket)
- return input;
+ if (input->getbNodeSocket() == b_socket) {
+ result.push_back(input);
+ }
}
}
- return NULL;
+ return result;
}
NodeOutput *NodeGraph::find_output(const NodeRange &node_range, bNodeSocket *b_socket)
@@ -165,8 +166,9 @@ NodeOutput *NodeGraph::find_output(const NodeRange &node_range, bNodeSocket *b_s
Node *node = *it;
for (int index = 0; index < node->getNumberOfOutputSockets(); index++) {
NodeOutput *output = node->getOutputSocket(index);
- if (output->getbNodeSocket() == b_socket)
+ if (output->getbNodeSocket() == b_socket) {
return output;
+ }
}
}
return NULL;
@@ -177,15 +179,22 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink
/// @note: ignore invalid links
if (!(b_nodelink->flag & NODE_LINK_VALID))
return;
-
- NodeInput *input = find_input(node_range, b_nodelink->tosock);
+
+ /* Note: a DNA input socket can have multiple NodeInput in the compositor tree! (proxies)
+ * The output then gets linked to each one of them.
+ */
+
NodeOutput *output = find_output(node_range, b_nodelink->fromsock);
- if (!input || !output)
- return;
- if (input->isLinked())
+ if (!output)
return;
- add_link(output, input);
+ NodeInputs inputs = find_inputs(node_range, b_nodelink->tosock);
+ for (NodeInputs::const_iterator it = inputs.begin(); it != inputs.end(); ++it) {
+ NodeInput *input = *it;
+ if (input->isLinked())
+ continue;
+ add_link(output, input);
+ }
}
/* **** Special proxy node type conversions **** */
@@ -193,7 +202,7 @@ void NodeGraph::add_bNodeLink(const NodeRange &node_range, bNodeLink *b_nodelink
void NodeGraph::add_proxies_mute(bNodeTree *b_ntree, bNode *b_node, bNodeInstanceKey key, bool is_active_group)
{
for (bNodeLink *b_link = (bNodeLink *)b_node->internal_links.first; b_link; b_link = b_link->next) {
- SocketProxyNode *proxy = new SocketProxyNode(b_node, b_link->fromsock, b_link->tosock);
+ SocketProxyNode *proxy = new SocketProxyNode(b_node, b_link->fromsock, b_link->tosock, false);
add_node(proxy, b_ntree, key, is_active_group);
}
}
@@ -210,7 +219,7 @@ void NodeGraph::add_proxies_skip(bNodeTree *b_ntree, bNode *b_node, bNodeInstanc
}
if (input) {
- SocketProxyNode *proxy = new SocketProxyNode(b_node, input, output);
+ SocketProxyNode *proxy = new SocketProxyNode(b_node, input, output, true);
add_node(proxy, b_ntree, key, is_active_group);
}
}
@@ -228,7 +237,7 @@ void NodeGraph::add_proxies_group_inputs(bNode *b_node, bNode *b_node_io)
for (bNodeSocket *b_sock_io = (bNodeSocket *)b_node_io->outputs.first; b_sock_io; b_sock_io = b_sock_io->next) {
bNodeSocket *b_sock_group = find_b_node_input(b_node, b_sock_io->identifier);
if (b_sock_group) {
- SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_group, b_sock_io);
+ SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_group, b_sock_io, true);
add_node(proxy, b_group_tree, key, is_active_group);
}
}
@@ -251,7 +260,7 @@ void NodeGraph::add_proxies_group_outputs(bNode *b_node, bNode *b_node_io, bool
add_node(buffer, b_group_tree, key, is_active_group);
}
else {
- SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_io, b_sock_group);
+ SocketProxyNode *proxy = new SocketProxyNode(b_node_io, b_sock_io, b_sock_group, true);
add_node(proxy, b_group_tree, key, is_active_group);
}
}
@@ -285,6 +294,6 @@ void NodeGraph::add_proxies_group(const CompositorContext &context, bNode *b_nod
void NodeGraph::add_proxies_reroute(bNodeTree *b_ntree, bNode *b_node, bNodeInstanceKey key, bool is_active_group)
{
- SocketProxyNode *proxy = new SocketProxyNode(b_node, (bNodeSocket *)b_node->inputs.first, (bNodeSocket *)b_node->outputs.first);
+ SocketProxyNode *proxy = new SocketProxyNode(b_node, (bNodeSocket *)b_node->inputs.first, (bNodeSocket *)b_node->outputs.first, false);
add_node(proxy, b_ntree, key, is_active_group);
}
diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h
index 81799d76e1d..67f94bf3465 100644
--- a/source/blender/compositor/intern/COM_NodeGraph.h
+++ b/source/blender/compositor/intern/COM_NodeGraph.h
@@ -78,6 +78,7 @@ public:
protected:
typedef std::pair<NodeIterator, NodeIterator> NodeRange;
+ typedef std::vector<NodeInput *> NodeInputs;
static bNodeSocket *find_b_node_input(bNode *b_node, const char *identifier);
static bNodeSocket *find_b_node_output(bNode *b_node, const char *identifier);
@@ -89,7 +90,7 @@ protected:
void add_bNode(const CompositorContext &context, bNodeTree *b_ntree, bNode *b_node, bNodeInstanceKey key, bool is_active_group);
- NodeInput *find_input(const NodeRange &node_range, bNodeSocket *b_socket);
+ NodeInputs find_inputs(const NodeRange &node_range, bNodeSocket *b_socket);
NodeOutput *find_output(const NodeRange &node_range, bNodeSocket *b_socket);
void add_bNodeLink(const NodeRange &node_range, bNodeLink *bNodeLink);
diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h
index 3f636dff63c..d9c16615fb6 100644
--- a/source/blender/compositor/intern/COM_NodeOperation.h
+++ b/source/blender/compositor/intern/COM_NodeOperation.h
@@ -38,7 +38,7 @@ extern "C" {
#include "COM_MemoryProxy.h"
#include "COM_SocketReader.h"
-#include "OCL_opencl.h"
+#include "clew.h"
using std::list;
using std::min;
@@ -288,6 +288,8 @@ public:
virtual bool isFileOutputOperation() const { return false; }
virtual bool isProxyOperation() const { return false; }
+ virtual bool useDatatypeConversion() const { return true; }
+
inline bool isBreaked() const {
return this->m_btree->test_break(this->m_btree->tbh);
}
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
index a90bac847c0..fb5bc8fcd9b 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
@@ -38,12 +38,14 @@ extern "C" {
#include "COM_SocketProxyOperation.h"
#include "COM_ReadBufferOperation.h"
#include "COM_WriteBufferOperation.h"
+#include "COM_ViewerOperation.h"
#include "COM_NodeOperationBuilder.h" /* own include */
NodeOperationBuilder::NodeOperationBuilder(const CompositorContext *context, bNodeTree *b_nodetree) :
m_context(context),
- m_current_node(NULL)
+ m_current_node(NULL),
+ m_active_viewer(NULL)
{
m_graph.from_bNodeTree(*context, b_nodetree);
}
@@ -239,6 +241,25 @@ void NodeOperationBuilder::addNodeInputPreview(NodeInput *input)
}
}
+void NodeOperationBuilder::registerViewer(ViewerOperation *viewer)
+{
+ if (m_active_viewer) {
+ if (m_current_node->isInActiveGroup()) {
+ /* deactivate previous viewer */
+ m_active_viewer->setActive(false);
+
+ m_active_viewer = viewer;
+ viewer->setActive(true);
+ }
+ }
+ else {
+ if (m_current_node->getbNodeTree() == m_context->getbNodeTree()) {
+ m_active_viewer = viewer;
+ viewer->setActive(true);
+ }
+ }
+}
+
/****************************
**** Optimization Steps ****
****************************/
@@ -248,6 +269,13 @@ void NodeOperationBuilder::add_datatype_conversions()
Links convert_links;
for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) {
const Link &link = *it;
+
+ /* proxy operations can skip data type conversion */
+ NodeOperation *from_op = &link.from()->getOperation();
+ NodeOperation *to_op = &link.to()->getOperation();
+ if (!(from_op->useDatatypeConversion() || to_op->useDatatypeConversion()))
+ continue;
+
if (link.from()->getDataType() != link.to()->getDataType())
convert_links.push_back(link);
}
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
index ab890282bab..633ddc9152a 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h
@@ -44,6 +44,7 @@ class NodeOperationOutput;
class PreviewOperation;
class WriteBufferOperation;
+class ViewerOperation;
class NodeOperationBuilder {
public:
@@ -87,6 +88,12 @@ private:
Node *m_current_node;
+ /** Operation that will be writing to the viewer image
+ * Only one operation can occupy this place at a time,
+ * to avoid race conditions
+ */
+ ViewerOperation *m_active_viewer;
+
public:
NodeOperationBuilder(const CompositorContext *context, bNodeTree *b_nodetree);
~NodeOperationBuilder();
@@ -110,6 +117,11 @@ public:
/** Add a preview operation for a node input */
void addNodeInputPreview(NodeInput *input);
+ /** Define a viewer operation as the active output, if possible */
+ void registerViewer(ViewerOperation *viewer);
+ /** The currently active viewer output operation */
+ ViewerOperation *active_viewer() const { return m_active_viewer; }
+
protected:
static NodeInput *find_node_input(const InputSocketMap &map, NodeOperationInput *op_input);
static const OpInputs &find_operation_inputs(const OpInputInverseMap &map, NodeInput *node_input);
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
index 2cfc10cff29..c5b663d2aef 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
@@ -103,7 +103,7 @@ void OpenCLDevice::COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel ker
if (offsetIndex != -1) {
cl_int error;
rcti *rect = memoryBuffer->getRect();
- cl_int2 offset = {rect->xmin, rect->ymin};
+ cl_int2 offset = {{rect->xmin, rect->ymin}};
error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
@@ -114,7 +114,7 @@ void OpenCLDevice::COM_clAttachSizeToKernelParameter(cl_kernel kernel, int offse
{
if (offsetIndex != -1) {
cl_int error;
- cl_int2 offset = {(cl_int)operation->getWidth(), (cl_int)operation->getHeight()};
+ cl_int2 offset = {{(cl_int)operation->getWidth(), (cl_int)operation->getHeight()}};
error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
@@ -154,7 +154,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemo
bool breaked = false;
for (offsety = 0; offsety < height && (!breaked); offsety += localSize) {
- offset[1] = offsety;
+ offset.y = offsety;
if (offsety + localSize < height) {
size[1] = localSize;
}
@@ -169,7 +169,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, MemoryBuffer *outputMemo
else {
size[0] = width - offsetx;
}
- offset[0] = offsetx;
+ offset.x = offsetx;
error = clSetKernelArg(kernel, offsetIndex, sizeof(cl_int2), &offset);
if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h
index 50cc6f25f70..94df2f2b44c 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.h
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.h
@@ -26,7 +26,7 @@ class OpenCLDevice;
#define _COM_OpenCLDevice_h
#include "COM_Device.h"
-#include "OCL_opencl.h"
+#include "clew.h"
#include "COM_WorkScheduler.h"
#include "COM_ReadBufferOperation.h"
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index d60f9cb7f10..e1016731c7f 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -28,7 +28,7 @@
#include "COM_CPUDevice.h"
#include "COM_OpenCLDevice.h"
#include "COM_OpenCLKernels.cl.h"
-#include "OCL_opencl.h"
+#include "clew.h"
#include "COM_WriteBufferOperation.h"
#include "MEM_guardedalloc.h"
@@ -274,7 +274,7 @@ bool WorkScheduler::hasGPUDevices()
#endif
}
-static void 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);
}
@@ -326,7 +326,7 @@ void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads)
g_context = NULL;
g_program = NULL;
- if (!OCL_init()) /* this will check for errors and skip if already initialized */
+ if (clewInit() != CLEW_SUCCESS) /* this will check for errors and skip if already initialized */
return;
if (clCreateContextFromType) {
diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cpp
index 99655c67a3f..ec9ef6c7e68 100644
--- a/source/blender/compositor/intern/COM_compositor.cpp
+++ b/source/blender/compositor/intern/COM_compositor.cpp
@@ -32,7 +32,7 @@ extern "C" {
#include "COM_compositor.h"
#include "COM_ExecutionSystem.h"
#include "COM_WorkScheduler.h"
-#include "OCL_opencl.h"
+#include "clew.h"
#include "COM_MovieDistortionOperation.h"
static ThreadMutex s_compositorMutex;
diff --git a/source/blender/compositor/nodes/COM_BlurNode.cpp b/source/blender/compositor/nodes/COM_BlurNode.cpp
index b8421dcb102..f3d0c33d3b3 100644
--- a/source/blender/compositor/nodes/COM_BlurNode.cpp
+++ b/source/blender/compositor/nodes/COM_BlurNode.cpp
@@ -53,7 +53,6 @@ void BlurNode::convertToOperations(NodeConverter &converter, const CompositorCon
if (data->filtertype == R_FILTER_FAST_GAUSS) {
FastGaussianBlurOperation *operationfgb = new FastGaussianBlurOperation();
operationfgb->setData(data);
- operationfgb->setChunksize(context.getChunksize());
converter.addOperation(operationfgb);
converter.mapInputSocket(getInputSocket(1), operationfgb->getInputSocket(1));
@@ -106,6 +105,7 @@ void BlurNode::convertToOperations(NodeConverter &converter, const CompositorCon
GaussianXBlurOperation *operationx = new GaussianXBlurOperation();
operationx->setData(data);
operationx->setQuality(quality);
+ operationx->checkOpenCL();
converter.addOperation(operationx);
converter.mapInputSocket(getInputSocket(1), operationx->getInputSocket(1));
@@ -113,6 +113,7 @@ void BlurNode::convertToOperations(NodeConverter &converter, const CompositorCon
GaussianYBlurOperation *operationy = new GaussianYBlurOperation();
operationy->setData(data);
operationy->setQuality(quality);
+ operationy->checkOpenCL();
converter.addOperation(operationy);
converter.mapInputSocket(getInputSocket(1), operationy->getInputSocket(1));
diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
index f750a44a788..48c8acfc6a1 100644
--- a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
+++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
@@ -29,7 +29,9 @@
#include "COM_WriteBufferOperation.h"
#include "COM_ReadBufferOperation.h"
-SocketProxyNode::SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput) : Node(editorNode, false)
+SocketProxyNode::SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput, bool use_conversion) :
+ Node(editorNode, false),
+ m_use_conversion(use_conversion)
{
DataType dt;
@@ -46,7 +48,7 @@ SocketProxyNode::SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bN
void SocketProxyNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
- NodeOperationOutput *proxy_output = converter.addInputProxy(getInputSocket(0));
+ NodeOperationOutput *proxy_output = converter.addInputProxy(getInputSocket(0), m_use_conversion);
converter.mapOutputSocket(getOutputSocket(), proxy_output);
}
diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.h b/source/blender/compositor/nodes/COM_SocketProxyNode.h
index 2fbaa71421c..5dbf39382cc 100644
--- a/source/blender/compositor/nodes/COM_SocketProxyNode.h
+++ b/source/blender/compositor/nodes/COM_SocketProxyNode.h
@@ -31,8 +31,15 @@
*/
class SocketProxyNode : public Node {
public:
- SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput);
+ SocketProxyNode(bNode *editorNode, bNodeSocket *editorInput, bNodeSocket *editorOutput, bool use_conversion);
void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+
+ bool getUseConversion() const { return m_use_conversion; }
+ void setUseConversion(bool use_conversion) { m_use_conversion = use_conversion; }
+
+private:
+ /** If true, the proxy will convert input and output data to/from the proxy socket types. */
+ bool m_use_conversion;
};
diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
index 8eb1b76e890..15eca0a97e5 100644
--- a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cpp
@@ -35,8 +35,7 @@ SplitViewerNode::SplitViewerNode(bNode *editorNode) : Node(editorNode)
void SplitViewerNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
bNode *editorNode = this->getbNode();
- bool is_active = ((editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) &&
- (editorNode->flag & NODE_DO_OUTPUT) && this->isInActiveGroup());
+ bool do_output = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) && (editorNode->flag & NODE_DO_OUTPUT);
NodeInput *image1Socket = this->getInputSocket(0);
NodeInput *image2Socket = this->getInputSocket(1);
@@ -54,7 +53,6 @@ void SplitViewerNode::convertToOperations(NodeConverter &converter, const Compos
ViewerOperation *viewerOperation = new ViewerOperation();
viewerOperation->setImage(image);
viewerOperation->setImageUser(imageUser);
- viewerOperation->setActive(is_active);
viewerOperation->setViewSettings(context.getViewSettings());
viewerOperation->setDisplaySettings(context.getDisplaySettings());
@@ -68,4 +66,7 @@ void SplitViewerNode::convertToOperations(NodeConverter &converter, const Compos
converter.addLink(splitViewerOperation->getOutputSocket(), viewerOperation->getInputSocket(0));
converter.addPreview(splitViewerOperation->getOutputSocket());
+
+ if (do_output)
+ converter.registerViewer(viewerOperation);
}
diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
new file mode 100644
index 00000000000..ed14acabf36
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2014, 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:
+ * Lukas Toenne
+ */
+
+#include "COM_SunBeamsNode.h"
+#include "COM_SunBeamsOperation.h"
+
+SunBeamsNode::SunBeamsNode(bNode *editorNode) : Node(editorNode)
+{
+ /* pass */
+}
+
+void SunBeamsNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
+{
+ NodeInput *inputSocket = this->getInputSocket(0);
+ NodeOutput *outputSocket = this->getOutputSocket(0);
+ NodeSunBeams *data = (NodeSunBeams *)getbNode()->storage;
+
+ SunBeamsOperation *operation = new SunBeamsOperation();
+ operation->setData(*data);
+ converter.addOperation(operation);
+
+ converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
+ converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
+}
diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.h b/source/blender/compositor/nodes/COM_SunBeamsNode.h
new file mode 100644
index 00000000000..4024eb276bc
--- /dev/null
+++ b/source/blender/compositor/nodes/COM_SunBeamsNode.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2014, 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:
+ * Lukas Toenne
+ */
+
+#ifndef _COM_SunBeamsNode_h_
+#define _COM_SunBeamsNode_h_
+
+#include "COM_Node.h"
+
+/**
+ * @brief SunBeamsNode
+ * @ingroup Node
+ */
+class SunBeamsNode : public Node {
+public:
+ SunBeamsNode(bNode *editorNode);
+ void convertToOperations(NodeConverter &converter, const CompositorContext &context) const;
+};
+
+#endif
diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cpp b/source/blender/compositor/nodes/COM_SwitchNode.cpp
index 692b8d743f6..10f0ee3821d 100644
--- a/source/blender/compositor/nodes/COM_SwitchNode.cpp
+++ b/source/blender/compositor/nodes/COM_SwitchNode.cpp
@@ -33,9 +33,9 @@ void SwitchNode::convertToOperations(NodeConverter &converter, const CompositorC
NodeOperationOutput *result;
if (!condition)
- result = converter.addInputProxy(getInputSocket(0));
+ result = converter.addInputProxy(getInputSocket(0), false);
else
- result = converter.addInputProxy(getInputSocket(1));
+ result = converter.addInputProxy(getInputSocket(1), false);
converter.mapOutputSocket(getOutputSocket(0), result);
}
diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cpp b/source/blender/compositor/nodes/COM_ViewerNode.cpp
index 09a3cea2da1..07aa960c4d9 100644
--- a/source/blender/compositor/nodes/COM_ViewerNode.cpp
+++ b/source/blender/compositor/nodes/COM_ViewerNode.cpp
@@ -34,8 +34,7 @@ ViewerNode::ViewerNode(bNode *editorNode) : Node(editorNode)
void ViewerNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
bNode *editorNode = this->getbNode();
- bool is_active = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) &&
- ((editorNode->flag & NODE_DO_OUTPUT) && this->isInActiveGroup());
+ bool do_output = (editorNode->flag & NODE_DO_OUTPUT_RECALC || context.isRendering()) && (editorNode->flag & NODE_DO_OUTPUT);
bool ignore_alpha = editorNode->custom2 & CMP_NODE_OUTPUT_IGNORE_ALPHA;
NodeInput *imageSocket = this->getInputSocket(0);
@@ -47,7 +46,6 @@ void ViewerNode::convertToOperations(NodeConverter &converter, const CompositorC
viewerOperation->setbNodeTree(context.getbNodeTree());
viewerOperation->setImage(image);
viewerOperation->setImageUser(imageUser);
- viewerOperation->setActive(is_active);
viewerOperation->setChunkOrder((OrderOfChunks)editorNode->custom1);
viewerOperation->setCenterX(editorNode->custom3);
viewerOperation->setCenterY(editorNode->custom4);
@@ -74,4 +72,7 @@ void ViewerNode::convertToOperations(NodeConverter &converter, const CompositorC
converter.mapInputSocket(depthSocket, viewerOperation->getInputSocket(2));
converter.addNodeInputPreview(imageSocket);
+
+ if (do_output)
+ converter.registerViewer(viewerOperation);
}
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
index e7af9319f88..d5aafc7c2ae 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cpp
@@ -91,6 +91,18 @@ float *BlurBaseOperation::make_gausstab(float rad, int size)
return gausstab;
}
+#ifdef __SSE2__
+__m128 *BlurBaseOperation::convert_gausstab_sse(const float *gausstab, float rad, int size)
+{
+ int n = 2 * size + 1;
+ __m128 *gausstab_sse = (__m128 *) MEM_mallocN_aligned(sizeof(__m128) * n, 16, "gausstab sse");
+ for (int i = 0; i < n; ++i) {
+ gausstab_sse[i] = _mm_set1_ps(gausstab[i]);
+ }
+ return gausstab_sse;
+}
+#endif
+
/* normalized distance from the current (inverted so 1.0 is close and 0.0 is far)
* 'ease' is applied after, looks nicer */
float *BlurBaseOperation::make_dist_fac_inverse(float rad, int size, int falloff)
diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.h b/source/blender/compositor/operations/COM_BlurBaseOperation.h
index 052a525ef2c..e97dd4d766d 100644
--- a/source/blender/compositor/operations/COM_BlurBaseOperation.h
+++ b/source/blender/compositor/operations/COM_BlurBaseOperation.h
@@ -27,6 +27,10 @@
#define MAX_GAUSSTAB_RADIUS 30000
+#ifdef __SSE2__
+# include <emmintrin.h>
+#endif
+
class BlurBaseOperation : public NodeOperation, public QualityStepHelper {
private:
@@ -34,6 +38,9 @@ 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);
+#endif
float *make_dist_fac_inverse(float rad, int size, int falloff);
void updateSize();
diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.h b/source/blender/compositor/operations/COM_BokehImageOperation.h
index f1f0f1ed11c..3cf9afda32a 100644
--- a/source/blender/compositor/operations/COM_BokehImageOperation.h
+++ b/source/blender/compositor/operations/COM_BokehImageOperation.h
@@ -88,7 +88,7 @@ private:
bool m_deleteData;
/**
- * @brief detemine the coordinate of a flap cornder
+ * @brief determine the coordinate of a flap cornder
*
* @param r result in bokehimage space are stored [x,y]
* @param flapNumber the flap number to calculate
diff --git a/source/blender/compositor/operations/COM_CropOperation.cpp b/source/blender/compositor/operations/COM_CropOperation.cpp
index c514b576dcf..9bcc6fb2541 100644
--- a/source/blender/compositor/operations/COM_CropOperation.cpp
+++ b/source/blender/compositor/operations/COM_CropOperation.cpp
@@ -109,9 +109,9 @@ bool CropImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBuffe
return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
}
-void CropImageOperation::determineResolution(unsigned int resolution[2], unsigned int preferedResolution[2])
+void CropImageOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
{
- NodeOperation::determineResolution(resolution, preferedResolution);
+ NodeOperation::determineResolution(resolution, preferredResolution);
updateArea();
resolution[0] = this->m_xmax - this->m_xmin;
resolution[1] = this->m_ymax - this->m_ymin;
diff --git a/source/blender/compositor/operations/COM_CropOperation.h b/source/blender/compositor/operations/COM_CropOperation.h
index 4890ede18a9..0b396ca7800 100644
--- a/source/blender/compositor/operations/COM_CropOperation.h
+++ b/source/blender/compositor/operations/COM_CropOperation.h
@@ -56,7 +56,7 @@ private:
public:
CropImageOperation();
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
- void determineResolution(unsigned int resolution[2], unsigned int preferedResolution[2]);
+ void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
index b54e47c136d..cbf4ce693d9 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
@@ -371,7 +371,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
float *rectf = result->buffer;
// temp holds maxima for every step in the algorithm, buf holds a
- // single row or column of input values, padded with MAXFLOATs to
+ // single row or column of input values, padded with FLT_MAX's to
// simplify the logic.
float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp");
float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), "dilate erode buf");
@@ -380,7 +380,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
// first pass, horizontal dilate/erode
for (y = ymin; y < ymax; y++) {
for (x = 0; x < bwidth + 5 * half_window; x++) {
- buf[x] = -MAXFLOAT;
+ buf[x] = -FLT_MAX;
}
for (x = xmin; x < xmax; ++x) {
buf[x - rect->xmin + window - 1] = buffer[4 * (y * width + x)];
@@ -405,7 +405,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
// second pass, vertical dilate/erode
for (x = 0; x < bwidth; x++) {
for (y = 0; y < bheight + 5 * half_window; y++) {
- buf[y] = -MAXFLOAT;
+ buf[y] = -FLT_MAX;
}
for (y = ymin; y < ymax; y++) {
buf[y - rect->ymin + window - 1] = rectf[(y - ymin) * bwidth + x];
@@ -498,7 +498,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
float *rectf = result->buffer;
// temp holds maxima for every step in the algorithm, buf holds a
- // single row or column of input values, padded with MAXFLOATs to
+ // single row or column of input values, padded with FLT_MAX's to
// simplify the logic.
float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp");
float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), "dilate erode buf");
@@ -507,7 +507,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
// first pass, horizontal dilate/erode
for (y = ymin; y < ymax; y++) {
for (x = 0; x < bwidth + 5 * half_window; x++) {
- buf[x] = MAXFLOAT;
+ buf[x] = FLT_MAX;
}
for (x = xmin; x < xmax; ++x) {
buf[x - rect->xmin + window - 1] = buffer[4 * (y * width + x)];
@@ -532,7 +532,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
// second pass, vertical dilate/erode
for (x = 0; x < bwidth; x++) {
for (y = 0; y < bheight + 5 * half_window; y++) {
- buf[y] = MAXFLOAT;
+ buf[y] = FLT_MAX;
}
for (y = ymin; y < ymax; y++) {
buf[y - rect->ymin + window - 1] = rectf[(y - ymin) * bwidth + x];
diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
index 0cea2a7183f..962a95ebd05 100644
--- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp
@@ -69,16 +69,16 @@ void DirectionalBlurOperation::initExecution()
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, 0, 0, 0};
- float col2[4] = {0, 0, 0, 0};
- this->m_inputProgram->readSampled(col2, x, y, COM_PS_NEAREST);
+ float col[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ float col2[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ this->m_inputProgram->readSampled(col2, x, y, COM_PS_BILINEAR);
float ltx = this->m_tx;
float lty = this->m_ty;
float lsc = this->m_sc;
float lrot = this->m_rot;
/* blur the image */
for (int i = 0; i < iterations; ++i) {
- const float cs = cos(lrot), ss = sin(lrot);
+ const float cs = cosf(lrot), ss = sinf(lrot);
const float isc = 1.0f / (1.0f + lsc);
const float v = isc * (y - this->m_center_y_pix) + lty;
@@ -87,7 +87,7 @@ void DirectionalBlurOperation::executePixel(float output[4], int x, int y, void
this->m_inputProgram->readSampled(col,
cs * u + ss * v + this->m_center_x_pix,
cs * v - ss * u + this->m_center_y_pix,
- COM_PS_NEAREST);
+ COM_PS_BILINEAR);
add_v4_v4(col2, col);
@@ -109,8 +109,8 @@ void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device,
cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", NULL);
cl_int iterations = pow(2.0f, this->m_data->iter);
- cl_float2 ltxy = {this->m_tx, this->m_ty};
- cl_float2 centerpix = {this->m_center_x_pix, this->m_center_y_pix};
+ cl_float2 ltxy = {{this->m_tx, this->m_ty}};
+ cl_float2 centerpix = {{this->m_center_x_pix, this->m_center_y_pix}};
cl_float lsc = this->m_sc;
cl_float lrot = this->m_rot;
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
index 9d96ebbb33f..705a8c07381 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
@@ -29,7 +29,6 @@
FastGaussianBlurOperation::FastGaussianBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
this->m_iirgaus = NULL;
- this->m_chunksize = 256;
}
void FastGaussianBlurOperation::executePixel(float output[4], int x, int y, void *data)
@@ -38,57 +37,22 @@ void FastGaussianBlurOperation::executePixel(float output[4], int x, int y, void
newData->read(output, x, y);
}
-// Calculate the depending area of interest. This depends on the
-// size of the blur operation; if the blur is large it is faster
-// to just calculate the whole image at once.
-// Returns true if the area is just a tile and false if it is
-// the whole image.
-bool FastGaussianBlurOperation::getDAI(rcti *rect, rcti *output)
-{
- // m_data.sizex * m_size should be enough? For some reason there
- // seem to be errors in the boundary between tiles.
- float size = this->m_size * COM_FAST_GAUSSIAN_MULTIPLIER;
- int sx = this->m_data.sizex * size;
- if (sx < 1)
- sx = 1;
- int sy = this->m_data.sizey * size;
- if (sy < 1)
- sy = 1;
-
- if (sx >= this->m_chunksize || sy >= this->m_chunksize) {
- output->xmin = 0;
- output->xmax = this->getWidth();
- output->ymin = 0;
- output->ymax = this->getHeight();
- return false;
- }
- else {
- output->xmin = rect->xmin - sx - 1;
- output->xmax = rect->xmax + sx + 1;
- output->ymin = rect->ymin - sy - 1;
- output->ymax = rect->ymax + sy + 1;
- return true;
- }
-}
-
bool FastGaussianBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
-
- if (!this->m_sizeavailable) {
- rcti sizeInput;
- sizeInput.xmin = 0;
- sizeInput.ymin = 0;
- sizeInput.xmax = 5;
- sizeInput.ymax = 5;
- NodeOperation *operation = this->getInputOperation(1);
- if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
- return true;
- }
+ rcti sizeInput;
+ sizeInput.xmin = 0;
+ sizeInput.ymin = 0;
+ sizeInput.xmax = 5;
+ sizeInput.ymax = 5;
+
+ NodeOperation *operation = this->getInputOperation(1);
+ if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
+ return true;
}
- {
- if (this->m_sizeavailable) {
- getDAI(input, &newInput);
+ else {
+ if (this->m_iirgaus) {
+ return false;
}
else {
newInput.xmin = 0;
@@ -117,7 +81,6 @@ void FastGaussianBlurOperation::deinitExecution()
void *FastGaussianBlurOperation::initializeTileData(rcti *rect)
{
-#if 0
lockMutex();
if (!this->m_iirgaus) {
MemoryBuffer *newBuf = (MemoryBuffer *)this->m_inputProgram->initializeTileData(rect);
@@ -146,68 +109,8 @@ void *FastGaussianBlurOperation::initializeTileData(rcti *rect)
}
unlockMutex();
return this->m_iirgaus;
-#else
-
- lockMutex();
- if (this->m_iirgaus) {
- // if this->m_iirgaus is set, we don't do tile rendering, so
- // we can return the already calculated cache
- unlockMutex();
- return this->m_iirgaus;
- }
- updateSize();
- rcti dai;
- bool use_tiles = getDAI(rect, &dai);
- if (use_tiles) {
- unlockMutex();
- }
-
- MemoryBuffer *buffer = (MemoryBuffer *)this->m_inputProgram->initializeTileData(NULL);
- rcti *buf_rect = buffer->getRect();
-
- dai.xmin = max(dai.xmin, buf_rect->xmin);
- dai.xmax = min(dai.xmax, buf_rect->xmax);
- dai.ymin = max(dai.ymin, buf_rect->ymin);
- dai.ymax = min(dai.ymax, buf_rect->ymax);
-
- MemoryBuffer *tile = new MemoryBuffer(NULL, &dai);
- tile->copyContentFrom(buffer);
-
- int c;
- float sx = this->m_data.sizex * this->m_size / 2.0f;
- float sy = this->m_data.sizey * this->m_size / 2.0f;
-
- if ((sx == sy) && (sx > 0.f)) {
- for (c = 0; c < COM_NUMBER_OF_CHANNELS; ++c)
- IIR_gauss(tile, sx, c, 3);
- }
- else {
- if (sx > 0.0f) {
- for (c = 0; c < COM_NUMBER_OF_CHANNELS; ++c)
- IIR_gauss(tile, sx, c, 1);
- }
- if (sy > 0.0f) {
- for (c = 0; c < COM_NUMBER_OF_CHANNELS; ++c)
- IIR_gauss(tile, sy, c, 2);
- }
- }
- if (!use_tiles) {
- this->m_iirgaus = tile;
- unlockMutex();
- }
- return tile;
-#endif
}
-void FastGaussianBlurOperation::deinitializeTileData(rcti *rect, void *data)
-{
- if (!this->m_iirgaus && data) {
- MemoryBuffer *tile = (MemoryBuffer *)data;
- delete tile;
- }
-}
-
-
void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, float sigma, unsigned int chan, unsigned int xy)
{
double q, q2, sc, cf[4], tsM[9], tsu[3], tsv[3];
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h
index e12d437b43e..58bf1d4f596 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.h
@@ -28,19 +28,16 @@
class FastGaussianBlurOperation : public BlurBaseOperation {
private:
+ float m_sx;
+ float m_sy;
MemoryBuffer *m_iirgaus;
- int m_chunksize;
-
public:
FastGaussianBlurOperation();
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
void executePixel(float output[4], int x, int y, void *data);
- void setChunksize(int size) { this->m_chunksize = size; }
static void IIR_gauss(MemoryBuffer *src, float sigma, unsigned int channel, unsigned int xy);
- bool getDAI(rcti *rect, rcti *output);
void *initializeTileData(rcti *rect);
- void deinitializeTileData(rcti *rect, void *data);
void deinitExecution();
void initExecution();
};
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
index 69aa7d0fee5..c78347e7b1c 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
@@ -146,10 +146,16 @@ void GaussianAlphaXBlurOperation::executePixel(float output[4], int x, int y, vo
void GaussianAlphaXBlurOperation::deinitExecution()
{
BlurBaseOperation::deinitExecution();
- MEM_freeN(this->m_gausstab);
- this->m_gausstab = NULL;
- MEM_freeN(this->m_distbuf_inv);
- this->m_distbuf_inv = NULL;
+
+ if (this->m_gausstab) {
+ MEM_freeN(this->m_gausstab);
+ this->m_gausstab = NULL;
+ }
+
+ if (this->m_distbuf_inv) {
+ MEM_freeN(this->m_distbuf_inv);
+ this->m_distbuf_inv = NULL;
+ }
deinitMutex();
}
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
index ae1f309c54f..ab97c8b0d13 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
@@ -146,10 +146,16 @@ void GaussianAlphaYBlurOperation::executePixel(float output[4], int x, int y, vo
void GaussianAlphaYBlurOperation::deinitExecution()
{
BlurBaseOperation::deinitExecution();
- MEM_freeN(this->m_gausstab);
- this->m_gausstab = NULL;
- MEM_freeN(this->m_distbuf_inv);
- this->m_distbuf_inv = NULL;
+
+ if (this->m_gausstab) {
+ MEM_freeN(this->m_gausstab);
+ this->m_gausstab = NULL;
+ }
+
+ if (this->m_distbuf_inv) {
+ MEM_freeN(this->m_distbuf_inv);
+ this->m_distbuf_inv = NULL;
+ }
deinitMutex();
}
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
index d5743c41c94..441b623b589 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
@@ -157,8 +157,11 @@ void GaussianBokehBlurOperation::executePixel(float output[4], int x, int y, voi
void GaussianBokehBlurOperation::deinitExecution()
{
BlurBaseOperation::deinitExecution();
- MEM_freeN(this->m_gausstab);
- this->m_gausstab = NULL;
+
+ if (this->m_gausstab) {
+ MEM_freeN(this->m_gausstab);
+ this->m_gausstab = NULL;
+ }
deinitMutex();
}
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
index 815b89ae8d9..0838d281de7 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp
@@ -21,6 +21,7 @@
*/
#include "COM_GaussianXBlurOperation.h"
+#include "COM_OpenCLDevice.h"
#include "BLI_math.h"
#include "MEM_guardedalloc.h"
@@ -31,6 +32,9 @@ extern "C" {
GaussianXBlurOperation::GaussianXBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
this->m_gausstab = NULL;
+#ifdef __SSE2__
+ this->m_gausstab_sse = NULL;
+#endif
this->m_filtersize = 0;
}
@@ -54,8 +58,14 @@ void GaussianXBlurOperation::initExecution()
if (this->m_sizeavailable) {
float rad = max_ff(m_size * m_data.sizex, 0.0f);
m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
-
+
+ /* TODO(sergey): De-duplicate with the case below and Y blur. */
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
}
}
@@ -65,8 +75,13 @@ void GaussianXBlurOperation::updateGauss()
updateSize();
float rad = max_ff(m_size * m_data.sizex, 0.0f);
m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
-
+
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
}
}
@@ -88,22 +103,68 @@ void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *d
int step = getStep();
int offsetadd = getOffsetAdd();
int bufferindex = ((xmin - bufferstartx) * 4) + ((ymin - bufferstarty) * 4 * bufferwidth);
+
+#ifdef __SSE2__
+ __m128 accum_r = _mm_load_ps(color_accum);
+ for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax; nx += step, index += step) {
+ __m128 reg_a = _mm_load_ps(&buffer[bufferindex]);
+ reg_a = _mm_mul_ps(reg_a, this->m_gausstab_sse[index]);
+ accum_r = _mm_add_ps(accum_r, reg_a);
+ multiplier_accum += this->m_gausstab[index];
+ bufferindex += offsetadd;
+ }
+ _mm_store_ps(color_accum, accum_r);
+#else
for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax; nx += step, index += step) {
const float multiplier = this->m_gausstab[index];
madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier);
multiplier_accum += multiplier;
bufferindex += offsetadd;
}
+#endif
mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum);
}
+void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device,
+ MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
+ MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
+ list<cl_kernel> *clKernelsToCleanUp)
+{
+ cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel("gaussianXBlurOperationKernel", NULL);
+ cl_int filter_size = this->m_filtersize;
+
+ cl_mem gausstab = clCreateBuffer(device->getContext(),
+ CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,
+ sizeof(float) * (this->m_filtersize * 2 + 1),
+ this->m_gausstab,
+ NULL);
+
+ device->COM_clAttachMemoryBufferToKernelParameter(gaussianXBlurOperationKernel, 0, 1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
+ device->COM_clAttachOutputMemoryBufferToKernelParameter(gaussianXBlurOperationKernel, 2, clOutputBuffer);
+ device->COM_clAttachMemoryBufferOffsetToKernelParameter(gaussianXBlurOperationKernel, 3, outputMemoryBuffer);
+ clSetKernelArg(gaussianXBlurOperationKernel, 4, sizeof(cl_int), &filter_size);
+ device->COM_clAttachSizeToKernelParameter(gaussianXBlurOperationKernel, 5, this);
+ clSetKernelArg(gaussianXBlurOperationKernel, 6, sizeof(cl_mem), &gausstab);
+
+ device->COM_clEnqueueRange(gaussianXBlurOperationKernel, outputMemoryBuffer, 7, this);
+
+ clReleaseMemObject(gausstab);
+}
+
void GaussianXBlurOperation::deinitExecution()
{
BlurBaseOperation::deinitExecution();
+
if (this->m_gausstab) {
MEM_freeN(this->m_gausstab);
this->m_gausstab = NULL;
}
+#ifdef __SSE2__
+ if (this->m_gausstab_sse) {
+ MEM_freeN(this->m_gausstab_sse);
+ this->m_gausstab_sse = NULL;
+ }
+#endif
deinitMutex();
}
diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
index 6442f214138..d7ae8b1e3dc 100644
--- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h
@@ -28,6 +28,9 @@
class GaussianXBlurOperation : public BlurBaseOperation {
private:
float *m_gausstab;
+#ifdef __SSE2__
+ __m128 *m_gausstab_sse;
+#endif
int m_filtersize;
void updateGauss();
public:
@@ -37,7 +40,12 @@ public:
* @brief the inner loop of this program
*/
void executePixel(float output[4], int x, int y, void *data);
-
+
+ void executeOpenCL(OpenCLDevice *device,
+ MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
+ MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
+ list<cl_kernel> *clKernelsToCleanUp);
+
/**
* @brief initialize the execution
*/
@@ -50,5 +58,9 @@ public:
void *initializeTileData(rcti *rect);
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
+
+ void checkOpenCL() {
+ this->setOpenCL(m_data.sizex >= 128);
+ }
};
#endif
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
index 47c031757fb..6172f954087 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp
@@ -21,6 +21,7 @@
*/
#include "COM_GaussianYBlurOperation.h"
+#include "COM_OpenCLDevice.h"
#include "BLI_math.h"
#include "MEM_guardedalloc.h"
@@ -31,6 +32,9 @@ extern "C" {
GaussianYBlurOperation::GaussianYBlurOperation() : BlurBaseOperation(COM_DT_COLOR)
{
this->m_gausstab = NULL;
+#ifdef __SSE2__
+ this->m_gausstab_sse = NULL;
+#endif
this->m_filtersize = 0;
}
@@ -54,8 +58,13 @@ void GaussianYBlurOperation::initExecution()
if (this->m_sizeavailable) {
float rad = max_ff(m_size * m_data.sizey, 0.0f);
m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
-
+
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
}
}
@@ -65,8 +74,13 @@ void GaussianYBlurOperation::updateGauss()
updateSize();
float rad = max_ff(m_size * m_data.sizey, 0.0f);
m_filtersize = min_ii(ceil(rad), MAX_GAUSSTAB_RADIUS);
-
+
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
}
}
@@ -88,6 +102,20 @@ void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *d
int index;
int step = getStep();
const int bufferIndexx = ((xmin - bufferstartx) * 4);
+
+#ifdef __SSE2__
+ __m128 accum_r = _mm_load_ps(color_accum);
+ for (int ny = ymin; ny < ymax; ny += step) {
+ index = (ny - y) + this->m_filtersize;
+ int bufferindex = bufferIndexx + ((ny - bufferstarty) * 4 * bufferwidth);
+ const float multiplier = this->m_gausstab[index];
+ __m128 reg_a = _mm_load_ps(&buffer[bufferindex]);
+ reg_a = _mm_mul_ps(reg_a, this->m_gausstab_sse[index]);
+ accum_r = _mm_add_ps(accum_r, reg_a);
+ multiplier_accum += multiplier;
+ }
+ _mm_store_ps(color_accum, accum_r);
+#else
for (int ny = ymin; ny < ymax; ny += step) {
index = (ny - y) + this->m_filtersize;
int bufferindex = bufferIndexx + ((ny - bufferstarty) * 4 * bufferwidth);
@@ -95,16 +123,50 @@ void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *d
madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier);
multiplier_accum += multiplier;
}
+#endif
mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum);
}
+void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device,
+ MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
+ MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
+ list<cl_kernel> *clKernelsToCleanUp)
+{
+ cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel("gaussianYBlurOperationKernel", NULL);
+ cl_int filter_size = this->m_filtersize;
+
+ cl_mem gausstab = clCreateBuffer(device->getContext(),
+ CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR,
+ sizeof(float) * (this->m_filtersize * 2 + 1),
+ this->m_gausstab,
+ NULL);
+
+ device->COM_clAttachMemoryBufferToKernelParameter(gaussianYBlurOperationKernel, 0, 1, clMemToCleanUp, inputMemoryBuffers, this->m_inputProgram);
+ device->COM_clAttachOutputMemoryBufferToKernelParameter(gaussianYBlurOperationKernel, 2, clOutputBuffer);
+ device->COM_clAttachMemoryBufferOffsetToKernelParameter(gaussianYBlurOperationKernel, 3, outputMemoryBuffer);
+ clSetKernelArg(gaussianYBlurOperationKernel, 4, sizeof(cl_int), &filter_size);
+ device->COM_clAttachSizeToKernelParameter(gaussianYBlurOperationKernel, 5, this);
+ clSetKernelArg(gaussianYBlurOperationKernel, 6, sizeof(cl_mem), &gausstab);
+
+ device->COM_clEnqueueRange(gaussianYBlurOperationKernel, outputMemoryBuffer, 7, this);
+
+ clReleaseMemObject(gausstab);
+}
+
void GaussianYBlurOperation::deinitExecution()
{
BlurBaseOperation::deinitExecution();
+
if (this->m_gausstab) {
MEM_freeN(this->m_gausstab);
this->m_gausstab = NULL;
}
+#ifdef __SSE2__
+ if (this->m_gausstab_sse) {
+ MEM_freeN(this->m_gausstab_sse);
+ this->m_gausstab_sse = NULL;
+ }
+#endif
deinitMutex();
}
diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
index 16503360de2..4b5751c0968 100644
--- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
+++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h
@@ -28,6 +28,9 @@
class GaussianYBlurOperation : public BlurBaseOperation {
private:
float *m_gausstab;
+#ifdef __SSE2__
+ __m128 *m_gausstab_sse;
+#endif
int m_filtersize;
void updateGauss();
public:
@@ -37,7 +40,12 @@ public:
* the inner loop of this program
*/
void executePixel(float output[4], int x, int y, void *data);
-
+
+ void executeOpenCL(OpenCLDevice *device,
+ MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer,
+ MemoryBuffer **inputMemoryBuffers, list<cl_mem> *clMemToCleanUp,
+ list<cl_kernel> *clKernelsToCleanUp);
+
/**
* @brief initialize the execution
*/
@@ -50,5 +58,9 @@ public:
void *initializeTileData(rcti *rect);
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
+
+ void checkOpenCL() {
+ this->setOpenCL(m_data.sizex >= 128);
+ }
};
#endif
diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
index 9fb9efe4fc7..ddc09ecb483 100644
--- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
@@ -49,37 +49,27 @@ void *KeyingBlurOperation::initializeTileData(rcti *rect)
void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data)
{
MemoryBuffer *inputBuffer = (MemoryBuffer *)data;
+ const int bufferWidth = inputBuffer->getWidth();
float *buffer = inputBuffer->getBuffer();
-
- int bufferWidth = inputBuffer->getWidth();
- int bufferHeight = inputBuffer->getHeight();
-
- int i, count = 0;
-
+ int count = 0;
float average = 0.0f;
if (this->m_axis == 0) {
- for (i = -this->m_size + 1; i < this->m_size; i++) {
- int cx = x + i;
-
- if (cx >= 0 && cx < bufferWidth) {
- int bufferIndex = (y * bufferWidth + cx) * 4;
-
- average += buffer[bufferIndex];
- count++;
- }
+ const int start = max(0, x - this->m_size + 1),
+ end = min(bufferWidth, x + this->m_size);
+ for (int cx = start; cx < end; ++cx) {
+ int bufferIndex = (y * bufferWidth + cx) * 4;
+ average += buffer[bufferIndex];
+ count++;
}
}
else {
- for (i = -this->m_size + 1; i < this->m_size; i++) {
- int cy = y + i;
-
- if (cy >= 0 && cy < bufferHeight) {
- int bufferIndex = (cy * bufferWidth + x) * 4;
-
- average += buffer[bufferIndex];
- count++;
- }
+ const int start = max(0, y - this->m_size + 1),
+ end = min(inputBuffer->getHeight(), y + this->m_size);
+ for (int cy = start; cy < end; ++cy) {
+ int bufferIndex = (cy * bufferWidth + x) * 4;
+ average += buffer[bufferIndex];
+ count++;
}
}
diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
index 909eeed8937..d9eb7b588a8 100644
--- a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
@@ -62,34 +62,39 @@ void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data
int bufferWidth = inputBuffer->getWidth();
int bufferHeight = inputBuffer->getHeight();
- int i, j, count = 0, totalCount = 0;
-
float value = buffer[(y * bufferWidth + x) * 4];
bool ok = false;
+ int start_x = max_ff(0, x - delta + 1),
+ start_y = max_ff(0, y - delta + 1),
+ end_x = min_ff(x + delta - 1, bufferWidth - 1),
+ end_y = min_ff(y + delta - 1, bufferHeight - 1);
+
+ int count = 0, totalCount = (end_x - start_x + 1) * (end_y - start_y + 1) - 1;
+ int thresholdCount = ceil((float) totalCount * 0.9f);
- for (i = -delta + 1; i < delta; i++) {
- for (j = -delta + 1; j < delta; j++) {
- int cx = x + j, cy = y + i;
+ if (delta == 0) {
+ ok = true;
+ }
- if (i == 0 && j == 0)
+ for (int cx = start_x; ok == false && cx <= end_x; ++cx) {
+ for (int cy = start_y; ok == false && cy <= end_y; ++cy) {
+ if (UNLIKELY(cx == x && cy == y)) {
continue;
+ }
- if (cx >= 0 && cx < bufferWidth && cy >= 0 && cy < bufferHeight) {
- int bufferIndex = (cy * bufferWidth + cx) * 4;
- float currentValue = buffer[bufferIndex];
+ int bufferIndex = (cy * bufferWidth + cx) * 4;
+ float currentValue = buffer[bufferIndex];
- if (fabsf(currentValue - value) < tolerance) {
- count++;
+ if (fabsf(currentValue - value) < tolerance) {
+ count++;
+ if (count >= thresholdCount) {
+ ok = true;
}
-
- totalCount++;
}
}
}
- ok = count >= (float) totalCount * 0.9f;
-
if (this->m_isEdgeMatte) {
if (ok)
output[0] = 0.0f;
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp b/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
index 17b85847fcf..1633d2a2f1d 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp
@@ -188,9 +188,9 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTri
BLI_freelistN(&edges);
if (triangulation->triangles_total) {
- rctf *rect;
+ rcti *rect;
rect = triangulation->triangles_AABB =
- (rctf *) MEM_callocN(sizeof(rctf) * triangulation->triangles_total, "voronoi triangulation AABB");
+ (rcti *) MEM_callocN(sizeof(rcti) * triangulation->triangles_total, "voronoi triangulation AABB");
for (i = 0; i < triangulation->triangles_total; i++, rect++) {
int *triangle = triangulation->triangles[i];
@@ -206,11 +206,11 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::buildVoronoiTri
minmax_v2v2_v2(min, max, b->co);
minmax_v2v2_v2(min, max, c->co);
- rect->xmin = min[0];
- rect->ymin = min[1];
+ rect->xmin = (int)min[0];
+ rect->ymin = (int)min[1];
- rect->xmax = max[0];
- rect->ymax = max[1];
+ rect->xmax = (int)max[0] + 1;
+ rect->ymax = (int)max[1] + 1;
}
}
@@ -224,7 +224,6 @@ void *KeyingScreenOperation::initializeTileData(rcti *rect)
int triangles_allocated = 0;
int chunk_size = 20;
int i;
- rctf rect_float;
if (this->m_movieClip == NULL)
return NULL;
@@ -242,14 +241,10 @@ void *KeyingScreenOperation::initializeTileData(rcti *rect)
if (!triangulation)
return NULL;
- BLI_rctf_init(&rect_float, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
-
tile_data = (TileData *) MEM_callocN(sizeof(TileData), "keying screen tile data");
for (i = 0; i < triangulation->triangles_total; i++) {
- bool ok = BLI_rctf_isect(&rect_float, &triangulation->triangles_AABB[i], NULL);
-
- if (ok) {
+ if (BLI_rcti_isect(rect, &triangulation->triangles_AABB[i], NULL)) {
tile_data->triangles_total++;
if (tile_data->triangles_total > triangles_allocated) {
@@ -316,7 +311,7 @@ void KeyingScreenOperation::executePixel(float output[4], int x, int y, void *da
for (i = 0; i < tile_data->triangles_total; i++) {
int triangle_idx = tile_data->triangles[i];
- rctf *rect = &triangulation->triangles_AABB[triangle_idx];
+ rcti *rect = &triangulation->triangles_AABB[triangle_idx];
if (IN_RANGE_INCL(x, rect->xmin, rect->xmax) && IN_RANGE_INCL(y, rect->ymin, rect->ymax)) {
int *triangle = triangulation->triangles[triangle_idx];
diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.h b/source/blender/compositor/operations/COM_KeyingScreenOperation.h
index 10cf48e57f4..b1a5c0c39c7 100644
--- a/source/blender/compositor/operations/COM_KeyingScreenOperation.h
+++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.h
@@ -47,7 +47,7 @@ protected:
VoronoiTriangulationPoint *triangulated_points;
int (*triangles)[3];
int triangulated_points_total, triangles_total;
- rctf *triangles_AABB;
+ rcti *triangles_AABB;
} TriangulationData;
typedef struct TileData {
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp
index 87ad1d6afa4..6bf730253e7 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp
@@ -62,7 +62,7 @@ void MapUVOperation::executePixelSampled(float output[4], float x, float y, Pixe
*/
float du = len_v2(deriv[0]);
float dv = len_v2(deriv[1]);
- float factor = 1.0f - threshold * (du + dv);
+ float factor = 1.0f - threshold * (du / m_inputColorProgram->getWidth() + dv / m_inputColorProgram->getHeight());
if (factor < 0.f) alpha = 0.f;
else alpha *= factor;
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cpp
index cbc60b5091d..32a1e77b9a7 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.cpp
@@ -335,12 +335,11 @@ void MathModuloOperation::executePixelSampled(float output[4], float x, float y,
void MathAbsoluteOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- float inputValue1[4];
+ float inputValue1[4];
- this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
+ this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler);
- output[0] = fabs(inputValue1[0]);
+ output[0] = fabs(inputValue1[0]);
- clampIfNeeded(output);
+ clampIfNeeded(output);
}
-
diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.h b/source/blender/compositor/operations/COM_MathBaseOperation.h
index 05d2bb054d3..32cd19f1fb9 100644
--- a/source/blender/compositor/operations/COM_MathBaseOperation.h
+++ b/source/blender/compositor/operations/COM_MathBaseOperation.h
@@ -165,8 +165,8 @@ public:
class MathAbsoluteOperation : public MathBaseOperation {
public:
- MathAbsoluteOperation() : MathBaseOperation() {}
- void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+ MathAbsoluteOperation() : MathBaseOperation() {}
+ void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
};
#endif
diff --git a/source/blender/compositor/operations/COM_MixOperation.h b/source/blender/compositor/operations/COM_MixOperation.h
index 479ce161eea..d399edba6e9 100644
--- a/source/blender/compositor/operations/COM_MixOperation.h
+++ b/source/blender/compositor/operations/COM_MixOperation.h
@@ -76,7 +76,7 @@ public:
void setUseValueAlphaMultiply(const bool value) { this->m_valueAlphaMultiply = value; }
- bool useValueAlphaMultiply() { return this->m_valueAlphaMultiply; }
+ inline bool useValueAlphaMultiply() { return this->m_valueAlphaMultiply; }
void setUseClamp(bool value) { this->m_useClamp = value; }
};
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
index 28b1fc11a7c..50fabb09dbb 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp
@@ -68,34 +68,33 @@ void MovieDistortionOperation::initExecution()
{
this->m_cache = c;
this->m_cache->updateLastUsage();
+ this->m_cache->getMargin(this->m_margin);
return;
}
}
- DistortionCache *newC = new DistortionCache(this->m_movieClip, this->m_width, this->m_height,
- calibration_width, calibration_height, this->m_distortion);
+
+ float delta[2];
+ rcti full_frame;
+ full_frame.xmin = full_frame.ymin = 0;
+ full_frame.xmax = this->m_width;
+ full_frame.ymax = this->m_height;
+ BKE_tracking_max_distortion_delta_across_bound(
+ &this->m_movieClip->tracking, &full_frame,
+ !this->m_distortion, delta);
+
+ /* 5 is just in case we didn't hit real max of distortion in
+ * BKE_tracking_max_undistortion_delta_across_bound
+ */
+ m_margin[0] = delta[0] + 5;
+ m_margin[1] = delta[1] + 5;
+
+ DistortionCache *newC = new DistortionCache(this->m_movieClip,
+ this->m_width, this->m_height,
+ calibration_width, calibration_height,
+ this->m_distortion,
+ this->m_margin);
s_cache.push_back(newC);
this->m_cache = newC;
-
- if (this->m_distortion) {
- float delta[2];
- rcti full_frame;
- full_frame.xmin = full_frame.ymin = 0;
- full_frame.xmax = this->m_width;
- full_frame.ymax = this->m_height;
- BKE_tracking_max_undistortion_delta_across_bound(&this->m_movieClip->tracking, &full_frame, delta);
-
- /* 5 is just in case we didn't hit real max of distortion in
- * BKE_tracking_max_undistortion_delta_across_bound
- */
- m_margin[0] = delta[0] + 5;
- m_margin[1] = delta[1] + 5;
- }
- else {
- /* undistortion with sane distortion coefficients would be mapped inside
- * of each tile, should be no need in margin in this case
- */
- m_margin[0] = m_margin[1] = 0;
- }
}
else {
this->m_cache = NULL;
diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.h b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
index a1dd08d8624..577712eda56 100644
--- a/source/blender/compositor/operations/COM_MovieDistortionOperation.h
+++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.h
@@ -50,9 +50,15 @@ private:
float *m_buffer;
int *m_bufferCalculated;
double timeLastUsage;
+ int m_margin[2];
public:
- DistortionCache(MovieClip *movieclip, int width, int height, int calibration_width, int calibration_height, bool inverted) {
+ DistortionCache(MovieClip *movieclip,
+ int width, int height,
+ int calibration_width, int calibration_height,
+ bool inverted,
+ const int margin[2])
+ {
this->m_k1 = movieclip->tracking.camera.k1;
this->m_k2 = movieclip->tracking.camera.k2;
this->m_k3 = movieclip->tracking.camera.k3;
@@ -66,6 +72,7 @@ public:
this->m_inverted = inverted;
this->m_bufferCalculated = (int *)MEM_callocN(sizeof(int) * this->m_width * this->m_height, __func__);
this->m_buffer = (float *)MEM_mallocN(sizeof(float) * this->m_width * this->m_height * 2, __func__);
+ copy_v2_v2_int(this->m_margin, margin);
this->updateLastUsage();
}
@@ -89,7 +96,11 @@ public:
return this->timeLastUsage;
}
- bool isCacheFor(MovieClip *movieclip, int width, int height, int calibration_width, int claibration_height, bool inverted) {
+ bool isCacheFor(MovieClip *movieclip,
+ int width, int height,
+ int calibration_width, int claibration_height,
+ bool inverted)
+ {
return this->m_k1 == movieclip->tracking.camera.k1 &&
this->m_k2 == movieclip->tracking.camera.k2 &&
this->m_k3 == movieclip->tracking.camera.k3 &&
@@ -141,6 +152,11 @@ public:
*v = this->m_buffer[offset2 + 1];
}
}
+
+ void getMargin(int margin[2])
+ {
+ copy_v2_v2_int(margin, m_margin);
+ }
};
class MovieDistortionOperation : public NodeOperation {
diff --git a/source/blender/compositor/operations/COM_OpenCLKernels.cl b/source/blender/compositor/operations/COM_OpenCLKernels.cl
index 00b3825d8b3..1b965eb8659 100644
--- a/source/blender/compositor/operations/COM_OpenCLKernels.cl
+++ b/source/blender/compositor/operations/COM_OpenCLKernels.cl
@@ -250,3 +250,66 @@ __kernel void directionalBlurKernel(__read_only image2d_t inputImage, __write_o
write_imagef(output, coords, col);
}
+
+// KERNEL --- GAUSSIAN BLUR ---
+__kernel void gaussianXBlurOperationKernel(__read_only image2d_t inputImage,
+ int2 offsetInput,
+ __write_only image2d_t output,
+ int2 offsetOutput,
+ int filter_size,
+ int2 dimension,
+ __global float *gausstab,
+ int2 offset)
+{
+ float4 color = {0.0f, 0.0f, 0.0f, 0.0f};
+ int2 coords = {get_global_id(0), get_global_id(1)};
+ coords += offset;
+ const int2 realCoordinate = coords + offsetOutput;
+ int2 inputCoordinate = realCoordinate - offsetInput;
+ float weight = 0.0f;
+
+ int xmin = max(realCoordinate.x - filter_size, 0) - offsetInput.x;
+ int xmax = min(realCoordinate.x + filter_size + 1, dimension.x) - offsetInput.x;
+
+ for (int nx = xmin, i = max(filter_size - realCoordinate.x, 0); nx < xmax; ++nx, ++i) {
+ float w = gausstab[i];
+ inputCoordinate.x = nx;
+ color += read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate) * w;
+ weight += w;
+ }
+
+ color *= (1.0f / weight);
+
+ write_imagef(output, coords, color);
+}
+
+__kernel void gaussianYBlurOperationKernel(__read_only image2d_t inputImage,
+ int2 offsetInput,
+ __write_only image2d_t output,
+ int2 offsetOutput,
+ int filter_size,
+ int2 dimension,
+ __global float *gausstab,
+ int2 offset)
+{
+ float4 color = {0.0f, 0.0f, 0.0f, 0.0f};
+ int2 coords = {get_global_id(0), get_global_id(1)};
+ coords += offset;
+ const int2 realCoordinate = coords + offsetOutput;
+ int2 inputCoordinate = realCoordinate - offsetInput;
+ float weight = 0.0f;
+
+ int ymin = max(realCoordinate.y - filter_size, 0) - offsetInput.y;
+ int ymax = min(realCoordinate.y + filter_size + 1, dimension.y) - offsetInput.y;
+
+ for (int ny = ymin, i = max(filter_size - realCoordinate.y, 0); ny < ymax; ++ny, ++i) {
+ float w = gausstab[i];
+ inputCoordinate.y = ny;
+ color += read_imagef(inputImage, SAMPLER_NEAREST, inputCoordinate) * w;
+ weight += w;
+ }
+
+ color *= (1.0f / weight);
+
+ write_imagef(output, coords, color);
+}
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index af0d1b0b4f4..06f4f6d77cf 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -142,16 +142,13 @@ void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y
int ix = x - dx;
int iy = y - dy;
-#else
- int ix = x;
- int iy = y;
#endif
if (this->m_inputBuffer == NULL) {
zero_v4(output);
}
else {
- doInterpolation(output, ix, iy, sampler);
+ doInterpolation(output, x, y, sampler);
}
}
@@ -204,19 +201,15 @@ RenderLayersAlphaProg::RenderLayersAlphaProg() : RenderLayersBaseProg(SCE_PASS_C
void RenderLayersAlphaProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- int ix = x;
- int iy = y;
float *inputBuffer = this->getInputBuffer();
- if (inputBuffer == NULL || ix < 0 || iy < 0 || ix >= (int)this->getWidth() || iy >= (int)this->getHeight() ) {
- output[0] = 0.0f;
- output[1] = 0.0f;
- output[2] = 0.0f;
- output[3] = 0.0f;
+ if (inputBuffer == NULL) {
+ zero_v4(output);
}
else {
- unsigned int offset = (iy * this->getWidth() + ix) * 4;
- output[0] = inputBuffer[offset + 3];
+ float temp[4];
+ doInterpolation(temp, x, y, sampler);
+ output[0] = temp[3];
output[1] = 0.0f;
output[2] = 0.0f;
output[3] = 0.0f;
diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp b/source/blender/compositor/operations/COM_SocketProxyOperation.cpp
index da345b282fd..21d2f28332e 100644
--- a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp
+++ b/source/blender/compositor/operations/COM_SocketProxyOperation.cpp
@@ -22,7 +22,9 @@
#include "COM_SocketProxyOperation.h"
-SocketProxyOperation::SocketProxyOperation(DataType type) : NodeOperation()
+SocketProxyOperation::SocketProxyOperation(DataType type, bool use_conversion) :
+ NodeOperation(),
+ m_use_conversion(use_conversion)
{
this->addInputSocket(type);
this->addOutputSocket(type);
diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.h b/source/blender/compositor/operations/COM_SocketProxyOperation.h
index 9733a1fbeec..c9d6cb6ef9e 100644
--- a/source/blender/compositor/operations/COM_SocketProxyOperation.h
+++ b/source/blender/compositor/operations/COM_SocketProxyOperation.h
@@ -27,9 +27,16 @@
class SocketProxyOperation : public NodeOperation {
public:
- SocketProxyOperation(DataType type);
+ SocketProxyOperation(DataType type, bool use_conversion);
bool isProxyOperation() const { return true; }
+ bool useDatatypeConversion() const { return m_use_conversion; }
+
+ bool getUseConversion() const { return m_use_conversion; }
+ void setUseConversion(bool use_conversion) { m_use_conversion = use_conversion; }
+
+private:
+ bool m_use_conversion;
};
#endif
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
new file mode 100644
index 00000000000..bcef652a8b5
--- /dev/null
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2014, 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:
+ * Lukas Toenne
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "COM_SunBeamsOperation.h"
+
+SunBeamsOperation::SunBeamsOperation() : NodeOperation()
+{
+ this->addInputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_COLOR);
+ this->setResolutionInputSocketIndex(0);
+
+ this->setComplex(true);
+}
+
+void SunBeamsOperation::initExecution()
+{
+ /* convert to pixels */
+ this->m_source_px[0] = this->m_data.source[0] * this->getWidth();
+ this->m_source_px[1] = this->m_data.source[1] * this->getHeight();
+ this->m_ray_length_px = this->m_data.ray_length * max(this->getWidth(), this->getHeight());
+}
+
+/**
+ * Defines a line accumulator for a specific sector,
+ * given by the four matrix entries that rotate from buffer space into the sector
+ *
+ * (x,y) is used to designate buffer space coordinates
+ * (u,v) is used to designate sector space coordinates
+ *
+ * For a target point (x,y) the sector should be chosen such that
+ * ``u >= v >= 0``
+ * This removes the need to handle all sorts of special cases.
+ */
+template <int fxx, int fxy, int fyx, int fyy>
+struct BufferLineAccumulator {
+
+ /* utility functions implementing the matrix transform to/from sector space */
+
+ static inline void buffer_to_sector(int x, int y, int &u, int &v)
+ {
+ u = x * fxx + y * fyx;
+ v = x * fxy + y * fyy;
+ }
+
+ static inline void buffer_to_sector(float x, float y, float &u, float &v)
+ {
+ u = x * fxx + y * fyx;
+ v = x * fxy + y * fyy;
+ }
+
+ static inline void sector_to_buffer(int u, int v, int &x, int &y)
+ {
+ x = u * fxx + v * fxy;
+ y = u * fyx + v * fyy;
+ }
+
+ static inline void sector_to_buffer(float u, float v, float &x, float &y)
+ {
+ x = u * fxx + v * fxy;
+ y = u * fyx + v * fyy;
+ }
+
+ /**
+ * Set up the initial buffer pointer and calculate necessary variables for looping.
+ *
+ * Note that sector space is centered around the "source" point while the loop starts
+ * at dist_min from the target pt. This way the loop can be canceled as soon as it runs
+ * out of the buffer rect, because no pixels further along the line can contribute.
+ *
+ * \param x, y Start location in the buffer
+ * \param num Total steps in the loop
+ * \param v, dv Vertical offset in sector space, for line offset perpendicular to the loop axis
+ */
+ static float *init_buffer_iterator(MemoryBuffer *input, const float source[2], const float pt_ofs[2],
+ float dist_min, float dist_max,
+ int &x, int &y, int &num, float &v, float &dv, float &falloff_factor)
+ {
+ float pu, pv;
+ buffer_to_sector(pt_ofs[0], pt_ofs[1], pu, pv);
+
+ /* line angle */
+ float tan_phi = pv / pu;
+ float dr = sqrtf(tan_phi * tan_phi + 1.0f);
+ float cos_phi = 1.0f / dr;
+
+ /* clamp u range to avoid influence of pixels "behind" the source */
+ float umin = max_ff(pu - cos_phi * dist_min, 0.0f);
+ float umax = max_ff(pu - cos_phi * dist_max, 0.0f);
+ v = umin * tan_phi;
+ dv = tan_phi;
+
+ int start = (int)floorf(umax);
+ int end = (int)ceilf(umin);
+ num = end - start;
+
+ sector_to_buffer(end, (int)ceilf(v), x, y);
+ x += (int)source[0];
+ y += (int)source[1];
+
+ falloff_factor = dist_max > dist_min ? dr / (float)(dist_max - dist_min) : 0.0f;
+
+ float *iter = input->getBuffer() + COM_NUMBER_OF_CHANNELS * (x + input->getWidth() * y);
+ return iter;
+ }
+
+ /**
+ * Perform the actual accumulation along a ray segment from source to pt.
+ * Only pixels withing dist_min..dist_max contribute.
+ *
+ * The loop runs backwards(!) over the primary sector space axis u, i.e. increasing distance to pt.
+ * After each step it decrements v by dv < 1, adding a buffer shift when necessary.
+ */
+ static void eval(MemoryBuffer *input, float output[4], const float pt_ofs[2], const float source[2],
+ float dist_min, float dist_max)
+ {
+ rcti rect = *input->getRect();
+ int buffer_width = input->getWidth();
+ int x, y, num;
+ float v, dv;
+ float falloff_factor;
+ float border[4];
+
+ if ((int)pt_ofs[0] == 0 && (int)pt_ofs[1] == 0) {
+ copy_v4_v4(output, input->getBuffer() + COM_NUMBER_OF_CHANNELS * ((int)source[0] + input->getWidth() * (int)source[1]));
+ return;
+ }
+
+ /* initialise the iteration variables */
+ float *buffer = init_buffer_iterator(input, source, pt_ofs, dist_min, dist_max, x, y, num, v, dv, falloff_factor);
+ zero_v3(border);
+ border[3] = 1.0f;
+
+ /* v_local keeps track of when to decrement v (see below) */
+ float v_local = v - floorf(v);
+
+ for (int i = 0; i < num; i++) {
+ float weight = 1.0f - (float)i * falloff_factor;
+ weight *= weight;
+
+ /* range check, use last valid color when running beyond the image border */
+ if (x >= rect.xmin && x < rect.xmax && y >= rect.ymin && y < rect.ymax) {
+ madd_v4_v4fl(output, buffer, buffer[3] * weight);
+ /* use as border color in case subsequent pixels are out of bounds */
+ copy_v4_v4(border, buffer);
+ }
+ else {
+ madd_v4_v4fl(output, border, border[3] * weight);
+ }
+
+ /* TODO implement proper filtering here, see
+ * http://en.wikipedia.org/wiki/Lanczos_resampling
+ * http://en.wikipedia.org/wiki/Sinc_function
+ *
+ * using lanczos with x = distance from the line segment,
+ * normalized to a == 0.5f, could give a good result
+ *
+ * for now just divide equally at the end ...
+ */
+
+ /* decrement u */
+ x -= fxx;
+ y -= fyx;
+ buffer -= (fxx + fyx * buffer_width) * COM_NUMBER_OF_CHANNELS;
+
+ /* decrement v (in steps of dv < 1) */
+ v_local -= dv;
+ if (v_local < 0.0f) {
+ v_local += 1.0f;
+
+ x -= fxy;
+ y -= fyy;
+ buffer -= (fxy + fyy * buffer_width) * COM_NUMBER_OF_CHANNELS;
+ }
+ }
+
+ /* normalize */
+ if (num > 0) {
+ mul_v4_fl(output, 1.0f / (float)num);
+ }
+ }
+};
+
+/**
+ * Dispatch function which selects an appropriate accumulator based on the sector of the target point,
+ * relative to the source.
+ *
+ * The BufferLineAccumulator defines the actual loop over the buffer, with an efficient inner loop
+ * due to using compile time constants instead of a local matrix variable defining the sector space.
+ */
+static void accumulate_line(MemoryBuffer *input, float output[4], const float co[2], const float source[2],
+ float dist_min, float dist_max)
+{
+ /* coordinates relative to source */
+ float pt_ofs[2] = {co[0] - source[0], co[1] - source[1]};
+
+ /* The source sectors are defined like so:
+ *
+ * \ 3 | 2 /
+ * \ | /
+ * 4 \ | / 1
+ * \|/
+ * -----------
+ * /|\
+ * 5 / | \ 8
+ * / | \
+ * / 6 | 7 \
+ *
+ * The template arguments encode the transformation into "sector space",
+ * by means of rotation/mirroring matrix elements.
+ */
+
+ if (fabsf(pt_ofs[1]) > fabsf(pt_ofs[0])) {
+ if (pt_ofs[0] > 0.0f) {
+ if (pt_ofs[1] > 0.0f) {
+ /* 2 */
+ BufferLineAccumulator<0, 1, 1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max);
+ }
+ else {
+ /* 7 */
+ BufferLineAccumulator<0, 1, -1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max);
+ }
+ }
+ else {
+ if (pt_ofs[1] > 0.0f) {
+ /* 3 */
+ BufferLineAccumulator<0, -1, 1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max);
+ }
+ else {
+ /* 6 */
+ BufferLineAccumulator<0, -1, -1, 0>::eval(input, output, pt_ofs, source, dist_min, dist_max);
+ }
+ }
+ }
+ else {
+ if (pt_ofs[0] > 0.0f) {
+ if (pt_ofs[1] > 0.0f) {
+ /* 1 */
+ BufferLineAccumulator< 1, 0, 0, 1>::eval(input, output, pt_ofs, source, dist_min, dist_max);
+ }
+ else {
+ /* 8 */
+ BufferLineAccumulator< 1, 0, 0, -1>::eval(input, output, pt_ofs, source, dist_min, dist_max);
+ }
+ }
+ else {
+ if (pt_ofs[1] > 0.0f) {
+ /* 4 */
+ BufferLineAccumulator<-1, 0, 0, 1>::eval(input, output, pt_ofs, source, dist_min, dist_max);
+ }
+ else {
+ /* 5 */
+ BufferLineAccumulator<-1, 0, 0, -1>::eval(input, output, pt_ofs, source, dist_min, dist_max);
+ }
+ }
+ }
+}
+
+void *SunBeamsOperation::initializeTileData(rcti *rect)
+{
+ void *buffer = getInputOperation(0)->initializeTileData(NULL);
+ return buffer;
+}
+
+void SunBeamsOperation::executePixel(float output[4], int x, int y, void *data)
+{
+ const float co[2] = {(float)x, (float)y};
+
+ accumulate_line((MemoryBuffer *)data, output, co, this->m_source_px, 0.0f, this->m_ray_length_px);
+}
+
+static void calc_ray_shift(rcti *rect, float x, float y, const float source[2], float ray_length)
+{
+ float co[2] = {(float)x, (float)y};
+ float dir[2], dist;
+
+ /* move (x,y) vector toward the source by ray_length distance */
+ sub_v2_v2v2(dir, co, source);
+ dist = normalize_v2(dir);
+ mul_v2_fl(dir, min_ff(dist, ray_length));
+ sub_v2_v2(co, dir);
+
+ int ico[2] = {(int)co[0], (int)co[1]};
+ BLI_rcti_do_minmax_v(rect, ico);
+}
+
+bool SunBeamsOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
+{
+ /* Enlarges the rect by moving each corner toward the source.
+ * This is the maximum distance that pixels can influence each other
+ * and gives a rect that contains all possible accumulated pixels.
+ */
+ rcti rect = *input;
+ calc_ray_shift(&rect, input->xmin, input->ymin, this->m_source_px, this->m_ray_length_px);
+ calc_ray_shift(&rect, input->xmin, input->ymax, this->m_source_px, this->m_ray_length_px);
+ calc_ray_shift(&rect, input->xmax, input->ymin, this->m_source_px, this->m_ray_length_px);
+ calc_ray_shift(&rect, input->xmax, input->ymax, this->m_source_px, this->m_ray_length_px);
+
+ return NodeOperation::determineDependingAreaOfInterest(&rect, readOperation, output);
+}
+
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.h b/source/blender/compositor/operations/COM_SunBeamsOperation.h
new file mode 100644
index 00000000000..ef80a31fe40
--- /dev/null
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2014, 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:
+ * Lukas Toenne
+ */
+
+#ifndef _COM_SunBeamsOperation_h
+#define _COM_SunBeamsOperation_h
+
+#include "COM_NodeOperation.h"
+
+class SunBeamsOperation : public NodeOperation {
+public:
+ SunBeamsOperation();
+
+ void executePixel(float output[4], int x, int y, void *data);
+
+ void initExecution();
+
+ void *initializeTileData(rcti *rect);
+
+ bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
+
+ void setData(const NodeSunBeams &data) { m_data = data; }
+
+private:
+ NodeSunBeams m_data;
+
+ float m_source_px[2];
+ float m_ray_length_px;
+};
+
+#endif
diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cpp b/source/blender/compositor/operations/COM_TranslateOperation.cpp
index 64da954a2e1..191388a42fb 100644
--- a/source/blender/compositor/operations/COM_TranslateOperation.cpp
+++ b/source/blender/compositor/operations/COM_TranslateOperation.cpp
@@ -59,7 +59,7 @@ void TranslateOperation::executePixelSampled(float output[4], float x, float y,
float originalXPos = x - this->getDeltaX();
float originalYPos = y - this->getDeltaY();
- this->m_inputOperation->readSampled(output, originalXPos, originalYPos, sampler);
+ this->m_inputOperation->readSampled(output, originalXPos, originalYPos, COM_PS_BILINEAR);
}
bool TranslateOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
diff --git a/source/blender/compositor/operations/COM_WrapOperation.cpp b/source/blender/compositor/operations/COM_WrapOperation.cpp
index e6cde05eae2..c30361d1df8 100644
--- a/source/blender/compositor/operations/COM_WrapOperation.cpp
+++ b/source/blender/compositor/operations/COM_WrapOperation.cpp
@@ -77,26 +77,25 @@ void WrapOperation::executePixelSampled(float output[4], float x, float y, Pixel
bool WrapOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
rcti newInput;
-
newInput.xmin = input->xmin;
newInput.xmax = input->xmax;
newInput.ymin = input->ymin;
newInput.ymax = input->ymax;
- if (m_wrappingType == 1 || m_wrappingType == 3) {
+ if (m_wrappingType == CMP_NODE_WRAP_X || m_wrappingType == CMP_NODE_WRAP_XY) {
// wrap only on the x-axis if tile is wrapping
newInput.xmin = getWrappedOriginalXPos(input->xmin);
- newInput.xmax = getWrappedOriginalXPos(input->xmax);
- if (newInput.xmin > newInput.xmax) {
+ newInput.xmax = getWrappedOriginalXPos(input->xmax) + 0.5f;
+ if (newInput.xmin >= newInput.xmax) {
newInput.xmin = 0;
newInput.xmax = this->getWidth();
}
}
- if (m_wrappingType == 2 || m_wrappingType == 3) {
+ if (m_wrappingType == CMP_NODE_WRAP_Y || m_wrappingType == CMP_NODE_WRAP_XY) {
// wrap only on the y-axis if tile is wrapping
newInput.ymin = getWrappedOriginalYPos(input->ymin);
- newInput.ymax = getWrappedOriginalYPos(input->ymax);
- if (newInput.ymin > newInput.ymax) {
+ newInput.ymax = getWrappedOriginalYPos(input->ymax) + 0.5f;
+ if (newInput.ymin >= newInput.ymax) {
newInput.ymin = 0;
newInput.ymax = this->getHeight();
}
diff --git a/source/blender/datatoc/CMakeLists.txt b/source/blender/datatoc/CMakeLists.txt
index 53fe8c32e9c..4c35a941757 100644
--- a/source/blender/datatoc/CMakeLists.txt
+++ b/source/blender/datatoc/CMakeLists.txt
@@ -53,7 +53,7 @@ if(NOT WITH_HEADLESS)
)
endif()
- include_directories(${PNG_INCLUDE_DIR})
+ include_directories(${PNG_INCLUDE_DIRS})
link_directories(${PNG_LIBPATH} ${ZLIB_LIBPATH})
add_executable(datatoc_icon ${SRC})
diff --git a/source/blender/datatoc/datatoc_icon.c b/source/blender/datatoc/datatoc_icon.c
index 59c9eeb3ed1..7df9269a4a8 100644
--- a/source/blender/datatoc/datatoc_icon.c
+++ b/source/blender/datatoc/datatoc_icon.c
@@ -314,6 +314,9 @@ static bool icon_merge(const char *file_src,
free(pixels);
+ /* only for bounds check */
+ (void)canvas_h;
+
return true;
}
diff --git a/source/blender/editors/animation/CMakeLists.txt b/source/blender/editors/animation/CMakeLists.txt
index d6030a967d5..b9f50a6cdf1 100644
--- a/source/blender/editors/animation/CMakeLists.txt
+++ b/source/blender/editors/animation/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -57,4 +59,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_animation "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/animation/SConscript b/source/blender/editors/animation/SConscript
index 91d480978c4..ed4b794cbce 100644
--- a/source/blender/editors/animation/SConscript
+++ b/source/blender/editors/animation/SConscript
@@ -31,17 +31,19 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index 1cd1a26678d..7d8e278f0cf 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -344,7 +344,7 @@ static void acf_generic_idblock_name(bAnimListElem *ale, char *name)
/* name property for ID block entries */
static bool acf_generic_idblock_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop)
{
- RNA_id_pointer_create(ale->id, ptr);
+ RNA_id_pointer_create(ale->data, ptr);
*prop = RNA_struct_name_property(ptr->type);
return (*prop != NULL);
@@ -650,6 +650,15 @@ static void acf_object_name(bAnimListElem *ale, char *name)
BLI_strncpy(name, ob->id.name + 2, ANIM_CHAN_NAME_SIZE);
}
+/* name property for object */
+static bool acf_object_name_prop(bAnimListElem *ale, PointerRNA *ptr, PropertyRNA **prop)
+{
+ RNA_id_pointer_create(ale->id, ptr);
+ *prop = RNA_struct_name_property(ptr->type);
+
+ return (*prop != NULL);
+}
+
/* check if some setting exists for this channel */
static bool acf_object_setting_valid(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
@@ -740,7 +749,7 @@ static bAnimChannelType ACF_OBJECT =
NULL, /* offset */
acf_object_name, /* name */
- acf_generic_idblock_name_prop, /* name prop */
+ acf_object_name_prop, /* name prop */
acf_object_icon, /* icon */
acf_object_setting_valid, /* has setting */
@@ -3219,7 +3228,7 @@ void ANIM_channel_debug_print_info(bAnimListElem *ale, short indent_level)
/* Check if some setting for a channel is enabled
* Returns: 1 = On, 0 = Off, -1 = Invalid
*/
-short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, int setting)
+short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting)
{
bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -3292,7 +3301,7 @@ short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, int setting
* - setting: eAnimChannel_Settings
* - mode: eAnimChannels_SetFlag
*/
-void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, int setting, short mode)
+void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
{
bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@@ -3569,7 +3578,7 @@ static void achannel_setting_flush_widget_cb(bContext *C, void *ale_npoin, void
ANIM_flush_setting_anim_channels(&ac, &anim_data, ale_setting, setting, on);
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* callback for wrapping NLA Track "solo" toggle logic */
@@ -3837,7 +3846,7 @@ void ANIM_channel_draw_widgets(bContext *C, bAnimContext *ac, bAnimListElem *ale
short offset;
/* sanity checks - don't draw anything */
- if (ELEM3(NULL, acf, ale, block))
+ if (ELEM(NULL, acf, ale, block))
return;
/* get initial offset */
diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c
index 5d97b7be9f7..b6ab0407711 100644
--- a/source/blender/editors/animation/anim_channels_edit.c
+++ b/source/blender/editors/animation/anim_channels_edit.c
@@ -49,6 +49,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "BKE_animsys.h"
#include "BKE_action.h"
#include "BKE_fcurve.h"
#include "BKE_gpencil.h"
@@ -74,7 +75,7 @@
/* Set the given animation-channel as the active one for the active context */
// TODO: extend for animdata types...
-void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type)
+void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datatype, eAnimFilter_Flags filter, void *channel_data, eAnim_ChannelType channel_type)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -173,6 +174,8 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
case ANIMTYPE_DSLAT:
case ANIMTYPE_DSLINESTYLE:
case ANIMTYPE_DSSPK:
+ case ANIMTYPE_DSNTREE:
+ case ANIMTYPE_DSTEX:
{
/* need to verify that this data is valid for now */
if (ale && ale->adt) {
@@ -180,11 +183,22 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
}
break;
}
+
+ /* unhandled currently, but may be interesting */
+ case ANIMTYPE_GPLAYER:
+ case ANIMTYPE_MASKLAYER:
+ case ANIMTYPE_SHAPEKEY:
+ case ANIMTYPE_NLAACTION:
+ break;
+
+ /* other types */
+ default:
+ break;
}
}
/* clean up */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* Deselect all animation channels
@@ -193,7 +207,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
* - test: check if deselecting instead of selecting
* - sel: eAnimChannels_SetFlag;
*/
-void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, short test, short sel)
+void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types datatype, bool test, eAnimChannels_SetFlag sel)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -373,7 +387,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ---------------------------- Graph Editor ------------------------------------- */
@@ -387,7 +401,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
* - setting: type of setting to set
* - on: whether the visibility setting has been enabled or disabled
*/
-void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, int setting, short mode)
+void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode)
{
bAnimListElem *ale, *match = NULL;
int prevLevel = 0, matchLevel = 0;
@@ -591,7 +605,7 @@ static int animedit_poll_channels_active(bContext *C)
if (ELEM(NULL, sa, CTX_wm_region(C)))
return 0;
/* animation editor test */
- if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
+ if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
return 0;
return 1;
@@ -608,7 +622,7 @@ static int animedit_poll_channels_nla_tweakmode_off(bContext *C)
if (ELEM(NULL, sa, CTX_wm_region(C)))
return 0;
/* animation editor test */
- if (ELEM3(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
+ if (ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA) == 0)
return 0;
/* NLA TweakMode test */
@@ -623,13 +637,13 @@ static int animedit_poll_channels_nla_tweakmode_off(bContext *C)
/* ****************** Rearrange Channels Operator ******************* */
/* constants for channel rearranging */
-/* WARNING: don't change exising ones without modifying rearrange func accordingly */
-enum {
+/* WARNING: don't change existing ones without modifying rearrange func accordingly */
+typedef enum eRearrangeAnimChan_Mode {
REARRANGE_ANIMCHAN_TOP = -2,
REARRANGE_ANIMCHAN_UP = -1,
REARRANGE_ANIMCHAN_DOWN = 1,
REARRANGE_ANIMCHAN_BOTTOM = 2
-};
+} eRearrangeAnimChan_Mode;
/* defines for rearranging channels */
static EnumPropertyItem prop_animchannel_rearrange_types[] = {
@@ -733,13 +747,13 @@ static bool rearrange_island_down(ListBase *list, tReorderChannelIsland *island)
/* push it down */
BLI_insertlinkafter(list, next, island);
- return 1;
+ return true;
}
}
/* else: no next channel, so we're at the bottom already, so can't move */
}
- return 0;
+ return false;
}
static bool rearrange_island_bottom(ListBase *list, tReorderChannelIsland *island)
@@ -761,23 +775,25 @@ static bool rearrange_island_bottom(ListBase *list, tReorderChannelIsland *islan
}
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/* ............................. */
-/* typedef for channel rearranging function
- * < list: list that channels belong to
- * < island: island to be moved
- * > return[0]: whether operation was a success
+/**
+ * typedef for channel rearranging function
+ *
+ * \param list List of tReorderChannelIsland's that channels belong to
+ * \param island Island to be moved
+ * \return Whether operation was a success
*/
typedef bool (*AnimChanRearrangeFp)(ListBase *list, tReorderChannelIsland *island);
/* get rearranging function, given 'rearrange' mode */
-static AnimChanRearrangeFp rearrange_get_mode_func(short mode)
+static AnimChanRearrangeFp rearrange_get_mode_func(eRearrangeAnimChan_Mode mode)
{
switch (mode) {
case REARRANGE_ANIMCHAN_TOP:
@@ -796,7 +812,9 @@ static AnimChanRearrangeFp rearrange_get_mode_func(short mode)
/* Rearrange Islands Generics ------------------------------------- */
/* add channel into list of islands */
-static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *srcList, Link *channel, short type, const bool is_hidden)
+static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *srcList,
+ Link *channel, eAnim_ChannelType type,
+ const bool is_hidden)
{
tReorderChannelIsland *island = islands->last; /* always try to add to last island if possible */
bool is_sel = false, is_untouchable = false;
@@ -839,7 +857,7 @@ static void rearrange_animchannel_add_to_islands(ListBase *islands, ListBase *sr
(is_sel == 0) ||
/* 4) hidden status changes */
((island->flag & REORDER_ISLAND_HIDDEN) != is_hidden)
- )
+ )
{
/* create a new island now */
island = MEM_callocN(sizeof(tReorderChannelIsland), "tReorderChannelIsland");
@@ -878,16 +896,33 @@ static void rearrange_animchannel_flatten_islands(ListBase *islands, ListBase *s
/* ............................. */
-static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, bAnimContext *ac, short type)
+/* get a list of all bAnimListElem's of a certain type which are currently visible */
+static void rearrange_animchannels_filter_visible(ListBase *anim_data_visible, bAnimContext *ac, eAnim_ChannelType type)
{
- int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
-
- ANIM_animdata_filter(ac, anim_data_visible, filter, ac->data, type);
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale, *ale_next;
+ int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
+
+ /* get all visible channels */
+ ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
+
+ /* now, only keep the ones that are of the types we are interested in */
+ for (ale = anim_data.first; ale; ale = ale_next) {
+ ale_next = ale->next;
+
+ if (ale->type != type) {
+ BLI_freelinkN(&anim_data, ale);
+ }
+ }
+
+ /* return cleaned up list */
+ *anim_data_visible = anim_data;
}
/* performing rearranging of channels using islands */
static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp rearrange_func,
- short mode, short type, ListBase *anim_data_visible)
+ eRearrangeAnimChan_Mode mode, eAnim_ChannelType type,
+ ListBase *anim_data_visible)
{
ListBase islands = {NULL, NULL};
Link *channel, *chanNext = NULL;
@@ -937,7 +972,7 @@ static bool rearrange_animchannel_islands(ListBase *list, AnimChanRearrangeFp re
* ! NLA tracks are displayed in opposite order, so directions need care
* mode: REARRANGE_ANIMCHAN_*
*/
-static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, short mode)
+static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
{
AnimChanRearrangeFp rearrange_func;
ListBase anim_data_visible = {NULL, NULL};
@@ -950,10 +985,6 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, short mode)
if (rearrange_func == NULL)
return;
- /* only consider NLA data if it's accessible */
- //if (EXPANDED_DRVD(adt) == 0)
- // return;
-
/* Filter visible data. */
rearrange_animchannels_filter_visible(&anim_data_visible, ac, ANIMTYPE_NLATRACK);
@@ -969,7 +1000,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, short mode)
/* Change the order drivers within AnimData block
* mode: REARRANGE_ANIMCHAN_*
*/
-static void rearrange_driver_channels(bAnimContext *ac, AnimData *adt, short mode)
+static void rearrange_driver_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
{
/* get rearranging function */
AnimChanRearrangeFp rearrange_func = rearrange_get_mode_func(mode);
@@ -1035,6 +1066,13 @@ static void split_groups_action_temp(bAction *act, bActionGroup *tgrp)
fcu->next = NULL;
tgrp->channels.last = fcu;
act->curves.last = NULL;
+
+ /* ensure that all of these get their group set to this temp group
+ * (so that visibility filtering works)
+ */
+ for (fcu = tgrp->channels.first; fcu; fcu = fcu->next) {
+ fcu->grp = tgrp;
+ }
}
/* Add temp-group to list */
@@ -1057,8 +1095,17 @@ static void join_groups_action_temp(bAction *act)
/* clear moved flag */
agrp->flag &= ~AGRP_MOVED;
- /* if temp-group... remove from list (but don't free as it's on the stack!) */
+ /* if group was temporary one:
+ * - unassign all FCurves which were temporarily added to it
+ * - remove from list (but don't free as it's on the stack!)
+ */
if (agrp->flag & AGRP_TEMP) {
+ FCurve *fcu;
+
+ for (fcu = agrp->channels.first; fcu; fcu = fcu->next) {
+ fcu->grp = NULL;
+ }
+
BLI_remlink(&act->groups, agrp);
break;
}
@@ -1068,7 +1115,7 @@ static void join_groups_action_temp(bAction *act)
/* Change the order of anim-channels within action
* mode: REARRANGE_ANIMCHAN_*
*/
-static void rearrange_action_channels(bAnimContext *ac, bAction *act, short mode)
+static void rearrange_action_channels(bAnimContext *ac, bAction *act, eRearrangeAnimChan_Mode mode)
{
bActionGroup tgrp;
ListBase anim_data_visible = {NULL, NULL};
@@ -1123,7 +1170,7 @@ static void rearrange_action_channels(bAnimContext *ac, bAction *act, short mode
static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
- short mode;
+ eRearrangeAnimChan_Mode mode;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1177,7 +1224,7 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* send notifier that things have changed */
@@ -1290,7 +1337,7 @@ static void animchannels_group_channels(bAnimContext *ac, bAnimListElem *adt_ref
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
}
@@ -1321,7 +1368,7 @@ static int animchannels_group_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* updatss */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -1393,7 +1440,7 @@ static int animchannels_ungroup_exec(bContext *C, wmOperator *UNUSED(op))
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* updates */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -1470,7 +1517,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* filter data */
@@ -1515,7 +1562,7 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -1586,7 +1633,7 @@ static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(op))
ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 0);
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* make all the selected channels visible */
filter = (ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
@@ -1605,7 +1652,7 @@ static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(op))
ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1);
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
BLI_freelistN(&all_data);
@@ -1683,7 +1730,7 @@ static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *UNUSED(o
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
BLI_freelistN(&all_data);
/* send notifier that things have changed */
@@ -1735,7 +1782,7 @@ static EnumPropertyItem prop_animchannel_settings_types[] = {
* onlysel: only selected channels get the flag set
*/
// TODO: enable a setting which turns flushing on/off?
-static void setflag_anim_channels(bAnimContext *ac, short setting, short mode, short onlysel, short flush)
+static void setflag_anim_channels(bAnimContext *ac, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode, bool onlysel, bool flush)
{
ListBase anim_data = {NULL, NULL};
ListBase all_data = {NULL, NULL};
@@ -1799,7 +1846,7 @@ static void setflag_anim_channels(bAnimContext *ac, short setting, short mode, s
ANIM_flush_setting_anim_channels(ac, &all_data, ale, setting, mode);
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
BLI_freelistN(&all_data);
}
@@ -1808,8 +1855,9 @@ static void setflag_anim_channels(bAnimContext *ac, short setting, short mode, s
static int animchannels_setflag_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
- short mode, setting;
- short flush = 1;
+ eAnimChannel_Settings setting;
+ eAnimChannels_SetFlag mode;
+ bool flush = true;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1821,12 +1869,12 @@ static int animchannels_setflag_exec(bContext *C, wmOperator *op)
/* check if setting is flushable */
if (setting == ACHANNEL_SETTING_EXPAND)
- flush = 0;
+ flush = false;
/* modify setting
* - only selected channels are affected
*/
- setflag_anim_channels(&ac, setting, mode, 1, flush);
+ setflag_anim_channels(&ac, setting, mode, true, flush);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -1939,7 +1987,7 @@ static void ANIM_OT_channels_editable_toggle(wmOperatorType *ot)
static int animchannels_expand_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
- short onlysel = 1;
+ bool onlysel = true;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1947,10 +1995,10 @@ static int animchannels_expand_exec(bContext *C, wmOperator *op)
/* only affect selected channels? */
if (RNA_boolean_get(op->ptr, "all"))
- onlysel = 0;
+ onlysel = false;
/* modify setting */
- setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, 0);
+ setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_ADD, onlysel, false);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -1981,7 +2029,7 @@ static void ANIM_OT_channels_expand(wmOperatorType *ot)
static int animchannels_collapse_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
- short onlysel = 1;
+ bool onlysel = true;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -1989,10 +2037,10 @@ static int animchannels_collapse_exec(bContext *C, wmOperator *op)
/* only affect selected channels? */
if (RNA_boolean_get(op->ptr, "all"))
- onlysel = 0;
+ onlysel = false;
/* modify setting */
- setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, 0);
+ setflag_anim_channels(&ac, ACHANNEL_SETTING_EXPAND, ACHANNEL_SETFLAG_CLEAR, onlysel, false);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -2015,7 +2063,114 @@ static void ANIM_OT_channels_collapse(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- ot->prop = RNA_def_boolean(ot->srna, "all", 1, "All", "Collapse all channels (not just selected ones)");
+ ot->prop = RNA_def_boolean(ot->srna, "all", true, "All", "Collapse all channels (not just selected ones)");
+}
+
+/* ************ Remove All "Empty" AnimData Blocks Operator ********* */
+/* We define "empty" AnimData blocks here as those which have all 3 of criteria:
+ * 1) No active action OR that active actions are empty
+ * Assuming that all legitimate entries will have an action,
+ * and that empty actions
+ * 2) No NLA Tracks + NLA Strips
+ * Assuming that users haven't set up any of these as "placeholders"
+ * for convenience sake, and that most that exist were either unintentional
+ * or are no longer wanted
+ * 3) No drivers
+ */
+
+static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ bAnimContext ac;
+
+ ListBase anim_data = {NULL, NULL};
+ bAnimListElem *ale;
+ int filter;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* get animdata blocks */
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA);
+ ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+
+ for (ale = anim_data.first; ale; ale = ale->next) {
+ ID *id = ale->id;
+ AnimData *adt = ale->data;
+
+ bool action_empty = false;
+ bool nla_empty = false;
+ bool drivers_empty = false;
+
+ /* sanity checks */
+ BLI_assert((id != NULL) && (adt != NULL));
+
+ /* check if this is "empty" and can be deleted */
+ /* (For now, there are only these 3 criteria) */
+
+ /* 1) Active Action is missing or empty */
+ if (ELEM(NULL, adt->action, adt->action->curves.first)) {
+ action_empty = true;
+ }
+ else {
+ /* TODO: check for keyframe + fmodifier data on these too */
+ }
+
+ /* 2) No NLA Tracks and/or NLA Strips */
+ if (adt->nla_tracks.first == NULL) {
+ nla_empty = true;
+ }
+ else {
+ NlaTrack *nlt;
+
+ /* empty tracks? */
+ for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
+ if (nlt->strips.first) {
+ /* stop searching, as we found one that actually had stuff we don't want lost
+ * NOTE: nla_empty gets reset to false, as a previous track may have been empty
+ */
+ nla_empty = false;
+ break;
+ }
+ else if (nlt->strips.first == NULL) {
+ /* this track is empty, but another one may still have stuff in it, so can't break yet */
+ nla_empty = true;
+ }
+ }
+ }
+
+ /* 3) Drivers */
+ drivers_empty = (adt->drivers.first == NULL);
+
+
+ /* remove AnimData? */
+ if (action_empty && nla_empty && drivers_empty) {
+ BKE_free_animdata(id);
+ }
+ }
+
+ /* free temp data */
+ ANIM_animdata_freelist(&anim_data);
+
+ /* send notifier that things have changed */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_channels_clean_empty(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Empty Animation Data";
+ ot->idname = "ANIM_OT_channels_clean_empty";
+ ot->description = "Delete all empty animation data containers from visible datablocks";
+
+ /* api callbacks */
+ ot->exec = animchannels_clean_empty_exec;
+ ot->poll = animedit_poll_channels_nla_tweakmode_off;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************* Reenable Disabled Operator ******************* */
@@ -2023,7 +2178,7 @@ static void ANIM_OT_channels_collapse(wmOperatorType *ot)
static int animchannels_enable_poll(bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
-
+
/* channels region test */
/* TODO: could enhance with actually testing if channels region? */
if (ELEM(NULL, sa, CTX_wm_region(C)))
@@ -2064,11 +2219,11 @@ static int animchannels_enable_exec(bContext *C, wmOperator *UNUSED(op))
fcu->driver->flag &= ~DRIVER_FLAG_INVALID;
/* tag everything for updates - in particular, this is needed to get drivers working again */
- ANIM_list_elem_update(ac.scene, ale);
+ ale->update |= ANIM_UPDATE_DEPS;
}
- /* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_update(&ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
@@ -2091,6 +2246,82 @@ static void ANIM_OT_channels_fcurves_enable(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* ****************** Find / Set Filter Operator ******************** */
+
+/* XXX: make this generic? */
+static int animchannels_find_poll(bContext *C)
+{
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa == NULL)
+ return 0;
+
+ /* animation editor with dopesheet */
+ return ELEM(sa->spacetype, SPACE_ACTION, SPACE_IPO, SPACE_NLA);
+}
+
+/* find_invoke() - Get initial channels */
+static int animchannels_find_invoke(bContext *C, wmOperator *op, const wmEvent *evt)
+{
+ bAnimContext ac;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* set initial filter text, and enable filter */
+ RNA_string_set(op->ptr, "query", ac.ads->searchstr);
+
+ /* defer to popup */
+ return WM_operator_props_popup(C, op, evt);
+}
+
+/* find_exec() - Called to set the value */
+static int animchannels_find_exec(bContext *C, wmOperator *op)
+{
+ bAnimContext ac;
+
+ /* get editor data */
+ if (ANIM_animdata_get_context(C, &ac) == 0)
+ return OPERATOR_CANCELLED;
+
+ /* update filter text, and ensure that filter is enabled if there's something there
+ * NOTE: we turn the filter off if there's nothing (this is a quick shortcut for dismissing)
+ */
+ RNA_string_get(op->ptr, "query", ac.ads->searchstr);
+
+ if (ac.ads->searchstr[0]) {
+ ac.ads->filterflag |= ADS_FILTER_BY_FCU_NAME;
+ }
+ else {
+ ac.ads->filterflag &= ~ADS_FILTER_BY_FCU_NAME;
+ }
+
+ /* redraw */
+ WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_channels_find(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Find Channels";
+ ot->idname = "ANIM_OT_channels_find";
+ ot->description = "Filter the set of channels shown to only include those with matching names";
+
+ /* callbacks */
+ ot->invoke = animchannels_find_invoke;
+ ot->exec = animchannels_find_exec;
+ ot->poll = animchannels_find_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ot->prop = RNA_def_string(ot->srna, "query", "Query", sizeof(((bDopeSheet *)NULL)->searchstr), "", "Text to search for in channel names");
+}
+
/* ********************** Select All Operator *********************** */
static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
@@ -2103,9 +2334,9 @@ static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
/* 'standard' behavior - check if selected, then apply relevant selection */
if (RNA_boolean_get(op->ptr, "invert"))
- ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, false, ACHANNEL_SETFLAG_TOGGLE);
else
- ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_ADD);
/* send notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, NULL);
@@ -2128,7 +2359,7 @@ static void ANIM_OT_channels_select_all_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
- ot->prop = RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
+ ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "");
}
/* ******************** Borderselect Operator *********************** */
@@ -2228,7 +2459,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -2252,7 +2483,7 @@ static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
extend = RNA_boolean_get(op->ptr, "extend");
if (!extend)
- ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_CLEAR);
+ ANIM_deselect_anim_channels(&ac, ac.data, ac.datatype, true, ACHANNEL_SETFLAG_CLEAR);
if (gesture_mode == GESTURE_MODAL_SELECT)
selectmode = ACHANNEL_SETFLAG_ADD;
@@ -2312,7 +2543,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
if (G.debug & G_DEBUG)
printf("Error: animation channel (index = %d) not found in rename_anim_channels()\n", channel_index);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return;
}
@@ -2338,7 +2569,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
}
/* free temp data and tag for refresh */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
ED_region_tag_redraw(ac->ar);
}
@@ -2413,7 +2644,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
if (G.debug & G_DEBUG)
printf("Error: animation channel (index = %d) not found in mouse_anim_channels()\n", channel_index);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return 0;
}
@@ -2421,7 +2652,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* TODO: should this feature be extended to work with other channel types too? */
if ((selectmode == -1) && (ale->type != ANIMTYPE_GROUP)) {
/* normal channels should not behave normally in this case */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return 0;
}
@@ -2515,7 +2746,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
else {
/* select AnimData block by itself */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
ale->adt->flag |= ADT_UI_SELECTED;
}
@@ -2570,8 +2801,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
FCurve *fcu;
/* deselect all other channels */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
- if (pchan) ED_pose_deselectall(ob, 0);
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
+ if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
/* only select channels in group and group itself */
for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next)
@@ -2580,8 +2811,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
else {
/* select group by itself */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
- if (pchan) ED_pose_deselectall(ob, 0);
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
+ if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
agrp->flag |= AGRP_SELECTED;
}
@@ -2610,7 +2841,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
else {
/* select F-Curve by itself */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
fcu->flag |= FCURVE_SELECTED;
}
@@ -2632,7 +2863,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
else {
/* select ShapeKey by itself */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
kb->flag |= KEYBLOCK_SEL;
}
@@ -2662,7 +2893,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
else {
/* select layer by itself */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
gpl->flag |= GP_LAYER_SELECT;
}
@@ -2692,7 +2923,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
else {
/* select layer by itself */
- ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
+ ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
masklay->flag |= MASK_LAYERFLAG_SELECT;
}
@@ -2706,7 +2937,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
}
/* free channels */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* return notifier flags */
return notifierFlags;
@@ -2777,10 +3008,10 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
/* properties */
/* NOTE: don't save settings, otherwise, can end up with some weird behaviour (sticky extend) */
- prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend Select", ""); // SHIFTKEY
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "children_only", 0, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
+ prop = RNA_def_boolean(ot->srna, "children_only", false, "Select Children Only", ""); // CTRLKEY|SHIFTKEY
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -2795,6 +3026,8 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channels_click);
WM_operatortype_append(ANIM_OT_channels_rename);
+ WM_operatortype_append(ANIM_OT_channels_find);
+
WM_operatortype_append(ANIM_OT_channels_setting_enable);
WM_operatortype_append(ANIM_OT_channels_setting_disable);
WM_operatortype_append(ANIM_OT_channels_setting_toggle);
@@ -2814,6 +3047,8 @@ void ED_operatortypes_animchannels(void)
WM_operatortype_append(ANIM_OT_channels_fcurves_enable);
+ WM_operatortype_append(ANIM_OT_channels_clean_empty);
+
WM_operatortype_append(ANIM_OT_channels_group);
WM_operatortype_append(ANIM_OT_channels_ungroup);
}
@@ -2823,8 +3058,7 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_find(keyconf, "Animation Channels", 0, 0);
wmKeyMapItem *kmi;
-
- /* selection */
+
/* click-select */
/* XXX for now, only leftmouse.... */
WM_keymap_add_item(keymap, "ANIM_OT_channels_click", LEFTMOUSE, KM_PRESS, 0, 0);
@@ -2833,6 +3067,10 @@ 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);
+
+ /* 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);
/* deselect all */
WM_keymap_add_item(keymap, "ANIM_OT_channels_select_all_toggle", AKEY, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index c0543862265..f3b47b168e9 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -45,6 +45,7 @@
#include "BKE_animsys.h"
#include "BKE_action.h"
+#include "BKE_fcurve.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
@@ -192,7 +193,7 @@ static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve **
/* major priority is selection status, so refer to the checks done in anim_filter.c
* skip_fcurve_selected_data() for reference about what's going on here...
*/
- if (ELEM3(NULL, fcu, fcu->rna_path, owner_id))
+ if (ELEM(NULL, fcu, fcu->rna_path, owner_id))
return;
if (GS(owner_id->name) == ID_OB) {
@@ -341,5 +342,58 @@ void ANIM_sync_animchannels_to_data(const bContext *C)
}
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
+}
+
+void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
+{
+ bAnimListElem *ale;
+
+ if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK)) {
+#ifdef DEBUG
+ /* quiet assert */
+ for (ale = anim_data->first; ale; ale = ale->next) {
+ ale->update = 0;
+ }
+#endif
+ return;
+ }
+
+ for (ale = anim_data->first; ale; ale = ale->next) {
+ FCurve *fcu = ale->key_data;
+
+ if (ale->update & ANIM_UPDATE_ORDER) {
+ ale->update &= ~ANIM_UPDATE_ORDER;
+ if (fcu)
+ sort_time_fcurve(fcu);
+ }
+
+ if (ale->update & ANIM_UPDATE_HANDLES) {
+ ale->update &= ~ANIM_UPDATE_HANDLES;
+ if (fcu)
+ calchandles_fcurve(fcu);
+ }
+
+ if (ale->update & ANIM_UPDATE_DEPS) {
+ ale->update &= ~ANIM_UPDATE_DEPS;
+ ANIM_list_elem_update(ac->scene, ale);
+ }
+
+ BLI_assert(ale->update == 0);
+ }
+}
+
+void ANIM_animdata_freelist(ListBase *anim_data)
+{
+#ifndef NDEBUG
+ bAnimListElem *ale, *ale_next;
+ for (ale = anim_data->first; ale; ale = ale_next) {
+ ale_next = ale->next;
+ BLI_assert(ale->update == 0);
+ MEM_freeN(ale);
+ }
+ BLI_listbase_clear(anim_data);
+#else
+ BLI_freelistN(anim_data);
+#endif
}
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 6c28d05110f..dad25eb04af 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -987,8 +987,10 @@ static bool skip_fcurve_with_name(bDopeSheet *ads, FCurve *fcu, ID *owner_id)
return true;
}
-/* Check if F-Curve has errors and/or is disabled
- * > returns: (bool) True if F-Curve has errors/is disabled
+/**
+ * Check if F-Curve has errors and/or is disabled
+ *
+ * \return true if F-Curve has errors/is disabled
*/
static bool fcurve_has_errors(FCurve *fcu)
{
@@ -2593,7 +2595,7 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data)
* - just use ale->data for now, though it would be nicer to involve
* ale->type in combination too to capture corner cases (where same data performs differently)
*/
- if (BLI_gset_reinsert(gs, ale->data, NULL)) {
+ if (BLI_gset_add(gs, ale->data)) {
/* this entry is 'unique' and can be kept */
items++;
}
@@ -2619,7 +2621,7 @@ static size_t animdata_filter_remove_duplis(ListBase *anim_data)
* will be placed for use.
* filter_mode: how should the data be filtered - bitmapping accessed flags
*/
-size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype)
+size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype)
{
size_t items = 0;
@@ -2712,6 +2714,13 @@ size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, int filter_mo
items = animdata_filter_animchan(ac, anim_data, ads, data, filter_mode);
break;
}
+
+ /* unhandled */
+ default:
+ {
+ printf("ANIM_animdata_filter() - Invalid datatype argument %d\n", datatype);
+ break;
+ }
}
/* remove any 'weedy' entries */
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index d3e6d8f474f..57df6d32f03 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -63,7 +63,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
/* sanity checks */
if (name == NULL)
return icon;
- else if (ELEM3(NULL, id, fcu, fcu->rna_path)) {
+ else if (ELEM(NULL, id, fcu, fcu->rna_path)) {
if (fcu == NULL)
strcpy(name, IFACE_("<invalid>"));
else if (fcu->rna_path == NULL)
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index 04363f61fd6..7cd47fab83a 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -115,12 +115,15 @@ ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
/* --------------------------------- */
-/* Apply some transformation to markers after the fact
- * < markers: list of markers to affect - this may or may not be the scene markers list, so don't assume anything
- * < scene: current scene (for getting current frame)
- * < mode: (TfmMode) transform mode that this transform is for
- * < value: from the transform code, this is t->vec[0] (which is delta transform for grab/extend, and scale factor for scale)
- * < side: (B/L/R) for 'extend' functionality, which side of current frame to use
+/**
+ * Apply some transformation to markers after the fact
+ *
+ * \param markers List of markers to affect - this may or may not be the scene markers list, so don't assume anything
+ * \param scene Current scene (for getting current frame)
+ * \param mode (TfmMode) transform mode that this transform is for
+ * \param value From the transform code, this is ``t->vec[0]``
+ * (which is delta transform for grab/extend, and scale factor for scale)
+ * \param side (B/L/R) for 'extend' functionality, which side of current frame to use
*/
int ED_markers_post_apply_transform(ListBase *markers, Scene *scene, int mode, float value, char side)
{
@@ -201,7 +204,7 @@ void ED_markers_get_minmax(ListBase *markers, short sel, float *first, float *la
/* sanity check */
//printf("markers = %p - %p, %p\n", markers, markers->first, markers->last);
- if (ELEM3(NULL, markers, markers->first, markers->last)) {
+ if (ELEM(NULL, markers, markers->first, markers->last)) {
*first = 0.0f;
*last = 0.0f;
return;
@@ -472,13 +475,14 @@ static int ed_markers_poll_markers_exist(bContext *C)
/* ------------------------ */
-/* Second-tier invoke() callback that performs context validation before running the
+/**
+ * Second-tier invoke() callback that performs context validation before running the
* "custom"/third-tier invoke() callback supplied as the last arg (which would normally
* be the operator's invoke() callback elsewhere)
*
- * < invoke_func: (fn(bContext *, wmOperator *, wmEvent *)=int) "standard" invoke function
- * that operator would otherwise have used. If NULL, the operator's standard
- * exec() callback will be called instead in the appropriate places.
+ * \param invoke_func "standard" invoke function that operator would otherwise have used.
+ * If NULL, the operator's standard exec()
+ * callback will be called instead in the appropriate places.
*/
static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, const wmEvent *event,
int (*invoke_func)(bContext *, wmOperator *, const wmEvent *))
@@ -600,24 +604,88 @@ typedef struct MarkerMove {
NumInput num;
} MarkerMove;
+static bool ed_marker_move_use_time(MarkerMove *mm)
+{
+ if (((mm->slink->spacetype == SPACE_TIME) && !(((SpaceTime *)mm->slink)->flag & TIME_DRAWFRAMES)) ||
+ ((mm->slink->spacetype == SPACE_SEQ) && !(((SpaceSeq *)mm->slink)->flag & SEQ_DRAWFRAMES)) ||
+ ((mm->slink->spacetype == SPACE_ACTION) && (((SpaceAction *)mm->slink)->flag & SACTION_DRAWTIME)) ||
+ ((mm->slink->spacetype == SPACE_IPO) && !(((SpaceIpo *)mm->slink)->flag & SIPO_DRAWTIME)) ||
+ ((mm->slink->spacetype == SPACE_NLA) && !(((SpaceNla *)mm->slink)->flag & SNLA_DRAWTIME)))
+ {
+ return true;
+ }
+
+ return false;
+}
+
+static void ed_marker_move_update_header(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ MarkerMove *mm = op->customdata;
+ TimeMarker *marker, *selmarker = NULL;
+ const int offs = RNA_int_get(op->ptr, "frames");
+ char str[256];
+ char str_offs[NUM_STR_REP_LEN];
+ int totmark;
+ const bool use_time = ed_marker_move_use_time(mm);
+
+ for (totmark = 0, marker = mm->markers->first; marker; marker = marker->next) {
+ if (marker->flag & SELECT) {
+ selmarker = marker;
+ totmark++;
+ }
+ }
+
+ if (hasNumInput(&mm->num)) {
+ outputNumInput(&mm->num, str_offs, &scene->unit);
+ }
+ else if (use_time) {
+ BLI_snprintf(str_offs, sizeof(str_offs), "%.2f", FRA2TIME(offs));
+ }
+ else {
+ BLI_snprintf(str_offs, sizeof(str_offs), "%d", offs);
+ }
+
+ if (totmark == 1 && selmarker) {
+ /* we print current marker value */
+ if (use_time) {
+ BLI_snprintf(str, sizeof(str), "Marker %.2f offset %s", FRA2TIME(selmarker->frame), str_offs);
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), "Marker %d offset %s", selmarker->frame, str_offs);
+ }
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), "Marker offset %s", str_offs);
+ }
+
+ ED_area_headerprint(CTX_wm_area(C), str);
+}
+
/* copy selection to temp buffer */
/* return 0 if not OK */
-static int ed_marker_move_init(bContext *C, wmOperator *op)
+static bool ed_marker_move_init(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
ListBase *markers = ED_context_get_markers(C);
MarkerMove *mm;
TimeMarker *marker;
- int totmark = 0;
- int a;
+ int a, totmark;
+
+ if (markers == NULL) {
+ return false;
+ }
+
+ for (totmark = 0, marker = markers->first; marker; marker = marker->next) {
+ if (marker->flag & SELECT) {
+ totmark++;
+ }
+ }
+
+ if (totmark == 0) {
+ return false;
+ }
- if (markers == NULL) return 0;
-
- for (marker = markers->first; marker; marker = marker->next)
- if (marker->flag & SELECT) totmark++;
-
- if (totmark == 0) return 0;
-
op->customdata = mm = MEM_callocN(sizeof(MarkerMove), "Markermove");
mm->slink = CTX_wm_space_data(C);
mm->markers = markers;
@@ -628,16 +696,16 @@ static int ed_marker_move_init(bContext *C, wmOperator *op)
mm->num.val_flag[0] |= NUM_NO_FRACTION;
mm->num.unit_sys = scene->unit.system;
/* No time unit supporting frames currently... */
- mm->num.unit_type[0] = B_UNIT_NONE;
-
+ mm->num.unit_type[0] = ed_marker_move_use_time(mm) ? B_UNIT_TIME : B_UNIT_NONE;
+
for (a = 0, marker = markers->first; marker; marker = marker->next) {
if (marker->flag & SELECT) {
mm->oldframe[a] = marker->frame;
a++;
}
}
-
- return 1;
+
+ return true;
}
/* free stuff */
@@ -668,7 +736,9 @@ static int ed_marker_move_invoke(bContext *C, wmOperator *op, const wmEvent *eve
/* reset frs delta */
RNA_int_set(op->ptr, "frames", 0);
-
+
+ ed_marker_move_update_header(C, op);
+
return OPERATOR_RUNNING_MODAL;
}
@@ -722,138 +792,88 @@ static void ed_marker_move_cancel(bContext *C, wmOperator *op)
ed_marker_move_exit(C, op);
}
-
-
static int ed_marker_move_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
MarkerMove *mm = op->customdata;
View2D *v2d = UI_view2d_fromcontext(C);
- TimeMarker *marker, *selmarker = NULL;
- char str[256];
-
- switch (event->type) {
- case ESCKEY:
- ed_marker_move_cancel(C, op);
- return OPERATOR_CANCELLED;
- case RIGHTMOUSE:
- /* press = user manually demands transform to be canceled */
- if (event->val == KM_PRESS) {
+ const bool has_numinput = hasNumInput(&mm->num);
+ const bool use_time = ed_marker_move_use_time(mm);
+
+ /* Modal numinput active, try to handle numeric inputs first... */
+ if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &mm->num, event)) {
+ float value = (float)RNA_int_get(op->ptr, "frames");
+
+ applyNumInput(&mm->num, &value);
+ if (use_time) {
+ value = TIME2FRA(value);
+ }
+
+ RNA_int_set(op->ptr, "frames", (int)value);
+ ed_marker_move_apply(C, op);
+ ed_marker_move_update_header(C, op);
+ }
+ else {
+ bool handled = false;
+ switch (event->type) {
+ case ESCKEY:
ed_marker_move_cancel(C, op);
return OPERATOR_CANCELLED;
- }
- /* else continue; <--- see if release event should be caught for tweak-end */
-
- case RETKEY:
- case PADENTER:
- case LEFTMOUSE:
- case MIDDLEMOUSE:
- if (WM_modal_tweak_exit(event, mm->event_type)) {
- ed_marker_move_exit(C, op);
- WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
- WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
- return OPERATOR_FINISHED;
- }
- break;
- case MOUSEMOVE:
- {
- float dx, fac;
-
- if (hasNumInput(&mm->num))
- break;
-
- dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
-
- if (event->x != mm->evtx) { /* XXX maybe init for first time */
- int a, offs, totmark = 0;
-
- mm->evtx = event->x;
-
- fac = ((float)(event->x - mm->firstx) * dx);
-
- if (mm->slink->spacetype == SPACE_TIME)
- apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
- else
- apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
-
- offs = (int)fac;
- RNA_int_set(op->ptr, "frames", offs);
- ed_marker_move_apply(C, op);
-
- /* cruft below is for header print */
- for (a = 0, marker = mm->markers->first; marker; marker = marker->next) {
- if (marker->flag & SELECT) {
- selmarker = marker;
- a++; totmark++;
- }
+ case RIGHTMOUSE:
+ /* press = user manually demands transform to be canceled */
+ if (event->val == KM_PRESS) {
+ ed_marker_move_cancel(C, op);
+ return OPERATOR_CANCELLED;
}
-
- if (totmark == 1) {
- /* we print current marker value */
- if (mm->slink->spacetype == SPACE_TIME) {
- SpaceTime *stime = (SpaceTime *)mm->slink;
- if (stime->flag & TIME_DRAWFRAMES)
- BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs);
- else
- BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
- }
- else if (mm->slink->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)mm->slink;
- if (saction->flag & SACTION_DRAWTIME)
- BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
- else
- BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
- }
- else {
- BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
- }
+ /* else continue; <--- see if release event should be caught for tweak-end */
+
+ case RETKEY:
+ case PADENTER:
+ case LEFTMOUSE:
+ case MIDDLEMOUSE:
+ if (WM_modal_tweak_exit(event, mm->event_type)) {
+ ed_marker_move_exit(C, op);
+ WM_event_add_notifier(C, NC_SCENE | ND_MARKERS, NULL);
+ WM_event_add_notifier(C, NC_ANIMATION | ND_MARKERS, NULL);
+ return OPERATOR_FINISHED;
}
- else {
- /* we only print the offset */
- if (mm->slink->spacetype == SPACE_TIME) {
- SpaceTime *stime = (SpaceTime *)mm->slink;
- if (stime->flag & TIME_DRAWFRAMES)
- BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs);
- else
- BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
- }
- else if (mm->slink->spacetype == SPACE_ACTION) {
- SpaceAction *saction = (SpaceAction *)mm->slink;
- if (saction->flag & SACTION_DRAWTIME)
- BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
+ break;
+ case MOUSEMOVE:
+ if (!has_numinput) {
+ float dx;
+
+ dx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
+
+ if (event->x != mm->evtx) { /* XXX maybe init for first time */
+ float fac;
+
+ mm->evtx = event->x;
+ fac = ((float)(event->x - mm->firstx) * dx);
+
+ if (mm->slink->spacetype == SPACE_TIME)
+ apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, FPS, 0.1 * FPS, 0);
else
- BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
- }
- else {
- BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
+ apply_keyb_grid(event->shift, event->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
+
+ RNA_int_set(op->ptr, "frames", (int)fac);
+ ed_marker_move_apply(C, op);
+ ed_marker_move_update_header(C, op);
}
}
-
- ED_area_headerprint(CTX_wm_area(C), str);
- }
- break;
+ break;
}
- }
- if (event->val == KM_PRESS) {
- if (handleNumInput(C, &mm->num, event)) {
- char str_tx[NUM_STR_REP_LEN];
- float value = RNA_int_get(op->ptr, "frames");
- applyNumInput(&mm->num, &value);
+ if (!handled && event->val == KM_PRESS && handleNumInput(C, &mm->num, event)) {
+ float value = (float)RNA_int_get(op->ptr, "frames");
- if (hasNumInput(&mm->num)) {
- outputNumInput(&mm->num, str_tx);
- }
- else {
- BLI_snprintf(str_tx, sizeof(str_tx), "%d", (int)value);
+ applyNumInput(&mm->num, &value);
+ if (use_time) {
+ value = TIME2FRA(value);
}
- RNA_int_set(op->ptr, "frames", value);
+ RNA_int_set(op->ptr, "frames", (int)value);
ed_marker_move_apply(C, op);
- // ed_marker_header_update(C, op, str, (int)value);
- // strcat(str, str_tx);
- BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx);
- ED_area_headerprint(CTX_wm_area(C), str);
+ ed_marker_move_update_header(C, op);
}
}
@@ -1008,14 +1028,14 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, bool exte
}
}
- LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) {
+ BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) {
/* this way a not-extend select will allways give 1 selected marker */
if (marker->frame == frame) {
marker->flag ^= SELECT;
break;
}
}
- LISTBASE_CIRCULAR_FORWARD_END (markers, marker, marker_first);
+ BLI_LISTBASE_CIRCULAR_FORWARD_END (markers, marker, marker_first);
}
static int ed_marker_select(bContext *C, const wmEvent *event, bool extend, bool camera)
diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c
index 88429aa3867..0f202003dd8 100644
--- a/source/blender/editors/animation/anim_ops.c
+++ b/source/blender/editors/animation/anim_ops.c
@@ -72,7 +72,7 @@ static int change_frame_poll(bContext *C)
* this shouldn't show up in 3D editor (or others without 2D timeline view) via search
*/
if (sa) {
- if (ELEM5(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
+ if (ELEM(sa->spacetype, SPACE_TIME, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) {
return true;
}
else if (sa->spacetype == SPACE_IPO) {
@@ -168,6 +168,7 @@ static int change_frame_modal(bContext *C, wmOperator *op, const wmEvent *event)
case LEFTMOUSE:
case RIGHTMOUSE:
+ case MIDDLEMOUSE:
/* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init
* the modal op) doesn't work for some reason
*/
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c
index 839284905ff..296a52e7f20 100644
--- a/source/blender/editors/animation/drivers.c
+++ b/source/blender/editors/animation/drivers.c
@@ -109,7 +109,7 @@ FCurve *verify_driver_fcurve(ID *id, const char rna_path[], const int array_inde
fcu->flag = (FCURVE_VISIBLE | FCURVE_SELECTED);
/* store path - make copy, and store that */
- fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
+ fcu->rna_path = BLI_strdup(rna_path);
fcu->array_index = array_index;
/* if add is negative, don't init this data yet, since it will be filled in by the pasted driver */
@@ -426,74 +426,6 @@ bool ANIM_paste_driver(ReportList *reports, ID *id, const char rna_path[], int a
/* ************************************************** */
/* UI-Button Interface */
-/* Temporary wrapper for driver operators for buttons to make it easier to create
- * such drivers by rerouting all paths through the active object instead so that
- * they will get picked up by the dependency system.
- *
- * < C: context pointer - for getting active data
- * <> ptr: RNA pointer for property's datablock. May be modified as result of path remapping.
- * < prop: RNA definition of property to add for
- *
- * > returns: MEM_alloc'd string representing the path to the property from the given PointerRNA
- */
-static char *get_driver_path_hack(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
-{
- ID *id = (ID *)ptr->id.data;
- ScrArea *sa = CTX_wm_area(C);
-
- /* get standard path which may be extended */
- char *basepath = RNA_path_from_ID_to_property(ptr, prop);
- char *path = basepath; /* in case no remapping is needed */
-
-
- /* Remapping will only be performed in the Properties Editor, as only this
- * restricts the subspace of options to the 'active' data (a manageable state)
- */
- // TODO: watch out for pinned context?
- if ((sa) && (sa->spacetype == SPACE_BUTS)) {
- Object *ob = CTX_data_active_object(C);
-
- if (ob && id) {
- /* only id-types which can be remapped to go through objects should be considered */
- switch (GS(id->name)) {
- case ID_TE: /* textures */
- {
- Material *ma = give_current_material(ob, ob->actcol);
- Tex *tex = give_current_material_texture(ma);
-
- /* assumes: texture will only be shown if it is active material's active texture it's ok */
- if ((ID *)tex == id) {
- char name_esc_ma[(sizeof(ma->id.name) - 2) * 2];
- char name_esc_tex[(sizeof(tex->id.name) - 2) * 2];
-
- BLI_strescape(name_esc_ma, ma->id.name + 2, sizeof(name_esc_ma));
- BLI_strescape(name_esc_tex, tex->id.name + 2, sizeof(name_esc_tex));
-
- /* create new path */
- // TODO: use RNA path functions to construct step by step instead?
- // FIXME: maybe this isn't even needed anymore...
- path = BLI_sprintfN("material_slots[\"%s\"].material.texture_slots[\"%s\"].texture.%s",
- name_esc_ma, name_esc_tex, basepath);
-
- /* free old one */
- MEM_freeN(basepath);
- }
- break;
- }
- }
-
- /* fix RNA pointer, as we've now changed the ID root by changing the paths */
- if (basepath != path) {
- /* rebase provided pointer so that it starts from object... */
- RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr);
- }
- }
- }
-
- /* the path should now have been corrected for use */
- return path;
-}
-
/* Add Driver Button Operator ------------------------ */
static int add_driver_button_exec(bContext *C, wmOperator *op)
@@ -511,7 +443,7 @@ static int add_driver_button_exec(bContext *C, wmOperator *op)
index = -1;
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = get_driver_path_hack(C, &ptr, prop);
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
short flags = CREATEDRIVER_WITH_DEFAULT_DVAR;
if (path) {
@@ -566,7 +498,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op)
index = -1;
if (ptr.id.data && ptr.data && prop) {
- char *path = get_driver_path_hack(C, &ptr, prop);
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
success = ANIM_remove_driver(op->reports, ptr.id.data, path, index, 0);
MEM_freeN(path);
@@ -613,7 +545,7 @@ static int copy_driver_button_exec(bContext *C, wmOperator *op)
uiContextActiveProperty(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = get_driver_path_hack(C, &ptr, prop);
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
if (path) {
/* only copy the driver for the button that this was involved for */
@@ -657,7 +589,7 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op)
uiContextActiveProperty(C, &ptr, &prop, &index);
if (ptr.id.data && ptr.data && prop && RNA_property_animateable(&ptr, prop)) {
- char *path = get_driver_path_hack(C, &ptr, prop);
+ char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL);
if (path) {
/* only copy the driver for the button that this was involved for */
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index e233608dea2..c5e54cc1c7c 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -798,7 +798,7 @@ void summary_to_keylist(bAnimContext *ac, DLRBT_Tree *keys, DLRBT_Tree *blocks)
}
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
}
@@ -832,7 +832,7 @@ void scene_to_keylist(bDopeSheet *ads, Scene *sce, DLRBT_Tree *keys, DLRBT_Tree
for (ale = anim_data.first; ale; ale = ale->next)
fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *blocks)
@@ -868,7 +868,7 @@ void ob_to_keylist(bDopeSheet *ads, Object *ob, DLRBT_Tree *keys, DLRBT_Tree *bl
for (ale = anim_data.first; ale; ale = ale->next)
fcurve_to_keylist(ale->adt, ale->data, keys, blocks);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, DLRBT_Tree *keys, DLRBT_Tree *blocks)
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 7e7453487b8..7f612de14b7 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_lasso.h"
+#include "BLI_math.h"
#include "DNA_anim_types.h"
#include "DNA_object_types.h"
@@ -222,7 +223,7 @@ static short ob_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Object *o
}
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* return return code - defaults to zero if nothing happened */
return ret;
@@ -264,7 +265,7 @@ static short scene_keyframes_loop(KeyframeEditData *ked, bDopeSheet *ads, Scene
}
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* return return code - defaults to zero if nothing happened */
return ret;
@@ -300,7 +301,7 @@ static short summary_keyframes_loop(KeyframeEditData *ked, bAnimContext *ac, Key
break;
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return ret_code;
}
@@ -381,9 +382,6 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac)
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
- /* when not in graph view, don't use handles */
- SpaceIpo *sipo = (ac->spacetype == SPACE_IPO) ? (SpaceIpo *)ac->sl : NULL;
- const bool use_handle = sipo ? !(sipo->flag & SIPO_NOHANDLES) : false;
/* filter animation data */
filter = ANIMFILTER_DATA_VISIBLE;
@@ -395,11 +393,11 @@ void ANIM_editkeyframes_refresh(bAnimContext *ac)
/* make sure keyframes in F-Curve are all in order, and handles are in valid positions */
sort_time_fcurve(fcu);
- testhandles_fcurve(fcu, use_handle);
+ calchandles_fcurve(fcu);
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ************************************************************************** */
@@ -645,7 +643,7 @@ static short snap_bezier_nearestsec(KeyframeEditData *ked, BezTriple *bezt)
const float secf = (float)FPS;
if (bezt->f2 & SELECT)
- bezt->vec[1][0] = ((float)floor(bezt->vec[1][0] / secf + 0.5f) * secf);
+ bezt->vec[1][0] = (floorf(bezt->vec[1][0] / secf + 0.5f) * secf);
return 0;
}
@@ -672,8 +670,8 @@ static short snap_bezier_horizontal(KeyframeEditData *UNUSED(ked), BezTriple *be
if (bezt->f2 & SELECT) {
bezt->vec[0][1] = bezt->vec[2][1] = bezt->vec[1][1];
- if (ELEM3(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN;
- if (ELEM3(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN;
+ if (ELEM(bezt->h1, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h1 = HD_ALIGN;
+ if (ELEM(bezt->h2, HD_AUTO, HD_AUTO_ANIM, HD_VECT)) bezt->h2 = HD_ALIGN;
}
return 0;
}
@@ -709,14 +707,38 @@ KeyframeEditFunc ANIM_editkeyframes_snap(short type)
/* --------- */
+static void mirror_bezier_xaxis_ex(BezTriple *bezt, const float center)
+{
+ float diff;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ diff = (center - bezt->vec[i][0]);
+ bezt->vec[i][0] = (center + diff);
+ }
+ swap_v3_v3(bezt->vec[0], bezt->vec[2]);
+
+ SWAP(char, bezt->h1, bezt->h2);
+ SWAP(char, bezt->f1, bezt->f3);
+}
+
+static void mirror_bezier_yaxis_ex(BezTriple *bezt, const float center)
+{
+ float diff;
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ diff = (center - bezt->vec[i][1]);
+ bezt->vec[i][1] = (center + diff);
+ }
+}
+
static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
{
const Scene *scene = ked->scene;
- float diff;
if (bezt->f2 & SELECT) {
- diff = ((float)CFRA - bezt->vec[1][0]);
- bezt->vec[1][0] = ((float)CFRA + diff);
+ mirror_bezier_xaxis_ex(bezt, CFRA);
}
return 0;
@@ -724,11 +746,8 @@ static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
- float diff;
-
if (bezt->f2 & SELECT) {
- diff = (0.0f - bezt->vec[1][0]);
- bezt->vec[1][0] = (0.0f + diff);
+ mirror_bezier_yaxis_ex(bezt, 0.0f);
}
return 0;
@@ -736,11 +755,8 @@ static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
- float diff;
-
if (bezt->f2 & SELECT) {
- diff = (0.0f - bezt->vec[1][1]);
- bezt->vec[1][1] = (0.0f + diff);
+ mirror_bezier_xaxis_ex(bezt, 0.0f);
}
return 0;
@@ -750,8 +766,7 @@ static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
{
/* mirroring time stored in f1 */
if (bezt->f2 & SELECT) {
- const float diff = (ked->f1 - bezt->vec[1][0]);
- bezt->vec[1][0] = (ked->f1 + diff);
+ mirror_bezier_xaxis_ex(bezt, ked->f1);
}
return 0;
@@ -759,12 +774,9 @@ static short mirror_bezier_marker(KeyframeEditData *ked, BezTriple *bezt)
static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
{
- float diff;
-
/* value to mirror over is stored in the custom data -> first float value slot */
if (bezt->f2 & SELECT) {
- diff = (ked->f1 - bezt->vec[1][1]);
- bezt->vec[1][1] = (ked->f1 + diff);
+ mirror_bezier_xaxis_ex(bezt, ked->f1);
}
return 0;
@@ -798,9 +810,9 @@ KeyframeEditFunc ANIM_editkeyframes_mirror(short type)
*/
#define ENSURE_HANDLES_MATCH(bezt) \
if (bezt->h1 != bezt->h2) { \
- if (ELEM3(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
+ if (ELEM(bezt->h1, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
bezt->h1 = HD_FREE; \
- if (ELEM3(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
+ if (ELEM(bezt->h2, HD_ALIGN, HD_AUTO, HD_AUTO_ANIM)) \
bezt->h2 = HD_FREE; \
} (void)0
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index c610595c4ba..56165c36efa 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -408,8 +408,8 @@ void sample_fcurve(FCurve *fcu)
* keyframes while sampling will affect the outcome...
* - only start sampling+adding from index=1, so that we don't overwrite original keyframe
*/
- range = (int)(ceil(end->vec[1][0] - start->vec[1][0]) );
- sfra = (int)(floor(start->vec[1][0]) );
+ range = (int)(ceil(end->vec[1][0] - start->vec[1][0]));
+ sfra = (int)(floor(start->vec[1][0]));
if (range) {
value_cache = MEM_callocN(sizeof(TempFrameValCache) * range, "IcuFrameValCache");
@@ -732,9 +732,9 @@ static void paste_animedit_keys_fcurve(FCurve *fcu, tAnimCopybufItem *aci, float
bezt->vec[2][0] += offset;
/* insert the keyframe
- * NOTE: no special flags here for now
+ * NOTE: we do not want to inherit handles from existing keyframes in this case!
*/
- insert_bezt_fcurve(fcu, bezt, 0);
+ insert_bezt_fcurve(fcu, bezt, INSERTKEY_OVERWRITE_FULL);
/* un-apply offset from src beztriple after copying */
bezt->vec[0][0] -= offset;
@@ -763,8 +763,10 @@ EnumPropertyItem keyframe_paste_merge_items[] = {
{0, NULL, 0, NULL, NULL}};
-/* This function pastes data from the keyframes copy/paste buffer
- * > return status code is whether the method FAILED to do anything
+/**
+ * This function pastes data from the keyframes copy/paste buffer
+ *
+ * \return Status code is whether the method FAILED to do anything
*/
short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
const eKeyPasteOffset offset_mode, const eKeyMergeMode merge_mode)
@@ -857,6 +859,8 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
totmatch++;
paste_animedit_keys_fcurve(fcu, aci, offset, merge_mode);
}
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
/* don't continue if some fcurves were pasted */
@@ -865,6 +869,8 @@ short paste_animedit_keys(bAnimContext *ac, ListBase *anim_data,
}
}
+ ANIM_animdata_update(ac, anim_data);
+
return 0;
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 78c87d58766..4c2d90179a7 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -186,7 +186,7 @@ FCurve *verify_fcurve(bAction *act, const char group[], PointerRNA *ptr,
fcu->flag |= FCURVE_ACTIVE; /* first one added active */
/* store path - make copy, and store that */
- fcu->rna_path = BLI_strdupn(rna_path, strlen(rna_path));
+ fcu->rna_path = BLI_strdup(rna_path);
fcu->array_index = array_index;
/* if a group name has been provided, try to add or find a group, then add F-Curve to it */
@@ -310,20 +310,25 @@ int insert_bezt_fcurve(FCurve *fcu, BezTriple *bezt, short flag)
if (replace) {
/* sanity check: 'i' may in rare cases exceed arraylen */
if ((i >= 0) && (i < fcu->totvert)) {
- /* just change the values when replacing, so as to not overwrite handles */
- BezTriple *dst = (fcu->bezt + i);
- float dy = bezt->vec[1][1] - dst->vec[1][1];
-
- /* just apply delta value change to the handle values */
- dst->vec[0][1] += dy;
- dst->vec[1][1] += dy;
- dst->vec[2][1] += dy;
-
- dst->f1 = bezt->f1;
- dst->f2 = bezt->f2;
- dst->f3 = bezt->f3;
-
- /* TODO: perform some other operations? */
+ if (flag & INSERTKEY_OVERWRITE_FULL) {
+ fcu->bezt[i] = *bezt;
+ }
+ else {
+ /* just change the values when replacing, so as to not overwrite handles */
+ BezTriple *dst = (fcu->bezt + i);
+ float dy = bezt->vec[1][1] - dst->vec[1][1];
+
+ /* just apply delta value change to the handle values */
+ dst->vec[0][1] += dy;
+ dst->vec[1][1] += dy;
+ dst->vec[2][1] += dy;
+
+ dst->f1 = bezt->f1;
+ dst->f2 = bezt->f2;
+ dst->f3 = bezt->f3;
+
+ /* TODO: perform some other operations? */
+ }
}
}
/* keyframing modes allow to not replace keyframe */
@@ -394,23 +399,42 @@ int insert_vert_fcurve(FCurve *fcu, float x, float y, short flag)
beztr.vec[2][0] = x + 1.0f;
beztr.vec[2][1] = y;
beztr.f1 = beztr.f2 = beztr.f3 = SELECT;
-
+
+ /* set default handle types and interpolation mode */
if (flag & INSERTKEY_NO_USERPREF) {
+ /* for Py-API, we want scripts to have predictable behaviour,
+ * hence the option to not depend on the userpref defaults
+ */
beztr.h1 = beztr.h2 = HD_AUTO_ANIM;
beztr.ipo = BEZT_IPO_BEZ;
}
else {
+ /* for UI usage - defaults should come from the */
beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */
//BEZKEYTYPE(&beztr)= scene->keytype; /* default keyframe type */
-
+
/* use default interpolation mode, with exceptions for int/discrete values */
beztr.ipo = U.ipo_new;
}
-
- if (fcu->flag & FCURVE_DISCRETE_VALUES)
+
+ /* interpolation type used is constrained by the type of values the curve can take */
+ if (fcu->flag & FCURVE_DISCRETE_VALUES) {
beztr.ipo = BEZT_IPO_CONST;
- else if (beztr.ipo == BEZT_IPO_BEZ && (fcu->flag & FCURVE_INT_VALUES))
+ }
+ else if ((beztr.ipo == BEZT_IPO_BEZ) && (fcu->flag & FCURVE_INT_VALUES)) {
beztr.ipo = BEZT_IPO_LIN;
+ }
+
+ /* set default values for "easing" interpolation mode settings
+ * NOTE: Even if these modes aren't currently used, if users switch
+ * to these later, we want these to work in a sane way out of
+ * the box.
+ */
+ beztr.back = 1.70158f; /* "back" easing - this value used to be used when overshoot=0, but that */
+ /* introduced discontinuities in how the param worked */
+
+ beztr.amplitude = 0.8f; /* "elastic" easing - values here were hand-optimised for a default duration of */
+ beztr.period = 4.1f; /* ~10 frames (typical mograph motion length) */
/* add temp beztriple to keyframes */
a = insert_bezt_fcurve(fcu, &beztr, flag);
@@ -633,7 +657,7 @@ static bool visualkey_can_use(PointerRNA *ptr, PropertyRNA *prop)
const char *identifier = NULL;
/* validate data */
- if (ELEM3(NULL, ptr, ptr->data, prop))
+ if (ELEM(NULL, ptr, ptr->data, prop))
return 0;
/* get first constraint and determine type of keyframe constraints to check for
@@ -1023,7 +1047,7 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou
/* for Loc/Rot/Scale and also Color F-Curves, the color of the F-Curve in the Graph Editor,
* is determined by the array index for the F-Curve
*/
- if (ELEM5(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
+ if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) {
fcu->color_mode = FCURVE_COLOR_AUTO_RGB;
}
}
diff --git a/source/blender/editors/armature/CMakeLists.txt b/source/blender/editors/armature/CMakeLists.txt
index ca2dc1b66e2..fc211f0e60b 100644
--- a/source/blender/editors/armature/CMakeLists.txt
+++ b/source/blender/editors/armature/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -73,4 +75,6 @@ if(WITH_OPENNL)
)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_armature "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/armature/SConscript b/source/blender/editors/armature/SConscript
index b3c1ea2dbe9..97bc1a138b3 100644
--- a/source/blender/editors/armature/SConscript
+++ b/source/blender/editors/armature/SConscript
@@ -31,19 +31,21 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/opennl/extern',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index 16975eed75e..eba1bc4d78d 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -84,7 +84,7 @@ EditBone *ED_armature_edit_bone_add(bArmature *arm, const char *name)
return bone;
}
-void add_primitive_bone(Object *obedit_arm, bool view_aligned)
+EditBone *ED_armature_edit_bone_add_primitive(Object *obedit_arm, float length, bool view_aligned)
{
bArmature *arm = obedit_arm->data;
EditBone *bone;
@@ -99,10 +99,9 @@ void add_primitive_bone(Object *obedit_arm, bool view_aligned)
zero_v3(bone->head);
zero_v3(bone->tail);
- if (view_aligned)
- bone->tail[1] = 1.0f;
- else
- bone->tail[2] = 1.0f;
+ bone->tail[view_aligned ? 1 : 2] = length;
+
+ return bone;
}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index c5aa81c3a37..8bcee52baab 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -70,7 +70,7 @@ void ED_armature_apply_transform(Object *ob, float mat[4][4])
/* Put the armature into editmode */
ED_armature_to_edit(arm);
- /* Transform the bones*/
+ /* Transform the bones */
ED_armature_transform_bones(arm, mat);
/* Turn the list into an armature */
@@ -100,7 +100,7 @@ void ED_armature_transform_bones(struct bArmature *arm, float mat[4][4])
mul_m4_v3(mat, ebone->head);
mul_m4_v3(mat, ebone->tail);
- /* apply the transfiormed roll back */
+ /* apply the transformed roll back */
mat3_to_vec_roll(tmat, NULL, &ebone->roll);
ebone->rad_head *= scale;
@@ -190,7 +190,7 @@ void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int cente
/* Adjust object location for new centerpoint */
if (centermode && obedit == NULL) {
- mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
+ mul_mat3_m4_v3(ob->obmat, cent); /* omit translation part */
add_v3_v3(ob->loc, cent);
}
}
@@ -209,17 +209,12 @@ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const bool
sub_v3_v3v3(nor, bone->tail, bone->head);
- /* if tail == head! */
- if (is_zero_v3(nor)) {
+ /* If tail == head or the bone is aligned with the axis... */
+ if (normalize_v3(nor) <= FLT_EPSILON || (fabsf(dot_v3v3(align_axis, nor)) >= (1.0f - FLT_EPSILON))) {
return roll;
}
- vec_roll_to_mat3(nor, 0.0f, mat);
-
- /* check the bone isn't aligned with the axis */
- if (dot_v3v3(align_axis, mat[2]) >= (1.0f - FLT_EPSILON)) {
- return roll;
- }
+ vec_roll_to_mat3_normalized(nor, 0.0f, mat);
/* project the new_up_axis along the normal */
project_v3_v3v3(vec, align_axis, nor);
@@ -301,7 +296,9 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
float cursor_rel[3];
sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
if (axis_flip) negate_v3(cursor_rel);
- ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
+ if (normalize_v3(cursor_rel) != 0.0f) {
+ ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
+ }
}
}
}
@@ -405,7 +402,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
}
/* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
return OPERATOR_FINISHED;
}
@@ -1136,7 +1133,7 @@ static int armature_align_bones_exec(bContext *C, wmOperator *op)
}
/* note, notifier might evolve */
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
+ WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
return OPERATOR_FINISHED;
}
@@ -1348,7 +1345,9 @@ static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op))
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (arm->layer & ebone->layer) {
if (ebone->flag & BONE_HIDDEN_A) {
- ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ if (!(ebone->flag & BONE_UNSELECTABLE)) {
+ ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
+ }
ebone->flag &= ~BONE_HIDDEN_A;
}
}
diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h
index 1d054ffc2e9..6d616384b9a 100644
--- a/source/blender/editors/armature/armature_intern.h
+++ b/source/blender/editors/armature/armature_intern.h
@@ -237,7 +237,7 @@ void armature_select_mirrored(struct bArmature *arm);
void armature_tag_unselect(struct bArmature *arm);
void *get_nearest_bone(struct bContext *C, short findunsel, int x, int y);
-void *get_bone_from_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer, short hits, short findunsel);
+void *get_bone_from_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer, short hits, short findunsel, bool do_nearest);
int bone_looper(struct Object *ob, struct Bone *bone, void *data,
int (*bone_func)(struct Object *, struct Bone *, void *));
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index e4ba8728e55..75fa4a5433f 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -245,7 +245,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
invert_m4_m4(imat, premat);
mul_m4_m4m4(difmat, imat, postmat);
- curbone->roll -= (float)atan2(difmat[2][0], difmat[2][2]);
+ curbone->roll -= atan2f(difmat[2][0], difmat[2][2]);
}
/* Fix Constraints and Other Links to this Bone and Armature */
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index 9c3c93e4850..c6ef76c570c 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -73,7 +73,7 @@ Bone *get_indexed_bone(Object *ob, int index)
/* See if there are any selected bones in this buffer */
/* only bones from base are checked on */
-void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short findunsel)
+void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits, short findunsel, bool do_nearest)
{
Object *obedit = scene->obedit; // XXX get from context
Bone *bone;
@@ -82,6 +82,7 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer,
unsigned int hitresult;
short i;
bool takeNext = false;
+ int minsel = 0xffffffff, minunsel = 0xffffffff;
for (i = 0; i < hits; i++) {
hitresult = buffer[3 + (i * 4)];
@@ -102,7 +103,7 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer,
else
sel = !(bone->flag & BONE_SELECTED);
- data = bone;
+ data = bone;
}
else {
data = NULL;
@@ -123,14 +124,28 @@ void *get_bone_from_selectbuffer(Scene *scene, Base *base, unsigned int *buffer,
if (data) {
if (sel) {
- if (!firstSel) firstSel = data;
- takeNext = 1;
+ if (do_nearest) {
+ if (minsel > buffer[4 * i + 1]) {
+ firstSel = data;
+ minsel = buffer[4 * i + 1];
+ }
+ }
+ else {
+ if (!firstSel) firstSel = data;
+ takeNext = 1;
+ }
}
else {
- if (!firstunSel)
- firstunSel = data;
- if (takeNext)
- return data;
+ if (do_nearest) {
+ if (minunsel > buffer[4 * i + 1]) {
+ firstunSel = data;
+ minunsel = buffer[4 * i + 1];
+ }
+ }
+ else {
+ if (!firstunSel) firstunSel = data;
+ if (takeNext) return data;
+ }
}
}
}
@@ -160,10 +175,10 @@ void *get_nearest_bone(bContext *C, short findunsel, int x, int y)
rect.ymin = rect.ymax = y;
glInitNames();
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
if (hits > 0)
- return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel);
+ return get_bone_from_selectbuffer(vc.scene, vc.scene->basact, buffer, hits, findunsel, true);
return NULL;
}
@@ -295,13 +310,13 @@ static EditBone *get_nearest_editbonepoint(ViewContext *vc, const int mval[2],
rect.ymin = mval[1] - 5;
rect.ymax = mval[1] + 5;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
if (hits == 0) {
rect.xmin = mval[0] - 12;
rect.xmax = mval[0] + 12;
rect.ymin = mval[1] - 12;
rect.ymax = mval[1] + 12;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, true);
}
/* See if there are any selected bones in this group */
if (hits > 0) {
diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c
index e898e600e9b..5ff15b84284 100644
--- a/source/blender/editors/armature/armature_skinning.c
+++ b/source/blender/editors/armature/armature_skinning.c
@@ -180,15 +180,6 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
return 0;
}
-static void add_vgroups__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
-{
- /* DerivedMesh mapFunc for getting final coords in weight paint mode */
-
- float (*verts)[3] = userData;
- copy_v3_v3(verts[index], co);
-}
-
static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], int numbones, Bone **bonelist,
bDeformGroup **dgrouplist, bDeformGroup **dgroupflip,
float (*root)[3], float (*tip)[3], const int *selected, float scale)
@@ -200,10 +191,22 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
float distance;
int i, iflip, j;
bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ bool use_mask = false;
+
+ if ((ob->mode & OB_MODE_WEIGHT_PAINT) &&
+ (mesh->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL)))
+ {
+ use_mask = true;
+ }
/* for each vertex in the mesh */
for (i = 0; i < mesh->totvert; i++) {
- iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i, use_topology) : 0;
+
+ if (use_mask && !(mesh->mvert[i].flag & SELECT)) {
+ continue;
+ }
+
+ iflip = (dgroupflip) ? mesh_get_x_mirror_vert(ob, i, use_topology) : -1;
/* for each skinnable bone */
for (j = 0; j < numbones; ++j) {
@@ -224,7 +227,7 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
ED_vgroup_vert_remove(ob, dgroup, i);
/* do same for mirror */
- if (dgroupflip && dgroupflip[j] && iflip >= 0) {
+ if (dgroupflip && dgroupflip[j] && iflip != -1) {
if (distance != 0.0f)
ED_vgroup_vert_add(ob, dgroupflip[j], iflip, distance,
WEIGHT_REPLACE);
@@ -235,7 +238,8 @@ static void envelope_bone_weighting(Object *ob, Mesh *mesh, float (*verts)[3], i
}
}
-static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par, int heat, bool mirror)
+static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob, Object *par,
+ int heat, const bool mirror)
{
/* This functions implements the automatic computation of vertex group
* weights, either through envelopes or using a heat equilibrium.
@@ -362,7 +366,7 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
if (dm->foreachMappedVert) {
- dm->foreachMappedVert(dm, add_vgroups__mapFunc, (void *)verts, DM_FOREACH_NOP);
+ mesh_get_mapped_verts_coords(dm, verts, mesh->totvert);
vertsfilled = 1;
}
@@ -415,7 +419,8 @@ static void add_verts_to_dgroups(ReportList *reports, Scene *scene, Object *ob,
MEM_freeN(verts);
}
-void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par, int mode, bool mirror)
+void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob, Object *par,
+ const int mode, const bool mirror)
{
/* Lets try to create some vertex groups
* based on the bones of the parent armature.
@@ -436,7 +441,7 @@ void create_vgroups_from_armature(ReportList *reports, Scene *scene, Object *ob,
ED_vgroup_data_clamp_range(ob->data, defbase_tot);
}
}
- else if (mode == ARM_GROUPS_ENVELOPE || mode == ARM_GROUPS_AUTO) {
+ else if (ELEM(mode, ARM_GROUPS_ENVELOPE, ARM_GROUPS_AUTO)) {
/* Traverse the bone list, trying to create vertex groups
* that are populated with the vertices for which the
* bone is closest.
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index 475ffd23617..d75a23a6322 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -53,6 +53,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "GPU_select.h"
+
typedef int (*GestureDetectFct)(bContext *, SK_Gesture *, SK_Sketch *);
typedef void (*GestureApplyFct)(bContext *, SK_Gesture *, SK_Sketch *);
@@ -493,7 +495,7 @@ static void sk_drawStroke(SK_Stroke *stk, int id, float color[3], int start, int
gluQuadricNormals(quad, GLU_SMOOTH);
if (id != -1) {
- glLoadName(id);
+ GPU_select_load_id(id);
for (i = 0; i < stk->nb_points; i++) {
glPushMatrix();
@@ -1490,9 +1492,9 @@ static int sk_getSelfIntersections(bContext *C, ListBase *list, SK_Stroke *gestu
return added;
}
-static int cmpIntersections(void *i1, void *i2)
+static int cmpIntersections(const void *i1, const void *i2)
{
- SK_Intersection *isect1 = i1, *isect2 = i2;
+ const SK_Intersection *isect1 = i1, *isect2 = i2;
if (isect1->stroke == isect2->stroke) {
if (isect1->before < isect2->before) {
@@ -1969,7 +1971,7 @@ static int sk_selectStroke(bContext *C, SK_Sketch *sketch, const int mval[2], in
rect.ymin = mval[1] - 5;
rect.ymax = mval[1] + 5;
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
if (hits > 0) {
int besthitresult = -1;
@@ -2032,7 +2034,7 @@ static void sk_drawSketch(Scene *scene, View3D *UNUSED(v3d), SK_Sketch *sketch,
sk_drawStroke(stk, id, NULL, -1, -1);
}
- glLoadName(-1);
+ GPU_select_load_id(-1);
}
else {
float selected_rgb[3] = {1, 0, 0};
diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c
index 56e7bde0081..b7d14e089cf 100644
--- a/source/blender/editors/armature/meshlaplacian.c
+++ b/source/blender/editors/armature/meshlaplacian.c
@@ -635,8 +635,8 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
MVert *mvert = me->mvert;
- bool use_vert_sel = false;
- bool use_face_sel = false;
+ bool use_vert_sel = (me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0;
+ bool use_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0;
*err_str = NULL;
@@ -652,9 +652,8 @@ void heat_bone_weighting(Object *ob, Mesh *me, float (*verts)[3], int numsource,
return;
/* count triangles and create mask */
- if (ob->mode == OB_MODE_WEIGHT_PAINT &&
- ((use_face_sel = ((me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0)) ||
- (use_vert_sel = ((me->editflag & ME_EDIT_PAINT_VERT_SEL) != 0))))
+ if (ob->mode & OB_MODE_WEIGHT_PAINT &&
+ (use_face_sel || use_vert_sel))
{
mask = MEM_callocN(sizeof(int) * me->totvert, "heat_bone_weighting mask");
@@ -1304,7 +1303,7 @@ static int meshdeform_inside_cage(MeshDeformBind *mdb, float *co)
/* solving */
-static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
+BLI_INLINE int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
{
int size = mdb->size;
@@ -1322,7 +1321,7 @@ static int meshdeform_index(MeshDeformBind *mdb, int x, int y, int z, int n)
return x + y * size + z * size * size;
}
-static void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
+BLI_INLINE void meshdeform_cell_center(MeshDeformBind *mdb, int x, int y, int z, int n, float *center)
{
x += MESHDEFORM_OFFSET[n][0];
y += MESHDEFORM_OFFSET[n][1];
diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c
index de8b2e36d5b..da68108285f 100644
--- a/source/blender/editors/armature/pose_edit.c
+++ b/source/blender/editors/armature/pose_edit.c
@@ -1034,6 +1034,10 @@ static int pose_hide_exec(bContext *C, wmOperator *op)
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm = ob->data;
+ if (ob->proxy != NULL) {
+ BKE_report(op->reports, RPT_INFO, "Undo of hiding can only be done with Reveal Selected");
+ }
+
if (RNA_boolean_get(op->ptr, "unselected"))
bone_looper(ob, arm->bonebase.first, NULL, hide_unselected_pose_bone_cb);
else
@@ -1070,7 +1074,9 @@ static int show_pose_bone_cb(Object *ob, Bone *bone, void *UNUSED(ptr))
if (arm->layer & bone->layer) {
if (bone->flag & BONE_HIDDEN_P) {
bone->flag &= ~BONE_HIDDEN_P;
- bone->flag |= BONE_SELECTED;
+ if (!(bone->flag & BONE_UNSELECTABLE)) {
+ bone->flag |= BONE_SELECTED;
+ }
}
}
diff --git a/source/blender/editors/armature/pose_group.c b/source/blender/editors/armature/pose_group.c
index 376c1bc0838..50d9d300d15 100644
--- a/source/blender/editors/armature/pose_group.c
+++ b/source/blender/editors/armature/pose_group.c
@@ -62,12 +62,12 @@ static int pose_group_add_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_pose_object_from_context(C);
- /* only continue if there's an object */
- if (ob == NULL)
+ /* only continue if there's an object and pose */
+ if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
/* for now, just call the API function for this */
- BKE_pose_add_group(ob);
+ BKE_pose_add_group(ob->pose, NULL);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -95,12 +95,12 @@ static int pose_group_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = ED_pose_object_from_context(C);
- /* only continue if there's an object */
- if (ob == NULL)
+ /* only continue if there's an object and pose */
+ if (ELEM(NULL, ob, ob->pose))
return OPERATOR_CANCELLED;
/* for now, just call the API function for this */
- BKE_pose_remove_group(ob);
+ BKE_pose_remove_group_index(ob->pose, ob->pose->active_group);
/* notifiers for updates */
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
@@ -189,7 +189,7 @@ static int pose_group_assign_exec(bContext *C, wmOperator *op)
*/
pose->active_group = RNA_int_get(op->ptr, "type");
if (pose->active_group == 0)
- BKE_pose_add_group(ob);
+ BKE_pose_add_group(ob->pose, NULL);
/* add selected bones to group then */
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones)
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 3f4f720ccdb..0609fcc29e8 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -189,7 +189,9 @@ static bAction *poselib_init_new(Object *ob)
/* init object's poselib action (unlink old one if there) */
if (ob->poselib)
id_us_min(&ob->poselib->id);
+
ob->poselib = add_empty_action(G.main, "PoseLib");
+ ob->poselib->idroot = ID_OB;
return ob->poselib;
}
@@ -305,7 +307,7 @@ static int poselib_sanitize_exec(bContext *C, wmOperator *op)
/* check if any pose matches this */
/* TODO: don't go looking through the list like this every time... */
for (marker = act->markers.first; marker; marker = marker->next) {
- if (IS_EQ(marker->frame, (double)ak->cfra)) {
+ if (IS_EQ((double)marker->frame, (double)ak->cfra)) {
marker->flag = -1;
break;
}
@@ -1415,7 +1417,7 @@ static void poselib_preview_init_data(bContext *C, wmOperator *op)
pld->marker = (pld->act) ? BLI_findlink(&pld->act->markers, pose_index) : NULL;
/* check if valid poselib */
- if (ELEM3(NULL, pld->ob, pld->pose, pld->arm)) {
+ if (ELEM(NULL, pld->ob, pld->pose, pld->arm)) {
BKE_report(op->reports, RPT_ERROR, "Pose lib is only for armatures in pose mode");
pld->state = PL_PREVIEW_ERROR;
return;
@@ -1488,7 +1490,6 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op)
DAG_id_tag_update(&ob->id, OB_RECALC_DATA); /* sets recalc flags */
else
BKE_pose_where_is(scene, ob);
-
}
else if (pld->state == PL_PREVIEW_CONFIRM) {
/* tag poses as appropriate */
@@ -1509,6 +1510,9 @@ static void poselib_preview_cleanup(bContext *C, wmOperator *op)
BKE_pose_where_is(scene, ob);
}
+ /* Request final redraw of the view. */
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pld->ob);
+
/* free memory used for backups and searching */
poselib_backup_free_data(pld);
BLI_freelistN(&pld->searchp);
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index d783c1dcfde..ba5ef4f3b5d 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -45,6 +45,7 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_object.h"
+#include "BKE_report.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -68,6 +69,29 @@
/* ***************** Pose Select Utilities ********************* */
+/* Note: SEL_TOGGLE is assumed to have already been handled! */
+static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode)
+{
+ /* select pchan only if selectable, but deselect works always */
+ switch (select_mode) {
+ case SEL_SELECT:
+ if (!(pchan->bone->flag & BONE_UNSELECTABLE))
+ pchan->bone->flag |= BONE_SELECTED;
+ break;
+ case SEL_DESELECT:
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ break;
+ case SEL_INVERT:
+ if (pchan->bone->flag & BONE_SELECTED) {
+ pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
+ }
+ else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) {
+ pchan->bone->flag |= BONE_SELECTED;
+ }
+ break;
+ }
+}
+
/* Utility method for changing the selection status of a bone */
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
{
@@ -75,7 +99,7 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
/* sanity checks */
// XXX: actually, we can probably still get away with no object - at most we have no updates
- if (ELEM4(NULL, ob, ob->pose, pchan, pchan->bone))
+ if (ELEM(NULL, ob, ob->pose, pchan, pchan->bone))
return;
arm = ob->data;
@@ -109,14 +133,14 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
/* called from editview.c, for mode-less pose selection */
/* assumes scene obact and basact is still on old situation */
int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, short hits,
- bool extend, bool deselect, bool toggle)
+ bool extend, bool deselect, bool toggle, bool do_nearest)
{
Object *ob = base->object;
Bone *nearBone;
if (!ob || !ob->pose) return 0;
- nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1);
+ nearBone = get_bone_from_selectbuffer(scene, base, buffer, hits, 1, do_nearest);
/* if the bone cannot be affected, don't do anything */
if ((nearBone) && !(nearBone->flag & BONE_UNSELECTABLE)) {
@@ -138,7 +162,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
}
if (!extend && !deselect && !toggle) {
- ED_pose_deselectall(ob, 0);
+ ED_pose_de_selectall(ob, SEL_DESELECT, true);
nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
arm->act_bone = nearBone;
}
@@ -190,16 +214,12 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
return nearBone != NULL;
}
-/* test==0: deselect all
- * test==1: swap select (apply to all the opposite of current situation)
- * test==2: only clear active tag
- * test==3: swap select (no test / inverse selection status of all independently)
- */
-void ED_pose_deselectall(Object *ob, int test)
+/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
+ * When true, 'ignore_visibility' makes this func also affect invisible bones (hidden or on hidden layers). */
+void ED_pose_de_selectall(Object *ob, int select_mode, const bool ignore_visibility)
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
- int selectmode = 0;
/* we call this from outliner too */
if (ob->pose == NULL) {
@@ -207,31 +227,23 @@ void ED_pose_deselectall(Object *ob, int test)
}
/* Determine if we're selecting or deselecting */
- if (test == 1) {
+ if (select_mode == SEL_TOGGLE) {
+ select_mode = SEL_SELECT;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
- if (PBONE_VISIBLE(arm, pchan->bone)) {
- if (pchan->bone->flag & BONE_SELECTED)
+ if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ if (pchan->bone->flag & BONE_SELECTED) {
+ select_mode = SEL_DESELECT;
break;
+ }
}
}
-
- if (pchan == NULL)
- selectmode = 1;
}
- else if (test == 2)
- selectmode = 2;
- /* Set the flags accordingly */
+ /* Set the flags accordingly */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* ignore the pchan if it isn't visible or if its selection cannot be changed */
- if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
- if (test == 3) {
- pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else {
- if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED;
- }
+ if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
+ pose_do_bone_select(pchan, select_mode);
}
}
}
@@ -242,7 +254,7 @@ static void selectconnected_posebonechildren(Object *ob, Bone *bone, int extend)
{
Bone *curBone;
- /* stop when unconnected child is encontered, or when unselectable bone is encountered */
+ /* stop when unconnected child is encountered, or when unselectable bone is encountered */
if (!(bone->flag & BONE_CONNECTED) || (bone->flag & BONE_UNSELECTABLE))
return;
@@ -352,24 +364,7 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
/* Set the flags */
CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
{
- /* select pchan only if selectable, but deselect works always */
- switch (action) {
- case SEL_SELECT:
- if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
- pchan->bone->flag |= BONE_SELECTED;
- break;
- case SEL_DESELECT:
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- break;
- case SEL_INVERT:
- if (pchan->bone->flag & BONE_SELECTED) {
- pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
- }
- else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
- pchan->bone->flag |= BONE_SELECTED;
- }
- break;
- }
+ pose_do_bone_select(pchan, action);
}
CTX_DATA_END;
@@ -627,6 +622,13 @@ void POSE_OT_select_hierarchy(wmOperatorType *ot)
/* -------------------------------------- */
+/* modes for select same */
+typedef enum ePose_SelectSame_Mode {
+ POSE_SEL_SAME_LAYER = 0,
+ POSE_SEL_SAME_GROUP = 1,
+ POSE_SEL_SAME_KEYINGSET = 2,
+} ePose_SelectSame_Mode;
+
static bool pose_select_same_group(bContext *C, Object *ob, bool extend)
{
bArmature *arm = (ob) ? ob->data : NULL;
@@ -636,7 +638,7 @@ static bool pose_select_same_group(bContext *C, Object *ob, bool extend)
bool changed = false, tagged = false;
/* sanity checks */
- if (ELEM3(NULL, ob, pose, arm))
+ if (ELEM(NULL, ob, pose, arm))
return 0;
/* count the number of groups */
@@ -693,7 +695,7 @@ static bool pose_select_same_layer(bContext *C, Object *ob, bool extend)
bool changed = false;
int layers = 0;
- if (ELEM3(NULL, ob, pose, arm))
+ if (ELEM(NULL, ob, pose, arm))
return 0;
/* figure out what bones are selected */
@@ -725,7 +727,7 @@ static bool pose_select_same_layer(bContext *C, Object *ob, bool extend)
return changed;
}
-static bool pose_select_same_keyingset(bContext *C, Object *ob, bool extend)
+static bool pose_select_same_keyingset(bContext *C, ReportList *reports, Object *ob, bool extend)
{
KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
KS_Path *ksp;
@@ -735,11 +737,26 @@ static bool pose_select_same_keyingset(bContext *C, Object *ob, bool extend)
bool changed = false;
/* sanity checks: validate Keying Set and object */
- if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
- return 0;
+ if (ks == NULL) {
+ BKE_report(reports, RPT_ERROR, "No active Keying Set to use");
+ return false;
+ }
+ else if (ANIM_validate_keyingset(C, NULL, ks) != 0) {
+ if (ks->paths.first == NULL) {
+ if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
+ BKE_report(reports, RPT_ERROR,
+ "Use another Keying Set, as the active one depends on the currently "
+ "selected items or cannot find any targets due to unsuitable context");
+ }
+ else {
+ BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths");
+ }
+ }
+ return false;
+ }
- if (ELEM3(NULL, ob, pose, arm))
- return 0;
+ if (ELEM(NULL, ob, pose, arm))
+ return false;
/* if not extending selection, deselect all selected first */
if (extend == false) {
@@ -785,6 +802,7 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
{
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
bArmature *arm = (bArmature *)ob->data;
+ const ePose_SelectSame_Mode type = RNA_enum_get(op->ptr, "type");
const bool extend = RNA_boolean_get(op->ptr, "extend");
bool changed = false;
@@ -792,18 +810,22 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
if (ob->pose == NULL)
return OPERATOR_CANCELLED;
- /* selection types
- * NOTE: for the order of these, see the enum in POSE_OT_select_grouped()
- */
- switch (RNA_enum_get(op->ptr, "type")) {
- case 1: /* group */
+ /* selection types */
+ switch (type) {
+ case POSE_SEL_SAME_LAYER: /* layer */
+ changed = pose_select_same_layer(C, ob, extend);
+ break;
+
+ case POSE_SEL_SAME_GROUP: /* group */
changed = pose_select_same_group(C, ob, extend);
break;
- case 2: /* Keying Set */
- changed = pose_select_same_keyingset(C, ob, extend);
+
+ case POSE_SEL_SAME_KEYINGSET: /* Keying Set */
+ changed = pose_select_same_keyingset(C, op->reports, ob, extend);
break;
- default: /* layer */
- changed = pose_select_same_layer(C, ob, extend);
+
+ default:
+ printf("pose_select_grouped() - Unknown selection type %d\n", type);
break;
}
@@ -825,9 +847,9 @@ static int pose_select_grouped_exec(bContext *C, wmOperator *op)
void POSE_OT_select_grouped(wmOperatorType *ot)
{
static EnumPropertyItem prop_select_grouped_types[] = {
- {0, "LAYER", 0, "Layer", "Shared layers"},
- {1, "GROUP", 0, "Group", "Shared group"},
- {2, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"},
+ {POSE_SEL_SAME_LAYER, "LAYER", 0, "Layer", "Shared layers"},
+ {POSE_SEL_SAME_GROUP, "GROUP", 0, "Group", "Shared group"},
+ {POSE_SEL_SAME_KEYINGSET, "KEYINGSET", 0, "Keying Set", "All bones affected by active Keying Set"},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index 375cbb0fe2b..5f9f24d23a4 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -134,7 +134,7 @@ static int pose_slide_init(bContext *C, wmOperator *op, short mode)
pso->nextFrame = RNA_int_get(op->ptr, "next_frame");
/* check the settings from the context */
- if (ELEM4(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
+ if (ELEM(NULL, pso->ob, pso->arm, pso->ob->adt, pso->ob->adt->action))
return 0;
else
act = pso->ob->adt->action;
diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c
index 094af99776b..0cde8f30ace 100644
--- a/source/blender/editors/armature/pose_transform.c
+++ b/source/blender/editors/armature/pose_transform.c
@@ -290,13 +290,14 @@ static void set_pose_keys(Object *ob)
}
}
-/* perform paste pose, for a single bone
- * < ob: object where bone to paste to lives
- * < chan: bone that pose to paste comes from
- * < selOnly: only paste on selected bones
- * < flip: flip on x-axis
+/**
+ * Perform paste pose, for a single bone.
*
- * > returns: whether the bone that we pasted to if we succeeded
+ * \param ob Object where bone to paste to lives
+ * \param chan Bone that pose to paste comes from
+ * \param selOnly Only paste on selected bones
+ * \param flip Flip on x-axis
+ * \return Whether the bone that we pasted to if we succeeded
*/
static bPoseChannel *pose_bone_do_paste(Object *ob, bPoseChannel *chan, const bool selOnly, const bool flip)
{
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 2fdc9ff846b..a52b2a619dc 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -1042,7 +1042,7 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
{
int nu_index = 0, a, pt_index;
EditNurb *editnurb = cu->editnurb;
- Nurb *nu = editnurb->nurbs.first;
+ Nurb *nu;
CVKeyIndex *keyIndex;
char rna_path[64], orig_rna_path[64];
AnimData *adt = BKE_animdata_from_id(&cu->id);
@@ -1191,7 +1191,7 @@ static int *initialize_index_map(Object *obedit, int *r_old_totvert)
for (nu = editnurb->nurbs.first, vertex_index = 0;
nu != NULL;
- nu = nu->next, vertex_index++)
+ nu = nu->next)
{
if (nu->bezt) {
BezTriple *bezt = nu->bezt;
@@ -1238,9 +1238,18 @@ static void remap_hooks_and_vertex_parents(Object *obedit)
{
Object *object;
Curve *curve = (Curve *) obedit->data;
+ EditNurb *editnurb = curve->editnurb;
int *old_to_new_map = NULL;
int old_totvert;
+ if (editnurb->keyindex == NULL) {
+ /* TODO(sergey): Happens when separating curves, this would lead to
+ * the wrong indices in the hook modifier, address this together with
+ * other indices issues.
+ */
+ return;
+ }
+
for (object = G.main->object.first; object; object = object->id.next) {
ModifierData *md;
int index;
@@ -1467,37 +1476,6 @@ void ED_curve_select_swap(EditNurb *editnurb, bool hide_handles)
}
}
-/******************** transform operator **********************/
-
-void ED_curve_transform(Curve *cu, float mat[4][4])
-{
- Nurb *nu;
- BPoint *bp;
- BezTriple *bezt;
- int a;
-
- float scale = mat4_to_scale(mat);
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
- for (bezt = nu->bezt; a--; bezt++) {
- mul_m4_v3(mat, bezt->vec[0]);
- mul_m4_v3(mat, bezt->vec[1]);
- mul_m4_v3(mat, bezt->vec[2]);
- bezt->radius *= scale;
- }
- BKE_nurb_handles_calc(nu);
- }
- else {
- a = nu->pntsu * nu->pntsv;
- for (bp = nu->bp; a--; bp++)
- mul_m4_v3(mat, bp->vec);
- }
- }
- DAG_id_tag_update(&cu->id, 0);
-}
-
/******************** separate operator ***********************/
static int separate_exec(bContext *C, wmOperator *op)
@@ -1926,7 +1904,7 @@ static void ed_curve_delete_selected(Object *obedit)
}
if (a == 0) {
if (cu->actnu == nuindex)
- cu->actnu = -1;
+ cu->actnu = CU_ACT_NONE;
BLI_remlink(nubase, nu);
keyIndex_delNurb(editnurb, nu);
@@ -1950,7 +1928,7 @@ static void ed_curve_delete_selected(Object *obedit)
}
if (a == 0) {
if (cu->actnu == nuindex)
- cu->actnu = -1;
+ cu->actnu = CU_ACT_NONE;
BLI_remlink(nubase, nu);
keyIndex_delNurb(editnurb, nu);
@@ -1975,17 +1953,15 @@ static void ed_curve_delete_selected(Object *obedit)
next = nu->next;
type = 0;
if (nu->type == CU_BEZIER) {
- int delta = 0;
bezt = nu->bezt;
for (a = 0; a < nu->pntsu; a++) {
if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
memmove(bezt, bezt + 1, (nu->pntsu - a - 1) * sizeof(BezTriple));
- keyIndex_delBezt(editnurb, bezt + delta);
+ keyIndex_delBezt(editnurb, bezt);
keyIndex_updateBezt(editnurb, bezt + 1, bezt, nu->pntsu - a - 1);
nu->pntsu--;
a--;
type = 1;
- delta++;
}
else {
bezt++;
@@ -2001,18 +1977,16 @@ static void ed_curve_delete_selected(Object *obedit)
}
}
else if (nu->pntsv == 1) {
- int delta = 0;
bp = nu->bp;
for (a = 0; a < nu->pntsu; a++) {
if (bp->f1 & SELECT) {
memmove(bp, bp + 1, (nu->pntsu - a - 1) * sizeof(BPoint));
- keyIndex_delBP(editnurb, bp + delta);
+ keyIndex_delBP(editnurb, bp);
keyIndex_updateBP(editnurb, bp + 1, bp, nu->pntsu - a - 1);
nu->pntsu--;
a--;
type = 1;
- delta++;
}
else {
bp++;
@@ -2427,11 +2401,15 @@ static int switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
Curve *cu = (Curve *)obedit->data;
EditNurb *editnurb = cu->editnurb;
Nurb *nu;
+ int i;
- for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ for (nu = editnurb->nurbs.first, i = 0; nu; nu = nu->next, i++) {
if (isNurbsel(nu)) {
BKE_nurb_direction_switch(nu);
keyData_switchDirectionNurb(cu, nu);
+ if ((i == cu->actnu) && (cu->actvert != CU_ACT_NONE)) {
+ cu->actvert = (nu->pntsu - 1) - cu->actvert;
+ }
}
}
@@ -3916,6 +3894,7 @@ static int set_spline_type_exec(bContext *C, wmOperator *op)
ListBase *editnurb = object_editcurve_get(obedit);
Nurb *nu;
bool changed = false;
+ bool changed_size = false;
const bool use_handles = RNA_boolean_get(op->ptr, "use_handles");
const int type = RNA_enum_get(op->ptr, "type");
@@ -3926,10 +3905,16 @@ static int set_spline_type_exec(bContext *C, wmOperator *op)
for (nu = editnurb->first; nu; nu = nu->next) {
if (isNurbsel(nu)) {
- if (BKE_nurb_type_convert(nu, type, use_handles) == false)
- BKE_report(op->reports, RPT_ERROR, "No conversion possible");
- else
+ const int pntsu_prev = nu->pntsu;
+ if (BKE_nurb_type_convert(nu, type, use_handles)) {
changed = true;
+ if (pntsu_prev != nu->pntsu) {
+ changed_size = true;
+ }
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "No conversion possible");
+ }
}
}
@@ -3940,6 +3925,11 @@ static int set_spline_type_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(obedit->data, 0);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ if (changed_size) {
+ Curve *cu = obedit->data;
+ cu->actvert = CU_ACT_NONE;
+ }
+
return OPERATOR_FINISHED;
}
else {
@@ -4927,7 +4917,7 @@ static int addvert_Nurb(bContext *C, short mode, float location[3])
if ((nu == NULL) || (nu->type == CU_BEZIER && bezt == NULL) || (nu->type != CU_BEZIER && bp == NULL)) {
if (mode != 'e') {
- if (cu->actnu >= 0)
+ if (cu->actnu != CU_ACT_NONE)
nu = BLI_findlink(&editnurb->nurbs, cu->actnu);
if (!nu || nu->type == CU_BEZIER) {
@@ -5701,7 +5691,7 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
bp = nu->bp;
selbpoints = BLI_BITMAP_NEW(a, "selectlist");
while (a > 0) {
- if ((!BLI_BITMAP_GET(selbpoints, a)) && (bp->hide == 0) && (bp->f1 & SELECT)) {
+ if ((!BLI_BITMAP_TEST(selbpoints, a)) && (bp->hide == 0) && (bp->f1 & SELECT)) {
/* upper control point */
if (a % nu->pntsu != 0) {
tempbp = bp - 1;
@@ -5714,7 +5704,7 @@ static int select_more_exec(bContext *C, wmOperator *UNUSED(op))
tempbp = bp + nu->pntsu;
if (!(tempbp->f1 & SELECT)) sel = select_bpoint(tempbp, SELECT, SELECT, VISIBLE);
/* make sure selected bpoint is discarded */
- if (sel == 1) BLI_BITMAP_SET(selbpoints, a - nu->pntsu);
+ if (sel == 1) BLI_BITMAP_ENABLE(selbpoints, a - nu->pntsu);
}
/* right control point */
@@ -5798,7 +5788,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
}
else {
bp--;
- if (BLI_BITMAP_GET(selbpoints, a + 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
+ if (BLI_BITMAP_TEST(selbpoints, a + 1) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
bp++;
}
@@ -5816,7 +5806,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
}
else {
bp -= nu->pntsu;
- if (BLI_BITMAP_GET(selbpoints, a + nu->pntsu) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
+ if (BLI_BITMAP_TEST(selbpoints, a + nu->pntsu) || ((bp->hide == 0) && (bp->f1 & SELECT))) sel++;
bp += nu->pntsu;
}
@@ -5831,7 +5821,7 @@ static int select_less_exec(bContext *C, wmOperator *UNUSED(op))
if (sel != 4) {
select_bpoint(bp, DESELECT, SELECT, VISIBLE);
- BLI_BITMAP_SET(selbpoints, a);
+ BLI_BITMAP_ENABLE(selbpoints, a);
}
}
else {
@@ -7007,7 +6997,7 @@ static int match_texture_space_poll(bContext *C)
{
Object *object = CTX_data_active_object(C);
- return object && ELEM3(object->type, OB_CURVE, OB_SURF, OB_FONT);
+ return object && ELEM(object->type, OB_CURVE, OB_SURF, OB_FONT);
}
static int match_texture_space_exec(bContext *C, wmOperator *UNUSED(op))
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index c2a7a509fb3..8a3d4f3f4f5 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -109,21 +109,23 @@ Nurb *add_nurbs_primitive(bContext *C, Object *obedit, float mat[4][4], int type
{
static int xzproj = 0; /* this function calls itself... */
ListBase *editnurb = object_editcurve_get(obedit);
- View3D *v3d = CTX_wm_view3d(C);
RegionView3D *rv3d = ED_view3d_context_rv3d(C);
Nurb *nu = NULL;
BezTriple *bezt;
BPoint *bp;
Curve *cu = (Curve *)obedit->data;
float vec[3], zvec[3] = {0.0f, 0.0f, 1.0f};
- float umat[4][4] = MAT4_UNITY, viewmat[4][4] = MAT4_UNITY;
+ float umat[4][4], viewmat[4][4];
float fac;
int a, b;
- const float grid = v3d ? v3d->grid : 1.0f;
+ 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 */
+ unit_m4(umat);
+ unit_m4(viewmat);
+
if (rv3d) {
copy_m4_m4(viewmat, rv3d->viewmat);
copy_v3_v3(zvec, rv3d->viewinv[2]);
diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c
index 5c448effcd5..4655deec4c4 100644
--- a/source/blender/editors/curve/editfont.c
+++ b/source/blender/editors/curve/editfont.c
@@ -247,18 +247,10 @@ static void text_update_edited(bContext *C, Object *obedit, int mode)
struct Main *bmain = CTX_data_main(C);
Curve *cu = obedit->data;
EditFont *ef = cu->editfont;
- cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
-
- if (obedit->totcol > 0) {
- obedit->actcol = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0].mat_nr;
- /* since this array is calloc'd, it can be 0 even though we try ensure
- * (mat_nr > 0) almost everywhere */
- if (obedit->actcol < 1) {
- obedit->actcol = 1;
- }
- }
+ BLI_assert(ef->len >= 0);
+ /* run update first since it can move the cursor */
if (mode == FO_EDIT) {
/* re-tesselllate */
DAG_id_tag_update(obedit->data, 0);
@@ -268,6 +260,18 @@ static void text_update_edited(bContext *C, Object *obedit, int mode)
BKE_vfont_to_curve(bmain, obedit, mode);
}
+ cu->curinfo = ef->textbufinfo[ef->pos ? ef->pos - 1 : 0];
+
+ if (obedit->totcol > 0) {
+ obedit->actcol = cu->curinfo.mat_nr;
+
+ /* since this array is calloc'd, it can be 0 even though we try ensure
+ * (mat_nr > 0) almost everywhere */
+ if (obedit->actcol < 1) {
+ obedit->actcol = 1;
+ }
+ }
+
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
}
@@ -973,9 +977,12 @@ static int move_cursor(bContext *C, int type, const bool select)
EditFont *ef = cu->editfont;
int cursmove = -1;
+ if ((select) && (ef->selstart == 0)) {
+ ef->selstart = ef->selend = ef->pos + 1;
+ }
+
switch (type) {
case LINE_BEGIN:
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
while (ef->pos > 0) {
if (ef->textbuf[ef->pos - 1] == '\n') break;
if (ef->textbufinfo[ef->pos - 1].flag & CU_CHINFO_WRAP) break;
@@ -985,7 +992,6 @@ static int move_cursor(bContext *C, int type, const bool select)
break;
case LINE_END:
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
while (ef->pos < ef->len) {
if (ef->textbuf[ef->pos] == 0) break;
if (ef->textbuf[ef->pos] == '\n') break;
@@ -998,7 +1004,6 @@ static int move_cursor(bContext *C, int type, const bool select)
case PREV_WORD:
{
int pos = ef->pos;
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
BLI_str_cursor_step_wchar(ef->textbuf, ef->len, &pos, STRCUR_DIR_PREV, STRCUR_JUMP_DELIM, true);
ef->pos = pos;
cursmove = FO_CURS;
@@ -1008,7 +1013,6 @@ static int move_cursor(bContext *C, int type, const bool select)
case NEXT_WORD:
{
int pos = ef->pos;
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
BLI_str_cursor_step_wchar(ef->textbuf, ef->len, &pos, STRCUR_DIR_NEXT, STRCUR_JUMP_DELIM, true);
ef->pos = pos;
cursmove = FO_CURS;
@@ -1016,35 +1020,29 @@ static int move_cursor(bContext *C, int type, const bool select)
}
case PREV_CHAR:
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
ef->pos--;
cursmove = FO_CURS;
break;
case NEXT_CHAR:
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
ef->pos++;
cursmove = FO_CURS;
break;
case PREV_LINE:
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
cursmove = FO_CURSUP;
break;
case NEXT_LINE:
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
cursmove = FO_CURSDOWN;
break;
case PREV_PAGE:
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
cursmove = FO_PAGEUP;
break;
case NEXT_PAGE:
- if ((select) && (ef->selstart == 0)) ef->selstart = ef->selend = ef->pos + 1;
cursmove = FO_PAGEDOWN;
break;
}
@@ -1056,6 +1054,14 @@ static int move_cursor(bContext *C, int type, const bool select)
else if (ef->pos >= MAXTEXT) ef->pos = MAXTEXT;
else if (ef->pos < 0) ef->pos = 0;
+ /* apply virtical cursor motion to position immediately
+ * otherwise the selection will lag behind */
+ if (FO_CURS_IS_MOTION(cursmove)) {
+ struct Main *bmain = CTX_data_main(C);
+ BKE_vfont_to_curve(bmain, obedit, cursmove);
+ cursmove = FO_CURS;
+ }
+
if (select == 0) {
if (ef->selstart) {
struct Main *bmain = CTX_data_main(C);
@@ -1573,6 +1579,7 @@ void make_editText(Object *obedit)
len_wchar = BLI_strncpy_wchar_from_utf8(ef->textbuf, cu->str, MAXTEXT + 4);
BLI_assert(len_wchar == cu->len_wchar);
ef->len = len_wchar;
+ BLI_assert(ef->len >= 0);
memcpy(ef->textbufinfo, cu->strinfo, ef->len * sizeof(CharInfo));
@@ -1584,6 +1591,9 @@ void make_editText(Object *obedit)
ef->pos = cu->pos;
ef->selstart = cu->selstart;
ef->selend = cu->selend;
+
+ /* text may have been modified by Python */
+ BKE_vfont_select_clamp(obedit);
}
void load_editText(Object *obedit)
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 3fc6e2e6f0d..2a84ca7f297 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -93,6 +93,8 @@ if(WITH_BLENDER)
data_to_c_simple(../../../../release/datafiles/brushicons/soften.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/subtract.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/texdraw.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/texfill.png SRC)
+ data_to_c_simple(../../../../release/datafiles/brushicons/texmask.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/thumb.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/twist.png SRC)
data_to_c_simple(../../../../release/datafiles/brushicons/vertexdraw.png SRC)
diff --git a/source/blender/editors/datafiles/SConscript b/source/blender/editors/datafiles/SConscript
index 47819d0e33c..6bc8f21e384 100644
--- a/source/blender/editors/datafiles/SConscript
+++ b/source/blender/editors/datafiles/SConscript
@@ -77,6 +77,8 @@ sources.extend((
os.path.join(env['DATA_SOURCES'], "soften.png.c"),
os.path.join(env['DATA_SOURCES'], "subtract.png.c"),
os.path.join(env['DATA_SOURCES'], "texdraw.png.c"),
+ os.path.join(env['DATA_SOURCES'], "texfill.png.c"),
+ os.path.join(env['DATA_SOURCES'], "texmask.png.c"),
os.path.join(env['DATA_SOURCES'], "thumb.png.c"),
os.path.join(env['DATA_SOURCES'], "twist.png.c"),
os.path.join(env['DATA_SOURCES'], "vertexdraw.png.c"),
diff --git a/source/blender/editors/gpencil/CMakeLists.txt b/source/blender/editors/gpencil/CMakeLists.txt
index 904ad4892ed..5dc9679777f 100644
--- a/source/blender/editors/gpencil/CMakeLists.txt
+++ b/source/blender/editors/gpencil/CMakeLists.txt
@@ -24,10 +24,12 @@ set(INC
../../blenkernel
../../blenlib
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -50,4 +52,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_gpencil "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/gpencil/SConscript b/source/blender/editors/gpencil/SConscript
index 8b891fcb8cf..ab42bad52dc 100644
--- a/source/blender/editors/gpencil/SConscript
+++ b/source/blender/editors/gpencil/SConscript
@@ -31,7 +31,8 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/elbeem/extern',
'../include',
'../../blenfont',
@@ -46,7 +47,7 @@ incs = [
'../../windowmanager',
]
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c
index 38dd9048790..5a838d7bc39 100644
--- a/source/blender/editors/gpencil/drawgpencil.c
+++ b/source/blender/editors/gpencil/drawgpencil.c
@@ -676,7 +676,7 @@ static void gp_draw_data(bGPdata *gpd, int offsx, int offsy, int winx, int winy,
* ............................ */
/* draw grease-pencil sketches to specified 2d-view that uses ibuf corrections */
-void draw_gpencil_2dimage(const bContext *C)
+void ED_gpencil_draw_2dimage(const bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -685,7 +685,7 @@ void draw_gpencil_2dimage(const bContext *C)
int offsx, offsy, sizex, sizey;
int dflag = GP_DRAWDATA_NOSTATUS;
- gpd = gpencil_data_get_active(C); // XXX
+ gpd = ED_gpencil_data_get_active(C); // XXX
if (gpd == NULL) return;
/* calculate rect */
@@ -738,7 +738,7 @@ void draw_gpencil_2dimage(const bContext *C)
/* draw grease-pencil sketches to specified 2d-view assuming that matrices are already set correctly
* Note: this gets called twice - first time with onlyv2d=1 to draw 'canvas' strokes,
* second time with onlyv2d=0 for screen-aligned strokes */
-void draw_gpencil_view2d(const bContext *C, bool onlyv2d)
+void ED_gpencil_draw_view2d(const bContext *C, bool onlyv2d)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -748,7 +748,7 @@ void draw_gpencil_view2d(const bContext *C, bool onlyv2d)
/* check that we have grease-pencil stuff to draw */
if (sa == NULL) return;
- gpd = gpencil_data_get_active(C); // XXX
+ gpd = ED_gpencil_data_get_active(C); // XXX
if (gpd == NULL) return;
/* special hack for Image Editor */
@@ -764,7 +764,7 @@ void draw_gpencil_view2d(const bContext *C, bool onlyv2d)
/* draw grease-pencil sketches to specified 3d-view assuming that matrices are already set correctly
* Note: this gets called twice - first time with only3d=1 to draw 3d-strokes,
* second time with only3d=0 for screen-aligned strokes */
-void draw_gpencil_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
+void ED_gpencil_draw_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
{
bGPdata *gpd;
int dflag = 0;
@@ -772,7 +772,7 @@ void draw_gpencil_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
int offsx, offsy, winx, winy;
/* check that we have grease-pencil stuff to draw */
- gpd = gpencil_data_get_active_v3d(scene); // XXX
+ gpd = ED_gpencil_data_get_active_v3d(scene, v3d);
if (gpd == NULL) return;
/* when rendering to the offscreen buffer we don't want to
@@ -799,4 +799,11 @@ void draw_gpencil_view3d(Scene *scene, View3D *v3d, ARegion *ar, bool only3d)
gp_draw_data(gpd, offsx, offsy, winx, winy, CFRA, dflag);
}
+void ED_gpencil_draw_ex(bGPdata *gpd, int winx, int winy, const int cfra)
+{
+ int dflag = GP_DRAWDATA_NOSTATUS | GP_DRAWDATA_ONLYV2D;
+
+ gp_draw_data(gpd, 0, 0, winx, winy, cfra, dflag);
+}
+
/* ************************************************** */
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index f5bf1422488..dba80164e93 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -61,30 +61,30 @@
/* Generics - Loopers */
/* Loops over the gp-frames for a gp-layer, and applies the given callback */
-short ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPDframe *, Scene *))
+bool ED_gplayer_frames_looper(bGPDlayer *gpl, Scene *scene, short (*gpf_cb)(bGPDframe *, Scene *))
{
bGPDframe *gpf;
/* error checker */
if (gpl == NULL)
- return 0;
+ return false;
/* do loop */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
/* execute callback */
if (gpf_cb(gpf, scene))
- return 1;
+ return true;
}
/* nothing to return */
- return 0;
+ return false;
}
/* ****************************************** */
/* Data Conversion Tools */
/* make a listing all the gp-frames in a layer as cfraelems */
-void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, short onlysel)
+void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, bool onlysel)
{
bGPDframe *gpf;
CfraElem *ce;
@@ -110,22 +110,22 @@ void ED_gplayer_make_cfra_list(bGPDlayer *gpl, ListBase *elems, short onlysel)
/* Selection Tools */
/* check if one of the frames in this layer is selected */
-short ED_gplayer_frame_select_check(bGPDlayer *gpl)
+bool ED_gplayer_frame_select_check(bGPDlayer *gpl)
{
bGPDframe *gpf;
/* error checking */
if (gpl == NULL)
- return 0;
+ return false;
/* stop at the first one found */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
if (gpf->flag & GP_FRAME_SELECT)
- return 1;
+ return true;
}
/* not found */
- return 0;
+ return false;
}
/* helper function - select gp-frame based on SELECT_* mode */
diff --git a/source/blender/editors/gpencil/gpencil_buttons.c b/source/blender/editors/gpencil/gpencil_buttons.c
index 0fe4d7e7157..0acff8fc0a5 100644
--- a/source/blender/editors/gpencil/gpencil_buttons.c
+++ b/source/blender/editors/gpencil/gpencil_buttons.c
@@ -350,7 +350,7 @@ static void draw_gpencil_panel(bContext *C, uiLayout *layout, bGPdata *gpd, Poin
}
}
-void gpencil_panel_standard_header(const bContext *C, Panel *pa)
+void ED_gpencil_panel_standard_header(const bContext *C, Panel *pa)
{
PointerRNA ptr;
RNA_pointer_create((ID *)CTX_wm_screen(C), &RNA_Space, CTX_wm_space_data(C), &ptr);
@@ -359,7 +359,7 @@ void gpencil_panel_standard_header(const bContext *C, Panel *pa)
}
/* Standard panel to be included wherever Grease Pencil is used... */
-void gpencil_panel_standard(const bContext *C, Panel *pa)
+void ED_gpencil_panel_standard(const bContext *C, Panel *pa)
{
bGPdata **gpd_ptr = NULL;
PointerRNA ptr;
@@ -369,7 +369,7 @@ void gpencil_panel_standard(const bContext *C, Panel *pa)
draw_gpencil_space_specials(C, pa->layout);
/* get pointer to Grease Pencil Data */
- gpd_ptr = gpencil_data_get_pointers((bContext *)C, &ptr);
+ gpd_ptr = ED_gpencil_data_get_pointers((bContext *)C, &ptr);
if (gpd_ptr)
draw_gpencil_panel((bContext *)C, pa->layout, *gpd_ptr, &ptr);
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index d25de906e31..13334448941 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -62,6 +62,7 @@
#include "BKE_object.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "BKE_tracking.h"
#include "UI_interface.h"
@@ -86,7 +87,7 @@
/* Context Wrangling... */
/* Get pointer to active Grease Pencil datablock, and an RNA-pointer to trace back to whatever owns it */
-bGPdata **gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
+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);
@@ -180,21 +181,21 @@ bGPdata **gpencil_data_get_pointers(const bContext *C, PointerRNA *ptr)
}
/* Get the active Grease Pencil datablock */
-bGPdata *gpencil_data_get_active(const bContext *C)
+bGPdata *ED_gpencil_data_get_active(const bContext *C)
{
- bGPdata **gpd_ptr = gpencil_data_get_pointers(C, NULL);
+ bGPdata **gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
return (gpd_ptr) ? *(gpd_ptr) : NULL;
}
-/* needed for offscreen rendering */
-bGPdata *gpencil_data_get_active_v3d(Scene *scene)
+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 gpencil_data_get_active's behavior.
+ * to be consistent with ED_gpencil_data_get_active's behavior.
*/
- if (base && (scene->lay & base->lay) && (base->object->flag & SELECT)) {
+
+ if (base && TESTBASE(v3d, base)) {
gpd = base->object->gpd;
}
return gpd ? gpd : scene->gpd;
@@ -207,7 +208,7 @@ bGPdata *gpencil_data_get_active_v3d(Scene *scene)
static int gp_add_poll(bContext *C)
{
/* the base line we have is that we have somewhere to add Grease Pencil data */
- return gpencil_data_get_pointers(C, NULL) != NULL;
+ return ED_gpencil_data_get_pointers(C, NULL) != NULL;
}
/* ******************* Add New Data ************************ */
@@ -215,7 +216,7 @@ static int gp_add_poll(bContext *C)
/* add new datablock - wrapper around API */
static int gp_data_add_exec(bContext *C, wmOperator *op)
{
- bGPdata **gpd_ptr = gpencil_data_get_pointers(C, NULL);
+ 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");
@@ -253,7 +254,7 @@ void GPENCIL_OT_data_add(wmOperatorType *ot)
/* poll callback for adding data/layers - special */
static int gp_data_unlink_poll(bContext *C)
{
- bGPdata **gpd_ptr = gpencil_data_get_pointers(C, NULL);
+ 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);
@@ -263,7 +264,7 @@ static int gp_data_unlink_poll(bContext *C)
/* unlink datablock - wrapper around API */
static int gp_data_unlink_exec(bContext *C, wmOperator *op)
{
- bGPdata **gpd_ptr = gpencil_data_get_pointers(C, NULL);
+ 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");
@@ -301,7 +302,7 @@ void GPENCIL_OT_data_unlink(wmOperatorType *ot)
/* add new layer - wrapper around API */
static int gp_layer_add_exec(bContext *C, wmOperator *op)
{
- bGPdata **gpd_ptr = gpencil_data_get_pointers(C, NULL);
+ 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) {
@@ -337,7 +338,7 @@ void GPENCIL_OT_layer_add(wmOperatorType *ot)
static int gp_actframe_delete_poll(bContext *C)
{
- bGPdata *gpd = gpencil_data_get_active(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
/* only if there's an active layer with an active frame */
@@ -348,7 +349,7 @@ static int gp_actframe_delete_poll(bContext *C)
static int gp_actframe_delete_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- bGPdata *gpd = gpencil_data_get_active(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = gpencil_layer_getactive(gpd);
bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0);
@@ -1399,6 +1400,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
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;
@@ -1412,7 +1414,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
rctf subrect, *subrect_ptr = NULL;
/* error checking */
- if (ELEM3(NULL, gpd, gpl, gpf))
+ if (ELEM(NULL, gpd, gpl, gpf))
return;
/* only convert if there are any strokes on this layer's frame to convert */
@@ -1493,7 +1495,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG
}
/* set the layer and select */
- base_new->lay = ob->lay = base_orig ? base_orig->lay : scene->lay;
+ 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;
}
@@ -1559,7 +1561,7 @@ static void gp_convert_set_end_frame(struct Main *UNUSED(main), struct Scene *UN
static int gp_convert_poll(bContext *C)
{
- bGPdata *gpd = gpencil_data_get_active(C);
+ bGPdata *gpd = ED_gpencil_data_get_active(C);
bGPDlayer *gpl = NULL;
bGPDframe *gpf = NULL;
ScrArea *sa = CTX_wm_area(C);
@@ -1578,7 +1580,7 @@ static int gp_convert_poll(bContext *C)
static int gp_convert_layer_exec(bContext *C, wmOperator *op)
{
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "use_timing_data");
- bGPdata *gpd = gpencil_data_get_active(C);
+ 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");
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 2f941142d9e..7c1976df3e0 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -113,6 +113,7 @@ typedef struct tGPsdata {
float imat[4][4]; /* inverted transformation matrix applying when converting coords from screen-space
* to region space */
+ float mat[4][4];
float custom_color[4]; /* custom color - hack for enforcing a particular color for track/mask editing */
@@ -177,7 +178,7 @@ static int gpencil_draw_poll(bContext *C)
{
if (ED_operator_regionactive(C)) {
/* check if current context can support GPencil data */
- if (gpencil_data_get_pointers(C, NULL) != NULL) {
+ if (ED_gpencil_data_get_pointers(C, NULL) != NULL) {
/* check if Grease Pencil isn't already running */
if (ED_gpencil_session_active() == 0)
return 1;
@@ -891,9 +892,12 @@ static short gp_stroke_eraser_strokeinside(const int mval[2], const int UNUSED(m
return false;
}
-static void gp_point_to_xy(ARegion *ar, View2D *v2d, rctf *subrect, bGPDstroke *gps, bGPDspoint *pt,
+static void gp_point_to_xy(tGPsdata *p, bGPDstroke *gps, bGPDspoint *pt,
int *r_x, int *r_y)
{
+ ARegion *ar = p->ar;
+ View2D *v2d = p->v2d;
+ rctf *subrect = p->subrect;
int xyval[2];
if (gps->flag & GP_STROKE_3DSPACE) {
@@ -907,7 +911,9 @@ static void gp_point_to_xy(ARegion *ar, View2D *v2d, rctf *subrect, bGPDstroke *
}
}
else if (gps->flag & GP_STROKE_2DSPACE) {
- UI_view2d_view_to_region_clip(v2d, pt->x, pt->y, r_x, r_y);
+ float vec[3] = {pt->x, pt->y, 0.0f};
+ mul_m4_v3(p->mat, vec);
+ UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
}
else {
if (subrect == NULL) { /* normal 3D view */
@@ -939,7 +945,7 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
BLI_freelinkN(&gpf->strokes, gps);
}
else if (gps->totpoints == 1) {
- gp_point_to_xy(p->ar, p->v2d, p->subrect, gps, gps->points, &x0, &y0);
+ gp_point_to_xy(p, gps, gps->points, &x0, &y0);
/* do boundbox check first */
if ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) {
@@ -960,8 +966,8 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p,
pt1 = gps->points + i;
pt2 = gps->points + i + 1;
- gp_point_to_xy(p->ar, p->v2d, p->subrect, gps, pt1, &x0, &y0);
- gp_point_to_xy(p->ar, p->v2d, p->subrect, gps, pt2, &x1, &y1);
+ gp_point_to_xy(p, gps, pt1, &x0, &y0);
+ gp_point_to_xy(p, gps, pt2, &x1, &y1);
/* check that point segment of the boundbox of the eraser stroke */
if (((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(rect, x0, y0)) ||
@@ -1148,6 +1154,7 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
p->imat[3][0] -= marker->pos[0];
p->imat[3][1] -= marker->pos[1];
}
+ invert_m4_m4(p->mat, p->imat);
break;
}
/* unsupported views */
@@ -1161,7 +1168,7 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
}
/* get gp-data */
- gpd_ptr = gpencil_data_get_pointers(C, &p->ownerPtr);
+ gpd_ptr = ED_gpencil_data_get_pointers(C, &p->ownerPtr);
if (gpd_ptr == NULL) {
p->status = GP_STATUS_ERROR;
if (G.debug & G_DEBUG)
@@ -1861,7 +1868,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* we don't pass on key events, GP is used with key-modifiers - prevents Dkey to insert drivers */
if (ISKEYBOARD(event->type)) {
- if (ELEM4(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) {
+ if (ELEM(event->type, LEFTARROWKEY, DOWNARROWKEY, RIGHTARROWKEY, UPARROWKEY)) {
/* allow some keys - for frame changing: [#33412] */
}
else {
@@ -1874,7 +1881,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* exit painting mode (and/or end current stroke)
* NOTE: cannot do RIGHTMOUSE (as is standard for canceling) as that would break polyline [#32647]
*/
- if (ELEM4(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) {
+ if (ELEM(event->type, RETKEY, PADENTER, ESCKEY, SPACEKEY)) {
/* exit() ends the current stroke before cleaning up */
/* printf("\t\tGP - end of paint op + end of stroke\n"); */
p->status = GP_STATUS_DONE;
@@ -1949,7 +1956,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
/* eraser size */
else if ((p->paintmode == GP_PAINTMODE_ERASER) &&
- ELEM4(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS))
+ ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, PADPLUSKEY, PADMINUS))
{
/* just resize the brush (local version)
* TODO: fix the hardcoded size jumps (set to make a visible difference) and hardcoded keys
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 136e9da389d..ff92d69f39d 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -70,7 +70,7 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
{
bGPdata **gpd_ptr = NULL, *new_gpd = NULL;
- gpd_ptr = gpencil_data_get_pointers(C, NULL);
+ gpd_ptr = ED_gpencil_data_get_pointers(C, NULL);
if (step == 1) { /* undo */
//printf("\t\tGP - undo step\n");
diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h
index 477a7c0ce17..cd26bb22ada 100644
--- a/source/blender/editors/include/BIF_gl.h
+++ b/source/blender/editors/include/BIF_gl.h
@@ -33,7 +33,7 @@
#ifndef __BIF_GL_H__
#define __BIF_GL_H__
-#include "GL/glew.h"
+#include "GPU_glew.h"
#ifdef __APPLE__
@@ -58,8 +58,24 @@
* */
void cpack(unsigned int x);
-#define glMultMatrixf(x) glMultMatrixf( (float *)(x))
-#define glLoadMatrixf(x) glLoadMatrixf( (float *)(x))
+
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# define glMultMatrixf(x) \
+ glMultMatrixf(_Generic((x), \
+ float *: (float *)(x), \
+ float (*)[4]: (float *)(x), \
+ const float *: (float *)(x), \
+ const float (*)[4]: (float *)(x)) \
+)
+# define glLoadMatrixf(x) \
+ glLoadMatrixf(_Generic((x), \
+ float *: (float *)(x), \
+ float (*)[4]: (float *)(x)) \
+)
+#else
+# define glMultMatrixf(x) glMultMatrixf((float *)(x))
+# define glLoadMatrixf(x) glLoadMatrixf((float *)(x))
+#endif
#define GLA_PIXEL_OFS 0.375f
diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h
index 48440d10ae3..4272fd49f7f 100644
--- a/source/blender/editors/include/BIF_glutil.h
+++ b/source/blender/editors/include/BIF_glutil.h
@@ -41,10 +41,12 @@ struct ColorManagedDisplaySettings;
void fdrawbezier(float vec[4][3]);
void fdrawline(float x1, float y1, float x2, float y2);
void fdrawbox(float x1, float y1, float x2, float y2);
-void sdrawline(short x1, short y1, short x2, short y2);
-void sdrawtri(short x1, short y1, short x2, short y2);
-void sdrawtrifill(short x1, short y1, short x2, short y2);
-void sdrawbox(short x1, short y1, short x2, short y2);
+void sdrawline(int x1, int y1, int x2, int y2);
+#if 0
+void sdrawtri(int x1, int y1, int x2, int y2);
+void sdrawtrifill(int x1, int y1, int x2, int y2);
+#endif
+void sdrawbox(int x1, int y1, int x2, int y2);
void sdrawXORline(int x0, int y0, int x1, int y1);
void sdrawXORline4(int nr, int x0, int y0, int x1, int y1);
@@ -222,5 +224,7 @@ void glaDrawImBuf_glsl(struct ImBuf *ibuf, float x, float y, int zoomfilter,
/* Draw imbuf on a screen, preferably using GLSL display transform */
void glaDrawImBuf_glsl_ctx(const struct bContext *C, struct ImBuf *ibuf, float x, float y, int zoomfilter);
+void glaDrawBorderCorners(const struct rcti *border, float zoomx, float zoomy);
+
#endif /* __BIF_GLUTIL_H__ */
diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h
index 10f3f1bef4c..956ec308daa 100644
--- a/source/blender/editors/include/ED_anim_api.h
+++ b/source/blender/editors/include/ED_anim_api.h
@@ -111,11 +111,12 @@ typedef struct bAnimListElem {
struct bAnimListElem *next, *prev;
void *data; /* source data this elem represents */
- int type; /* one of the ANIMTYPE_* values */
+ int type; /* (eAnim_ChannelType) one of the ANIMTYPE_* values */
int flag; /* copy of elem's flags for quick access */
- int index; /* for un-named data, the index of the data in it's collection */
+ int index; /* for un-named data, the index of the data in its collection */
- short datatype; /* type of motion data to expect */
+ short update; /* (eAnim_Update_Flags) tag the element for updating */
+ short datatype; /* (eAnim_KeyType) type of motion data to expect */
void *key_data; /* motion data - mostly F-Curves, but can be other types too */
@@ -189,6 +190,20 @@ typedef enum eAnim_KeyType {
ALE_GROUP /* Action Group summary */
} eAnim_KeyType;
+/* Flags for specifying the types of updates (i.e. recalculation/refreshing) that
+ * needs to be performed to the data contained in a channel following editing.
+ * For use with ANIM_animdata_update()
+ */
+typedef enum eAnim_Update_Flags {
+ ANIM_UPDATE_DEPS = (1 << 0), /* referenced data and dependencies get refreshed */
+ ANIM_UPDATE_ORDER = (1 << 1), /* keyframes need to be sorted */
+ ANIM_UPDATE_HANDLES = (1 << 2), /* recalculate handles */
+} eAnim_Update_Flags;
+
+/* used for most tools which change keyframes (flushed by ANIM_animdata_update) */
+#define ANIM_UPDATE_DEFAULT (ANIM_UPDATE_DEPS | ANIM_UPDATE_ORDER | ANIM_UPDATE_HANDLES)
+#define ANIM_UPDATE_DEFAULT_NOHANDLES (ANIM_UPDATE_DEFAULT & ~ANIM_UPDATE_HANDLES)
+
/* ----------------- Filtering -------------------- */
/* filtering flags - under what circumstances should a channel be returned */
@@ -343,7 +358,7 @@ typedef enum eAnimFilter_Flags {
/* Obtain list of filtered Animation channels to operate on.
* Returns the number of channels in the list
*/
-size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, int filter_mode, void *data, short datatype);
+size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype);
/* Obtain current anim-data context from Blender Context info.
* Returns whether the operation was successful.
@@ -356,6 +371,11 @@ bool ANIM_animdata_get_context(const struct bContext *C, bAnimContext *ac);
*/
bool ANIM_animdata_context_getdata(bAnimContext *ac);
+/* Acts on bAnimListElem eAnim_Update_Flags */
+void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data);
+
+void ANIM_animdata_freelist(ListBase *anim_data);
+
/* ************************************************ */
/* ANIMATION CHANNELS LIST */
/* anim_channels_*.c */
@@ -447,13 +467,13 @@ void ANIM_channel_draw_widgets(struct bContext *C, bAnimContext *ac, bAnimListEl
*
* - setting: eAnimChannel_Settings
*/
-short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, int setting);
+short ANIM_channel_setting_get(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting);
/* Change value of some setting for a channel
* - setting: eAnimChannel_Settings
* - mode: eAnimChannels_SetFlag
*/
-void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, int setting, short mode);
+void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode);
/* Flush visibility (for Graph Editor) changes up/down hierarchy for changes in the given setting
@@ -465,14 +485,14 @@ void ANIM_channel_setting_set(bAnimContext *ac, bAnimListElem *ale, int setting,
* - setting: type of setting to set
* - on: whether the visibility setting has been enabled or disabled
*/
-void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, int setting, short mode);
+void ANIM_flush_setting_anim_channels(bAnimContext *ac, ListBase *anim_data, bAnimListElem *ale_setting, eAnimChannel_Settings setting, eAnimChannels_SetFlag mode);
/* Deselect all animation channels */
-void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, short test, short sel);
+void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, eAnimCont_Types datatype, bool test, eAnimChannels_SetFlag sel);
/* Set the 'active' channel of type channel_type, in the given action */
-void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int filter, void *channel_data, short channel_type);
+void ANIM_set_active_channel(bAnimContext *ac, void *data, eAnimCont_Types datatype, eAnimFilter_Flags filter, void *channel_data, eAnim_ChannelType channel_type);
/* Delete the F-Curve from the given AnimData block (if possible), as appropriate according to animation context */
diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h
index 7579f6cba65..b08cc12dc3e 100644
--- a/source/blender/editors/include/ED_armature.h
+++ b/source/blender/editors/include/ED_armature.h
@@ -123,7 +123,7 @@ void ED_armature_deselect_all(struct Object *obedit, int toggle);
void ED_armature_deselect_all_visible(struct Object *obedit);
int ED_do_pose_selectbuffer(struct Scene *scene, struct Base *base, unsigned int *buffer,
- short hits, bool extend, bool deselect, bool toggle);
+ 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);
struct Bone *get_indexed_bone(struct Object *ob, int index);
@@ -133,8 +133,8 @@ EditBone *ED_armature_bone_get_mirrored(const struct ListBase *edbo, EditBone *e
void ED_armature_sync_selection(struct ListBase *edbo);
void ED_armature_validate_active(struct bArmature *arm);
-void add_primitive_bone(struct Object *obedit_arm, bool view_aligned);
-struct EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *name);
+EditBone *ED_armature_edit_bone_add_primitive(struct Object *obedit_arm, float length, bool view_aligned);
+EditBone *ED_armature_edit_bone_add(struct bArmature *arm, const char *name);
void ED_armature_edit_bone_remove(struct bArmature *arm, EditBone *exBone);
bool ED_armature_ebone_is_child_recursive(EditBone *ebone_parent, EditBone *ebone_child);
@@ -157,9 +157,11 @@ void ED_armature_transform(struct bArmature *arm, float mat[4][4]);
#define ARM_GROUPS_ENVELOPE 2
#define ARM_GROUPS_AUTO 3
-void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct Object *par, int mode, bool mirror);
+void create_vgroups_from_armature(struct ReportList *reports, struct Scene *scene, struct Object *ob,
+ struct Object *par, const int mode, const bool mirror);
-void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone); /* if bone is already in list, pass it as param to ignore it */
+/* if bone is already in list, pass it as param to ignore it */
+void unique_editbone_name(struct ListBase *ebones, char *name, EditBone *bone);
void ED_armature_bone_rename(struct bArmature *arm, const char *oldnamep, const char *newnamep);
void undo_push_armature(struct bContext *C, const char *name);
@@ -174,7 +176,7 @@ void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag);
/* poseobject.c */
void ED_armature_exit_posemode(struct bContext *C, struct Base *base);
void ED_armature_enter_posemode(struct bContext *C, struct Base *base);
-void ED_pose_deselectall(struct Object *ob, int test);
+void ED_pose_de_selectall(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
void ED_pose_recalculate_paths(struct Scene *scene, struct Object *ob);
struct Object *ED_pose_object_from_context(struct bContext *C);
diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h
index 330147db077..58e64f30b05 100644
--- a/source/blender/editors/include/ED_curve.h
+++ b/source/blender/editors/include/ED_curve.h
@@ -51,7 +51,6 @@ void ED_operatormacros_curve(void);
void ED_keymap_curve(struct wmKeyConfig *keyconf);
/* editcurve.c */
-void ED_curve_transform(struct Curve *cu, float mat[4][4]);
void ED_curve_deselect_all(struct EditNurb *editnurb);
void ED_curve_select_all(struct EditNurb *editnurb);
void ED_curve_select_swap(struct EditNurb *editnurb, bool hide_handles);
diff --git a/source/blender/editors/include/ED_datafiles.h b/source/blender/editors/include/ED_datafiles.h
index 9022a1481aa..661ab58b98c 100644
--- a/source/blender/editors/include/ED_datafiles.h
+++ b/source/blender/editors/include/ED_datafiles.h
@@ -150,6 +150,12 @@ extern char datatoc_subtract_png[];
extern int datatoc_texdraw_png_size;
extern char datatoc_texdraw_png[];
+extern int datatoc_texfill_png_size;
+extern char datatoc_texfill_png[];
+
+extern int datatoc_texmask_png_size;
+extern char datatoc_texmask_png[];
+
extern int datatoc_thumb_png_size;
extern char datatoc_thumb_png[];
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index e31221a42df..05fb76b7aea 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -65,9 +65,9 @@ typedef struct tGPspoint {
/* ----------- Grease Pencil Tools/Context ------------- */
-struct bGPdata **gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *ptr);
-struct bGPdata *gpencil_data_get_active(const struct bContext *C);
-struct bGPdata *gpencil_data_get_active_v3d(struct Scene *scene); /* for offscreen rendering */
+struct bGPdata **ED_gpencil_data_get_pointers(const struct bContext *C, struct PointerRNA *ptr);
+struct bGPdata *ED_gpencil_data_get_active(const struct bContext *C);
+struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct View3D *v3d);
/* ----------- Grease Pencil Operators ----------------- */
@@ -77,19 +77,20 @@ void ED_operatortypes_gpencil(void);
/* ------------ Grease-Pencil Drawing API ------------------ */
/* drawgpencil.c */
-void draw_gpencil_2dimage(const struct bContext *C);
-void draw_gpencil_view2d(const struct bContext *C, bool onlyv2d);
-void draw_gpencil_view3d(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, bool only3d);
+void ED_gpencil_draw_2dimage(const struct bContext *C);
+void ED_gpencil_draw_view2d(const struct bContext *C, bool onlyv2d);
+void ED_gpencil_draw_view3d(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, bool only3d);
+void ED_gpencil_draw_ex(struct bGPdata *gpd, int winx, int winy, const int cfra);
-void gpencil_panel_standard_header(const struct bContext *C, struct Panel *pa);
-void gpencil_panel_standard(const struct bContext *C, struct Panel *pa);
+void ED_gpencil_panel_standard_header(const struct bContext *C, struct Panel *pa);
+void ED_gpencil_panel_standard(const struct bContext *C, struct Panel *pa);
/* ----------- Grease-Pencil AnimEdit API ------------------ */
-short ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene,
+bool ED_gplayer_frames_looper(struct bGPDlayer *gpl, struct Scene *scene,
short (*gpf_cb)(struct bGPDframe *, struct Scene *));
-void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, short onlysel);
+void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool onlysel);
-short ED_gplayer_frame_select_check(struct bGPDlayer *gpl);
+bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl);
void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode);
void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode);
void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode);
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index b15a83809f5..a9995de068e 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -69,7 +69,8 @@ void ED_image_point_pos__reverse(struct SpaceImage *sima, struct ARegion *ar, co
bool ED_space_image_show_render(struct SpaceImage *sima);
bool ED_space_image_show_paint(struct SpaceImage *sima);
bool ED_space_image_show_uvedit(struct SpaceImage *sima, struct Object *obedit);
-bool ED_space_image_show_uvshadow(struct SpaceImage *sima, struct Object *obedit);
+
+bool ED_space_image_paint_curve(const struct bContext *C);
bool ED_space_image_check_show_maskedit(struct Scene *scene, struct SpaceImage *sima);
int ED_space_image_maskedit_poll(struct bContext *C);
diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h
index 4d19b6d5548..6636319dc9b 100644
--- a/source/blender/editors/include/ED_lattice.h
+++ b/source/blender/editors/include/ED_lattice.h
@@ -37,6 +37,5 @@ struct Lattice;
void free_editLatt(struct Object *ob);
void make_editLatt(struct Object *obedit);
void load_editLatt(struct Object *obedit);
-void ED_lattice_transform(struct Lattice *lt, float mat[4][4]);
#endif /* __ED_LATTICE_H__ */
diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h
index 680e9d79109..5e774c63841 100644
--- a/source/blender/editors/include/ED_mball.h
+++ b/source/blender/editors/include/ED_mball.h
@@ -50,6 +50,4 @@ void load_editMball(struct Object *obedit);
void undo_push_mball(struct bContext *C, const char *name);
-void ED_mball_transform(struct MetaBall *mb, float mat[4][4]);
-
#endif /* __ED_MBALL_H__ */
diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h
index ebc97c58e24..6a562da0a0e 100644
--- a/source/blender/editors/include/ED_mesh.h
+++ b/source/blender/editors/include/ED_mesh.h
@@ -119,7 +119,7 @@ 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 *em, const bool selected, const bool do_islands);
+struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm, const bool selected, 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);
@@ -264,7 +264,6 @@ void ED_mesh_faces_remove(struct Mesh *mesh, struct ReportList *reports, int cou
void ED_mesh_edges_remove(struct Mesh *mesh, struct ReportList *reports, int count);
void ED_mesh_vertices_remove(struct Mesh *mesh, struct ReportList *reports, int count);
-void ED_mesh_transform(struct Mesh *me, float mat[4][4]);
void ED_mesh_calc_tessface(struct Mesh *mesh);
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges, int calc_tessface);
diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h
index e7b52a49e8c..f9a22429fc2 100644
--- a/source/blender/editors/include/ED_numinput.h
+++ b/source/blender/editors/include/ED_numinput.h
@@ -64,6 +64,8 @@ enum {
/* (1 << 9) and above are reserved for internal flags! */
};
+struct UnitSettings;
+
/*********************** NumInput ********************************/
/* There are important things to note here for code using numinput:
@@ -76,7 +78,7 @@ enum {
*/
void initNumInput(NumInput *n);
-void outputNumInput(NumInput *n, char *str);
+void outputNumInput(NumInput *n, char *str, struct UnitSettings *unit_settings);
bool hasNumInput(const NumInput *n);
bool applyNumInput(NumInput *n, float *vec);
bool handleNumInput(struct bContext *C, NumInput *n, const struct wmEvent *event);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 5504b7e0352..39586039e8f 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -101,9 +101,10 @@ extern struct EnumPropertyItem prop_clear_parent_types[];
extern struct EnumPropertyItem prop_make_parent_types[];
#endif
-int ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob,
- struct Object *par, int partype, bool xmirror, bool keep_transform, const int vert_par[3]);
-void ED_object_parent_clear(struct Object *ob, int type);
+bool ED_object_parent_set(struct ReportList *reports, struct Main *bmain, struct Scene *scene, struct Object *ob,
+ struct Object *par, int partype, const bool xmirror, const bool keep_transform,
+ const int vert_par[3]);
+void ED_object_parent_clear(struct Object *ob, const int type);
struct Base *ED_object_scene_link(struct Scene *scene, struct Object *ob);
void ED_keymap_proportional_cycle(struct wmKeyConfig *keyconf, struct wmKeyMap *keymap);
@@ -122,7 +123,7 @@ void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, str
/* single object duplicate, if (dupflag == 0), fully linked, else it uses the flags given */
struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct Base *base, int dupflag);
-void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *substr);
+void ED_object_parent(struct Object *ob, struct Object *parent, const int type, const char *substr);
bool ED_object_mode_compat_set(struct bContext *C, struct Object *ob, int mode, struct ReportList *reports);
void ED_object_toggle_modes(struct bContext *C, int mode);
@@ -150,10 +151,11 @@ bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, c
float loc[3], float rot[3],
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);
+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;
-void ED_object_single_users(struct Main *bmain, struct Scene *scene, bool full, bool copy_groups);
+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);
/* object motion paths */
diff --git a/source/blender/editors/include/ED_paint.h b/source/blender/editors/include/ED_paint.h
new file mode 100644
index 00000000000..decd79fcc7b
--- /dev/null
+++ b/source/blender/editors/include/ED_paint.h
@@ -0,0 +1,65 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file ED_paint.h
+ * \ingroup editors
+ */
+
+#ifndef __ED_PAINT_H__
+#define __ED_PAINT_H__
+
+struct bContext;
+struct RegionView3D;
+struct wmKeyConfig;
+struct wmOperator;
+
+/* paint_ops.c */
+void ED_operatortypes_paint(void);
+void ED_operatormacros_paint(void);
+void ED_keymap_paint(struct wmKeyConfig *keyconf);
+
+/* paint_undo.c */
+enum {
+ UNDO_PAINT_IMAGE = 0,
+ UNDO_PAINT_MESH = 1,
+};
+
+typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
+typedef void (*UndoFreeCb)(struct ListBase *lb);
+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);
+void ED_undo_paint_free(void);
+int ED_undo_paint_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);
+
+/* paint_image.c */
+/* image painting specific undo */
+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_bucket_fill(struct bContext *C, float color[3], struct wmOperator *op);
+
+#endif /* __ED_PAINT_H__ */
diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h
index 14595a4c668..ab1dbabe793 100644
--- a/source/blender/editors/include/ED_render.h
+++ b/source/blender/editors/include/ED_render.h
@@ -35,7 +35,6 @@ struct ID;
struct Main;
struct MTex;
struct Render;
-struct RenderInfo;
struct Scene;
struct ScrArea;
struct RegionView3D;
@@ -56,18 +55,6 @@ void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated
void ED_viewport_render_kill_jobs(const struct bContext *C, bool free_database);
struct Scene *ED_render_job_get_scene(const struct bContext *C);
-/* render_preview.c */
-
-/* stores rendered preview - is also used for icons */
-typedef struct RenderInfo {
- int pr_rectx;
- int pr_recty;
- short curtile, tottile;
- rcti disprect; /* storage for view3d preview rect */
- unsigned int *rect;
- struct Render *re; /* persistent render */
-} RenderInfo;
-
/* Render the preview
*
* pr_method:
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index 060702f6d71..ed2465647da 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -60,6 +60,7 @@ void ED_region_init(struct bContext *C, struct ARegion *ar);
void ED_region_tag_redraw(struct ARegion *ar);
void ED_region_tag_redraw_partial(struct ARegion *ar, struct rcti *rct);
void ED_region_tag_redraw_overlay(struct ARegion *ar);
+void ED_region_tag_refresh_ui(struct ARegion *ar);
void ED_region_panels_init(struct wmWindowManager *wm, struct ARegion *ar);
void ED_region_panels(const struct bContext *C, struct ARegion *ar, int vertical, const char *context, int contextnr);
void ED_region_header_init(struct ARegion *ar);
@@ -109,7 +110,7 @@ void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, in
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_restore(struct bContext *C, ScrArea *sa);
-struct ScrArea *ED_screen_full_toggle(struct bContext *C, struct wmWindow *win, struct 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);
/* anim */
diff --git a/source/blender/editors/include/ED_screen_types.h b/source/blender/editors/include/ED_screen_types.h
index 2b02606c6d9..effecf43839 100644
--- a/source/blender/editors/include/ED_screen_types.h
+++ b/source/blender/editors/include/ED_screen_types.h
@@ -93,10 +93,13 @@ typedef struct AZone {
short x1, y1, x2, y2;
/* for clip */
rcti rect;
+ /* for fade in/out */
+ float alpha;
} AZone;
/* actionzone type */
#define AZONE_AREA 1 /* corner widgets for splitting areas */
#define AZONE_REGION 2 /* when a region is collapsed, draw a handle to expose */
+#define AZONE_FULLSCREEN 3 /* when in editor fullscreen draw a corner to go to normal mode */
#endif /* __ED_SCREEN_TYPES_H__ */
diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h
index 8fcb228803b..85ff9b5d246 100644
--- a/source/blender/editors/include/ED_sculpt.h
+++ b/source/blender/editors/include/ED_sculpt.h
@@ -32,47 +32,17 @@
struct ARegion;
struct bContext;
-struct MultiresModifierData;
struct Object;
struct RegionView3D;
-struct wmKeyConfig;
-struct wmWindowManager;
struct ViewContext;
struct rcti;
/* sculpt.c */
void ED_operatortypes_sculpt(void);
-void sculpt_get_redraw_planes(float planes[4][4], struct ARegion *ar,
- struct RegionView3D *rv3d, struct Object *ob);
-void ED_sculpt_get_average_stroke(struct Object *ob, float stroke[3]);
+void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar,
+ struct RegionView3D *rv3d, struct Object *ob);
+void ED_sculpt_stroke_get_average(struct Object *ob, float stroke[3]);
bool ED_sculpt_minmax(struct bContext *C, float min[3], float max[3]);
-int do_sculpt_mask_box_select(struct ViewContext *vc, struct rcti *rect, bool select, bool extend);
+int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select, bool extend);
-/* paint_ops.c */
-void ED_operatortypes_paint(void);
-void ED_keymap_paint(struct wmKeyConfig *keyconf);
-
-/* paint_undo.c */
-#define UNDO_PAINT_IMAGE 0
-#define UNDO_PAINT_MESH 1
-
-typedef void (*UndoRestoreCb)(struct bContext *C, struct ListBase *lb);
-typedef void (*UndoFreeCb)(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(int type, int nr, int *active);
-void ED_undo_paint_free(void);
-int ED_undo_paint_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);
-void ED_undo_paint_push_end(int type);
-
-/* image painting specific undo */
-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);
-
-
-#endif
+#endif /* __ED_SCULPT_H__ */
diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h
index 4fbe01a5fc7..d268c578cf2 100644
--- a/source/blender/editors/include/ED_space_api.h
+++ b/source/blender/editors/include/ED_space_api.h
@@ -35,6 +35,7 @@ struct ARegionType;
struct bContext;
void ED_spacetypes_init(void);
+void ED_spacemacros_init(void);
/* the pluginnable API for export to editors */
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 41ff9b88da9..daa6864b5aa 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -98,6 +98,7 @@ enum TfmMode {
#define CTX_NDOF (1 << 5)
#define CTX_MOVIECLIP (1 << 6)
#define CTX_MASK (1 << 7)
+#define CTX_PAINT_CURVE (1 << 8)
/* Standalone call to get the transformation center corresponding to the current situation
* returns 1 if successful, 0 otherwise (usually means there's no selection)
diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h
index 6d9f1c4eda0..e26e03473e0 100644
--- a/source/blender/editors/include/ED_util.h
+++ b/source/blender/editors/include/ED_util.h
@@ -46,7 +46,7 @@ struct Mesh;
void ED_editors_init(struct bContext *C);
void ED_editors_exit(struct bContext *C);
-void ED_editors_flush_edits(const struct bContext *C, bool for_render);
+bool ED_editors_flush_edits(const struct bContext *C, bool for_render);
/* ************** Undo ************************ */
diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h
index 04eb829979f..4b82fa40c6a 100644
--- a/source/blender/editors/include/ED_uvedit.h
+++ b/source/blender/editors/include/ED_uvedit.h
@@ -54,7 +54,7 @@ void ED_uvedit_assign_image(struct Main *bmain, struct Scene *scene, struct Obje
bool ED_uvedit_minmax(struct Scene *scene, struct Image *ima, struct Object *obedit, float min[2], float max[2]);
bool ED_object_get_active_image(struct Object *ob, int mat_nr,
- struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node);
+ struct Image **r_ima, struct ImageUser **r_iuser, struct bNode **r_node, struct bNodeTree **r_ntree);
void ED_object_assign_active_image(struct Main *bmain, struct Object *ob, int mat_nr, struct Image *ima);
bool ED_uvedit_test(struct Object *obedit);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 377bb7cebb1..bd4f37cfb1e 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -56,6 +56,7 @@ struct bContext;
struct bPoseChannel;
struct bScreen;
struct bglMats;
+struct rctf;
struct rcti;
struct wmOperator;
struct wmOperatorType;
@@ -84,6 +85,7 @@ typedef struct ViewDepths {
float *ED_view3d_cursor3d_get(struct Scene *scene, struct View3D *v3d);
void ED_view3d_cursor3d_position(struct bContext *C, float fp[3], const int mval[2]);
+void ED_view3d_cursor3d_update(struct bContext *C, const int mval[2]);
struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d);
@@ -217,7 +219,8 @@ void ED_view3d_unproject(struct bglMats *mats, float out[3], const float x, cons
/* 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,
@@ -269,7 +272,7 @@ bool ED_view3d_autodist_depth_seg(struct ARegion *ar, const int mval_sta[2], con
/* select */
#define MAXPICKBUF 10000
-short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input);
+short view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const struct rcti *input, bool do_nearest);
/* view3d_select.c */
float ED_view3d_select_dist_px(void);
@@ -332,6 +335,13 @@ void ED_view3d_camera_lock_init(struct View3D *v3d, struct RegionView3D *rv3d);
/* copy the view to the camera, return true if */
bool ED_view3d_camera_lock_sync(struct View3D *v3d, struct RegionView3D *rv3d);
+bool ED_view3d_camera_autokey(
+ struct Scene *scene, struct ID *id_key,
+ struct bContext *C, const bool do_rotate, const bool do_translate);
+bool ED_view3d_camera_lock_autokey(
+ struct View3D *v3d, struct RegionView3D *rv3d,
+ struct bContext *C, const bool do_rotate, const bool do_translate);
+
void ED_view3D_lock_clear(struct View3D *v3d);
struct BGpic *ED_view3D_background_image_new(struct View3D *v3d);
@@ -340,13 +350,14 @@ void ED_view3D_background_image_clear(struct View3D *v3d);
#define VIEW3D_MARGIN 1.4f
#define VIEW3D_DIST_FALLBACK 1.0f
+
float ED_view3d_offset_distance(float mat[4][4], const float ofs[3], const float dist_fallback);
void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist);
float ED_scene_grid_scale(struct Scene *scene, const char **grid_unit);
float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit);
-void ED_scene_draw_fps(struct Scene *scene, struct rcti *rect);
+void ED_scene_draw_fps(struct Scene *scene, const struct rcti *rect);
/* view matrix properties utilities */
/* unused */
@@ -357,6 +368,6 @@ void ED_view3d_operator_properties_viewmat_get(struct wmOperator *op, int *winx,
#endif
/* render */
-void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa);
+void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa);
#endif /* __ED_VIEW3D_H__ */
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index c776026a811..618fa44349e 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -426,13 +426,11 @@ DEF_ICON(CURVE_PATH)
DEF_ICON(COLOR_RED)
DEF_ICON(COLOR_GREEN)
DEF_ICON(COLOR_BLUE)
-#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK652)
- DEF_ICON(BLANK653)
- DEF_ICON(BLANK654)
- DEF_ICON(BLANK655)
-#endif
-
+DEF_ICON(TRIA_RIGHT_BAR)
+DEF_ICON(TRIA_DOWN_BAR)
+DEF_ICON(TRIA_LEFT_BAR)
+DEF_ICON(TRIA_UP_BAR)
+
/* EMPTY */
DEF_ICON(FORCE_FORCE)
DEF_ICON(FORCE_WIND)
@@ -668,8 +666,8 @@ DEF_ICON(IPO_EASE_IN_OUT)
DEF_ICON(VERTEXSEL)
DEF_ICON(EDGESEL)
DEF_ICON(FACESEL)
+DEF_ICON(LOOPSEL)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK209)
DEF_ICON(BLANK210)
#endif
DEF_ICON(ROTATE)
@@ -976,6 +974,8 @@ DEF_ICON(BRUSH_SNAKE_HOOK)
DEF_ICON(BRUSH_SOFTEN)
DEF_ICON(BRUSH_SUBTRACT)
DEF_ICON(BRUSH_TEXDRAW)
+DEF_ICON(BRUSH_TEXFILL)
+DEF_ICON(BRUSH_TEXMASK)
DEF_ICON(BRUSH_THUMB)
DEF_ICON(BRUSH_ROTATE)
DEF_ICON(BRUSH_VERTEXDRAW)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 8de9650ddef..bc794bf3350 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -75,6 +75,9 @@ struct ImBuf;
struct bNodeTree;
struct bNode;
struct bNodeSocket;
+struct wmDropBox;
+struct wmDrag;
+struct wmEvent;
typedef struct uiBut uiBut;
typedef struct uiBlock uiBlock;
@@ -99,6 +102,7 @@ typedef struct uiLayout uiLayout;
#define UI_EMBOSSN 1 /* Nothing, only icon and/or text */
#define UI_EMBOSSP 2 /* Pulldown menu style */
#define UI_EMBOSST 3 /* Table */
+#define UI_EMBOSSR 4 /* Pie Menu */
/* uiBlock->direction */
#define UI_DIRECTION (UI_TOP | UI_DOWN | UI_LEFT | UI_RIGHT)
@@ -134,6 +138,7 @@ typedef struct uiLayout uiLayout;
/* block->flag bits 14-17 are identical to but->drawflag bits */
#define UI_BLOCK_LIST_ITEM (1 << 19)
+#define UI_BLOCK_RADIAL (1 << 20)
/* uiPopupBlockHandle->menuretval */
#define UI_RETURN_CANCEL (1 << 0) /* cancel all menus cascading */
@@ -175,6 +180,7 @@ enum {
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_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 */
};
#define UI_PANEL_WIDTH 340
@@ -288,6 +294,8 @@ typedef enum {
#define UI_GRAD_V_ALT 9
#define UI_GRAD_L_ALT 10
+#define UI_PALETTE_COLOR 20
+
/* Drawing
*
* Functions to draw various shapes, taking theme settings into account.
@@ -353,6 +361,17 @@ struct uiLayout *uiPupMenuLayout(uiPopupMenu *head);
void uiPupMenuReports(struct bContext *C, struct ReportList *reports) ATTR_NONNULL();
bool uiPupMenuInvoke(struct bContext *C, const char *idname, struct ReportList *reports) ATTR_NONNULL(1, 2);
+/* Pie menus */
+typedef struct uiPieMenu uiPieMenu;
+
+void uiPieMenuInvoke(struct bContext *C, const char *idname, const struct wmEvent *event);
+void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname,
+ const char *propname, const struct wmEvent *event);
+void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path, const struct wmEvent *event);
+
+struct uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const struct wmEvent *event) ATTR_NONNULL();
+void uiPieMenuEnd(struct bContext *C, uiPieMenu *pie);
+struct uiLayout *uiPieMenuLayout(struct uiPieMenu *pie);
/* Popup Blocks
*
* Functions used to create popup blocks. These are like popup menus
@@ -380,8 +399,10 @@ void uiPupBlockClose(struct bContext *C, uiBlock *block);
* */
uiBlock *uiBeginBlock(const struct bContext *C, struct ARegion *region, const char *name, short dt);
+void uiEndBlock_ex(const struct bContext *C, uiBlock *block, const int xy[2]);
void uiEndBlock(const struct bContext *C, uiBlock *block);
void uiDrawBlock(const struct bContext *C, struct uiBlock *block);
+void uiBlockUpdateFromOld(const struct bContext *C, struct uiBlock *block);
uiBlock *uiGetBlock(const char *name, struct ARegion *ar);
@@ -408,7 +429,8 @@ typedef enum {
UI_BLOCK_BOUNDS_TEXT,
UI_BLOCK_BOUNDS_POPUP_MOUSE,
UI_BLOCK_BOUNDS_POPUP_MENU,
- UI_BLOCK_BOUNDS_POPUP_CENTER
+ UI_BLOCK_BOUNDS_POPUP_CENTER,
+ UI_BLOCK_BOUNDS_PIE_CENTER,
} eBlockBoundsCalc;
void uiBoundsBlock(struct uiBlock *block, int addval);
@@ -435,6 +457,7 @@ void uiButSetDragValue(uiBut *but);
void uiButSetDragImage(uiBut *but, const char *path, int icon, struct ImBuf *ima, float scale);
bool UI_but_active_drop_name(struct bContext *C);
+bool UI_but_active_drop_color(struct bContext *C);
void uiButSetFlag(uiBut *but, int flag);
void uiButClearFlag(uiBut *but, int flag);
@@ -695,7 +718,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_add_region_handlers(struct ListBase *handlers);
-void UI_add_popup_handlers(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup);
+void UI_add_popup_handlers(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click);
void UI_remove_popup_handlers(struct ListBase *handlers, uiPopupBlockHandle *popup);
void UI_remove_popup_handlers_all(struct bContext *C, struct ListBase *handlers);
@@ -706,7 +729,6 @@ void UI_remove_popup_handlers_all(struct bContext *C, struct ListBase *handlers)
void UI_init(void);
void UI_init_userdef(void);
-void UI_init_userdef_factory(void);
void UI_reinit_font(void);
void UI_exit(void);
@@ -728,6 +750,7 @@ void UI_exit(void);
#define UI_LAYOUT_HEADER 1
#define UI_LAYOUT_MENU 2
#define UI_LAYOUT_TOOLBAR 3
+#define UI_LAYOUT_PIEMENU 4
#define UI_UNIT_X ((void)0, U.widget_unit)
#define UI_UNIT_Y ((void)0, U.widget_unit)
@@ -818,8 +841,8 @@ uiLayout *uiLayoutListBox(uiLayout *layout, struct uiList *ui_list, struct Point
uiLayout *uiLayoutAbsolute(uiLayout *layout, int align);
uiLayout *uiLayoutSplit(uiLayout *layout, float percentage, int align);
uiLayout *uiLayoutOverlap(uiLayout *layout);
-
uiBlock *uiLayoutAbsoluteBlock(uiLayout *layout);
+uiLayout *uiLayoutRadial(uiLayout *layout);
/* templates */
void uiTemplateHeader(uiLayout *layout, struct bContext *C);
@@ -842,8 +865,10 @@ void uiTemplateIconView(uiLayout *layout, struct PointerRNA *ptr, const char *pr
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);
-void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, int levels, int brush);
+void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type,
+ int levels, int brush, int neg_slope);
void uiTemplateColorPicker(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int value_slider, int lock, int lock_luminosity, int cubic);
+void uiTemplatePalette(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color);
void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
PointerRNA *used_ptr, const char *used_propname, int active_layer);
void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *propname,
@@ -913,7 +938,14 @@ void uiItemMenuEnumO(uiLayout *layout, struct bContext *C, const char *opname, c
void uiItemMenuEnumR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name, int icon);
/* UI Operators */
+typedef struct uiDragColorHandle {
+ float color[3];
+ bool gamma_corrected;
+} uiDragColorHandle;
+
void UI_buttons_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);
/* Helpers for Operators */
uiBut *uiContextActiveButton(const struct bContext *C);
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index 0f11994e2d1..5b61e76f514 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -48,6 +48,9 @@ typedef enum {
#undef DEF_ICON
#undef DEF_VICO
+/* use to denote intentionally unset theme color */
+#define TH_UNDEFINED -1
+
enum {
TH_REDALERT,
@@ -84,6 +87,7 @@ enum {
TH_GRID,
TH_WIRE,
+ TH_WIRE_INNER,
TH_WIRE_EDIT,
TH_SELECT,
TH_ACTIVE,
@@ -103,6 +107,7 @@ enum {
TH_FACE_SELECT,
TH_NORMAL,
TH_VNORMAL,
+ TH_LNORMAL,
TH_FACE_DOT,
TH_FACEDOT_SIZE,
TH_CFRAME,
@@ -234,6 +239,9 @@ enum {
TH_STITCH_PREVIEW_UNSTITCHABLE,
TH_STITCH_PREVIEW_ACTIVE,
+ TH_PAINT_CURVE_HANDLE,
+ TH_PAINT_CURVE_PIVOT,
+
TH_UV_SHADOW,
TH_UV_OTHERS,
@@ -311,6 +319,7 @@ int UI_GetThemeValue(int colorid);
// get three color values, scaled to 0.0-1.0 range
void UI_GetThemeColor3fv(int colorid, float col[3]);
+void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3]);
// get the color, range 0.0-1.0, complete with shading offset
void UI_GetThemeColorShade3fv(int colorid, int offset, float col[3]);
void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]);
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index e13517adbb3..b921d17104c 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../../python
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -70,4 +71,6 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_interface "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/interface/SConscript b/source/blender/editors/interface/SConscript
index 1936e17a7bb..303ab7ff286 100644
--- a/source/blender/editors/interface/SConscript
+++ b/source/blender/editors/interface/SConscript
@@ -31,7 +31,8 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
@@ -45,7 +46,7 @@ incs = [
'../../windowmanager',
]
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 19d4e32152f..41bf5d5494e 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -51,6 +51,7 @@
#include "BKE_context.h"
#include "BKE_unit.h"
+#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_idprop.h"
@@ -97,6 +98,11 @@ bool ui_block_is_menu(const uiBlock *block)
((block->flag & UI_BLOCK_KEEP_OPEN) == 0));
}
+bool ui_block_is_pie_menu(const uiBlock *block)
+{
+ return ((block->flag & UI_BLOCK_RADIAL) != 0);
+}
+
static bool ui_is_but_unit_radians_ex(UnitSettings *unit, const int unit_type)
{
return (unit->system_rotation == USER_UNIT_ROT_RADIANS && unit_type == PROP_UNIT_ROTATION);
@@ -295,9 +301,8 @@ void ui_bounds_block(uiBlock *block)
block->safety.ymax = block->rect.ymax + xof;
}
-static void ui_centered_bounds_block(const bContext *C, uiBlock *block)
+static void ui_centered_bounds_block(wmWindow *window, uiBlock *block)
{
- wmWindow *window = CTX_wm_window(C);
int xmax, ymax;
int startx, starty;
int width, height;
@@ -322,9 +327,23 @@ static void ui_centered_bounds_block(const bContext *C, uiBlock *block)
ui_bounds_block(block);
}
-static void ui_popup_bounds_block(const bContext *C, uiBlock *block, eBlockBoundsCalc bounds_calc)
+
+static void ui_centered_pie_bounds_block(uiBlock *block)
+{
+ const int xy[2] = {
+ block->pie_data.pie_center_spawned[0],
+ block->pie_data.pie_center_spawned[1]
+ };
+
+ ui_block_translate(block, xy[0], xy[1]);
+
+ /* now recompute bounds and safety */
+ ui_bounds_block(block);
+}
+
+static void ui_popup_bounds_block(wmWindow *window, uiBlock *block,
+ eBlockBoundsCalc bounds_calc, const int xy[2])
{
- wmWindow *window = CTX_wm_window(C);
int startx, starty, endx, endy, width, height, oldwidth, oldheight;
int oldbounds, xmax, ymax;
const int margin = UI_SCREEN_MARGIN;
@@ -362,8 +381,8 @@ static void ui_popup_bounds_block(const bContext *C, uiBlock *block, eBlockBound
/* offset block based on mouse position, user offset is scaled
* along in case we resized the block in ui_text_bounds_block */
- startx = window->eventstate->x + block->rect.xmin + (block->mx * width) / oldwidth;
- starty = window->eventstate->y + block->rect.ymin + (block->my * height) / oldheight;
+ startx = xy[0] + block->rect.xmin + (block->mx * width) / oldwidth;
+ starty = xy[1] + block->rect.ymin + (block->my * height) / oldheight;
if (startx < margin)
startx = margin;
@@ -831,7 +850,7 @@ static void ui_menu_block_set_keyaccels(uiBlock *block)
* fun first pass on all buttons so first word chars always get first priority */
for (but = block->buttons.first; but; but = but->next) {
- if (!ELEM5(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) {
+ if (!ELEM(but->type, BUT, BUTM, MENU, BLOCK, PULLDOWN) || (but->flag & UI_HIDDEN)) {
/* pass */
}
else if (but->menu_key == '\0') {
@@ -1063,6 +1082,41 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but,
return found;
}
+/* this goes in a seemingly weird pattern:
+ *
+ * 4
+ * 5 6
+ * 1 2
+ * 7 8
+ * 3
+ *
+ * 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
+ * as new items are added to the menu later on. It also optimises efficiency -
+ * a radial menu is best kept symmetrical, with as large an angle between
+ * items as possible, so that the gestural mouse movements can be fast and inexact.
+
+ * It starts off with two opposite sides for the first two items
+ * then joined by the one below for the third (this way, even with three items,
+ * the menu seems to still be 'in order' reading left to right). Then the fourth is
+ * added to complete the compass directions. From here, it's just a matter of
+ * subdividing the rest of the angles for the last 4 items.
+ *
+ * --Matt 07/2006
+ */
+const char ui_radial_dir_order[8] = {
+ UI_RADIAL_W, UI_RADIAL_E, UI_RADIAL_S, UI_RADIAL_N,
+ UI_RADIAL_NW, UI_RADIAL_NE, UI_RADIAL_SW, UI_RADIAL_SE};
+
+const char ui_radial_dir_to_numpad[8] = {8, 9, 6, 3, 2, 1, 4, 7};
+const short ui_radial_dir_to_angle[8] = {90, 45, 0, 315, 270, 225, 180, 135};
+
+static void ui_but_pie_direction_string(uiBut *but, char *buf, int size)
+{
+ BLI_assert(but->pie_dir < ARRAY_SIZE(ui_radial_dir_to_numpad));
+ BLI_snprintf(buf, size, "%d", ui_radial_dir_to_numpad[but->pie_dir]);
+}
+
static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
{
uiBut *but;
@@ -1072,40 +1126,71 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block)
if (block->rect.xmin != block->rect.xmax)
return;
- for (but = block->buttons.first; but; but = but->next) {
-
- if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) {
- ui_but_add_shortcut(but, buf, false);
+ if (block->flag & UI_BLOCK_RADIAL) {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ ui_but_pie_direction_string(but, buf, sizeof(buf));
+ ui_but_add_shortcut(but, buf, false);
+ }
}
- else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) {
- ui_but_add_shortcut(but, buf, false);
+ }
+ else {
+ for (but = block->buttons.first; but; but = but->next) {
+
+ if (ui_but_event_operator_string(C, but, buf, sizeof(buf))) {
+ ui_but_add_shortcut(but, buf, false);
+ }
+ else if (ui_but_event_property_operator_string(C, but, buf, sizeof(buf))) {
+ ui_but_add_shortcut(but, buf, false);
+ }
}
}
}
-void uiEndBlock(const bContext *C, uiBlock *block)
+void uiBlockUpdateFromOld(const bContext *C, uiBlock *block)
{
- const bool has_old = (block->oldblock != NULL);
- /* avoid searches when old/new lists align */
- uiBut *but_old = has_old ? block->oldblock->buttons.first : NULL;
-
+ uiBut *but_old;
uiBut *but;
- Scene *scene = CTX_data_scene(C);
+ if (!block->oldblock)
+ return;
+
+ but_old = block->oldblock->buttons.first;
- if (has_old && BLI_listbase_is_empty(&block->oldblock->butstore) == false) {
+ if (BLI_listbase_is_empty(&block->oldblock->butstore) == false) {
UI_butstore_update(block);
}
+ for (but = block->buttons.first; but; but = but->next) {
+ if (ui_but_update_from_old_block(C, block, &but, &but_old)) {
+ ui_check_but(but);
+ }
+ }
+
+ block->auto_open = block->oldblock->auto_open;
+ block->auto_open_last = block->oldblock->auto_open_last;
+ block->tooltipdisabled = block->oldblock->tooltipdisabled;
+ copy_v3_v3(ui_block_hsv_get(block),
+ ui_block_hsv_get(block->oldblock));
+
+ block->oldblock = NULL;
+}
+
+void uiEndBlock_ex(const bContext *C, uiBlock *block, const int xy[2])
+{
+ wmWindow *window = CTX_wm_window(C);
+ Scene *scene = CTX_data_scene(C);
+ uiBut *but;
+
+ BLI_assert(block->active);
+
+ uiBlockUpdateFromOld(C, block);
+
/* inherit flags from 'old' buttons that was drawn here previous, based
* on matching buttons, we need this to make button event handling non
* blocking, while still allowing buttons to be remade each redraw as it
* is expected by blender code */
for (but = block->buttons.first; but; but = but->next) {
- if (has_old && ui_but_update_from_old_block(C, block, &but, &but_old)) {
- ui_check_but(but);
- }
-
/* temp? Proper check for graying out */
if (but->optype) {
wmOperatorType *ot = but->optype;
@@ -1125,15 +1210,7 @@ void uiEndBlock(const bContext *C, uiBlock *block)
ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f);
}
- if (block->oldblock) {
- block->auto_open = block->oldblock->auto_open;
- block->auto_open_last = block->oldblock->auto_open_last;
- block->tooltipdisabled = block->oldblock->tooltipdisabled;
- copy_v3_v3(ui_block_hsv_get(block),
- ui_block_hsv_get(block->oldblock));
- block->oldblock = NULL;
- }
/* handle pending stuff */
if (block->layouts.first) {
@@ -1159,13 +1236,16 @@ void uiEndBlock(const bContext *C, uiBlock *block)
ui_text_bounds_block(block, 0.0f);
break;
case UI_BLOCK_BOUNDS_POPUP_CENTER:
- ui_centered_bounds_block(C, block);
+ ui_centered_bounds_block(window, block);
+ break;
+ case UI_BLOCK_BOUNDS_PIE_CENTER:
+ ui_centered_pie_bounds_block(block);
break;
/* fallback */
case UI_BLOCK_BOUNDS_POPUP_MOUSE:
case UI_BLOCK_BOUNDS_POPUP_MENU:
- ui_popup_bounds_block(C, block, block->bounds_type);
+ ui_popup_bounds_block(window, block, block->bounds_type, xy);
break;
}
@@ -1179,6 +1259,13 @@ void uiEndBlock(const bContext *C, uiBlock *block)
block->endblock = 1;
}
+void uiEndBlock(const bContext *C, uiBlock *block)
+{
+ wmWindow *window = CTX_wm_window(C);
+
+ uiEndBlock_ex(C, block, &window->eventstate->x);
+}
+
/* ************** BLOCK DRAWING FUNCTION ************* */
void ui_fontscale(short *points, float aspect)
@@ -1256,11 +1343,13 @@ void uiDrawBlock(const bContext *C, uiBlock *block)
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
-
- wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f);
+
+ wmOrtho2_region_ui(ar);
/* back */
- if (block->flag & UI_BLOCK_LOOP)
+ if (block->flag & UI_BLOCK_RADIAL)
+ ui_draw_pie_center(block);
+ else if (block->flag & UI_BLOCK_LOOP)
ui_draw_menu_back(&style, block, &rect);
else if (block->panel)
ui_draw_aligned_panel(&style, block, &rect, UI_panel_category_is_visible(ar));
@@ -1301,7 +1390,7 @@ int ui_is_but_push_ex(uiBut *but, double *value)
int is_push = 0;
if (but->bit) {
- const bool state = ELEM3(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
+ const bool state = ELEM(but->type, TOGN, ICONTOGN, OPTIONN) ? false : true;
int lvalue;
UI_GET_BUT_VALUE_INIT(but, *value);
lvalue = (int)*value;
@@ -1430,7 +1519,7 @@ void uiComposeLinks(uiBlock *block)
}
}
else if (link->poin) {
- bt = ui_find_inlink(block, *(link->poin) );
+ bt = ui_find_inlink(block, *link->poin);
if (bt) {
if ((but->flag & UI_BUT_SCA_LINK_GREY) || (bt->flag & UI_BUT_SCA_LINK_GREY)) {
ui_add_link_line(&link->lines, but, bt, true);
@@ -1611,7 +1700,7 @@ bool ui_is_but_float(const uiBut *but)
bool ui_is_but_bool(const uiBut *but)
{
- if (ELEM4(but->type, TOG, TOGN, ICONTOG, ICONTOGN))
+ if (ELEM(but->type, TOG, TOGN, ICONTOG, ICONTOGN))
return true;
if (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_BOOLEAN)
@@ -1796,18 +1885,7 @@ void ui_set_but_val(uiBut *but, double value)
value = (char)floor(value + 0.5);
}
else if (but->pointype == UI_BUT_POIN_SHORT) {
- /* gcc 3.2.1 seems to have problems
- * casting a double like 32772.0 to
- * a short so we cast to an int, then
- * to a short.
- *
- * Update: even in gcc.4.6 using intermediate int cast gives -32764,
- * where as a direct cast from double to short gives -32768,
- * if this difference isn't important we could remove this hack,
- * since we dont support gcc3 anymore - Campbell */
- int gcckludge;
- gcckludge = (int) floor(value + 0.5);
- value = (short)gcckludge;
+ value = (short)floor(value + 0.5);
}
else if (but->pointype == UI_BUT_POIN_INT)
value = (int)floor(value + 0.5);
@@ -1835,7 +1913,7 @@ void ui_set_but_val(uiBut *but, double value)
int ui_get_but_string_max_length(uiBut *but)
{
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
return but->hardmax;
else
return UI_MAX_DRAW_STR;
@@ -1861,27 +1939,13 @@ static double ui_get_but_scale_unit(uiBut *but, double value)
UnitSettings *unit = but->block->unit;
int unit_type = uiButGetUnitType(but);
- if (unit_type == PROP_UNIT_LENGTH) {
- return value * (double)unit->scale_length;
- }
- else if (unit_type == PROP_UNIT_CAMERA) {
- return value * (double)unit->scale_length;
- }
- else if (unit_type == PROP_UNIT_AREA) {
- return value * pow(unit->scale_length, 2);
- }
- else if (unit_type == PROP_UNIT_VOLUME) {
- return value * pow(unit->scale_length, 3);
- }
- else if (unit_type == PROP_UNIT_MASS) {
- return value * pow(unit->scale_length, 3);
- }
- else if (unit_type == PROP_UNIT_TIME) { /* WARNING - using evil_C :| */
+ /* Time unit is a bit special, not handled by BKE_scene_unit_scale() for now. */
+ if (unit_type == PROP_UNIT_TIME) { /* WARNING - using evil_C :| */
Scene *scene = CTX_data_scene(but->block->evil_C);
return FRA2TIME(value);
}
else {
- return value;
+ return BKE_scene_unit_scale(unit, RNA_SUBTYPE_UNIT_VALUE(unit_type), value);
}
}
@@ -1893,8 +1957,7 @@ void ui_convert_to_unit_alt_name(uiBut *but, char *str, size_t maxlen)
int unit_type = uiButGetUnitType(but);
char *orig_str;
- orig_str = MEM_callocN(sizeof(char) * maxlen + 1, "textedit sub str");
- memcpy(orig_str, str, maxlen);
+ orig_str = BLI_strdup(str);
bUnit_ToUnitAltName(str, maxlen, orig_str, unit->system, RNA_SUBTYPE_UNIT_VALUE(unit_type));
@@ -1951,7 +2014,7 @@ static float ui_get_but_step_unit(uiBut *but, float step_default)
*/
void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int float_precision)
{
- if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
PropertyType type;
const char *buf = NULL;
int buf_len;
@@ -1984,7 +2047,7 @@ void ui_get_but_string_ex(uiBut *but, char *str, const size_t maxlen, const int
}
else if (buf && buf != str) {
/* string was too long, we have to truncate */
- memcpy(str, buf, MIN2(maxlen, (size_t)buf_len + 1));
+ memcpy(str, buf, MIN2(maxlen, (size_t)(buf_len + 1)));
MEM_freeN((void *)buf);
}
}
@@ -2088,7 +2151,7 @@ bool ui_set_but_string_eval_num(bContext *C, uiBut *but, const char *str, double
bool ui_set_but_string(bContext *C, uiBut *but, const char *str)
{
- if (but->rnaprop && ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (but->rnaprop && ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (RNA_property_editable(&but->rnapoin, but->rnaprop)) {
PropertyType type;
@@ -2430,6 +2493,7 @@ void uiBlockSetRegion(uiBlock *block, ARegion *region)
if (oldblock) {
oldblock->active = 0;
oldblock->panel = NULL;
+ oldblock->handle = NULL;
}
/* at the beginning of the list! for dynamical menus/blocks */
@@ -2739,7 +2803,7 @@ void uiBlockEndAlign(uiBlock *block)
bool ui_but_can_align(uiBut *but)
{
- return !ELEM5(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE);
+ return !ELEM(but->type, LABEL, OPTION, OPTIONN, SEPR, SEPRLINE);
}
static void ui_block_do_align_but(uiBut *first, short nr)
@@ -2994,6 +3058,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
but->lock = block->lock;
but->lockstr = block->lockstr;
but->dt = block->dt;
+ but->pie_dir = UI_RADIAL_NONE;
but->block = block; /* pointer back, used for frontbuffer status, and picker */
@@ -3020,8 +3085,11 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
}
}
- if ((block->flag & UI_BLOCK_LOOP) ||
- ELEM8(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
+ if (block->flag & UI_BLOCK_RADIAL) {
+ but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
+ }
+ else if ((block->flag & UI_BLOCK_LOOP) ||
+ ELEM(but->type, MENU, TEX, LABEL, BLOCK, BUTM, SEARCH_MENU, PROGRESSBAR, SEARCH_MENU_UNLINK))
{
but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT);
}
@@ -3040,7 +3108,7 @@ static uiBut *ui_def_but(uiBlock *block, int type, int retval, const char *str,
}
/* keep track of UI_interface.h */
- if (ELEM11(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {}
+ if (ELEM(but->type, BLOCK, BUT, LABEL, PULLDOWN, ROUNDBOX, LISTBOX, BUTM, SCROLL, SEPR, SEPRLINE, GRIP)) {}
else if (but->type >= SEARCH_MENU) {}
else but->flag |= UI_BUT_UNDO;
@@ -3170,12 +3238,12 @@ static void ui_def_but_rna__menu(bContext *UNUSED(C), uiLayout *layout, void *bu
}
else {
if (item->icon) {
- uiDefIconTextButF(block, BUTM, B_NOP, item->icon, item->name, 0, 0,
- UI_UNIT_X * 5, UI_UNIT_Y, &handle->retvalue, (float) item->value, 0.0, 0, -1, item->description);
+ uiDefIconTextButI(block, BUTM, B_NOP, item->icon, item->name, 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_Y, &handle->retvalue, item->value, 0.0, 0, -1, item->description);
}
else {
- uiDefButF(block, BUTM, B_NOP, item->name, 0, 0,
- UI_UNIT_X * 5, UI_UNIT_X, &handle->retvalue, (float) item->value, 0.0, 0, -1, item->description);
+ uiDefButI(block, BUTM, B_NOP, item->name, 0, 0,
+ UI_UNIT_X * 5, UI_UNIT_X, &handle->retvalue, item->value, 0.0, 0, -1, item->description);
}
}
}
@@ -3205,12 +3273,12 @@ static uiBut *ui_def_but_rna(uiBlock *block, int type, int retval, const char *s
int icon = 0;
uiMenuCreateFunc func = NULL;
- if (ELEM3(type, COLOR, HSVCIRCLE, HSVCUBE)) {
+ if (ELEM(type, COLOR, HSVCIRCLE, HSVCUBE)) {
BLI_assert(index == -1);
}
/* use rna values if parameters are not specified */
- if ((proptype == PROP_ENUM) && ELEM3(type, MENU, ROW, LISTROW)) {
+ if ((proptype == PROP_ENUM) && ELEM(type, MENU, ROW, LISTROW)) {
/* MENU is handled a little differently here */
EnumPropertyItem *item;
int value;
@@ -3783,8 +3851,7 @@ void uiBlockSetDirection(uiBlock *block, char direction)
/* this call escapes if there's alignment flags */
void uiBlockFlipOrder(uiBlock *block)
{
- ListBase lb;
- uiBut *but, *next;
+ uiBut *but;
float centy, miny = 10000, maxy = -10000;
if (U.uiflag & USER_MENUFIXEDORDER)
@@ -3804,17 +3871,6 @@ void uiBlockFlipOrder(uiBlock *block)
but->rect.ymax = centy - (but->rect.ymax - centy);
SWAP(float, but->rect.ymin, but->rect.ymax);
}
-
- /* also flip order in block itself, for example for arrowkey */
- BLI_listbase_clear(&lb);
- but = block->buttons.first;
- while (but) {
- next = but->next;
- BLI_remlink(&block->buttons, but);
- BLI_addtail(&lb, but);
- but = next;
- }
- block->buttons = lb;
}
@@ -4340,7 +4396,7 @@ void uiButGetStrInfo(bContext *C, uiBut *but, ...)
}
tmp = BLI_strdup(_tmp);
}
- else if (ELEM3(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) {
+ else if (ELEM(type, BUT_GET_RNAENUM_IDENTIFIER, BUT_GET_RNAENUM_LABEL, BUT_GET_RNAENUM_TIP)) {
PointerRNA *ptr = NULL;
PropertyRNA *prop = NULL;
int value = 0;
@@ -4430,11 +4486,6 @@ void UI_init_userdef(void)
uiStyleInit();
}
-void UI_init_userdef_factory(void)
-{
- init_userdef_factory();
-}
-
void UI_reinit_font(void)
{
uiStyleInit();
diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c
index f0f08358013..48e54270e95 100644
--- a/source/blender/editors/interface/interface_anim.c
+++ b/source/blender/editors/interface/interface_anim.c
@@ -61,7 +61,7 @@ static FCurve *ui_but_get_fcurve(uiBut *but, bAction **action, bool *r_driven)
* but works well enough in typical cases */
int rnaindex = (but->rnaindex == -1) ? 0 : but->rnaindex;
- return rna_get_fcurve(&but->rnapoin, but->rnaprop, rnaindex, action, r_driven);
+ return rna_get_fcurve_context_ui(but->block->evil_C, &but->rnapoin, but->rnaprop, rnaindex, action, r_driven);
}
void ui_but_anim_flag(uiBut *but, float cfra)
@@ -172,6 +172,9 @@ bool ui_but_anim_expression_create(uiBut *but, const char *str)
/* get path */
path = RNA_path_from_ID_to_property(&but->rnapoin, but->rnaprop);
+ if (path == NULL) {
+ return false;
+ }
/* create driver */
fcu = verify_driver_fcurve(id, path, but->rnaindex, 1);
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index d0f238bc5ba..235d7652539 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -587,7 +587,7 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
int i, c;
float w, w3, h, alpha, yofs;
GLint scissor[4];
- float colors[3][3] = MAT3_UNITY;
+ float colors[3][3];
float colorsycc[3][3] = {{1, 0, 1}, {1, 1, 0}, {0, 1, 1}};
float colors_alpha[3][3], colorsycc_alpha[3][3]; /* colors pre multiplied by alpha for speed up */
float min, max;
@@ -609,6 +609,8 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
/* log scale for alpha */
alpha = scopes->wavefrm_alpha * scopes->wavefrm_alpha;
+ unit_m3(colors);
+
for (c = 0; c < 3; c++) {
for (i = 0; i < 3; i++) {
colors_alpha[c][i] = colors[c][i] * alpha;
@@ -693,11 +695,11 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol),
}
/* RGB / YCC (3 channels) */
- else if (ELEM4(scopes->wavefrm_mode,
- SCOPES_WAVEFRM_RGB,
- SCOPES_WAVEFRM_YCC_601,
- SCOPES_WAVEFRM_YCC_709,
- SCOPES_WAVEFRM_YCC_JPEG))
+ else if (ELEM(scopes->wavefrm_mode,
+ SCOPES_WAVEFRM_RGB,
+ SCOPES_WAVEFRM_YCC_601,
+ SCOPES_WAVEFRM_YCC_709,
+ SCOPES_WAVEFRM_YCC_JPEG))
{
int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB);
@@ -1026,13 +1028,13 @@ static void ui_draw_colorband_handle(
if (active)
glColor3ub(196, 196, 196);
else
- glColor3ub(128, 128, 128);
+ glColor3ub(96, 96, 96);
ui_draw_colorband_handle_tri(x, y1 + height, half_width, half_width, true);
if (active)
glColor3ub(255, 255, 255);
else
- glColor3ub(196, 196, 196);
+ glColor3ub(128, 128, 128);
ui_draw_colorband_handle_tri_hlight(x, y1 + height - 1, (half_width - 1), (half_width - 1));
glColor3ub(0, 0, 0);
@@ -1149,9 +1151,11 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
}
/* layer: active handle */
- cbd = &coba->data[coba->cur];
- pos = x1 + cbd->pos * (sizex - 1) + 1;
- ui_draw_colorband_handle(rect, pos, &cbd->r, display, true);
+ if (coba->tot != 0) {
+ cbd = &coba->data[coba->cur];
+ pos = x1 + cbd->pos * (sizex - 1) + 1;
+ ui_draw_colorband_handle(rect, pos, &cbd->r, display, true);
+ }
}
void ui_draw_but_NORMAL(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
@@ -1324,9 +1328,9 @@ void ui_draw_but_CURVE(ARegion *ar, uiBut *but, uiWidgetColors *wcol, const rcti
float col[3] = {0.0f, 0.0f, 0.0f}; /* dummy arg */
grid.xmin = rect->xmin + zoomx * (-offsx);
- grid.xmax = rect->xmax + zoomx * (-offsx);
+ grid.xmax = grid.xmin + zoomx;
grid.ymin = rect->ymin + zoomy * (-offsy);
- grid.ymax = rect->ymax + zoomy * (-offsy);
+ grid.ymax = grid.ymin + zoomy;
ui_draw_gradient(&grid, col, UI_GRAD_H, 1.0f);
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 2da04ed56f3..a3c52ec3e3c 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -38,6 +38,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_brush_types.h"
#include "DNA_sensor_types.h"
#include "DNA_controller_types.h"
#include "DNA_actuator_types.h"
@@ -60,6 +61,7 @@
#include "PIL_time.h"
#include "BKE_blender.h"
+#include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_idprop.h"
@@ -99,6 +101,8 @@
/* drag popups by their header */
#define USE_DRAG_POPUP
+#define UI_MAX_PASSWORD_STR 128
+
/* proto */
static void ui_add_smart_controller(bContext *C, uiBut *from, uiBut *to);
static void ui_add_link(bContext *C, uiBut *from, uiBut *to);
@@ -114,6 +118,7 @@ static bool ui_mouse_motion_keynav_test(struct uiKeyNavLock *keynav, const wmEve
#define BUTTON_TOOLTIP_DELAY 0.500
#define BUTTON_FLASH_DELAY 0.020
#define MENU_SCROLL_INTERVAL 0.1
+#define PIE_MENU_INTERVAL 0.01
#define BUTTON_AUTO_OPEN_THRESH 0.3
#define BUTTON_MOUSE_TOWARDS_THRESH 1.0
/* pixels to move the cursor to get out of keyboard navigation */
@@ -151,7 +156,7 @@ typedef enum uiHandleButtonState {
* 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 checkign 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)
@@ -383,16 +388,16 @@ void ui_pan_to_scroll(const wmEvent *event, int *type, int *val)
}
}
-static bool ui_but_editable(uiBut *but)
+bool ui_but_is_editable(const uiBut *but)
{
- return ELEM6(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR);
+ return !ELEM(but->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX, PROGRESSBAR);
}
static uiBut *ui_but_prev(uiBut *but)
{
while (but->prev) {
but = but->prev;
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
}
return NULL;
}
@@ -401,7 +406,7 @@ static uiBut *ui_but_next(uiBut *but)
{
while (but->next) {
but = but->next;
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
}
return NULL;
}
@@ -412,7 +417,7 @@ static uiBut *ui_but_first(uiBlock *block)
but = block->buttons.first;
while (but) {
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
but = but->next;
}
return NULL;
@@ -424,7 +429,7 @@ static uiBut *ui_but_last(uiBlock *block)
but = block->buttons.last;
while (but) {
- if (!ui_but_editable(but)) return but;
+ if (ui_but_is_editable(but)) return but;
but = but->prev;
}
return NULL;
@@ -433,7 +438,7 @@ static uiBut *ui_but_last(uiBlock *block)
static bool ui_is_a_warp_but(uiBut *but)
{
if (U.uiflag & USER_CONTINUOUS_MOUSE) {
- if (ELEM6(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) {
+ if (ELEM(but->type, NUM, NUMSLI, HSVCIRCLE, TRACKPREVIEW, HSVCUBE, BUT_CURVE)) {
return true;
}
}
@@ -463,7 +468,7 @@ bool ui_is_but_utf8(const uiBut *but)
{
if (but->rnaprop) {
const int subtype = RNA_property_subtype(but->rnaprop);
- return !(ELEM4(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING));
+ return !(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME, PROP_BYTESTRING));
}
else {
return !(but->flag & UI_BUT_NO_UTF8);
@@ -599,7 +604,13 @@ static void ui_apply_autokey(bContext *C, uiBut *but)
/* make a little report about what we've done! */
if (but->rnaprop) {
- char *buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
+ char *buf;
+
+ if (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD) {
+ return;
+ }
+
+ buf = WM_prop_pystring_assign(C, &but->rnapoin, but->rnaprop, but->rnaindex);
if (buf) {
BKE_report(CTX_wm_reports(C), RPT_PROPERTY, buf);
MEM_freeN(buf);
@@ -633,7 +644,7 @@ static void ui_apply_but_funcs_after(bContext *C)
}
if (after.optype)
- WM_operator_name_call(C, after.optype->idname, after.opcontext, (after.opptr) ? &opptr : NULL);
+ WM_operator_name_call_ptr(C, after.optype, after.opcontext, (after.opptr) ? &opptr : NULL);
if (after.opptr)
WM_operator_properties_free(&opptr);
@@ -717,7 +728,7 @@ static void ui_apply_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data)
if (value == 0.0) push = 1;
else push = 0;
- if (ELEM3(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push;
+ if (ELEM(but->type, TOGN, ICONTOGN, OPTIONN)) push = !push;
ui_set_but_val(but, (double)push);
if (but->type == ICONTOG || but->type == ICONTOGN) ui_check_but(but);
}
@@ -986,6 +997,9 @@ static void ui_multibut_states_apply(bContext *C, uiHandleButtonData *data, uiBl
else {
but->active->value = mbut_state->origvalue + value_delta;
}
+
+ /* clamp based on soft limits, see: T40154 */
+ CLAMP(but->active->value, (double)but->softmin, (double)but->softmax);
}
ui_button_execute_end(C, ar, but, active_back);
}
@@ -1186,7 +1200,7 @@ static bool ui_but_mouse_inside_icon(uiBut *but, ARegion *ar, const wmEvent *eve
BLI_rcti_rctf_copy(&rect, &but->rect);
- if (but->imb) {
+ if (but->imb || but->type == COLOR) {
/* use button size itself */
}
else if (but->drawflag & UI_BUT_ICON_LEFT) {
@@ -1233,16 +1247,48 @@ static bool ui_but_start_drag(bContext *C, uiBut *but, uiHandleButtonData *data,
WM_event_add_ui_handler(C, &data->window->modalhandlers,
ui_handler_region_drag_toggle,
ui_handler_region_drag_toggle_remove,
- drag_info);
+ drag_info, false);
CTX_wm_region_set(C, ar_prev);
}
else
#endif
- {
+ if (but->type == COLOR) {
+ bool valid = false;
+ uiDragColorHandle *drag_info = MEM_callocN(sizeof(*drag_info), __func__);
+
+ /* TODO support more button pointer types */
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color);
+ drag_info->gamma_corrected = true;
+ valid = true;
+ }
+ else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, drag_info->color);
+ drag_info->gamma_corrected = false;
+ valid = true;
+ }
+ else if (but->pointype == UI_BUT_POIN_FLOAT) {
+ copy_v3_v3(drag_info->color, (float *)but->poin);
+ valid = true;
+ }
+ else if (but->pointype == UI_BUT_POIN_CHAR) {
+ rgb_uchar_to_float(drag_info->color, (unsigned char *)but->poin);
+ valid = true;
+ }
+
+ if (valid) {
+ WM_event_start_drag(C, ICON_COLOR, WM_DRAG_COLOR, drag_info, 0.0, WM_DRAG_FREE_DATA);
+ }
+ else {
+ MEM_freeN(drag_info);
+ return false;
+ }
+ }
+ else {
wmDrag *drag;
- drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but));
+ drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_get_but_val(but), WM_DRAG_NOP);
if (but->imb)
WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect));
}
@@ -1652,7 +1698,7 @@ 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 (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
ID *id = (ID *)wmd->poin;
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
@@ -1799,7 +1845,7 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
}
/* text/string and ID data */
- else if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ else if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
uiHandleButtonData *active_data = but->active;
if (but->poin == NULL && but->rnapoin.data == NULL) {
@@ -1908,28 +1954,35 @@ static void ui_but_copy_paste(bContext *C, uiBut *but, uiHandleButtonData *data,
static int ui_text_position_from_hidden(uiBut *but, int pos)
{
- const char *strpos;
+ const char *strpos, *butstr;
int i;
- for (i = 0, strpos = but->drawstr; i < pos; i++)
+ butstr = (but->editstr) ? but->editstr : but->drawstr;
+
+ for (i = 0, strpos = butstr; i < pos; i++)
strpos = BLI_str_find_next_char_utf8(strpos, NULL);
- return (strpos - but->drawstr);
+ return (strpos - butstr);
}
static int ui_text_position_to_hidden(uiBut *but, int pos)
{
- return BLI_strnlen_utf8(but->drawstr, pos);
+ const char *butstr = (but->editstr) ? but->editstr : but->drawstr;
+ return BLI_strnlen_utf8(butstr, pos);
}
-void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore)
+void ui_button_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *but, const bool restore)
{
+ char *butstr;
+
if (!(but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_PASSWORD))
return;
+ butstr = (but->editstr) ? but->editstr : but->drawstr;
+
if (restore) {
/* restore original string */
- BLI_strncpy(but->drawstr, password_str, UI_MAX_DRAW_STR);
+ BLI_strncpy(butstr, password_str, UI_MAX_PASSWORD_STR);
/* remap cursor positions */
if (but->pos >= 0) {
@@ -1939,8 +1992,8 @@ void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but
}
}
else {
- /* convert text to hidden test using asterisks (e.g. pass -> ****) */
- const size_t len = BLI_strlen_utf8(but->drawstr);
+ /* convert text to hidden text using asterisks (e.g. pass -> ****) */
+ const size_t len = BLI_strlen_utf8(butstr);
/* remap cursor positions */
if (but->pos >= 0) {
@@ -1950,10 +2003,9 @@ void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but
}
/* save original string */
- BLI_strncpy(password_str, but->drawstr, UI_MAX_DRAW_STR);
-
- memset(but->drawstr, '*', len);
- but->drawstr[len] = '\0';
+ BLI_strncpy(password_str, butstr, UI_MAX_PASSWORD_STR);
+ memset(butstr, '*', len);
+ butstr[len] = '\0';
}
}
@@ -1989,7 +2041,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
float startx = but->rect.xmin;
float starty_dummy = 0.0f;
- char *origstr, password_str[UI_MAX_DRAW_STR];
+ char *origstr, password_str[UI_MAX_PASSWORD_STR];
ui_block_to_window_fl(data->region, but->block, &startx, &starty_dummy);
@@ -2006,7 +2058,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
BLI_strncpy(origstr, but->editstr, data->maxlen);
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (but->flag & UI_HAS_ICON) {
startx += UI_DPI_ICON_SIZE / aspect;
}
@@ -2369,6 +2421,18 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
data->str = NULL;
}
+#ifdef USE_DRAG_MULTINUM
+ /* this can happen from multi-drag */
+ if (data->applied_interactive) {
+ /* remove any small changes so canceling edit doesn't restore invalid value: T40538 */
+ data->cancel = true;
+ ui_apply_button(C, but->block, but, data, true);
+ data->cancel = false;
+
+ data->applied_interactive = false;
+ }
+#endif
+
/* retrieve string */
data->maxlen = ui_get_but_string_max_length(but);
data->str = MEM_callocN(sizeof(char) * data->maxlen + 1, "textedit str");
@@ -2389,11 +2453,6 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data)
data->selextend = 0;
data->selstartx = 0.0f;
-#ifdef USE_DRAG_MULTINUM
- /* this can happen from multi-drag */
- data->applied_interactive = false;
-#endif
-
/* set cursor pos to the end of the text */
but->editstr = data->str;
but->pos = len;
@@ -2432,6 +2491,9 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data)
(ui_searchbox_find_index(data->searchbox, but->editstr) == -1))
{
data->cancel = true;
+
+ /* ensure menu (popup) too is closed! */
+ data->escapecancel = true;
}
}
@@ -2451,11 +2513,11 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
uiBut *but;
/* label and roundbox can overlap real buttons (backdrops...) */
- if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
+ if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
return;
for (but = actbut->next; but; but = but->next) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2464,7 +2526,7 @@ static void ui_textedit_next_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
}
for (but = block->buttons.first; but != actbut; but = but->next) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2479,11 +2541,11 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
uiBut *but;
/* label and roundbox can overlap real buttons (backdrops...) */
- if (ELEM5(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
+ if (ELEM(actbut->type, LABEL, SEPR, SEPRLINE, ROUNDBOX, LISTBOX))
return;
for (but = actbut->prev; but; but = but->prev) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2492,7 +2554,7 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa
}
}
for (but = block->buttons.last; but != actbut; but = but->prev) {
- if (ELEM5(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, NUM, NUMSLI, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
if (!(but->flag & UI_BUT_DISABLED)) {
data->postbut = but;
data->posttype = BUTTON_ACTIVATE_TEXT_EDITING;
@@ -2793,7 +2855,7 @@ static void ui_numedit_begin(uiBut *but, uiHandleButtonData *data)
data->coba = (ColorBand *)but->poin;
but->editcoba = data->coba;
}
- else if (ELEM4(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) {
+ else if (ELEM(but->type, BUT_NORMAL, HSVCUBE, HSVCIRCLE, COLOR)) {
ui_get_but_vectorf(but, data->origvec);
copy_v3_v3(data->vec, data->origvec);
but->editvec = data->vec;
@@ -2980,7 +3042,7 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons
static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
but->drawstr[0] = 0;
but->modifier_key = 0;
button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
@@ -3043,14 +3105,15 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data
static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_WAIT_KEY_EVENT);
return WM_UI_HANDLER_BREAK;
}
}
else if (data->state == BUTTON_STATE_WAIT_KEY_EVENT) {
- if (event->type == MOUSEMOVE)
+ if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
return WM_UI_HANDLER_CONTINUE;
+ }
if (event->val == KM_PRESS) {
if (WM_key_event_string(event->type)[0])
@@ -3068,7 +3131,7 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c
static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) {
if (ELEM(event->type, PADENTER, RETKEY) && (!ui_is_but_utf8(but))) {
/* pass - allow filesel, enter to execute */
}
@@ -3096,7 +3159,7 @@ 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)
{
/* unlink icon is on right */
- if (ELEM4(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS &&
+ if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS &&
ui_is_but_search_unlink_visible(but))
{
ARegion *ar = data->region;
@@ -3146,7 +3209,7 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
}
#endif
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
#if 0 /* UNUSED */
data->togdual = event->ctrl;
data->togonly = !event->shift;
@@ -3184,7 +3247,7 @@ static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, con
}
#endif
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
int ret = WM_UI_HANDLER_BREAK;
/* XXX (a bit ugly) Special case handling for filebrowser drag button */
if (but->dragpoin && but->imb && ui_but_mouse_inside_icon(but, data->region, event)) {
@@ -3233,7 +3296,7 @@ static float ui_numedit_apply_snapf(uiBut *but, float tempf, float softmin, floa
if (bUnit_IsValid(unit->system, unit_type)) {
fac = (float)bUnit_BaseScalar(unit->system, unit_type);
- if (ELEM3(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) {
+ if (ELEM(unit_type, B_UNIT_LENGTH, B_UNIT_AREA, B_UNIT_VOLUME)) {
fac /= unit->scale_length;
}
}
@@ -3305,6 +3368,11 @@ static bool ui_numedit_but_NUM(uiBut *but, uiHandleButtonData *data,
if (data->draglock) {
if (abs(mx - data->dragstartx) <= 3)
return changed;
+#ifdef USE_DRAG_MULTINUM
+ if (ELEM(data->multi_data.init, BUTTON_MULTI_INIT_UNSET, BUTTON_MULTI_INIT_SETUP)) {
+ return changed;
+ }
+#endif
data->draglock = false;
data->dragstartx = mx; /* ignore mouse movement within drag-lock */
@@ -3463,7 +3531,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 1;
}
else if (event->val == KM_PRESS) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
@@ -3752,7 +3820,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 2;
}
else if (event->val == KM_PRESS) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->ctrl) {
button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING);
retval = WM_UI_HANDLER_BREAK;
}
@@ -4009,7 +4077,7 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data,
/* hack to pass on ctrl+click and double click to overlapping text
* editing field for editing list item names
*/
- if ((ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) ||
+ if ((ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS && event->ctrl) ||
(event->type == LEFTMOUSE && event->val == KM_DBL_CLICK))
{
uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_TEXT_EDITING);
@@ -4038,7 +4106,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
}
#ifdef USE_DRAG_TOGGLE
- if (event->type == LEFTMOUSE && ui_is_but_drag_toggle(but)) {
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS && (ui_is_but_drag_toggle(but))) {
button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
data->dragstartx = event->x;
data->dragstarty = event->y;
@@ -4046,7 +4114,7 @@ static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, co
}
#endif
/* regular open menu */
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
@@ -4188,14 +4256,44 @@ static bool ui_numedit_but_NORMAL(uiBut *but, uiHandleButtonData *data,
return changed;
}
+static void ui_palette_set_active(uiBut *but)
+{
+ if ((int)(but->a1) == UI_PALETTE_COLOR) {
+ Palette *palette = but->rnapoin.id.data;
+ PaletteColor *color = but->rnapoin.data;
+ palette->active_color = BLI_findindex(&palette->colors, color);
+ }
+}
+
static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
{
if (data->state == BUTTON_STATE_HIGHLIGHT) {
- if (ELEM3(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ /* first handle click on icondrag type button */
+ if (event->type == LEFTMOUSE && but->dragpoin && event->val == KM_PRESS) {
+ ui_palette_set_active(but);
+ if (ui_but_mouse_inside_icon(but, data->region, event)) {
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->x;
+ data->dragstarty = event->y;
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+#ifdef USE_DRAG_TOGGLE
+ if (event->type == LEFTMOUSE && event->val == KM_PRESS) {
+ ui_palette_set_active(but);
+ button_activate_state(C, but, BUTTON_STATE_WAIT_DRAG);
+ data->dragstartx = event->x;
+ data->dragstarty = event->y;
+ return WM_UI_HANDLER_BREAK;
+ }
+#endif
+ /* regular open menu */
+ if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) {
+ ui_palette_set_active(but);
button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
return WM_UI_HANDLER_BREAK;
}
- else if (ELEM3(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ else if (ELEM(event->type, MOUSEPAN, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
float *hsv = ui_block_hsv_get(but->block);
float col[3];
@@ -4218,6 +4316,75 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co
ui_apply_button(C, but->block, but, data, true);
return WM_UI_HANDLER_BREAK;
}
+ else if ((int)(but->a1) == UI_PALETTE_COLOR &&
+ event->type == DELKEY && event->val == KM_PRESS)
+ {
+ Palette *palette = but->rnapoin.id.data;
+ PaletteColor *color = but->rnapoin.data;
+
+ BKE_palette_color_remove(palette, color);
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
+ else if (data->state == BUTTON_STATE_WAIT_DRAG) {
+
+ /* this function also ends state */
+ if (ui_but_start_drag(C, but, data, event)) {
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ /* outside icon quit, not needed if drag activated */
+ if (0 == ui_but_mouse_inside_icon(but, data->region, event)) {
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ data->cancel = true;
+ return WM_UI_HANDLER_BREAK;
+ }
+
+ if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
+ if ((int)(but->a1) == UI_PALETTE_COLOR) {
+ if (!event->ctrl) {
+ float color[3];
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active(scene);
+ Brush *brush = BKE_paint_brush(paint);
+
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ float *target = &brush->gradient->data[brush->gradient->cur].r;
+
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
+ ui_block_to_scene_linear_v3(but->block, target);
+ }
+ else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, target);
+ }
+ }
+ else {
+ if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
+ BKE_brush_color_set(scene, brush, color);
+ }
+ else if (but->rnaprop && RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ RNA_property_float_get_array(&but->rnapoin, but->rnaprop, color);
+ ui_block_to_display_space_v3(but->block, color);
+ BKE_brush_color_set(scene, brush, color);
+ }
+ }
+
+ button_activate_state(C, but, BUTTON_STATE_EXIT);
+ }
+ else {
+ button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
+ }
+ }
+ else {
+ button_activate_state(C, but, BUTTON_STATE_MENU_OPEN);
+ }
+ return WM_UI_HANDLER_BREAK;
+ }
+
}
return WM_UI_HANDLER_CONTINUE;
@@ -4397,7 +4564,7 @@ static bool ui_numedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
}
if (snap != SNAP_OFF) {
- if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
+ if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
ui_color_snap_hue(snap, &hsv[0]);
}
}
@@ -4474,7 +4641,7 @@ static void ui_ndofedit_but_HSVCUBE(uiBut *but, uiHandleButtonData *data,
}
if (snap != SNAP_OFF) {
- if (ELEM3((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
+ if (ELEM((int)but->a1, UI_GRAD_HV, UI_GRAD_HS, UI_GRAD_H)) {
ui_color_snap_hue(snap, &hsv[0]);
}
}
@@ -4863,6 +5030,9 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m
if (data->draglastx == mx)
return changed;
+ if (data->coba->tot == 0)
+ return changed;
+
dx = ((float)(mx - data->draglastx)) / BLI_rctf_size_x(&but->rect);
data->dragcbd->pos += dx;
CLAMP(data->dragcbd->pos, 0.0f, 1.0f);
@@ -5501,7 +5671,6 @@ static uiBlock *menu_change_shortcut(bContext *C, ARegion *ar, void *arg)
uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
uiPopupBoundsBlock(block, 6, -50, 26);
- uiEndBlock(C, block);
return block;
}
@@ -5546,11 +5715,22 @@ static uiBlock *menu_add_shortcut(bContext *C, ARegion *ar, void *arg)
uiItemR(layout, &ptr, "type", UI_ITEM_R_FULL_EVENT | UI_ITEM_R_IMMEDIATE, "", ICON_NONE);
uiPopupBoundsBlock(block, 6, -50, 26);
- uiEndBlock(C, block);
return block;
}
+static void menu_add_shortcut_cancel(struct bContext *C, void *arg1)
+{
+ uiBut *but = (uiBut *)arg1;
+ wmKeyMap *km;
+ wmKeyMapItem *kmi;
+ IDProperty *prop = (but->opptr) ? but->opptr->data : NULL;
+ int kmi_id = WM_key_event_operator_id(C, but->optype->idname, but->opcontext, prop, true, &km);
+
+ kmi = WM_keymap_item_find_id(km, kmi_id);
+ WM_keymap_remove_item(km, kmi);
+}
+
static void popup_change_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
@@ -5576,7 +5756,7 @@ static void popup_add_shortcut_func(bContext *C, void *arg1, void *UNUSED(arg2))
{
uiBut *but = (uiBut *)arg1;
button_timers_tooltip_remove(C, but);
- uiPupBlock(C, menu_add_shortcut, but);
+ uiPupBlockEx(C, menu_add_shortcut, NULL, menu_add_shortcut_cancel, but);
}
/**
@@ -5987,7 +6167,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle drivers */
else if ((event->type == DKEY) &&
- !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6001,7 +6181,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle keyingsets */
else if ((event->type == KKEY) &&
- !ELEM3(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6225,7 +6405,34 @@ static bool ui_but_contains_pt(uiBut *but, float mx, float my)
return BLI_rctf_isect_pt(&but->rect, mx, my);
}
-static uiBut *ui_but_find_activated(ARegion *ar)
+void ui_but_pie_dir(RadialDirection dir, float vec[2])
+{
+ float angle;
+
+ BLI_assert(dir != UI_RADIAL_NONE);
+
+ angle = DEG2RADF((float)ui_radial_dir_to_angle[dir]);
+ vec[0] = cosf(angle);
+ vec[1] = sinf(angle);
+}
+
+static bool ui_but_isect_pie_seg(uiBlock *block, uiBut *but)
+{
+ const float angle_range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_4 : M_PI_4 / 2.0;
+ float vec[2];
+
+ if (block->pie_data.flags & UI_PIE_INVALID_DIR)
+ return false;
+
+ ui_but_pie_dir(but->pie_dir, vec);
+
+ if (saacos(dot_v2v2(vec, block->pie_data.pie_dir)) < angle_range)
+ return true;
+
+ return false;
+}
+
+uiBut *ui_but_find_activated(ARegion *ar)
{
uiBlock *block;
uiBut *but;
@@ -6273,13 +6480,27 @@ bool UI_but_active_drop_name(bContext *C)
uiBut *but = ui_but_find_activated(ar);
if (but) {
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK))
return 1;
}
return 0;
}
+bool UI_but_active_drop_color(bContext *C)
+{
+ ARegion *ar = CTX_wm_region(C);
+
+ if (ar) {
+ uiBut *but = ui_but_find_activated(ar);
+
+ if (but && but->type == COLOR)
+ return true;
+ }
+
+ return false;
+}
+
static void ui_blocks_set_tooltips(ARegion *ar, const bool enable)
{
uiBlock *block;
@@ -6329,6 +6550,7 @@ static bool ui_mouse_inside_region(ARegion *ar, int x, int y)
static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
{
+ uiBlock *block = but->block;
float mx, my;
if (!ui_mouse_inside_region(ar, x, y))
return false;
@@ -6336,10 +6558,16 @@ static bool ui_mouse_inside_button(ARegion *ar, uiBut *but, int x, int y)
mx = x;
my = y;
- ui_window_to_block_fl(ar, but->block, &mx, &my);
+ ui_window_to_block_fl(ar, block, &mx, &my);
- if (!ui_but_contains_pt(but, mx, my))
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ if (!ui_but_isect_pie_seg(block, but)) {
+ return false;
+ }
+ }
+ else if (!ui_but_contains_pt(but, mx, my)) {
return false;
+ }
return true;
}
@@ -6353,7 +6581,7 @@ static bool ui_is_but_interactive(const uiBut *but, const bool labeledit)
/* note, LABEL is included for highlights, this allows drags */
if ((but->type == LABEL) && but->dragpoin == NULL)
return false;
- if (ELEM4(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX))
+ if (ELEM(but->type, ROUNDBOX, SEPR, SEPRLINE, LISTBOX))
return false;
if (but->flag & UI_HIDDEN)
return false;
@@ -6393,7 +6621,13 @@ static uiBut *ui_but_find_mouse_over_ex(ARegion *ar, const int x, const int y, c
for (but = block->buttons.last; but; but = but->prev) {
if (ui_is_but_interactive(but, labeledit)) {
- if (ui_but_contains_pt(but, mx, my)) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ if (ui_but_isect_pie_seg(block, but)) {
+ butover = but;
+ break;
+ }
+ }
+ else if (ui_but_contains_pt(but, mx, my)) {
butover = but;
break;
}
@@ -6446,9 +6680,13 @@ static uiBut *ui_list_find_mouse_over(ARegion *ar, int x, int y)
static bool button_modal_state(uiHandleButtonState state)
{
- return ELEM6(state, BUTTON_STATE_WAIT_RELEASE, BUTTON_STATE_WAIT_KEY_EVENT,
- BUTTON_STATE_NUM_EDITING, BUTTON_STATE_TEXT_EDITING,
- BUTTON_STATE_TEXT_SELECTING, BUTTON_STATE_MENU_OPEN);
+ return ELEM(state,
+ BUTTON_STATE_WAIT_RELEASE,
+ BUTTON_STATE_WAIT_KEY_EVENT,
+ BUTTON_STATE_NUM_EDITING,
+ BUTTON_STATE_TEXT_EDITING,
+ BUTTON_STATE_TEXT_SELECTING,
+ BUTTON_STATE_MENU_OPEN);
}
static void button_timers_tooltip_remove(bContext *C, uiBut *but)
@@ -6486,10 +6724,13 @@ static void button_tooltip_timer_reset(bContext *C, uiBut *but)
data->tooltiptimer = NULL;
}
- if (U.flag & USER_TOOLTIPS)
- if (!but->block->tooltipdisabled)
- if (!wm->drags.first)
+ if ((U.flag & USER_TOOLTIPS) || (but->flag & UI_BUT_TIP_FORCE)) {
+ if (!but->block->tooltipdisabled) {
+ if (!wm->drags.first) {
data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, BUTTON_TOOLTIP_DELAY);
+ }
+ }
+ }
}
static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState state)
@@ -6594,7 +6835,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);
+ WM_event_add_ui_handler(C, &data->window->modalhandlers, ui_handler_region_menu, NULL, data, false);
}
else {
if (button_modal_state(data->state)) {
@@ -6639,7 +6880,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
copy_v2_fl(data->ungrab_mval, FLT_MAX);
#endif
- if (ELEM3(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, BUT_CURVE, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
/* XXX curve is temp */
}
else {
@@ -6695,7 +6936,7 @@ static void button_activate_init(bContext *C, ARegion *ar, uiBut *but, uiButtonA
if (but->type == GRIP) {
const bool horizontal = (BLI_rctf_size_x(&but->rect) < BLI_rctf_size_y(&but->rect));
- WM_cursor_modal_set(data->window, horizontal ? BC_EW_ARROWCURSOR : BC_NS_ARROWCURSOR);
+ WM_cursor_modal_set(data->window, horizontal ? CURSOR_X_MOVE : CURSOR_Y_MOVE);
}
}
@@ -6891,7 +7132,7 @@ void uiContextActivePropertyHandle(bContext *C)
* operator redo panel - campbell */
uiBlock *block = activebut->block;
if (block->handle_func) {
- block->handle_func(C, block->handle_func_arg, 0);
+ block->handle_func(C, block->handle_func_arg, activebut->retval);
}
}
}
@@ -6998,6 +7239,13 @@ static int ui_handle_button_over(bContext *C, const wmEvent *event, ARegion *ar)
if (event->type == MOUSEMOVE) {
but = ui_but_find_mouse_over(ar, event);
if (but) {
+ if (event->alt) {
+ /* display tooltips if holding alt on mouseover when tooltips are off in prefs */
+ but->flag |= UI_BUT_TIP_FORCE;
+ }
+ else {
+ but->flag &= ~UI_BUT_TIP_FORCE;
+ }
button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
}
}
@@ -7029,9 +7277,20 @@ void ui_button_activate_do(bContext *C, ARegion *ar, uiBut *but)
ui_do_button(C, but->block, but, &event);
}
+/**
+ * Simulate moving the mouse over a button (or navigating to it with arrow keys).
+ *
+ * exported so menus can start with a highlighted button,
+ * even if the mouse isnt over it
+ */
+void ui_button_activate_over(bContext *C, ARegion *ar, uiBut *but)
+{
+ button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
+}
+
void ui_button_execute_begin(struct bContext *UNUSED(C), struct ARegion *ar, uiBut *but, void **active_back)
{
- /* note: ideally we would not have to change 'but->active' howevwer
+ /* note: ideally we would not have to change 'but->active' however
* some functions we call don't use data (as they should be doing) */
uiHandleButtonData *data;
*active_back = but->active;
@@ -7091,12 +7350,20 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
retval = WM_UI_HANDLER_CONTINUE;
break;
case MOUSEMOVE:
- /* verify if we are still over the button, if not exit */
- if (!ui_mouse_inside_button(ar, but, event->x, event->y)) {
- data->cancel = true;
- button_activate_state(C, but, BUTTON_STATE_EXIT);
+ {
+ 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)) &&
+ !ui_mouse_inside_button(ar, but, event->x, event->y))
+ {
+ exit = true;
+ }
+ else if (but_other && ui_but_is_editable(but_other) && (but_other != but)) {
+ exit = true;
}
- else if (ui_but_find_mouse_over(ar, event) != but) {
+
+ if (exit) {
data->cancel = true;
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
@@ -7107,6 +7374,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
}
break;
+ }
case TIMER:
{
/* handle tooltip timer */
@@ -7690,6 +7958,25 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
int retval;
if (but) {
+ /* Its possible there is an active menu item NOT under the mouse,
+ * in this case ignore mouse clicks outside the button (but Enter etc is accepted) */
+ if (event->val == KM_RELEASE) {
+ /* pass, needed so we can exit active menu-items when click-dragging out of them */
+ }
+ else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) {
+ /* pass, skip for dialogs */
+ }
+ else if (!ui_mouse_inside_region(but->active->region, event->x, event->y)) {
+ /* pass, needed to click-exit outside of non-flaoting menus */
+ }
+ else if ((!ELEM(event->type, MOUSEMOVE, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN)) && ISMOUSE(event->type)) {
+ if (!ui_mouse_inside_button(but->active->region, but, event->x, event->y)) {
+ but = NULL;
+ }
+ }
+ }
+
+ if (but) {
ScrArea *ctx_area = CTX_wm_area(C);
ARegion *ctx_region = CTX_wm_region(C);
@@ -7708,6 +7995,32 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock
return retval;
}
+float ui_block_calculate_pie_segment(uiBlock *block, const float event_xy[2])
+{
+ float seg1[2];
+ float seg2[2];
+ float len;
+
+ if (block->pie_data.flags & UI_PIE_INITIAL_DIRECTION) {
+ copy_v2_v2(seg1, block->pie_data.pie_center_init);
+ }
+ else {
+ copy_v2_v2(seg1, block->pie_data.pie_center_spawned);
+ }
+
+ sub_v2_v2v2(seg2, event_xy, seg1);
+
+ len = normalize_v2_v2(block->pie_data.pie_dir, seg2);
+
+ /* ten pixels for now, a bit arbitrary */
+ if (len < U.pie_menu_threshold * U.pixelsize)
+ block->pie_data.flags |= UI_PIE_INVALID_DIR;
+ else
+ block->pie_data.flags &= ~UI_PIE_INVALID_DIR;
+
+ return len;
+}
+
static int ui_handle_menu_event(
bContext *C, const wmEvent *event, uiPopupBlockHandle *menu,
int level, const bool is_parent_inside, const bool is_parent_menu, const bool is_floating)
@@ -7739,6 +8052,7 @@ static int ui_handle_menu_event(
if (menu->is_grab) {
if (event->type == LEFTMOUSE) {
menu->is_grab = false;
+ retval = WM_UI_HANDLER_BREAK;
}
else {
if (event->type == MOUSEMOVE) {
@@ -7747,6 +8061,8 @@ static int ui_handle_menu_event(
sub_v2_v2v2_int(mdiff, &event->x, menu->grab_xy_prev);
copy_v2_v2_int(menu->grab_xy_prev, &event->x);
+ add_v2_v2v2_int(menu->popup_create_vars.event_xy, menu->popup_create_vars.event_xy, mdiff);
+
ui_popup_translate(C, ar, mdiff);
}
@@ -7941,7 +8257,7 @@ static int ui_handle_menu_event(
for (but = block->buttons.first; but; but = but->next) {
bool doit = false;
- if (!ELEM3(but->type, LABEL, SEPR, SEPRLINE))
+ if (!ELEM(but->type, LABEL, SEPR, SEPRLINE))
count++;
/* exception for rna layer buts */
@@ -8052,7 +8368,7 @@ static int ui_handle_menu_event(
if (inside == 0) {
uiSafetyRct *saferct = block->saferct.first;
- if (ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) &&
+ if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) &&
ELEM(event->val, KM_PRESS, KM_DBL_CLICK))
{
if ((is_parent_menu == false) && (U.uiflag & USER_MENUOPENAUTO) == 0) {
@@ -8094,9 +8410,14 @@ static int ui_handle_menu_event(
else if ((event->type == LEFTMOUSE) && (event->val == KM_PRESS) &&
(inside && is_floating && inside_title))
{
- if (!ui_but_find_activated(ar)) {
+ if (!but || !ui_mouse_inside_button(ar, but, event->x, event->y)) {
+ if (but) {
+ button_timers_tooltip_remove(C, but);
+ }
+
menu->is_grab = true;
copy_v2_v2_int(menu->grab_xy_prev, &event->x);
+ retval = WM_UI_HANDLER_BREAK;
}
}
#endif
@@ -8201,10 +8522,336 @@ static int ui_handle_menu_return_submenu(bContext *C, const wmEvent *event, uiPo
ui_mouse_motion_towards_reinit(menu, &event->x);
}
- if (menu->menuretval)
+ if (menu->menuretval) {
return WM_UI_HANDLER_CONTINUE;
- else
+ }
+ else {
+ return WM_UI_HANDLER_BREAK;
+ }
+}
+
+static bool ui_but_pie_menu_supported_apply(uiBut *but)
+{
+ return (!ELEM(but->type, NUMSLI, NUM));
+}
+
+static int ui_but_pie_menu_apply(bContext *C, uiPopupBlockHandle *menu, uiBut *but, bool force_close)
+{
+ int retval = WM_UI_HANDLER_BREAK;
+
+ if (but && ui_but_pie_menu_supported_apply(but)) {
+ if (but->type == MENU) {
+ /* forcing the pie menu to close will not handle menus */
+ if (!force_close) {
+ uiBut *active_but = ui_but_find_activated(menu->region);
+
+ if (active_but) {
+ button_activate_exit(C, active_but, active_but->active, false, false);
+ }
+
+ button_activate_init(C, menu->region, but, BUTTON_ACTIVATE_OPEN);
+ return retval;
+ }
+ else {
+ menu->menuretval = UI_RETURN_CANCEL;
+ }
+ }
+ else {
+ ui_apply_button(C, but->block, but, but->active, false);
+ button_activate_exit((bContext *)C, but, but->active, false, true);
+
+ menu->menuretval = UI_RETURN_OK;
+ }
+ }
+ else {
+ menu->menuretval = UI_RETURN_CANCEL;
+
+ ED_region_tag_redraw(menu->region);
+ }
+
+ return retval;
+}
+
+static uiBut *ui_block_pie_dir_activate(uiBlock *block, const wmEvent *event, RadialDirection dir)
+{
+ uiBut *but;
+
+ if ((block->flag & UI_BLOCK_NUMSELECT) && event->val == KM_PRESS) {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->pie_dir == dir && !ELEM(but->type, SEPR, SEPRLINE)) {
+ return but;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+static int ui_but_pie_button_activate(bContext *C, uiBut *but, uiPopupBlockHandle *menu)
+{
+ uiBut *active_but;
+
+ if (but == NULL)
return WM_UI_HANDLER_BREAK;
+
+ active_but = ui_but_find_activated(menu->region);
+
+ if (active_but)
+ button_activate_exit(C, active_but, active_but->active, false, false);
+
+ button_activate_init(C, menu->region, but, BUTTON_ACTIVATE_OVER);
+ return ui_but_pie_menu_apply(C, menu, but, false);
+}
+
+static int ui_handler_pie(bContext *C, const wmEvent *event, uiPopupBlockHandle *menu)
+{
+ ARegion *ar;
+ uiBlock *block;
+ uiBut *but;
+ float event_xy[2];
+ double duration;
+ bool is_click_style;
+ float dist;
+
+ /* we block all events, this is modal interaction, except for drop events which is described below */
+ int retval = WM_UI_HANDLER_BREAK;
+
+ if (event->type == EVT_DROP) {
+ /* may want to leave this here for later if we support pie ovens */
+
+ retval = WM_UI_HANDLER_CONTINUE;
+ }
+
+ ar = menu->region;
+ block = ar->uiblocks.first;
+
+ is_click_style = (block->pie_data.flags & UI_PIE_CLICK_STYLE);
+
+ if (menu->scrolltimer == NULL) {
+ menu->scrolltimer =
+ WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, PIE_MENU_INTERVAL);
+ menu->scrolltimer->duration = 0.0;
+ }
+
+ duration = menu->scrolltimer->duration;
+
+ event_xy[0] = event->x;
+ event_xy[1] = event->y;
+
+ ui_window_to_block_fl(ar, block, &event_xy[0], &event_xy[1]);
+
+ dist = ui_block_calculate_pie_segment(block, event_xy);
+
+ if (event->type == TIMER) {
+ if (event->customdata == menu->scrolltimer) {
+ /* deactivate initial direction after a while */
+ if (duration > 0.01 * U.pie_initial_timeout) {
+ block->pie_data.flags &= ~UI_PIE_INITIAL_DIRECTION;
+ }
+
+ /* handle animation */
+ if (!(block->pie_data.flags & UI_PIE_ANIMATION_FINISHED)) {
+ uiBut *but;
+ double final_time = 0.01 * U.pie_animation_timeout;
+ float fac = duration / final_time;
+ float pie_radius = U.pie_menu_radius * UI_DPI_FAC;
+
+ if (fac > 1.0f) {
+ fac = 1.0f;
+ block->pie_data.flags |= UI_PIE_ANIMATION_FINISHED;
+ }
+
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ float vec[2];
+ float center[2];
+
+ ui_but_pie_dir(but->pie_dir, vec);
+
+ center[0] = (vec[0] > 0.01f) ? 0.5f : ((vec[0] < -0.01f) ? -0.5f : 0.0f);
+ center[1] = (vec[1] > 0.99f) ? 0.5f : ((vec[1] < -0.99f) ? -0.5f : 0.0f);
+
+ center[0] *= BLI_rctf_size_x(&but->rect);
+ center[1] *= BLI_rctf_size_y(&but->rect);
+
+ mul_v2_fl(vec, pie_radius);
+ add_v2_v2(vec, center);
+ mul_v2_fl(vec, fac);
+ add_v2_v2(vec, block->pie_data.pie_center_spawned);
+
+ BLI_rctf_recenter(&but->rect, vec[0], vec[1]);
+ }
+ }
+ block->pie_data.alphafac = fac;
+
+ ED_region_tag_redraw(ar);
+ }
+ }
+
+ /* check pie velociy here if gesture has ended */
+ if (block->pie_data.flags & UI_PIE_GESTURE_END_WAIT) {
+ float len_sq = 10;
+
+ /* use a time threshold to ensure we leave time to the mouse to move */
+ if (duration - block->pie_data.duration_gesture > 0.02) {
+ len_sq = len_squared_v2v2(event_xy, block->pie_data.last_pos);
+ copy_v2_v2(block->pie_data.last_pos, event_xy);
+ block->pie_data.duration_gesture = duration;
+ }
+
+ if (len_sq < 1.0) {
+ uiBut *but = ui_but_find_activated(menu->region);
+
+ if (but) {
+ return ui_but_pie_menu_apply(C, menu, but, true);
+ }
+ }
+ }
+ }
+
+ if (event->type == block->pie_data.event && !is_click_style) {
+ if (event->val != KM_RELEASE) {
+ ui_handle_menu_button(C, event, menu);
+
+ if (len_squared_v2v2(event_xy, block->pie_data.pie_center_init) > PIE_CLICK_THRESHOLD_SQ) {
+ block->pie_data.flags |= UI_PIE_DRAG_STYLE;
+ }
+ /* why redraw here? It's simple, we are getting many double click events here.
+ * Those operate like mouse move events almost */
+ ED_region_tag_redraw(ar);
+ }
+ else {
+ /* distance from initial point */
+ if (!(block->pie_data.flags & UI_PIE_DRAG_STYLE)) {
+ block->pie_data.flags |= UI_PIE_CLICK_STYLE;
+ }
+ else {
+ uiBut *but = ui_but_find_activated(menu->region);
+
+ if (but && (U.pie_menu_confirm > 0) &&
+ (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
+ {
+ if (but)
+ return ui_but_pie_menu_apply(C, menu, but, true);
+ }
+
+ retval = ui_but_pie_menu_apply(C, menu, but, true);
+
+ }
+ }
+ }
+ else {
+ /* direction from numpad */
+ RadialDirection num_dir = UI_RADIAL_NONE;
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ if (!is_click_style) {
+ float len_sq = len_squared_v2v2(event_xy, block->pie_data.pie_center_init);
+
+ /* here we use the initial position explicitly */
+ if (len_sq > PIE_CLICK_THRESHOLD_SQ) {
+ block->pie_data.flags |= UI_PIE_DRAG_STYLE;
+ }
+
+ /* here instead, we use the offset location to account for the initial direction timeout */
+ if ((U.pie_menu_confirm > 0) &&
+ (dist >= U.pie_menu_threshold + U.pie_menu_confirm))
+ {
+ block->pie_data.flags |= UI_PIE_GESTURE_END_WAIT;
+ copy_v2_v2(block->pie_data.last_pos, event_xy);
+ block->pie_data.duration_gesture = duration;
+ }
+ }
+
+ ui_handle_menu_button(C, event, menu);
+
+ /* mouse move should always refresh the area for pie menus */
+ ED_region_tag_redraw(ar);
+ break;
+
+ case LEFTMOUSE:
+ if (is_click_style) {
+ if (block->pie_data.flags & UI_PIE_INVALID_DIR) {
+ menu->menuretval = UI_RETURN_CANCEL;
+ }
+ else {
+ retval = ui_handle_menu_button(C, event, menu);
+ }
+ }
+ break;
+
+ case ESCKEY:
+ case RIGHTMOUSE:
+ menu->menuretval = UI_RETURN_CANCEL;
+ break;
+
+ case AKEY:
+ case BKEY:
+ case CKEY:
+ case DKEY:
+ case EKEY:
+ case FKEY:
+ case GKEY:
+ case HKEY:
+ case IKEY:
+ case JKEY:
+ case KKEY:
+ case LKEY:
+ case MKEY:
+ case NKEY:
+ case OKEY:
+ case PKEY:
+ case QKEY:
+ case RKEY:
+ case SKEY:
+ case TKEY:
+ case UKEY:
+ case VKEY:
+ case WKEY:
+ case XKEY:
+ case YKEY:
+ case ZKEY:
+ {
+ if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
+ (event->shift == 0) &&
+ (event->ctrl == 0) &&
+ (event->oskey == 0))
+ {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->menu_key == event->type) {
+ ui_but_pie_button_activate(C, but, menu);
+ }
+ }
+ }
+ break;
+ }
+
+#define CASE_NUM_TO_DIR(n, d) \
+ case (ZEROKEY + n): case (PAD0 + n): \
+ { if (num_dir == UI_RADIAL_NONE) num_dir = d; } (void)0
+
+ CASE_NUM_TO_DIR(1, UI_RADIAL_SW);
+ CASE_NUM_TO_DIR(2, UI_RADIAL_S);
+ CASE_NUM_TO_DIR(3, UI_RADIAL_SE);
+ CASE_NUM_TO_DIR(4, UI_RADIAL_W);
+ CASE_NUM_TO_DIR(6, UI_RADIAL_E);
+ CASE_NUM_TO_DIR(7, UI_RADIAL_NW);
+ CASE_NUM_TO_DIR(8, UI_RADIAL_N);
+ CASE_NUM_TO_DIR(9, UI_RADIAL_NE);
+ {
+ but = ui_block_pie_dir_activate(block, event, num_dir);
+ retval = ui_but_pie_button_activate(C, but, menu);
+ break;
+ }
+#undef CASE_NUM_TO_DIR
+ default:
+ retval = ui_handle_menu_button(C, event, menu);
+ break;
+ }
+ }
+
+ return retval;
}
static int ui_handle_menus_recursive(
@@ -8226,17 +8873,21 @@ static int ui_handle_menus_recursive(
uiBlock *block = menu->region->uiblocks.first;
const bool is_menu = ui_block_is_menu(block);
bool inside = false;
+ /* root pie menus accept the key that spawned them as double click to improve responsiveness */
+ bool do_recursion = (!(block->flag & UI_BLOCK_RADIAL) || event->type != block->pie_data.event);
- if (is_parent_inside == false) {
- int mx, my;
+ if (do_recursion) {
+ if (is_parent_inside == false) {
+ int mx, my;
- mx = event->x;
- my = event->y;
- ui_window_to_block(menu->region, block, &mx, &my);
- inside = BLI_rctf_isect_pt(&block->rect, mx, my);
- }
+ mx = event->x;
+ my = event->y;
+ ui_window_to_block(menu->region, block, &mx, &my);
+ inside = BLI_rctf_isect_pt(&block->rect, mx, my);
+ }
- retval = ui_handle_menus_recursive(C, event, submenu, level + 1, is_parent_inside || inside, is_menu, false);
+ retval = ui_handle_menus_recursive(C, event, submenu, level + 1, is_parent_inside || inside, is_menu, false);
+ }
}
/* now handle events for our own menu */
@@ -8269,7 +8920,12 @@ static int ui_handle_menus_recursive(
}
}
else {
- retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
+ uiBlock *block = menu->region->uiblocks.first;
+
+ if (block->flag & UI_BLOCK_RADIAL)
+ retval = ui_handler_pie(C, event, menu);
+ else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK)
+ retval = ui_handle_menu_event(C, event, menu, level, is_parent_inside, is_parent_menu, is_floating);
}
}
@@ -8355,12 +9011,24 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE
but = ui_but_find_activated(ar);
if (but) {
+ uiBut *but_other;
uiHandleButtonData *data;
/* handle activated button events */
data = but->active;
- if (data->state == BUTTON_STATE_MENU_OPEN) {
+ if ((data->state == BUTTON_STATE_MENU_OPEN) &&
+ (but->type == PULLDOWN) &&
+ (but_other = ui_but_find_mouse_over(ar, event)) &&
+ (but != but_other) &&
+ (but->type == but_other->type))
+ {
+ /* if mouse moves to a different root-level menu button,
+ * open it to replace the current menu */
+ ui_handle_button_activate(C, ar, but_other, BUTTON_ACTIVATE_OVER);
+ button_activate_state(C, but_other, BUTTON_STATE_MENU_OPEN);
+ }
+ else if (data->state == BUTTON_STATE_MENU_OPEN) {
int retval;
/* handle events for menus and their buttons recursively,
@@ -8399,9 +9067,13 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE
static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
{
uiPopupBlockHandle *menu = userdata;
-
+ struct ARegion *menu_region;
/* we block all events, this is modal interaction, except for drop events which is described below */
int retval = WM_UI_HANDLER_BREAK;
+ bool reset_pie = false;
+
+ menu_region = CTX_wm_menu(C);
+ CTX_wm_menu_set(C, menu->region);
if (event->type == EVT_DROP) {
/* if we're handling drop event we'll want it to be handled by popup callee as well,
@@ -8416,15 +9088,22 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
/* free if done, does not free handle itself */
if (menu->menuretval) {
+ wmWindow *win = CTX_wm_window(C);
/* copy values, we have to free first (closes region) */
uiPopupBlockHandle temp = *menu;
+ uiBlock *block = menu->region->uiblocks.first;
+
+ /* set last pie event to allow chained pie spawning */
+ if (block->flag & UI_BLOCK_RADIAL) {
+ win->last_pie_event = block->pie_data.event;
+ reset_pie = true;
+ }
ui_popup_block_free(C, menu);
- UI_remove_popup_handlers(&CTX_wm_window(C)->modalhandlers, menu);
+ UI_remove_popup_handlers(&win->modalhandlers, menu);
#ifdef USE_DRAG_TOGGLE
{
- wmWindow *win = CTX_wm_window(C);
WM_event_free_ui_handler_all(C, &win->modalhandlers,
ui_handler_region_drag_toggle, ui_handler_region_drag_toggle_remove);
}
@@ -8434,7 +9113,7 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
if (temp.popup_func)
temp.popup_func(C, temp.popup_arg, temp.retvalue);
if (temp.optype)
- WM_operator_name_call(C, temp.optype->idname, temp.opcontext, NULL);
+ WM_operator_name_call_ptr(C, temp.optype, temp.opcontext, NULL);
}
else if (temp.cancel_func)
temp.cancel_func(C, temp.popup_arg);
@@ -8450,6 +9129,16 @@ static int ui_handler_popup(bContext *C, const wmEvent *event, void *userdata)
/* delayed apply callbacks */
ui_apply_but_funcs_after(C);
+ if (reset_pie) {
+ /* reaqcuire window in case pie invalidates it somehow */
+ wmWindow *win = CTX_wm_window(C);
+
+ if (win)
+ win->last_pie_event = EVENT_NONE;
+ }
+
+ CTX_wm_region_set(C, menu_region);
+
return retval;
}
@@ -8467,12 +9156,12 @@ static void ui_handler_remove_popup(bContext *C, void *userdata)
void UI_add_region_handlers(ListBase *handlers)
{
WM_event_remove_ui_handler(handlers, ui_handler_region, ui_handler_remove_region, NULL, false);
- WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL);
+ WM_event_add_ui_handler(NULL, handlers, ui_handler_region, ui_handler_remove_region, NULL, false);
}
-void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup)
+void UI_add_popup_handlers(bContext *C, ListBase *handlers, uiPopupBlockHandle *popup, const bool accept_dbl_click)
{
- WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup);
+ WM_event_add_ui_handler(C, handlers, ui_handler_popup, ui_handler_remove_popup, popup, accept_dbl_click);
}
void UI_remove_popup_handlers(ListBase *handlers, uiPopupBlockHandle *popup)
diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c
index 546b2b85af5..51dd9166e46 100644
--- a/source/blender/editors/interface/interface_icons.c
+++ b/source/blender/editors/interface/interface_icons.c
@@ -508,6 +508,8 @@ static void init_brush_icons(void)
INIT_BRUSH_ICON(ICON_BRUSH_SOFTEN, soften);
INIT_BRUSH_ICON(ICON_BRUSH_SUBTRACT, subtract);
INIT_BRUSH_ICON(ICON_BRUSH_TEXDRAW, texdraw);
+ INIT_BRUSH_ICON(ICON_BRUSH_TEXFILL, texfill);
+ INIT_BRUSH_ICON(ICON_BRUSH_TEXMASK, texmask);
INIT_BRUSH_ICON(ICON_BRUSH_THUMB, thumb);
INIT_BRUSH_ICON(ICON_BRUSH_ROTATE, twist);
INIT_BRUSH_ICON(ICON_BRUSH_VERTEXDRAW, vertexdraw);
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 3fe6452e56b..47d0e29061c 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -88,6 +88,7 @@ typedef enum {
UI_WTYPE_PULLDOWN,
UI_WTYPE_MENU_ITEM,
+ UI_WTYPE_MENU_ITEM_RADIAL,
UI_WTYPE_MENU_BACK,
/* specials */
@@ -121,6 +122,23 @@ enum {
/* warn: rest of uiBut->flag in UI_interface.h */
};
+/* but->pie_dir */
+typedef enum RadialDirection {
+ UI_RADIAL_NONE = -1,
+ UI_RADIAL_N = 0,
+ UI_RADIAL_NE = 1,
+ UI_RADIAL_E = 2,
+ UI_RADIAL_SE = 3,
+ UI_RADIAL_S = 4,
+ UI_RADIAL_SW = 5,
+ UI_RADIAL_W = 6,
+ UI_RADIAL_NW = 7,
+} RadialDirection;
+
+extern const char ui_radial_dir_order[8];
+extern const char ui_radial_dir_to_numpad[8];
+extern const short ui_radial_dir_to_angle[8];
+
/* internal panel drawing defines */
#define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */
#define PNL_HEADER (UI_UNIT_Y + 4) /* 24 default */
@@ -144,6 +162,19 @@ enum {
/* split numbuts by ':' and align l/r */
#define USE_NUMBUTS_LR_ALIGN
+/* PieMenuData->flags */
+enum {
+ UI_PIE_DEGREES_RANGE_LARGE = (1 << 0), /* pie menu item collision is detected at 90 degrees */
+ UI_PIE_INITIAL_DIRECTION = (1 << 1), /* use initial center of pie menu to calculate direction */
+ UI_PIE_DRAG_STYLE = (1 << 2), /* pie menu is drag style */
+ UI_PIE_INVALID_DIR = (1 << 3), /* mouse not far enough from center position */
+ UI_PIE_CLICK_STYLE = (1 << 4), /* pie menu changed to click style, click to confirm */
+ UI_PIE_ANIMATION_FINISHED = (1 << 5), /* pie animation finished, do not calculate any more motion */
+ UI_PIE_GESTURE_END_WAIT = (1 << 6), /* pie gesture selection has been done, now wait for mouse motion to end */
+};
+
+#define PIE_CLICK_THRESHOLD_SQ 50.0f
+
typedef struct uiLinkLine { /* only for draw/edit */
struct uiLinkLine *next, *prev;
struct uiBut *from, *to;
@@ -186,6 +217,7 @@ struct uiBut {
* (type == LABEL), Use (a1 == 1.0f) to use a2 as a blending factor (wow, this is imaginative!).
* (type == SCROLL) Use as scroll size.
* (type == SEARCH_MENU) Use as number or rows.
+ * (type == COLOR) Use as indication of color palette
*/
float a1;
@@ -193,6 +225,7 @@ struct uiBut {
* (type == NUM), Use to store RNA 'precision' value, for dragging and click-step.
* (type == LABEL), If (a1 == 1.0f) use a2 as a blending factor.
* (type == SEARCH_MENU) Use as number or columns.
+ * (type == COLOR) Use as index in palette (not so good, needs refactor)
*/
float a2;
@@ -225,6 +258,7 @@ struct uiBut {
BIFIconID icon;
bool lock;
char dt; /* drawtype: UI_EMBOSS, UI_EMBOSSN ... etc, copied from the block */
+ signed char pie_dir; /* direction in a pie menu, used for collision detection (RadialDirection) */
char changed; /* could be made into a single flag */
unsigned char unit_type; /* so buttons can support unit systems which are not RNA */
short modifier_key;
@@ -272,6 +306,17 @@ struct uiBut {
uiBlock *block;
};
+struct PieMenuData {
+ float pie_dir[2];
+ float pie_center_init[2];
+ float pie_center_spawned[2];
+ float last_pos[2];
+ double duration_gesture;
+ int flags;
+ int event; /* initial event used to fire the pie menu, store here so we can query for release */
+ float alphafac;
+};
+
struct uiBlock {
uiBlock *next, *prev;
@@ -354,6 +399,7 @@ struct uiBlock {
char display_device[64]; /* display device name used to display this block,
* used by color widgets to transform colors from/to scene linear
*/
+ struct PieMenuData pie_data;
};
typedef struct uiSafetyRct {
@@ -369,6 +415,7 @@ extern void ui_delete_linkline(uiLinkLine *line, uiBut *but);
void ui_fontscale(short *points, float aspect);
extern bool ui_block_is_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
+extern bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT;
extern void ui_block_to_window_fl(const struct ARegion *ar, uiBlock *block, float *x, float *y);
extern void ui_block_to_window(const struct ARegion *ar, uiBlock *block, int *x, int *y);
extern void ui_block_to_window_rctf(const struct ARegion *ar, uiBlock *block, rctf *rct_dst, const rctf *rct_src);
@@ -428,6 +475,19 @@ struct uiKeyNavLock {
int event_xy[2];
};
+typedef uiBlock * (*uiBlockHandleCreateFunc)(struct bContext *C, struct uiPopupBlockHandle *handle, void *arg1);
+
+struct uiPopupBlockCreate {
+ uiBlockCreateFunc create_func;
+ uiBlockHandleCreateFunc handle_create_func;
+ void *arg;
+
+ int event_xy[2];
+
+ /* when popup is initialized from a button */
+ ARegion *butregion;
+};
+
struct uiPopupBlockHandle {
/* internal */
struct ARegion *region;
@@ -442,6 +502,9 @@ struct uiPopupBlockHandle {
void (*cancel_func)(struct bContext *C, void *arg);
void *popup_arg;
+ /* store data for refreshing popups */
+ struct uiPopupBlockCreate popup_create_vars;
+
struct wmTimer *scrolltimer;
struct uiKeyNavLock keynav_state;
@@ -455,7 +518,7 @@ struct uiPopupBlockHandle {
/* return values */
int butretval;
int menuretval;
- float retvalue;
+ int retvalue;
float retvec[4];
/* menu direction */
@@ -496,7 +559,8 @@ bool ui_searchbox_apply(uiBut *but, struct ARegion *ar);
void ui_searchbox_free(struct bContext *C, struct ARegion *ar);
void ui_but_search_test(uiBut *but);
-typedef uiBlock * (*uiBlockHandleCreateFunc)(struct bContext *C, struct uiPopupBlockHandle *handle, void *arg1);
+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,
@@ -533,12 +597,19 @@ void ui_draw_but_NODESOCKET(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol
PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext, bool create_props);
extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val);
extern void ui_button_activate_do(struct bContext *C, struct ARegion *ar, uiBut *but);
+extern void ui_button_activate_over(struct bContext *C, struct ARegion *ar, uiBut *but);
extern void ui_button_execute_begin(struct bContext *C, struct ARegion *ar, uiBut *but, void **active_back);
extern void ui_button_execute_end(struct bContext *C, struct ARegion *ar, uiBut *but, void *active_back);
extern void ui_button_active_free(const struct bContext *C, uiBut *but);
extern bool ui_button_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
extern int ui_button_open_menu_direction(uiBut *but);
extern void ui_button_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
+extern uiBut *ui_but_find_activated(struct ARegion *ar);
+bool ui_but_is_editable(const uiBut *but);
+void ui_but_pie_dir_visual(RadialDirection dir, float vec[2]);
+void ui_but_pie_dir(RadialDirection dir, float vec[2]);
+float ui_block_calculate_pie_segment(struct uiBlock *block, const float event_xy[2]);
+
void ui_button_clipboard_free(void);
void ui_panel_menu(struct bContext *C, ARegion *ar, Panel *pa);
uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new);
@@ -548,6 +619,7 @@ uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new);
void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3);
void ui_draw_anti_roundbox(int mode, float minx, float miny, float maxx, float maxy, float rad, bool use_alpha);
void ui_draw_menu_back(struct uiStyle *style, uiBlock *block, rcti *rect);
+void ui_draw_pie_center(uiBlock *block);
uiWidgetColors *ui_tooltip_get_theme(void);
void ui_draw_tooltip_background(uiStyle *UNUSED(style), uiBlock *block, rcti *rect);
void ui_draw_search_back(struct uiStyle *style, uiBlock *block, rcti *rect);
@@ -572,7 +644,6 @@ int ui_id_icon_get(struct bContext *C, struct ID *id, const bool big);
/* resources.c */
void init_userdef_do_versions(void);
-void init_userdef_factory(void);
void ui_theme_init_default(void);
void ui_style_init_default(void);
void ui_resources_init(void);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index 0bc679dede0..c2bd6d307d1 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -106,6 +106,7 @@ typedef enum uiItemType {
ITEM_LAYOUT_ABSOLUTE,
ITEM_LAYOUT_SPLIT,
ITEM_LAYOUT_OVERLAP,
+ ITEM_LAYOUT_RADIAL,
ITEM_LAYOUT_ROOT
#if 0
@@ -218,7 +219,9 @@ static int ui_item_fit(int item, int pos, int all, int available, int last, int
static int ui_layout_vary_direction(uiLayout *layout)
{
- return (layout->root->type == UI_LAYOUT_HEADER || layout->alignment != UI_LAYOUT_ALIGN_EXPAND) ? UI_ITEM_VARY_X : UI_ITEM_VARY_Y;
+ return ((ELEM(layout->root->type, UI_LAYOUT_HEADER, UI_LAYOUT_PIEMENU) ||
+ (layout->alignment != UI_LAYOUT_ALIGN_EXPAND)) ?
+ UI_ITEM_VARY_X : UI_ITEM_VARY_Y);
}
/* estimated size of text + icon */
@@ -553,15 +556,24 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt
*/
uiBut *but;
+ uiLayout *layout_radial = NULL;
EnumPropertyItem *item, *item_array;
const char *name;
int itemw, icon, value;
bool free;
+ bool radial = (layout->root->type == UI_LAYOUT_PIEMENU);
- RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free);
+ if (radial)
+ RNA_property_enum_items_gettexted_all(block->evil_C, ptr, prop, &item_array, NULL, &free);
+ else
+ RNA_property_enum_items_gettexted(block->evil_C, ptr, prop, &item_array, NULL, &free);
/* we dont want nested rows, cols in menus */
- if (layout->root->type != UI_LAYOUT_MENU) {
+ if (radial) {
+ layout_radial = uiLayoutRadial(layout);
+ uiBlockSetCurLayout(block, layout_radial);
+ }
+ else if (layout->root->type != UI_LAYOUT_MENU) {
uiBlockSetCurLayout(block, ui_item_local_sublayout(layout, layout, 1));
}
else {
@@ -569,8 +581,11 @@ static void ui_item_enum_expand(uiLayout *layout, uiBlock *block, PointerRNA *pt
}
for (item = item_array; item->identifier; item++) {
- if (!item->identifier[0])
+ if (!item->identifier[0]) {
+ if (radial)
+ uiItemS(layout_radial);
continue;
+ }
name = (!uiname || uiname[0]) ? item->name : "";
icon = item->icon;
@@ -869,6 +884,8 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
PointerRNA ptr;
PropertyRNA *prop;
uiBlock *block = layout->root->block;
+ const bool radial = (layout->item.type == ITEM_LAYOUT_RADIAL) ||
+ ((layout->item.type == ITEM_LAYOUT_ROOT) && (layout->root->type == UI_LAYOUT_PIEMENU));
if (!ot || !ot->srna) {
ui_item_disabled(layout, opname);
@@ -887,10 +904,24 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
if (prop && RNA_property_type(prop) == PROP_ENUM) {
EnumPropertyItem *item, *item_array = NULL;
bool free;
- uiLayout *split = uiLayoutSplit(layout, 0.0f, false);
- uiLayout *column = uiLayoutColumn(split, layout->align);
+ uiLayout *split;
+ uiLayout *target;
+
+ if (radial) {
+ target = uiLayoutRadial(layout);
+ }
+ else {
+ split = uiLayoutSplit(layout, 0.0f, false);
+ target = uiLayoutColumn(split, layout->align);
+ }
+
+ if (radial) {
+ RNA_property_enum_items_gettexted_all(block->evil_C, &ptr, prop, &item_array, NULL, &free);
+ }
+ else {
+ RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free);
+ }
- RNA_property_enum_items_gettexted(block->evil_C, &ptr, prop, &item_array, NULL, &free);
for (item = item_array; item->identifier; item++) {
if (item->identifier[0]) {
PointerRNA tptr;
@@ -905,20 +936,24 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
}
RNA_property_enum_set(&tptr, prop, item->value);
- uiItemFullO_ptr(column, ot, item->name, item->icon, tptr.data, context, flag);
+ uiItemFullO_ptr(target, ot, item->name, item->icon, tptr.data, context, flag);
+
ui_but_tip_from_enum_item(block->buttons.last, item);
}
else {
if (item->name) {
uiBut *but;
- if (item != item_array) {
- column = uiLayoutColumn(split, layout->align);
+
+ if (item != item_array && !radial) {
+ target = uiLayoutColumn(split, layout->align);
+
/* inconsistent, but menus with labels do not look good flipped */
block->flag |= UI_BLOCK_NO_FLIP;
}
- if (item->icon) {
- uiItemL(column, item->name, item->icon);
+ if (item->icon || radial) {
+ uiItemL(target, item->name, item->icon);
+
but = block->buttons.last;
}
else {
@@ -928,8 +963,14 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname
}
ui_but_tip_from_enum_item(but, item);
}
- else { /* XXX bug here, colums draw bottom item badly */
- uiItemS(column);
+ else {
+ if (radial) {
+ uiItemS(target);
+ }
+ else {
+ /* XXX bug here, colums draw bottom item badly */
+ uiItemS(target);
+ }
}
}
}
@@ -1181,7 +1222,7 @@ void uiItemFullR(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index
if (flag & UI_ITEM_R_ICON_ONLY) {
/* pass */
}
- else if (ELEM4(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
+ else if (ELEM(type, PROP_INT, PROP_FLOAT, PROP_STRING, PROP_POINTER)) {
name = ui_item_name_add_colon(name, namestr);
}
else if (type == PROP_BOOLEAN && is_array && index == RNA_NO_INDEX) {
@@ -1323,9 +1364,9 @@ void uiItemEnumR_string(uiLayout *layout, struct PointerRNA *ptr, const char *pr
for (a = 0; item[a].identifier; a++) {
if (item[a].value == ivalue) {
- const char *item_name = CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
+ const char *item_name = name ? name : CTX_IFACE_(RNA_property_translation_context(prop), item[a].name);
- uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name ? item_name : name, icon ? icon : item[a].icon);
+ uiItemFullR(layout, ptr, prop, RNA_ENUM_VALUE, ivalue, 0, item_name, icon ? icon : item[a].icon);
break;
}
}
@@ -1401,7 +1442,7 @@ typedef struct CollItemSearch {
int iconid;
} CollItemSearch;
-static int sort_search_items_list(void *a, void *b)
+static int sort_search_items_list(const void *a, const void *b)
{
CollItemSearch *cis1 = (CollItemSearch *)a;
CollItemSearch *cis2 = (CollItemSearch *)b;
@@ -1559,7 +1600,7 @@ void uiItemPointerR(uiLayout *layout, struct PointerRNA *ptr, const char *propna
}
type = RNA_property_type(prop);
- if (!ELEM3(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
+ if (!ELEM(type, PROP_POINTER, PROP_STRING, PROP_ENUM)) {
RNA_warning("Property %s must be a pointer, string or enum", propname);
return;
}
@@ -1759,7 +1800,7 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
{
/* label */
uiBlock *block = layout->root->block;
- float *retvalue = (block->handle) ? &block->handle->retvalue : NULL;
+ int *retvalue = (block->handle) ? &block->handle->retvalue : NULL;
int w;
uiBlockSetCurLayout(block, layout);
@@ -1772,11 +1813,11 @@ void uiItemV(uiLayout *layout, const char *name, int icon, int argval)
w = ui_text_icon_width(layout, name, icon, 0);
if (icon && name[0])
- uiDefIconTextButF(block, BUT, argval, icon, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
+ uiDefIconTextButI(block, BUT, argval, icon, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
else if (icon)
- uiDefIconButF(block, BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
+ uiDefIconButI(block, BUT, argval, icon, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
else
- uiDefButF(block, BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
+ uiDefButI(block, BUT, argval, name, 0, 0, w, UI_UNIT_Y, retvalue, 0.0, 0.0, 0, -1, "");
}
/* separator item */
@@ -2072,16 +2113,135 @@ static void ui_litem_layout_column(uiLayout *litem)
litem->y = y;
}
+/* calculates the angle of a specified button in a radial menu,
+ * stores a float vector in unit circle */
+static RadialDirection ui_get_radialbut_vec(float vec[2], short itemnum)
+{
+ RadialDirection dir;
+ BLI_assert(itemnum < 8);
+
+ dir = ui_radial_dir_order[itemnum];
+ ui_but_pie_dir(dir, vec);
+
+ return dir;
+}
+
+static bool ui_item_is_radial_displayable(uiItem *item)
+{
+
+ if ((item->type == ITEM_BUTTON) && (((uiButtonItem *)item)->but->type == LABEL))
+ return false;
+
+ return true;
+}
+
+static bool ui_item_is_radial_drawable(uiButtonItem *bitem)
+{
+
+ if (ELEM(bitem->but->type, SEPR, SEPRLINE))
+ return false;
+
+ return true;
+}
+
+static void ui_litem_layout_radial(uiLayout *litem)
+{
+ uiItem *item;
+ int itemh, itemw, x, y;
+ int itemnum = 0;
+ int totitems = 0;
+
+ int minx, miny, maxx, maxy;
+ /* For the radial layout we will use Matt Ebb's design
+ * for radiation, see http://mattebb.com/weblog/radiation/
+ * also the old code at http://developer.blender.org/T5103
+ */
+
+ int pie_radius = U.pie_menu_radius * UI_DPI_FAC;
+
+ x = litem->x;
+ y = litem->y;
+
+ minx = x, miny = y, maxx = x, maxy = y;
+
+ /* first count total items */
+ for (item = litem->items.first; item; item = item->next)
+ totitems++;
+
+ if (totitems < 5)
+ litem->root->block->pie_data.flags |= UI_PIE_DEGREES_RANGE_LARGE;
+
+ for (item = litem->items.first; item; item = item->next) {
+ /* not all button types are drawn in a radial menu, do filtering here */
+ if (ui_item_is_radial_displayable(item)) {
+ RadialDirection dir;
+ float vec[2];
+ float factor[2];
+
+ dir = ui_get_radialbut_vec(vec, itemnum);
+ factor[0] = (vec[0] > 0.01f) ? 0.0f : ((vec[0] < -0.01f) ? -1.0f : -0.5f);
+ factor[1] = (vec[1] > 0.99f) ? 0.0f : ((vec[1] < -0.99f) ? -1.0f : -0.5f);
+
+ itemnum++;
+
+ if (item->type == ITEM_BUTTON) {
+ uiButtonItem *bitem = (uiButtonItem *) item;
+
+ bitem->but->pie_dir = dir;
+ /* scale the buttons */
+ bitem->but->rect.ymax *= 1.5f;
+ /* add a little bit more here to include number */
+ bitem->but->rect.xmax += 1.5f * UI_UNIT_X;
+ /* enable drawing as pie item if supported by widget */
+ if (ui_item_is_radial_drawable(bitem))
+ bitem->but->dt = UI_EMBOSSR;
+ }
+
+ ui_item_size(item, &itemw, &itemh);
+
+ ui_item_position(item, x + vec[0] * pie_radius + factor[0] * itemw, y + vec[1] * pie_radius + factor[1] * itemh, itemw, itemh);
+
+ minx = min_ii(minx, x + vec[0] * pie_radius - itemw / 2);
+ maxx = max_ii(maxx, x + vec[0] * pie_radius + itemw / 2);
+ miny = min_ii(miny, y + vec[1] * pie_radius - itemh / 2);
+ maxy = max_ii(maxy, y + vec[1] * pie_radius + itemh / 2);
+ }
+ }
+
+ litem->x = minx;
+ litem->y = miny;
+ litem->w = maxx - minx;
+ litem->h = maxy - miny;
+}
+
/* root layout */
static void ui_litem_estimate_root(uiLayout *UNUSED(litem))
{
/* nothing to do */
}
+static void ui_litem_layout_root_radial(uiLayout *litem)
+{
+ /* first item is pie menu title, align on center of menu */
+ uiItem *item = litem->items.first;
+
+ if (item->type == ITEM_BUTTON) {
+ int itemh, itemw, x, y;
+ x = litem->x;
+ y = litem->y;
+
+ ui_item_size(item, &itemw, &itemh);
+
+ ui_item_position(item, x - itemw / 2, y + U.pixelsize * (U.pie_menu_threshold + 9.0f), itemw, itemh);
+ }
+}
+
static void ui_litem_layout_root(uiLayout *litem)
{
if (litem->root->type == UI_LAYOUT_HEADER)
ui_litem_layout_row(litem);
+ else if (litem->root->type == UI_LAYOUT_PIEMENU)
+ ui_litem_layout_root_radial(litem);
else
ui_litem_layout_column(litem);
}
@@ -2497,6 +2657,40 @@ static uiLayoutItemBx *ui_layout_box(uiLayout *layout, int type)
return box;
}
+uiLayout *uiLayoutRadial(uiLayout *layout)
+{
+ uiLayout *litem;
+ uiItem *item;
+
+ /* radial layouts are only valid for radial menus */
+ if (layout->root->type != UI_LAYOUT_PIEMENU)
+ return ui_item_local_sublayout(layout, layout, 0);
+
+ /* only one radial wheel per root layout is allowed, so check and return that, if it exists */
+ for (item = layout->root->layout->items.first; item; item = item->next) {
+ litem = (uiLayout *)item;
+ if (litem->item.type == ITEM_LAYOUT_RADIAL) {
+ uiBlockSetCurLayout(layout->root->block, litem);
+ return litem;
+ }
+ }
+
+ litem = MEM_callocN(sizeof(uiLayout), "uiLayoutRadial");
+ litem->item.type = ITEM_LAYOUT_RADIAL;
+ litem->root = layout->root;
+ litem->active = true;
+ litem->enabled = true;
+ litem->context = layout->context;
+ litem->redalert = layout->redalert;
+ litem->w = layout->w;
+ BLI_addtail(&layout->root->layout->items, litem);
+
+ uiBlockSetCurLayout(layout->root->block, litem);
+
+ return litem;
+}
+
+
uiLayout *uiLayoutBox(uiLayout *layout)
{
return (uiLayout *)ui_layout_box(layout, ROUNDBOX);
@@ -2843,6 +3037,9 @@ static void ui_item_layout(uiItem *item)
case ITEM_LAYOUT_OVERLAP:
ui_litem_layout_overlap(litem);
break;
+ case ITEM_LAYOUT_RADIAL:
+ ui_litem_layout_radial(litem);
+ break;
default:
break;
}
@@ -2916,7 +3113,7 @@ uiLayout *uiBlockLayout(uiBlock *block, int dir, int type, int x, int y, int siz
layout->enabled = 1;
layout->context = NULL;
- if (type == UI_LAYOUT_MENU)
+ if (type == UI_LAYOUT_MENU || type == UI_LAYOUT_PIEMENU)
layout->space = 0;
if (dir == UI_LAYOUT_HORIZONTAL) {
@@ -2983,6 +3180,8 @@ void uiBlockLayoutResolve(uiBlock *block, int *x, int *y)
{
uiLayoutRoot *root;
+ BLI_assert(block->active);
+
if (x) *x = 0;
if (y) *y = 0;
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 316a4d34881..817445cc14e 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -35,6 +35,7 @@
#include "DNA_text_types.h" /* for UI_OT_reports_to_text */
#include "BLI_blenlib.h"
+#include "BLI_math_color.h"
#include "BLF_api.h"
#include "BLF_translation.h"
@@ -44,6 +45,7 @@
#include "BKE_global.h"
#include "BKE_text.h" /* for UI_OT_reports_to_text */
#include "BKE_report.h"
+#include "BKE_paint.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -55,6 +57,8 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "ED_paint.h"
+
/* only for UI_OT_editsource */
#include "ED_screen.h"
#include "BKE_main.h"
@@ -258,28 +262,43 @@ static void UI_OT_unset_property_button(wmOperatorType *ot)
/* Copy To Selected Operator ------------------------ */
-static bool copy_to_selected_list(bContext *C, PointerRNA *ptr, ListBase *lb, bool *use_path)
+static bool copy_to_selected_list(
+ bContext *C, PointerRNA *ptr, PropertyRNA *prop,
+ ListBase *r_lb, bool *r_use_path_from_id, char **r_path)
{
- *use_path = false;
+ *r_use_path_from_id = false;
+ *r_path = NULL;
- if (RNA_struct_is_a(ptr->type, &RNA_EditBone))
- *lb = CTX_data_collection_get(C, "selected_editable_bones");
- else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone))
- *lb = CTX_data_collection_get(C, "selected_pose_bones");
- else if (RNA_struct_is_a(ptr->type, &RNA_Sequence))
- *lb = CTX_data_collection_get(C, "selected_editable_sequences");
- else {
+ if (RNA_struct_is_a(ptr->type, &RNA_EditBone)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_bones");
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_PoseBone)) {
+ *r_lb = CTX_data_collection_get(C, "selected_pose_bones");
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
+ }
+ else if (ptr->id.data) {
ID *id = ptr->id.data;
- if (id && GS(id->name) == ID_OB) {
- *lb = CTX_data_collection_get(C, "selected_editable_objects");
- *use_path = true;
+ if (GS(id->name) == ID_OB) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_objects");
+ *r_use_path_from_id = true;
+ *r_path = RNA_path_from_ID_to_property(ptr, prop);
}
- else {
- return false;
+ 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... */
+ if ((*r_path = RNA_path_resolve_from_type_to_property(ptr, prop, &RNA_Sequence)) != NULL) {
+ *r_lb = CTX_data_collection_get(C, "selected_editable_sequences");
+ }
}
+ return (*r_path != NULL);
}
-
+ else {
+ return false;
+ }
+
return true;
}
@@ -303,47 +322,54 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll)
/* if there is a valid property that is editable... */
if (ptr.data && prop) {
char *path = NULL;
- bool use_path;
+ bool use_path_from_id;
CollectionPointerLink *link;
ListBase lb;
- if (!copy_to_selected_list(C, &ptr, &lb, &use_path))
+ if (!copy_to_selected_list(C, &ptr, prop, &lb, &use_path_from_id, &path))
return success;
- if (!use_path || (path = RNA_path_from_ID_to_property(&ptr, prop))) {
- for (link = lb.first; link; link = link->next) {
- if (link->ptr.data != ptr.data) {
- if (use_path) {
- lprop = NULL;
- RNA_id_pointer_create(link->ptr.id.data, &idptr);
- RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
- }
- else {
- lptr = link->ptr;
- lprop = prop;
- }
+ for (link = lb.first; link; link = link->next) {
+ if (link->ptr.data != ptr.data) {
+ if (use_path_from_id) {
+ /* Path relative to ID. */
+ lprop = NULL;
+ RNA_id_pointer_create(link->ptr.id.data, &idptr);
+ RNA_path_resolve_property(&idptr, path, &lptr, &lprop);
+ }
+ else if (path) {
+ /* Path relative to elements from list. */
+ lprop = NULL;
+ RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop);
+ }
+ else {
+ lptr = link->ptr;
+ lprop = prop;
+ }
- if (lprop == prop) {
- if (RNA_property_editable(&lptr, lprop)) {
- if (poll) {
+ if (lptr.data == ptr.data) {
+ /* lptr might not be the same as link->ptr! */
+ continue;
+ }
+
+ if (lprop == prop) {
+ if (RNA_property_editable(&lptr, lprop)) {
+ if (poll) {
+ success = true;
+ break;
+ }
+ else {
+ if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
+ RNA_property_update(C, &lptr, prop);
success = true;
- break;
- }
- else {
- if (RNA_property_copy(&lptr, &ptr, prop, (all) ? -1 : index)) {
- RNA_property_update(C, &lptr, prop);
- success = true;
- }
}
}
}
}
}
-
- if (path)
- MEM_freeN(path);
}
+ MEM_SAFE_FREE(path);
BLI_freelistN(&lb);
}
@@ -693,6 +719,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
int ret = OPERATOR_CANCELLED;
if (but) {
+ wmOperatorType *ot;
PointerRNA ptr;
char popath[FILE_MAX];
const char *root = U.i18ndir;
@@ -714,7 +741,8 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
"Directory' path to a valid directory");
return OPERATOR_CANCELLED;
}
- if (!WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0)) {
+ ot = WM_operatortype_find(EDTSRC_I18N_OP_NAME, 0);
+ if (ot == NULL) {
BKE_reportf(op->reports, RPT_ERROR, "Could not find operator '%s'! Please enable ui_translate addon "
"in the User Preferences", EDTSRC_I18N_OP_NAME);
return OPERATOR_CANCELLED;
@@ -730,7 +758,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
uiButGetStrInfo(C, but, &but_label, &rna_label, &enum_label, &but_tip, &rna_tip, &enum_tip,
&rna_struct, &rna_prop, &rna_enum, &rna_ctxt, NULL);
- WM_operator_properties_create(&ptr, EDTSRC_I18N_OP_NAME);
+ WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "lang", uilng);
RNA_string_set(&ptr, "po_file", popath);
RNA_string_set(&ptr, "but_label", but_label.strinfo);
@@ -743,7 +771,7 @@ static int edittranslation_exec(bContext *C, wmOperator *op)
RNA_string_set(&ptr, "rna_prop", rna_prop.strinfo);
RNA_string_set(&ptr, "rna_enum", rna_enum.strinfo);
RNA_string_set(&ptr, "rna_ctxt", rna_ctxt.strinfo);
- ret = WM_operator_name_call(C, EDTSRC_I18N_OP_NAME, WM_OP_INVOKE_DEFAULT, &ptr);
+ ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
/* Clean up */
if (but_label.strinfo)
@@ -808,6 +836,99 @@ static void UI_OT_reloadtranslation(wmOperatorType *ot)
ot->exec = reloadtranslation_exec;
}
+int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(event))
+{
+ /* should only return true for regions that include buttons, for now
+ * return true always */
+ if (drag->type == WM_DRAG_COLOR) {
+ SpaceImage *sima = CTX_wm_space_image(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ if (UI_but_active_drop_color(C))
+ return 1;
+
+ if (sima && (sima->mode == SI_MODE_PAINT) &&
+ sima->image && (ar && ar->regiontype == RGN_TYPE_WINDOW))
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
+{
+ uiDragColorHandle *drag_info = (uiDragColorHandle *)drag->poin;
+
+ RNA_float_set_array(drop->ptr, "color", drag_info->color);
+ RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
+}
+
+static int drop_color_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ ARegion *ar = CTX_wm_region(C);
+ uiBut *but = NULL;
+ float color[4];
+ bool gamma;
+
+ RNA_float_get_array(op->ptr, "color", color);
+ gamma = RNA_boolean_get(op->ptr, "gamma");
+
+ /* find button under mouse, check if it has RNA color property and
+ * if it does copy the data */
+ but = ui_but_find_activated(ar);
+
+ if (but && but->type == COLOR && but->rnaprop) {
+ const int color_len = RNA_property_array_length(&but->rnapoin, but->rnaprop);
+ BLI_assert(color_len <= 4);
+
+ /* keep alpha channel as-is */
+ if (color_len == 4) {
+ color[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
+ }
+
+ if (RNA_property_subtype(but->rnaprop) == PROP_COLOR_GAMMA) {
+ if (!gamma)
+ ui_block_to_display_space_v3(but->block, color);
+ RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
+ RNA_property_update(C, &but->rnapoin, but->rnaprop);
+ }
+ else if (RNA_property_subtype(but->rnaprop) == PROP_COLOR) {
+ if (gamma)
+ ui_block_to_scene_linear_v3(but->block, color);
+ RNA_property_float_set_array(&but->rnapoin, but->rnaprop, color);
+ RNA_property_update(C, &but->rnapoin, but->rnaprop);
+ }
+ }
+ else {
+ if (gamma) {
+ srgb_to_linearrgb_v3_v3(color, color);
+ }
+
+ ED_imapaint_bucket_fill(C, color, op);
+ }
+
+ ED_region_tag_redraw(ar);
+
+ return OPERATOR_FINISHED;
+}
+
+
+static void UI_OT_drop_color(wmOperatorType *ot)
+{
+ ot->name = "Drop Color";
+ ot->idname = "UI_OT_drop_color";
+ ot->description = "Drop colors to buttons";
+
+ ot->invoke = drop_color_invoke;
+
+ RNA_def_float_color(ot->srna, "color", 3, NULL, 0.0, FLT_MAX, "Color", "Source color", 0.0, 1.0);
+ RNA_def_boolean(ot->srna, "gamma", 0, "Gamma Corrected", "The source color is gamma corrected ");
+}
+
+
+
/* ********************************************************* */
/* Registration */
@@ -819,7 +940,7 @@ void UI_buttons_operatortypes(void)
WM_operatortype_append(UI_OT_unset_property_button);
WM_operatortype_append(UI_OT_copy_to_selected_button);
WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */
-
+ WM_operatortype_append(UI_OT_drop_color);
#ifdef WITH_PYTHON
WM_operatortype_append(UI_OT_editsource);
WM_operatortype_append(UI_OT_edittranslation_init);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index 2ccb3740777..9265ca0d4b9 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -120,7 +120,7 @@ static int panel_aligned(ScrArea *sa, ARegion *ar)
return BUT_VERTICAL;
else if (sa->spacetype == SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
return BUT_VERTICAL;
- else if (ELEM3(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS))
+ else if (ELEM(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS))
return BUT_VERTICAL;
return 0;
@@ -201,20 +201,33 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
pa->ofsy = papar->ofsy + papar->sizey - pa->sizey;
}
+
+/* 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 */
+
Panel *uiPanelFindByType(ARegion *ar, PanelType *pt)
{
Panel *pa;
-
const char *idname = pt->idname;
- const char *tabname = pt->idname;
+#ifdef UI_USE_PANELTAB
+ const char *tabname = pt->idname;
for (pa = ar->panels.first; pa; pa = pa->next) {
if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
- if (STREQLEN(pa->tabname, tabname, sizeof(pa->panelname))) {
+ if (STREQLEN(pa->tabname, tabname, sizeof(pa->tabname))) {
return pa;
}
}
}
+#else
+ for (pa = ar->panels.first; pa; pa = pa->next) {
+ if (STREQLEN(pa->panelname, idname, sizeof(pa->panelname))) {
+ return pa;
+ }
+ }
+#endif
return NULL;
}
@@ -224,11 +237,13 @@ Panel *uiPanelFindByType(ARegion *ar, PanelType *pt)
*/
Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Panel *pa, bool *r_open)
{
- Panel *patab, *palast, *panext;
+ Panel *palast, *panext;
const char *drawname = CTX_IFACE_(pt->translation_context, pt->label);
const char *idname = pt->idname;
+#ifdef UI_USE_PANELTAB
const char *tabname = pt->idname;
const char *hookname = NULL;
+#endif
const bool newpanel = (pa == NULL);
int align = panel_aligned(sa, ar);
@@ -240,7 +255,6 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan
pa = MEM_callocN(sizeof(Panel), "new panel");
pa->type = pt;
BLI_strncpy(pa->panelname, idname, sizeof(pa->panelname));
- BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname));
if (pt->flag & PNL_DEFAULT_CLOSED) {
if (align == BUT_VERTICAL)
@@ -256,9 +270,13 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan
pa->runtime_flag |= PNL_NEW_ADDED;
BLI_addtail(&ar->panels, pa);
-
+
+#ifdef UI_USE_PANELTAB
+ BLI_strncpy(pa->tabname, tabname, sizeof(pa->tabname));
+
/* make new Panel tabbed? */
if (hookname) {
+ Panel *patab;
for (patab = ar->panels.first; patab; patab = patab->next) {
if ((patab->runtime_flag & PNL_ACTIVE) && patab->paneltab == NULL) {
if (STREQLEN(hookname, patab->panelname, sizeof(patab->panelname))) {
@@ -271,6 +289,9 @@ Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, Pan
}
}
}
+#else
+ BLI_strncpy(pa->tabname, idname, sizeof(pa->tabname));
+#endif
}
/* Do not allow closed panels without headers! Else user could get "disappeared" UI! */
@@ -462,31 +483,41 @@ static void ui_draw_panel_scalewidget(const rcti *rect)
fdrawline(xmin + dx, ymin + 1, xmax, ymax - dy + 1);
glDisable(GL_BLEND);
}
-
static void ui_draw_panel_dragwidget(const rctf *rect)
{
- float xmin, xmax, dx;
- float ymin, ymax, dy;
-
- xmin = rect->xmin;
- xmax = rect->xmax;
- ymin = rect->ymin;
- ymax = rect->ymax;
-
- dx = (xmax - xmin) / 3.0f;
- dy = (ymax - ymin) / 3.0f;
-
- glEnable(GL_BLEND);
- glColor4ub(255, 255, 255, 50);
- fdrawline(xmin, ymax, xmax, ymin);
- fdrawline(xmin + dx, ymax, xmax, ymin + dy);
- fdrawline(xmin + 2 * dx, ymax, xmax, ymin + 2 * dy);
-
- glColor4ub(0, 0, 0, 50);
- fdrawline(xmin, ymax + 1, xmax, ymin + 1);
- fdrawline(xmin + dx, ymax + 1, xmax, ymin + dy + 1);
- fdrawline(xmin + 2 * dx, ymax + 1, xmax, ymin + 2 * dy + 1);
- glDisable(GL_BLEND);
+ unsigned char col_back[3], col_high[3], col_dark[3];
+ const int col_tint = 84;
+
+ const int px = (int)U.pixelsize;
+ const int px_zoom = max_ii(iroundf(BLI_rctf_size_y(rect) / 22.0f), 1);
+
+ const int box_margin = max_ii(iroundf((float)(px_zoom * 2.0f)), px);
+ const int box_size = max_ii(iroundf((BLI_rctf_size_y(rect) / 8.0f) - px), px);
+
+ const int x_min = rect->xmin;
+ const int y_min = rect->ymin;
+ const int y_ofs = max_ii(iroundf(BLI_rctf_size_y(rect) / 3.0f), px);
+ const int x_ofs = y_ofs;
+ int i_x, i_y;
+
+
+ UI_GetThemeColor3ubv(UI_GetThemeValue(TH_PANEL_SHOW_HEADER) ? TH_PANEL_HEADER : TH_PANEL_BACK, col_back);
+ UI_GetColorPtrShade3ubv(col_back, col_high, col_tint);
+ UI_GetColorPtrShade3ubv(col_back, col_dark, -col_tint);
+
+
+ /* draw multiple boxes */
+ for (i_x = 0; i_x < 4; i_x++) {
+ for (i_y = 0; i_y < 2; i_y++) {
+ const int x_co = (x_min + x_ofs) + (i_x * (box_size + box_margin));
+ const int y_co = (y_min + y_ofs) + (i_y * (box_size + box_margin));
+
+ glColor3ubv(col_dark);
+ glRectf(x_co - box_size, y_co - px_zoom, x_co, (y_co + box_size) - px_zoom);
+ glColor3ubv(col_high);
+ glRectf(x_co - box_size, y_co, x_co, y_co + box_size);
+ }
+ }
}
@@ -1131,7 +1162,7 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
button = 1;
else if (event == AKEY)
button = 1;
- else if (ELEM3(event, 0, RETKEY, LEFTMOUSE) && shift) {
+ else if (ELEM(event, 0, RETKEY, LEFTMOUSE) && shift) {
block->panel->flag ^= PNL_PIN;
button = 2;
}
@@ -1524,6 +1555,12 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
const bool is_active = STREQ(category_id, category_id_active);
+#ifdef DEBUG
+ if (STREQ(category_id, PNL_CATEGORY_FALLBACK)) {
+ printf("WARNING: Panel has no 'bl_category', script needs updating!\n");
+ }
+#endif
+
glEnable(GL_BLEND);
#ifdef USE_FLAT_INACTIVE
@@ -1716,7 +1753,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
/* XXX hardcoded key warning */
if ((inside || inside_header) && event->val == KM_PRESS) {
- if (event->type == AKEY && !ELEM4(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) {
+ if (event->type == AKEY && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) {
if (pa->flag & PNL_CLOSEDY) {
if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my))
@@ -1902,7 +1939,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);
+ WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false);
}
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 97d4869bb2d..1574ceace8a 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -43,6 +43,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "PIL_time.h"
+
#include "BKE_context.h"
#include "BKE_screen.h"
#include "BKE_report.h"
@@ -146,25 +148,40 @@ static void ui_remove_temporary_region(bContext *C, bScreen *sc, ARegion *ar)
/************************* Creating Tooltips **********************/
-typedef enum {
- UI_TIP_LC_MAIN,
- UI_TIP_LC_NORMAL,
- UI_TIP_LC_PYTHON,
- UI_TIP_LC_ALERT,
- UI_TIP_LC_SUBMENU
-} uiTooltipLineColor;
-#define UI_TIP_LC_MAX 5
+#define UI_TIP_PAD_FAC 1.3f
+#define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y)
#define MAX_TOOLTIP_LINES 8
typedef struct uiTooltipData {
rcti bbox;
uiFontStyle fstyle;
char lines[MAX_TOOLTIP_LINES][512];
- uiTooltipLineColor color_id[MAX_TOOLTIP_LINES];
+ char header[512], active_info[512];
+ struct {
+ enum {
+ UI_TIP_STYLE_NORMAL = 0,
+ UI_TIP_STYLE_HEADER,
+ UI_TIP_STYLE_MONO,
+ } style : 3;
+ enum {
+ UI_TIP_LC_MAIN = 0, /* primary text */
+ UI_TIP_LC_VALUE, /* the value of buttons (also shortcuts) */
+ UI_TIP_LC_ACTIVE, /* titles of active enum values */
+ UI_TIP_LC_NORMAL, /* regular text */
+ UI_TIP_LC_PYTHON, /* Python snippet */
+ UI_TIP_LC_ALERT, /* description of why operator can't run */
+ } color_id : 4;
+ int is_pad : 1;
+ } format[MAX_TOOLTIP_LINES];
int totline;
- int toth, spaceh, lineh;
+ int toth, lineh;
} uiTooltipData;
+#define UI_TIP_LC_MAX 6
+
+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)
@@ -183,16 +200,18 @@ static void rgb_tint(float col[3],
static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
{
+ const float pad_px = UI_TIP_PADDING;
uiTooltipData *data = ar->regiondata;
uiWidgetColors *theme = ui_tooltip_get_theme();
rcti bbox = data->bbox;
float tip_colors[UI_TIP_LC_MAX][3];
float *main_color = tip_colors[UI_TIP_LC_MAIN]; /* the color from the theme */
+ float *value_color = tip_colors[UI_TIP_LC_VALUE];
+ float *active_color = tip_colors[UI_TIP_LC_ACTIVE];
float *normal_color = tip_colors[UI_TIP_LC_NORMAL];
float *python_color = tip_colors[UI_TIP_LC_PYTHON];
float *alert_color = tip_colors[UI_TIP_LC_ALERT];
- float *submenu_color = tip_colors[UI_TIP_LC_SUBMENU];
float background_color[3];
float tone_bg;
@@ -203,6 +222,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
if (multisample_enabled)
glDisable(GL_MULTISAMPLE_ARB);
+ wmOrtho2_region_ui(ar);
+
/* draw background */
ui_draw_tooltip_background(UI_GetStyle(), NULL, &bbox);
@@ -211,32 +232,79 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
/* calculate normal_color */
rgb_uchar_to_float(main_color, (const unsigned char *)theme->text);
+ copy_v3_v3(active_color, main_color);
copy_v3_v3(normal_color, main_color);
copy_v3_v3(python_color, main_color);
copy_v3_v3(alert_color, main_color);
- copy_v3_v3(submenu_color, main_color);
+ copy_v3_v3(value_color, main_color);
/* find the brightness difference between background and text colors */
tone_bg = rgb_to_grayscale(background_color);
/* tone_fg = rgb_to_grayscale(main_color); */
- rgb_tint(normal_color, 0.0f, 0.0f, tone_bg, 0.3f); /* a shade darker (to bg) */
- rgb_tint(python_color, 0.666f, 0.25f, tone_bg, 0.3f); /* blue */
- rgb_tint(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* bright red */
- rgb_tint(submenu_color, 0.0f, 0.0f, tone_bg, 0.3f); /* a shade darker (to bg) */
+ /* mix the colors */
+ rgb_tint(value_color, 0.0f, 0.0f, tone_bg, 0.2f); /* light grey */
+ 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(alert_color, 0.0f, 0.8f, tone_bg, 0.1f); /* red */
/* draw text */
- uiStyleFontSet(&data->fstyle);
- bbox.ymax = bbox.ymax - 0.5f * (BLI_rcti_size_y(&bbox) - data->toth);
+ bbox.xmin += 0.5f * pad_px; /* add padding to the text */
+ bbox.ymax -= 0.5f * (BLI_rcti_size_y(&bbox) - data->toth);
bbox.ymin = bbox.ymax - data->lineh;
for (i = 0; i < data->totline; i++) {
- glColor3fv(tip_colors[data->color_id[i]]);
- uiStyleFontDraw(&data->fstyle, &bbox, data->lines[i]);
- bbox.ymin -= data->lineh + data->spaceh;
- bbox.ymax -= data->lineh + data->spaceh;
+ if (data->format[i].style == UI_TIP_STYLE_HEADER) {
+ /* draw header and active data (is done here to be able to change color) */
+ uiFontStyle fstyle_header = data->fstyle;
+ float xofs;
+
+ /* override text-style */
+ fstyle_header.shadow = 1;
+ fstyle_header.shadowcolor = rgb_to_luma(tip_colors[UI_TIP_LC_MAIN]);
+ fstyle_header.shadx = fstyle_header.shady = 0;
+ fstyle_header.shadowalpha = 1.0f;
+
+ uiStyleFontSet(&fstyle_header);
+ glColor3fv(tip_colors[UI_TIP_LC_MAIN]);
+ uiStyleFontDraw(&fstyle_header, &bbox, data->header);
+
+ xofs = BLF_width(fstyle_header.uifont_id, data->header, sizeof(data->header));
+ bbox.xmin += xofs;
+
+ glColor3fv(tip_colors[UI_TIP_LC_ACTIVE]);
+ uiStyleFontDraw(&data->fstyle, &bbox, data->active_info);
+
+ bbox.xmin -= xofs;
+ }
+ else if (data->format[i].style == UI_TIP_STYLE_MONO) {
+ uiFontStyle fstyle_mono = data->fstyle;
+ fstyle_mono.uifont_id = blf_mono_font;
+
+ uiStyleFontSet(&fstyle_mono);
+ /* XXX, needed because we dont have mono in 'U.uifonts' */
+ BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi);
+ glColor3fv(tip_colors[data->format[i].color_id]);
+ uiStyleFontDraw(&fstyle_mono, &bbox, data->lines[i]);
+ }
+ else {
+ BLI_assert(data->format[i].style == UI_TIP_STYLE_NORMAL);
+ /* draw remaining data */
+ uiStyleFontSet(&data->fstyle);
+ glColor3fv(tip_colors[data->format[i].color_id]);
+ uiStyleFontDraw(&data->fstyle, &bbox, data->lines[i]);
+ }
+ if ((i + 1 != data->totline) && data->format[i + 1].is_pad) {
+ bbox.ymax -= data->lineh * UI_TIP_PAD_FAC;
+ bbox.ymin -= data->lineh * UI_TIP_PAD_FAC;
+ }
+ else {
+ bbox.ymax -= data->lineh;
+ bbox.ymin -= data->lineh;
+ }
}
if (multisample_enabled)
@@ -254,6 +322,7 @@ static void ui_tooltip_region_free_cb(ARegion *ar)
ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
{
+ const float pad_px = UI_TIP_PADDING;
wmWindow *win = CTX_wm_window(C);
uiStyle *style = UI_GetStyle();
static ARegionType type;
@@ -264,7 +333,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
/* aspect values that shrink text are likely unreadable */
const float aspect = min_ff(1.0f, but->block->aspect);
float fonth, fontw;
- int winx /*, winy */, ofsx, ofsy, w, h, a;
+ int winx, ofsx, ofsy, w = 0, h, i;
rctf rect_fl;
rcti rect_i;
@@ -284,52 +353,58 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
uiButGetStrInfo(C, but, &but_tip, &enum_label, &enum_tip, &op_keymap, &prop_keymap, &rna_struct, &rna_prop, NULL);
- /* special case, enum rna buttons only have enum item description,
- * use general enum description too before the specific one */
-
/* Tip */
if (but_tip.strinfo) {
- /* Expanded Bit-flag enums have a specific way to select multiple... */
- if ((but->type & ROW) && but->rnaprop && RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG) {
- BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]),
- "%s %s", but_tip.strinfo, IFACE_("(Shift-click to select multiple)"));
+ BLI_strncpy(data->header, but_tip.strinfo, sizeof(data->lines[0]));
+ if (enum_label.strinfo) {
+ BLI_snprintf(data->header, sizeof(data->header), "%s: ", but_tip.strinfo);
+ BLI_strncpy(data->active_info, enum_label.strinfo, sizeof(data->lines[0]));
}
- else {
- BLI_strncpy(data->lines[data->totline], but_tip.strinfo, sizeof(data->lines[0]));
- }
- data->color_id[data->totline] = UI_TIP_LC_MAIN;
+ data->format[data->totline].style = UI_TIP_STYLE_HEADER;
data->totline++;
+
+ /* special case enum rna buttons */
+ if ((but->type & ROW) && but->rnaprop && RNA_property_flag(but->rnaprop) & PROP_ENUM_FLAG) {
+ BLI_strncpy(data->lines[data->totline], IFACE_("(Shift-click to select multiple)"), sizeof(data->lines[0]));
+
+ data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
+ data->totline++;
+ }
+
}
/* Enum item label & tip */
- if (enum_label.strinfo && enum_tip.strinfo) {
- BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]),
- "%s: %s", enum_label.strinfo, enum_tip.strinfo);
- data->color_id[data->totline] = UI_TIP_LC_SUBMENU;
+ if (enum_tip.strinfo) {
+ BLI_strncpy(data->lines[data->totline], enum_tip.strinfo, sizeof(data->lines[0]));
+ data->format[data->totline].is_pad = true;
+ data->format[data->totline].color_id = UI_TIP_LC_VALUE;
data->totline++;
}
/* Op shortcut */
if (op_keymap.strinfo) {
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Shortcut: %s"), op_keymap.strinfo);
- data->color_id[data->totline] = UI_TIP_LC_NORMAL;
+ data->format[data->totline].is_pad = true;
+ data->format[data->totline].color_id = UI_TIP_LC_VALUE;
data->totline++;
}
/* Property context-toggle shortcut */
if (prop_keymap.strinfo) {
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Shortcut: %s"), prop_keymap.strinfo);
- data->color_id[data->totline] = UI_TIP_LC_NORMAL;
+ data->format[data->totline].is_pad = true;
+ data->format[data->totline].color_id = UI_TIP_LC_VALUE;
data->totline++;
}
- if (ELEM3(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
+ if (ELEM(but->type, TEX, SEARCH_MENU, SEARCH_MENU_UNLINK)) {
/* better not show the value of a password */
if ((but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PASSWORD)) == 0) {
/* full string */
ui_get_but_string(but, buf, sizeof(buf));
if (buf[0]) {
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Value: %s"), buf);
- data->color_id[data->totline] = UI_TIP_LC_NORMAL;
+ data->format[data->totline].is_pad = true;
+ data->format[data->totline].color_id = UI_TIP_LC_VALUE;
data->totline++;
}
}
@@ -344,7 +419,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
RNA_property_float_get_index(&but->rnapoin, but->rnaprop, but->rnaindex) :
RNA_property_float_get(&but->rnapoin, but->rnaprop);
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Radians: %f"), value);
- data->color_id[data->totline] = UI_TIP_LC_NORMAL;
+ data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
data->totline++;
}
}
@@ -353,7 +428,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
if (ui_but_anim_expression_get(but, buf, sizeof(buf))) {
/* expression */
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Expression: %s"), buf);
- data->color_id[data->totline] = UI_TIP_LC_NORMAL;
+ data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
data->totline++;
}
}
@@ -362,7 +437,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
ID *id = but->rnapoin.id.data;
if (id->lib) {
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Library: %s"), id->lib->name);
- data->color_id[data->totline] = UI_TIP_LC_NORMAL;
+ data->format[data->totline].color_id = UI_TIP_LC_NORMAL;
data->totline++;
}
}
@@ -383,7 +458,9 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
/* operator info */
if ((U.flag & USER_TOOLTIPS_PYTHON) == 0) {
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Python: %s"), str);
- data->color_id[data->totline] = UI_TIP_LC_PYTHON;
+ data->format[data->totline].style = UI_TIP_STYLE_MONO;
+ data->format[data->totline].is_pad = true;
+ data->format[data->totline].color_id = UI_TIP_LC_PYTHON;
data->totline++;
}
@@ -397,7 +474,7 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
poll_msg = CTX_wm_operator_poll_msg_get(C);
if (poll_msg) {
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Disabled: %s"), poll_msg);
- data->color_id[data->totline] = UI_TIP_LC_ALERT; /* alert */
+ data->format[data->totline].color_id = UI_TIP_LC_ALERT;
data->totline++;
}
}
@@ -414,7 +491,9 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]),
TIP_("Python: %s"), rna_struct.strinfo);
}
- data->color_id[data->totline] = UI_TIP_LC_PYTHON;
+ data->format[data->totline].style = UI_TIP_STYLE_MONO;
+ data->format[data->totline].is_pad = true;
+ data->format[data->totline].color_id = UI_TIP_LC_PYTHON;
data->totline++;
if (but->rnapoin.id.data) {
@@ -447,7 +526,8 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
}
MEM_freeN(id_path);
- data->color_id[data->totline] = UI_TIP_LC_PYTHON;
+ data->format[data->totline].style = UI_TIP_STYLE_MONO;
+ data->format[data->totline].color_id = UI_TIP_LC_PYTHON;
data->totline++;
}
}
@@ -486,22 +566,40 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
/* set font, get bb */
data->fstyle = style->widget; /* copy struct */
- data->fstyle.align = UI_STYLE_TEXT_CENTER;
ui_fontscale(&data->fstyle.points, aspect);
uiStyleFontSet(&data->fstyle);
/* these defines tweaked depending on font */
-#define TIP_MARGIN_Y (2.0f / aspect)
#define TIP_BORDER_X (16.0f / aspect)
#define TIP_BORDER_Y (6.0f / aspect)
h = BLF_height_max(data->fstyle.uifont_id);
- for (a = 0, fontw = 0, fonth = 0; a < data->totline; a++) {
- w = BLF_width(data->fstyle.uifont_id, data->lines[a], sizeof(data->lines[a]));
+ for (i = 0, fontw = 0, fonth = 0; i < data->totline; i++) {
+ if (data->format[i].style == UI_TIP_STYLE_HEADER) {
+ w = BLF_width(data->fstyle.uifont_id, data->header, sizeof(data->header));
+ if (enum_label.strinfo)
+ w += BLF_width(data->fstyle.uifont_id, data->active_info, sizeof(data->active_info));
+ }
+ else if (data->format[i].style == UI_TIP_STYLE_MONO) {
+ BLF_size(blf_mono_font, data->fstyle.points * U.pixelsize, U.dpi);
+
+ w = BLF_width(blf_mono_font, data->lines[i], sizeof(data->lines[i]));
+ }
+ else {
+ BLI_assert(data->format[i].style == UI_TIP_STYLE_NORMAL);
+ w = BLF_width(data->fstyle.uifont_id, data->lines[i], sizeof(data->lines[i]));
+ }
+
fontw = max_ff(fontw, (float)w);
- fonth += (a == 0) ? h : h + TIP_MARGIN_Y;
+
+ if ((i + 1 != data->totline) && data->format[i + 1].is_pad) {
+ fonth += h * UI_TIP_PAD_FAC;
+ }
+ else {
+ fonth += h;
+ }
}
//fontw *= aspect;
@@ -510,30 +608,38 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
data->toth = fonth;
data->lineh = h;
- data->spaceh = TIP_MARGIN_Y;
/* compute position */
ofsx = 0; //(but->block->panel) ? but->block->panel->ofsx : 0;
ofsy = 0; //(but->block->panel) ? but->block->panel->ofsy : 0;
rect_fl.xmin = BLI_rctf_cent_x(&but->rect) + ofsx - TIP_BORDER_X;
- rect_fl.xmax = rect_fl.xmin + fontw + (TIP_BORDER_X * 2);
+ rect_fl.xmax = rect_fl.xmin + fontw + pad_px;
rect_fl.ymax = but->rect.ymin + ofsy - TIP_BORDER_Y;
rect_fl.ymin = rect_fl.ymax - fonth - TIP_BORDER_Y;
-
-#undef TIP_MARGIN_Y
-#undef TIP_BORDER_X
-#undef TIP_BORDER_Y
/* since the text has beens caled already, the size of tooltips is defined now */
/* here we try to figure out the right location */
if (butregion) {
+ float mx, my;
float ofsx_fl = rect_fl.xmin, ofsy_fl = rect_fl.ymax;
ui_block_to_window_fl(butregion, but->block, &ofsx_fl, &ofsy_fl);
- BLI_rctf_translate(&rect_fl, ofsx_fl - rect_fl.xmin, ofsy_fl - rect_fl.ymax);
+
+#if 1
+ /* use X mouse location */
+ mx = (win->eventstate->x + (TIP_BORDER_X * 2)) - BLI_rctf_cent_x(&but->rect);
+#else
+ mx = ofsx_fl - rect_fl.xmin;
+#endif
+ my = ofsy_fl - rect_fl.ymax;
+
+ BLI_rctf_translate(&rect_fl, mx, my);
}
BLI_rcti_rctf_copy(&rect_i, &rect_fl);
+#undef TIP_BORDER_X
+#undef TIP_BORDER_Y
+
/* clip with window boundaries */
winx = WM_window_pixels_x(win);
@@ -555,20 +661,25 @@ ARegion *ui_tooltip_create(bContext *C, ARegion *butregion, uiBut *but)
rect_i.ymin = 30;
}
+ /* add padding */
+ BLI_rcti_resize(&rect_i,
+ BLI_rcti_size_x(&rect_i) + pad_px,
+ BLI_rcti_size_y(&rect_i) + pad_px);
+
/* widget rect, in region coords */
{
int width = UI_ThemeMenuShadowWidth();
data->bbox.xmin = width;
- data->bbox.xmax = BLI_rcti_size_x(&rect_i) + width;
+ data->bbox.xmax = BLI_rcti_size_x(&rect_i) - width;
data->bbox.ymin = width;
- data->bbox.ymax = BLI_rcti_size_y(&rect_i) + width;
+ data->bbox.ymax = BLI_rcti_size_y(&rect_i);
/* region bigger for shadow */
ar->winrct.xmin = rect_i.xmin - width;
ar->winrct.xmax = rect_i.xmax + width;
ar->winrct.ymin = rect_i.ymin - width;
- ar->winrct.ymax = rect_i.ymax + MENU_TOP;
+ ar->winrct.ymax = rect_i.ymax + width;
}
/* adds subwindow */
@@ -704,8 +815,10 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step)
data->active = 0;
ui_searchbox_update(C, ar, but, false);
}
- else if (data->active < -1)
- data->active = -1;
+ else {
+ /* only let users step into an 'unset' state for unlink buttons */
+ data->active = (but->type == SEARCH_MENU_UNLINK) ? -1 : 0;
+ }
}
ED_region_tag_redraw(ar);
@@ -775,6 +888,12 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar)
return true;
}
+ else if (but->type == SEARCH_MENU_UNLINK) {
+ /* It is valid for _UNLINK flavor to have no active element (it's a valid way to unlink). */
+ but->editstr[0] = '\0';
+
+ return true;
+ }
else {
return false;
}
@@ -911,7 +1030,7 @@ static void ui_searchbox_region_draw_cb(const bContext *UNUSED(C), ARegion *ar)
uiSearchboxData *data = ar->regiondata;
/* pixel space */
- wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f);
+ wmOrtho2_region_ui(ar);
if (data->noback == false)
ui_draw_search_back(NULL, NULL, &data->bbox); /* style not used yet */
@@ -1056,8 +1175,9 @@ ARegion *ui_searchbox_create(bContext *C, ARegion *butregion, uiBut *but)
/* widget rect, in region coords */
data->bbox.xmin = width;
data->bbox.xmax = BLI_rcti_size_x(&ar->winrct) - width;
- data->bbox.ymin = width;
- data->bbox.ymax = BLI_rcti_size_y(&ar->winrct) - width;
+ /* 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;
/* check if button is lower half */
if (but->rect.ymax < BLI_rctf_cent_y(&but->block->rect)) {
@@ -1421,6 +1541,15 @@ static void ui_block_region_draw(const bContext *C, ARegion *ar)
{
uiBlock *block;
+ if (ar->do_draw & RGN_DRAW_REFRESH_UI) {
+ uiBlock *block_next;
+ ar->do_draw &= ~RGN_DRAW_REFRESH_UI;
+ for (block = ar->uiblocks.first; block; block = block_next) {
+ block_next = block->next;
+ ui_popup_block_refresh((bContext *)C, block->handle, NULL, NULL);
+ }
+ }
+
for (block = ar->uiblocks.first; block; block = block->next)
uiDrawBlock(C, block);
}
@@ -1502,42 +1631,50 @@ void ui_popup_block_scrolltest(uiBlock *block)
}
}
-uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut *but,
- uiBlockCreateFunc create_func, uiBlockHandleCreateFunc handle_create_func,
- void *arg)
+static void ui_popup_block_remove(bContext *C, uiPopupBlockHandle *handle)
{
- wmWindow *window = CTX_wm_window(C);
- static ARegionType type;
- ARegion *ar;
- uiBlock *block;
- uiPopupBlockHandle *handle;
- uiSafetyRct *saferct;
- int width = UI_ThemeMenuShadowWidth();
+ ui_remove_temporary_region(C, CTX_wm_screen(C), handle->region);
- /* create handle */
- handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
+ if (handle->scrolltimer)
+ WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), handle->scrolltimer);
+}
- /* store context for operator */
- handle->ctx_area = CTX_wm_area(C);
- handle->ctx_region = CTX_wm_region(C);
-
- /* create area region */
- ar = ui_add_temporary_region(CTX_wm_screen(C));
- handle->region = ar;
+/**
+ * Called for creatign new popups and refreshing existing ones.
+ */
+uiBlock *ui_popup_block_refresh(
+ bContext *C, uiPopupBlockHandle *handle,
+ ARegion *butregion, uiBut *but)
+{
+ const int width = UI_ThemeMenuShadowWidth();
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = handle->region;
- memset(&type, 0, sizeof(ARegionType));
- type.draw = ui_block_region_draw;
- type.regionid = RGN_TYPE_TEMPORARY;
- ar->type = &type;
+ uiBlockCreateFunc create_func = handle->popup_create_vars.create_func;
+ uiBlockHandleCreateFunc handle_create_func = handle->popup_create_vars.handle_create_func;
+ void *arg = handle->popup_create_vars.arg;
- UI_add_region_handlers(&ar->handlers);
+ uiBlock *block_old = ar->uiblocks.first;
+ uiBlock *block;
+
+#ifdef DEBUG
+ wmEvent *event_back = window->eventstate;
+#endif
/* create ui block */
if (create_func)
- block = create_func(C, handle->region, arg);
+ block = create_func(C, ar, arg);
else
block = handle_create_func(C, handle, arg);
+ /* callbacks _must_ leave this for us, otherwise we can't call uiBlockUpdateFromOld */
+ BLI_assert(!block->endblock);
+
+ /* ensure we don't use mouse coords here! */
+#ifdef DEBUG
+ window->eventstate = NULL;
+#endif
+
if (block->handle) {
memcpy(block->handle, handle, sizeof(uiPopupBlockHandle));
MEM_freeN(handle);
@@ -1560,8 +1697,11 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut
block->flag |= UI_BLOCK_LOOP;
+ /* defer this until blocks are translated (below) */
+ block->oldblock = NULL;
+
if (!block->endblock)
- uiEndBlock(C, block);
+ uiEndBlock_ex(C, block, handle->popup_create_vars.event_xy);
/* if this is being created from a button */
if (but) {
@@ -1570,31 +1710,89 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut
handle->direction = block->direction;
}
else {
+ uiSafetyRct *saferct;
/* keep a list of these, needed for pulldown menus */
saferct = MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct");
saferct->safety = block->safety;
BLI_addhead(&block->saferct, saferct);
}
- /* clip block with window boundary */
- ui_popup_block_clip(window, block);
-
- /* the block and buttons were positioned in window space as in 2.4x, now
- * these menu blocks are regions so we bring it back to region space.
- * additionally we add some padding for the menu shadow or rounded menus */
- ar->winrct.xmin = block->rect.xmin - width;
- ar->winrct.xmax = block->rect.xmax + width;
- ar->winrct.ymin = block->rect.ymin - width;
- ar->winrct.ymax = block->rect.ymax + MENU_TOP;
-
- ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
+ if (block->flag & UI_BLOCK_RADIAL) {
+ uiBut *but;
+ int win_width = UI_SCREEN_MARGIN;
+ int winx, winy;
- /* adds subwindow */
- ED_region_init(C, ar);
+ int x_offset = 0, y_offset = 0;
+
+ winx = WM_window_pixels_x(window);
+ winy = WM_window_pixels_y(window);
+
+ copy_v2_v2(block->pie_data.pie_center_init, block->pie_data.pie_center_spawned);
+
+ /* only try translation if area is large enough */
+ if (BLI_rctf_size_x(&block->rect) < winx - (2.0f * win_width)) {
+ if (block->rect.xmin < win_width ) x_offset += win_width - block->rect.xmin;
+ if (block->rect.xmax > winx - win_width) x_offset += winx - win_width - block->rect.xmax;
+ }
+
+ if (BLI_rctf_size_y(&block->rect) < winy - (2.0f * win_width)) {
+ if (block->rect.ymin < win_width ) y_offset += win_width - block->rect.ymin;
+ if (block->rect.ymax > winy - win_width) y_offset += winy - win_width - block->rect.ymax;
+ }
+ /* if we are offsetting set up initial data for timeout functionality */
+
+ if ((x_offset != 0) || (y_offset != 0)) {
+ block->pie_data.pie_center_spawned[0] += x_offset;
+ block->pie_data.pie_center_spawned[1] += y_offset;
+
+ ui_block_translate(block, x_offset, y_offset);
+
+ if (U.pie_initial_timeout > 0)
+ block->pie_data.flags |= UI_PIE_INITIAL_DIRECTION;
+ }
+
+ ar->winrct.xmin = 0;
+ ar->winrct.xmax = winx;
+ ar->winrct.ymin = 0;
+ ar->winrct.ymax = winy;
+
+ ui_block_calculate_pie_segment(block, block->pie_data.pie_center_init);
+
+ /* lastly set the buttons at the center of the pie menu, ready for animation */
+ if (U.pie_animation_timeout > 0) {
+ for (but = block->buttons.first; but; but = but->next) {
+ if (but->pie_dir != UI_RADIAL_NONE) {
+ BLI_rctf_recenter(&but->rect, UNPACK2(block->pie_data.pie_center_spawned));
+ }
+ }
+ }
+ }
+ else {
+ /* clip block with window boundary */
+ ui_popup_block_clip(window, block);
+ /* the block and buttons were positioned in window space as in 2.4x, now
+ * these menu blocks are regions so we bring it back to region space.
+ * additionally we add some padding for the menu shadow or rounded menus */
+ ar->winrct.xmin = block->rect.xmin - width;
+ ar->winrct.xmax = block->rect.xmax + width;
+ ar->winrct.ymin = block->rect.ymin - width;
+ ar->winrct.ymax = block->rect.ymax + MENU_TOP;
+
+ ui_block_translate(block, -ar->winrct.xmin, -ar->winrct.ymin);
+ }
+
+ if (block_old) {
+ block->oldblock = block_old;
+ uiBlockUpdateFromOld(C, block);
+ uiFreeInactiveBlocks(C, &ar->uiblocks);
+ }
/* checks which buttons are visible, sets flags to prevent draw (do after region init) */
ui_popup_block_scrolltest(block);
+ /* adds subwindow */
+ ED_region_init(C, ar);
+
/* get winmat now that we actually have the subwindow */
wmSubWindowSet(window, ar->swinid);
@@ -1603,15 +1801,59 @@ uiPopupBlockHandle *ui_popup_block_create(bContext *C, ARegion *butregion, uiBut
/* notify change and redraw */
ED_region_tag_redraw(ar);
+ ED_region_update_rect(C, ar);
+
+#ifdef DEBUG
+ window->eventstate = event_back;
+#endif
+
+ return block;
+}
+
+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;
+ ARegion *ar;
+ uiBlock *block;
+ uiPopupBlockHandle *handle;
+
+ /* create handle */
+ handle = MEM_callocN(sizeof(uiPopupBlockHandle), "uiPopupBlockHandle");
+
+ /* store context for operator */
+ handle->ctx_area = CTX_wm_area(C);
+ handle->ctx_region = CTX_wm_region(C);
+
+ /* store vars to refresh popup (RGN_DRAW_REFRESH_UI) */
+ handle->popup_create_vars.create_func = create_func;
+ handle->popup_create_vars.handle_create_func = handle_create_func;
+ handle->popup_create_vars.arg = arg;
+ handle->popup_create_vars.butregion = but ? butregion : NULL;
+ copy_v2_v2_int(handle->popup_create_vars.event_xy, &window->eventstate->x);
+
+ /* create area region */
+ ar = ui_add_temporary_region(CTX_wm_screen(C));
+ handle->region = ar;
+
+ memset(&type, 0, sizeof(ARegionType));
+ type.draw = ui_block_region_draw;
+ type.regionid = RGN_TYPE_TEMPORARY;
+ ar->type = &type;
+
+ UI_add_region_handlers(&ar->handlers);
+
+ block = ui_popup_block_refresh(C, handle, butregion, but);
+ handle = block->handle;
+
return handle;
}
void ui_popup_block_free(bContext *C, uiPopupBlockHandle *handle)
{
- ui_remove_temporary_region(C, CTX_wm_screen(C), handle->region);
-
- if (handle->scrolltimer)
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), handle->scrolltimer);
+ ui_popup_block_remove(C, handle);
MEM_freeN(handle);
}
@@ -1694,7 +1936,7 @@ static void ui_update_block_buts_rgb(uiBlock *block, const float rgb[3], bool is
if (rgb_gamma[2] > 1.0f) rgb_gamma[2] = modf(rgb_gamma[2], &intpart);
rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma);
- BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar));
+ BLI_snprintf(col, sizeof(col), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
strcpy(bt->poin, col);
}
@@ -1982,7 +2224,7 @@ static void uiBlockPicker(uiBlock *block, float rgba[4], PointerRNA *ptr, Proper
}
rgb_float_to_uchar(rgb_gamma_uchar, rgb_gamma);
- BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3OP((unsigned int), rgb_gamma_uchar));
+ BLI_snprintf(hexcol, sizeof(hexcol), "%02X%02X%02X", UNPACK3_EX((unsigned int), rgb_gamma_uchar, ));
yco = -3.0f * UI_UNIT_Y;
bt = uiDefBut(block, TEX, 0, IFACE_("Hex: "), 0, yco, butwidth, UI_UNIT_Y, hexcol, 0, 8, 0, 0, TIP_("Hex triplet for color (#RRGGBB)"));
@@ -2175,6 +2417,12 @@ struct uiPopupMenu {
void *menu_arg;
};
+struct uiPieMenu {
+ uiBlock *block_radial; /* radial block of the pie menu (more could be added later) */
+ uiLayout *layout;
+ int mx, my;
+};
+
static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, void *arg_pup)
{
uiBlock *block;
@@ -2230,6 +2478,7 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
uiBlockSetFlag(block, UI_BLOCK_MOVEMOUSE_QUIT);
if (pup->popup) {
+ uiBut *but_activate = NULL;
uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT);
uiBlockSetDirection(block, direction);
@@ -2243,6 +2492,10 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
* block to be under the mouse */
offset[0] = -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect));
offset[1] = -(bt->rect.ymin + 0.5f * UI_UNIT_Y);
+
+ if (ui_but_is_editable(bt)) {
+ but_activate = bt;
+ }
}
else {
/* position mouse at 0.8*width of the button and below the tile
@@ -2252,6 +2505,20 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
offset[0] = min_ii(offset[0], -(bt->rect.xmin + 0.8f * BLI_rctf_size_x(&bt->rect)));
offset[1] = 2.1 * UI_UNIT_Y;
+
+ for (bt = block->buttons.first; bt; bt = bt->next) {
+ if (ui_but_is_editable(bt)) {
+ but_activate = bt;
+ break;
+ }
+ }
+ }
+
+ /* in rare cases this is needed since moving the popup
+ * to be within the window bounds may move it away from the mouse,
+ * This ensures we set an item to be active. */
+ if (but_activate) {
+ ui_button_activate_over(C, handle->region, but_activate);
}
block->minbounds = minwidth;
@@ -2278,8 +2545,6 @@ static uiBlock *ui_block_func_POPUP(bContext *C, uiPopupBlockHandle *handle, voi
if (pup->slideout)
uiBlockSetDirection(block, UI_RIGHT);
- uiEndBlock(C, block);
-
return pup->block;
}
@@ -2331,7 +2596,7 @@ uiPopupBlockHandle *ui_popup_menu_create(bContext *C, ARegion *butregion, uiBut
if (!but) {
handle->popup = true;
- UI_add_popup_handlers(C, &window->modalhandlers, handle);
+ UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
WM_event_add_mousemove(C);
}
@@ -2393,7 +2658,7 @@ void uiPupMenuEnd(bContext *C, uiPopupMenu *pup)
menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_POPUP, pup);
menu->popup = true;
- UI_add_popup_handlers(C, &window->modalhandlers, menu);
+ UI_add_popup_handlers(C, &window->modalhandlers, menu, false);
WM_event_add_mousemove(C);
MEM_freeN(pup);
@@ -2404,6 +2669,208 @@ uiLayout *uiPupMenuLayout(uiPopupMenu *pup)
return pup->layout;
}
+/*************************** Pie Menus ***************************************/
+
+static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handle, void *arg_pie)
+{
+ uiBlock *block;
+ uiPieMenu *pie = arg_pie;
+ int minwidth, width, height;
+
+ minwidth = 50;
+ block = pie->block_radial;
+
+ /* in some cases we create the block before the region,
+ * so we set it delayed here if necessary */
+ if (BLI_findindex(&handle->region->uiblocks, block) == -1)
+ uiBlockSetRegion(block, handle->region);
+
+ uiBlockLayoutResolve(block, &width, &height);
+
+ uiBlockSetFlag(block, UI_BLOCK_LOOP | UI_BLOCK_REDRAW | UI_BLOCK_NUMSELECT);
+
+ block->minbounds = minwidth;
+ block->bounds = 1;
+ block->mx = 0;
+ block->my = 0;
+ block->bounds_type = UI_BLOCK_BOUNDS_PIE_CENTER;
+
+ block->pie_data.pie_center_spawned[0] = pie->mx;
+ block->pie_data.pie_center_spawned[1] = pie->my;
+
+ return pie->block_radial;
+}
+
+static float uiPieTitleWidth(const char *name, int icon)
+{
+ return (UI_GetStringWidth(name) +
+ (UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
+}
+
+uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const wmEvent *event)
+{
+ uiStyle *style;
+ uiPieMenu *pie;
+ short event_type;
+
+ wmWindow *win = CTX_wm_window(C);
+
+ style = UI_GetStyleDraw();
+ pie = MEM_callocN(sizeof(uiPopupMenu), "pie menu");
+
+ pie->block_radial = uiBeginBlock(C, NULL, __func__, UI_EMBOSS);
+ /* may be useful later to allow spawning pies
+ * from old positions */
+ /* pie->block_radial->flag |= UI_BLOCK_POPUP_MEMORY; */
+ pie->block_radial->puphash = ui_popup_menu_hash(title);
+ pie->block_radial->flag |= UI_BLOCK_RADIAL;
+
+ /* if pie is spawned by a left click, it is always assumed to be click style */
+ if (event->type == LEFTMOUSE) {
+ pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE;
+ pie->block_radial->pie_data.event = EVENT_NONE;
+ win->lock_pie_event = EVENT_NONE;
+ }
+ else {
+ if (win->last_pie_event != EVENT_NONE) {
+ /* original pie key has been released, so don't propagate the event */
+ if (win->lock_pie_event == EVENT_NONE) {
+ event_type = EVENT_NONE;
+ pie->block_radial->pie_data.flags |= UI_PIE_CLICK_STYLE;
+ }
+ else
+ event_type = win->last_pie_event;
+ }
+ else {
+ event_type = event->type;
+ }
+
+ pie->block_radial->pie_data.event = event_type;
+ win->lock_pie_event = event_type;
+ }
+
+ pie->layout = uiBlockLayout(pie->block_radial, UI_LAYOUT_VERTICAL, UI_LAYOUT_PIEMENU, 0, 0, 200, 0, 0, style);
+ pie->mx = event->x;
+ pie->my = event->y;
+
+ /* create title button */
+ if (title[0]) {
+ uiBut *but;
+ char titlestr[256];
+ int w;
+ if (icon) {
+ BLI_snprintf(titlestr, sizeof(titlestr), " %s", title);
+ w = uiPieTitleWidth(titlestr, icon);
+ but = uiDefIconTextBut(pie->block_radial, LABEL, 0, icon, titlestr, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ }
+ else {
+ w = uiPieTitleWidth(title, 0);
+ but = uiDefBut(pie->block_radial, LABEL, 0, title, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
+ }
+ /* do not align left */
+ but->drawflag &= ~UI_BUT_TEXT_LEFT;
+ }
+
+ return pie;
+}
+
+void uiPieMenuEnd(bContext *C, uiPieMenu *pie)
+{
+ wmWindow *window = CTX_wm_window(C);
+ uiPopupBlockHandle *menu;
+
+ menu = ui_popup_block_create(C, NULL, NULL, NULL, ui_block_func_PIE, pie);
+ menu->popup = true;
+ menu->towardstime = PIL_check_seconds_timer();
+
+ UI_add_popup_handlers(C, &window->modalhandlers, menu, true);
+ WM_event_add_mousemove(C);
+
+ MEM_freeN(pie);
+}
+
+uiLayout *uiPieMenuLayout(uiPieMenu *pie)
+{
+ return pie->layout;
+}
+
+void uiPieMenuInvoke(struct bContext *C, const char *idname, const wmEvent *event)
+{
+ uiPieMenu *pie;
+ uiLayout *layout;
+ Menu menu;
+ MenuType *mt = WM_menutype_find(idname, true);
+
+ if (mt == NULL) {
+ printf("%s: named menu \"%s\" not found\n", __func__, idname);
+ return;
+ }
+
+ if (mt->poll && mt->poll(C, mt) == 0)
+ return;
+
+ pie = uiPieMenuBegin(C, IFACE_(mt->label), ICON_NONE, event);
+ layout = uiPieMenuLayout(pie);
+
+ menu.layout = layout;
+ menu.type = mt;
+
+ if (G.debug & G_DEBUG_WM) {
+ printf("%s: opening menu \"%s\"\n", __func__, idname);
+ }
+
+ mt->draw(C, &menu);
+
+ uiPieMenuEnd(C, pie);
+}
+
+void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname,
+ const char *propname, const wmEvent *event)
+{
+ uiPieMenu *pie;
+ uiLayout *layout;
+
+ pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event);
+ layout = uiPieMenuLayout(pie);
+
+ layout = uiLayoutRadial(layout);
+ uiItemsEnumO(layout, opname, propname);
+
+ uiPieMenuEnd(C, pie);
+}
+
+void uiPieEnumInvoke(struct bContext *C, const char *title, const char *path,
+ const wmEvent *event)
+{
+ PointerRNA ctx_ptr;
+ PointerRNA r_ptr;
+ PropertyRNA *r_prop;
+ uiPieMenu *pie;
+ uiLayout *layout;
+
+ RNA_pointer_create(NULL, &RNA_Context, C, &ctx_ptr);
+
+ if (!RNA_path_resolve(&ctx_ptr, path, &r_ptr, &r_prop)) {
+ return;
+ }
+
+ /* invalid property, only accept enums */
+ if (RNA_property_type(r_prop) != PROP_ENUM) {
+ BLI_assert(0);
+ return;
+ }
+
+ pie = uiPieMenuBegin(C, IFACE_(title), ICON_NONE, event);
+
+ layout = uiPieMenuLayout(pie);
+
+ layout = uiLayoutRadial(layout);
+ uiItemFullR(layout, &r_ptr, r_prop, RNA_NO_INDEX, 0, UI_ITEM_R_EXPAND, NULL, 0);
+
+ uiPieMenuEnd(C, pie);
+}
+
+
/*************************** Standard Popup Menus ****************************/
void uiPupMenuReports(bContext *C, ReportList *reports)
@@ -2500,13 +2967,13 @@ void uiPupBlockO(bContext *C, uiBlockCreateFunc func, void *arg, const char *opn
handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL;
handle->opcontext = opcontext;
- UI_add_popup_handlers(C, &window->modalhandlers, handle);
+ UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
WM_event_add_mousemove(C);
}
void uiPupBlock(bContext *C, uiBlockCreateFunc func, void *arg)
{
- uiPupBlockO(C, func, arg, NULL, 0);
+ uiPupBlockO(C, func, arg, NULL, WM_OP_INVOKE_DEFAULT);
}
void uiPupBlockEx(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, uiBlockCancelFunc cancel_func, void *arg)
@@ -2523,7 +2990,7 @@ void uiPupBlockEx(bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_f
handle->cancel_func = cancel_func;
// handle->opcontext = opcontext;
- UI_add_popup_handlers(C, &window->modalhandlers, handle);
+ UI_add_popup_handlers(C, &window->modalhandlers, handle, false);
WM_event_add_mousemove(C);
}
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index fa31c20eb74..c27789c0fc9 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -330,7 +330,7 @@ void UI_DrawString(float x, float y, const char *str)
/* reading without uifont will create one */
void uiStyleInit(void)
{
- uiFont *font = U.uifonts.first;
+ uiFont *font;
uiStyle *style = U.uistyles.first;
int monofont_size = datatoc_bmonofont_ttf_size;
unsigned char *monofont_ttf = (unsigned char *)datatoc_bmonofont_ttf;
@@ -340,11 +340,23 @@ void uiStyleInit(void)
U.dpi = 72;
CLAMP(U.dpi, 48, 144);
+ for (font = U.uifonts.first; font; font = font->next) {
+ BLF_unload_id(font->blf_id);
+ }
+
+ font = U.uifonts.first;
+
/* default builtin */
if (font == NULL) {
font = MEM_callocN(sizeof(uiFont), "ui font");
BLI_addtail(&U.uifonts, font);
-
+ }
+
+ if (U.font_path_ui[0]) {
+ BLI_strncpy(font->filename, U.font_path_ui, sizeof(font->filename));
+ font->uifont_id = UIFONT_CUSTOM1;
+ }
+ else {
BLI_strncpy(font->filename, "default", sizeof(font->filename));
font->uifont_id = UIFONT_DEFAULT;
}
@@ -381,8 +393,12 @@ void uiStyleInit(void)
}
else {
font->blf_id = BLF_load(font->filename);
- if (font->blf_id == -1)
+ if (font->blf_id == -1) {
font->blf_id = BLF_load_mem("default", (unsigned char *)datatoc_bfont_ttf, datatoc_bfont_ttf_size);
+ }
+ else {
+ BLF_default_set(font->blf_id);
+ }
}
if (font->blf_id == -1) {
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index e4c26d86044..b0bea42e3bc 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -36,6 +36,8 @@
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
+#include "DNA_brush_types.h"
+#include "DNA_texture_types.h"
#include "BLI_utildefines.h"
#include "BLI_string.h"
@@ -60,6 +62,7 @@
#include "BKE_object.h"
#include "BKE_packedFile.h"
#include "BKE_particle.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_sca.h"
#include "BKE_screen.h"
@@ -209,7 +212,6 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem)
uiBoundsBlock(block, 0.3f * U.widget_unit);
uiBlockSetDirection(block, UI_DOWN);
- uiEndBlock(C, block);
/* give search-field focus */
uiButSetFocusOnEnter(win, but);
@@ -340,7 +342,7 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_LA: return N_("Browse Lamp Data to be linked");
case ID_CA: return N_("Browse Camera Data to be linked");
case ID_WO: return N_("Browse World Settings to be linked");
- case ID_SCR: return N_("Choose Screen lay-out");
+ case ID_SCR: return N_("Choose Screen layout");
case ID_TXT: return N_("Browse Text to be linked");
case ID_SPK: return N_("Browse Speaker Data to be linked");
case ID_SO: return N_("Browse Sound to be linked");
@@ -350,6 +352,8 @@ static const char *template_id_browse_tip(StructRNA *type)
case ID_BR: return N_("Browse Brush to be linked");
case ID_PA: return N_("Browse Particle Settings to be linked");
case ID_GD: return N_("Browse Grease Pencil Data to be linked");
+ case ID_PAL: return N_("Browse Palette Data to be linked");
+ case ID_PC: return N_("Browse Paint Curve Data to be linked");
}
}
return N_("Browse ID data to be linked");
@@ -418,11 +422,9 @@ 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)));
- if (type) {
- but->icon = RNA_struct_ui_icon(type);
- if (id) but->icon = ui_id_icon_get(C, id, true);
- uiButSetFlag(but, UI_HAS_ICON | UI_ICON_PREVIEW);
- }
+ but->icon = id ? ui_id_icon_get(C, id, true) : RNA_struct_ui_icon(type);
+ uiButSetFlag(but, UI_HAS_ICON | UI_ICON_PREVIEW);
+
if ((idfrom && idfrom->lib) || !editable)
uiButSetFlag(but, UI_BUT_DISABLED);
@@ -431,14 +433,11 @@ 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)));
-
- if (type) {
- but->icon = RNA_struct_ui_icon(type);
- /* default dragging of icon for id browse buttons */
- uiButSetDragID(but, id);
- uiButSetFlag(but, UI_HAS_ICON);
- uiButSetDrawFlag(but, UI_BUT_ICON_LEFT);
- }
+ but->icon = RNA_struct_ui_icon(type);
+ /* default dragging of icon for id browse buttons */
+ uiButSetDragID(but, id);
+ uiButSetFlag(but, UI_HAS_ICON);
+ uiButSetDrawFlag(but, UI_BUT_ICON_LEFT);
if ((idfrom && idfrom->lib) || !editable)
uiButSetFlag(but, UI_BUT_DISABLED);
@@ -495,7 +494,7 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
if (user_alert) uiButSetFlag(but, UI_BUT_REDALERT);
- if (id->lib == NULL && !(ELEM5(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
+ if (id->lib == NULL && !(ELEM(GS(id->name), ID_GR, ID_SCE, ID_SCR, ID_TXT, ID_OB))) {
uiDefButR(block, TOG, 0, "F", 0, 0, UI_UNIT_X, UI_UNIT_Y, &idptr, "use_fake_user", -1, 0, 0, -1, -1, NULL);
}
}
@@ -577,24 +576,33 @@ static void template_ID(bContext *C, uiLayout *layout, TemplateID *template, Str
/* delete button */
/* don't use RNA_property_is_unlink here */
- if (id && (flag & UI_ID_DELETE) && (RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
+ if (id && (flag & UI_ID_DELETE)) {
+ /* allow unlink if 'unlinkop' is passed, even when 'PROP_NEVER_UNLINK' is set */
+ but = NULL;
+
if (unlinkop) {
but = uiDefIconButO(block, BUT, unlinkop, WM_OP_INVOKE_REGION_WIN, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
/* so we can access the template from operators, font unlinking needs this */
uiButSetNFunc(but, NULL, MEM_dupallocN(template), NULL);
}
else {
- but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
- TIP_("Unlink datablock "
- "(Shift + Click to set users to zero, data will then not be saved)"));
- uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
+ if ((RNA_property_flag(template->prop) & PROP_NEVER_UNLINK) == 0) {
+ but = uiDefIconBut(block, BUT, 0, ICON_X, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0,
+ TIP_("Unlink datablock "
+ "(Shift + Click to set users to zero, data will then not be saved)"));
+ uiButSetNFunc(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_DELETE));
- if (RNA_property_flag(template->prop) & PROP_NEVER_NULL)
- uiButSetFlag(but, UI_BUT_DISABLED);
+ if (RNA_property_flag(template->prop) & PROP_NEVER_NULL) {
+ uiButSetFlag(but, UI_BUT_DISABLED);
+ }
+ }
}
- if ((idfrom && idfrom->lib) || !editable)
- uiButSetFlag(but, UI_BUT_DISABLED);
+ if (but) {
+ if ((idfrom && idfrom->lib) || !editable) {
+ uiButSetFlag(but, UI_BUT_DISABLED);
+ }
+ }
}
if (idcode == ID_TE)
@@ -757,28 +765,6 @@ void uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propna
#define ERROR_LIBDATA_MESSAGE IFACE_("Can't edit external libdata")
-static void modifiers_setOnCage(bContext *C, void *ob_v, void *md_v)
-{
- Scene *scene = CTX_data_scene(C);
- Object *ob = ob_v;
- ModifierData *md = md_v;
- int i, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 0);
-
- /* undo button operation */
- md->mode ^= eModifierMode_OnCage;
-
- for (i = 0, md = ob->modifiers.first; md; ++i, md = md->next) {
- if (md == md_v) {
- if (i >= cageIndex)
- md->mode ^= eModifierMode_OnCage;
- break;
- }
- }
-
- WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
-}
-
static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v)
{
Object *ob = ob_v;
@@ -814,7 +800,7 @@ static int modifier_can_delete(ModifierData *md)
static int modifier_is_simulation(ModifierData *md)
{
/* Physic Tab */
- if (ELEM7(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke,
+ if (ELEM(md->type, eModifierType_Cloth, eModifierType_Collision, eModifierType_Fluidsim, eModifierType_Smoke,
eModifierType_Softbody, eModifierType_Surface, eModifierType_DynamicPaint))
{
return 1;
@@ -835,7 +821,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
PointerRNA ptr;
uiBut *but;
uiBlock *block;
- uiLayout *box, *column, *row;
+ uiLayout *box, *column, *row, *sub;
uiLayout *result = NULL;
int isVirtual = (md->mode & eModifierMode_Virtual);
char str[128];
@@ -876,7 +862,11 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
uiBlockSetEmboss(block, UI_EMBOSS);
/* modifier name */
+ if (mti->isDisabled && mti->isDisabled(md, 0)) {
+ uiLayoutSetRedAlert(row, true);
+ }
uiItemR(row, &ptr, "name", 0, "", ICON_NONE);
+ uiLayoutSetRedAlert(row, false);
/* mode enabling buttons */
uiBlockBeginAlign(block);
@@ -887,39 +877,32 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
uiItemR(row, &ptr, "show_render", 0, "", ICON_NONE);
uiItemR(row, &ptr, "show_viewport", 0, "", ICON_NONE);
- if (mti->flags & eModifierTypeFlag_SupportsEditmode)
- uiItemR(row, &ptr, "show_in_editmode", 0, "", ICON_NONE);
+ if (mti->flags & eModifierTypeFlag_SupportsEditmode) {
+ sub = uiLayoutRow(row, true);
+ if (!(md->mode & eModifierMode_Realtime)) {
+ uiLayoutSetActive(sub, false);
+ }
+ uiItemR(sub, &ptr, "show_in_editmode", 0, "", ICON_NONE);
+ }
}
if (ob->type == OB_MESH) {
- if (modifier_couldBeCage(scene, md) && (index <= lastCageIndex)) {
- /* -- convert to rna ? */
- but = uiDefIconButBitI(block, TOG, eModifierMode_OnCage, 0, ICON_MESH_DATA, 0, 0,
- UI_UNIT_X - 2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0,
- TIP_("Apply modifier to editing cage during Edit mode"));
- if (index < cageIndex)
- uiButSetFlag(but, UI_BUT_DISABLED);
- uiButSetFunc(but, modifiers_setOnCage, ob, md);
- }
- else if (modifier_supportsCage(scene, md) && (index <= lastCageIndex)) {
- uiBlockEndAlign(block);
-
- /* place holder button */
- uiBlockSetEmboss(block, UI_EMBOSSN);
- but = uiDefIconBut(block, BUT, 0, ICON_NONE, 0, 0, UI_UNIT_X - 2, UI_UNIT_Y,
- NULL, 0.0, 0.0, 0.0, 0.0, NULL);
- uiButSetFlag(but, UI_BUT_DISABLED);
- uiBlockSetEmboss(block, UI_EMBOSS);
+ if (modifier_supportsCage(scene, md) && (index <= lastCageIndex)) {
+ sub = uiLayoutRow(row, true);
+ if (index < cageIndex || !modifier_couldBeCage(scene, md)) {
+ uiLayoutSetActive(sub, false);
+ }
+ uiItemR(sub, &ptr, "show_on_cage", 0, "", ICON_NONE);
}
} /* tessellation point for curve-typed objects */
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
/* some modifiers could work with pre-tessellated curves only */
- if (ELEM3(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
+ if (ELEM(md->type, eModifierType_Hook, eModifierType_Softbody, eModifierType_MeshDeform)) {
/* add disabled pre-tessellated button, so users could have
* message for this modifiers */
but = uiDefIconButBitI(block, TOG, eModifierMode_ApplyOnSpline, 0, ICON_SURFACE_DATA, 0, 0,
UI_UNIT_X - 2, UI_UNIT_Y, &md->mode, 0.0, 0.0, 0.0, 0.0,
- TIP_("This modifier could be applied on splines' points only"));
+ TIP_("This modifier can only be applied on splines' points"));
uiButSetFlag(but, UI_BUT_DISABLED);
}
else if (mti->type != eModifierTypeType_Constructive) {
@@ -985,7 +968,7 @@ static uiLayout *draw_modifier(uiLayout *layout, Scene *scene, Object *ob,
uiBlockClearButLock(block);
uiBlockSetButLock(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE);
- if (!ELEM5(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem,
+ if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem,
eModifierType_Cloth, eModifierType_Smoke))
{
uiItemO(row, CTX_IFACE_(BLF_I18NCONTEXT_OPERATOR_DEFAULT, "Copy"), ICON_NONE,
@@ -1304,7 +1287,7 @@ void uiTemplatePreview(uiLayout *layout, bContext *C, ID *id, int show_buttons,
char _preview_id[UI_MAX_NAME_STR];
- if (id && !ELEM5(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) {
+ if (id && !ELEM(GS(id->name), ID_MA, ID_TE, ID_WO, ID_LA, ID_LS)) {
RNA_warning("Expected ID of type material, texture, lamp, world or line style");
return;
}
@@ -1531,7 +1514,15 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
row = uiLayoutRow(split, false);
- uiItemR(row, &ptr, "interpolation", 0, "", ICON_NONE);
+ uiBlockBeginAlign(block);
+ uiItemR(row, &ptr, "color_mode", 0, "", ICON_NONE);
+ if (ELEM(coba->color_mode, COLBAND_BLEND_HSV, COLBAND_BLEND_HSL)) {
+ uiItemR(row, &ptr, "hue_interpolation", 0, "", ICON_NONE);
+ }
+ else { /* COLBAND_BLEND_RGB */
+ uiItemR(row, &ptr, "interpolation", 0, "", ICON_NONE);
+ }
+ uiBlockEndAlign(block);
row = uiLayoutRow(layout, false);
@@ -1569,7 +1560,7 @@ static void colorband_buttons_layout(uiLayout *layout, uiBlock *block, ColorBand
uiDefButS(block, NUM, 0, "", 0, 0, 5.0f * UI_UNIT_X, UI_UNIT_Y, &coba->cur, 0.0, (float)(MAX2(0, coba->tot - 1)),
0, 0, TIP_("Choose active color stop"));
row = uiLayoutRow(subsplit, false);
- uiItemR(row, &ptr, "position", 0, IFACE_("Pos"), ICON_NONE);
+ uiItemR(row, &ptr, "position", UI_ITEM_R_SLIDER, IFACE_("Pos"), ICON_NONE);
bt = block->buttons.last;
uiButSetFunc(bt, colorband_update_cb, bt, coba);
@@ -1656,8 +1647,7 @@ static uiBlock *icon_view_menu(bContext *C, ARegion *ar, void *arg_litem)
uiBoundsBlock(block, 0.3f * U.widget_unit);
uiBlockSetDirection(block, UI_TOP);
- uiEndBlock(C, block);
-
+
if (free) {
MEM_freeN(item);
}
@@ -1957,10 +1947,11 @@ static void curvemap_tools_dofunc(bContext *C, void *cumap_v, int event)
curvemapping_changed(cumap, false);
break;
}
+ ED_undo_push(C, "CurveMap tools");
ED_region_tag_redraw(CTX_wm_region(C));
}
-static uiBlock *curvemap_tools_func(bContext *C, ARegion *ar, void *cumap_v)
+static uiBlock *curvemap_tools_posslope_func(bContext *C, ARegion *ar, void *cumap_v)
{
uiBlock *block;
short yco = 0, menuwidth = 10 * UI_UNIT_X;
@@ -1988,6 +1979,34 @@ static uiBlock *curvemap_tools_func(bContext *C, ARegion *ar, void *cumap_v)
return block;
}
+static uiBlock *curvemap_tools_negslope_func(bContext *C, ARegion *ar, void *cumap_v)
+{
+ uiBlock *block;
+ short yco = 0, menuwidth = 10 * UI_UNIT_X;
+
+ block = uiBeginBlock(C, ar, __func__, UI_EMBOSS);
+ uiBlockSetButmFunc(block, curvemap_tools_dofunc, cumap_v);
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset View"), 0, yco -= UI_UNIT_Y,
+ menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_VIEW, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Vector Handle"), 0, yco -= UI_UNIT_Y,
+ menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_VECTOR, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Auto Handle"), 0, yco -= UI_UNIT_Y,
+ menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_HANDLE_AUTO, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Extend Horizontal"), 0, yco -= UI_UNIT_Y,
+ menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_HOZ, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Extend Extrapolated"), 0, yco -= UI_UNIT_Y,
+ menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_EXTEND_EXP, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, IFACE_("Reset Curve"), 0, yco -= UI_UNIT_Y,
+ menuwidth, UI_UNIT_Y, NULL, 0.0, 0.0, 0, UICURVE_FUNC_RESET_NEG, "");
+
+ uiBlockSetDirection(block, UI_RIGHT);
+ uiTextBoundsBlock(block, 50);
+
+ uiEndBlock(C, block);
+ return block;
+}
+
static uiBlock *curvemap_brush_tools_func(bContext *C, ARegion *ar, void *cumap_v)
{
uiBlock *block;
@@ -2044,7 +2063,7 @@ 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, RNAUpdateCb *cb)
+ int brush, int neg_slope, RNAUpdateCb *cb)
{
CurveMapping *cumap = ptr->data;
CurveMap *cm = &cumap->cm[cumap->cur];
@@ -2138,8 +2157,12 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
if (brush)
bt = uiDefIconBlockBut(block, curvemap_brush_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
+ else if (neg_slope)
+ bt = uiDefIconBlockBut(block, curvemap_tools_negslope_func, cumap, 0, ICON_MODIFIER,
+ 0, 0, dx, dx, TIP_("Tools"));
else
- bt = uiDefIconBlockBut(block, curvemap_tools_func, cumap, 0, ICON_MODIFIER, 0, 0, dx, dx, TIP_("Tools"));
+ bt = uiDefIconBlockBut(block, curvemap_tools_posslope_func, cumap, 0, ICON_MODIFIER,
+ 0, 0, dx, dx, TIP_("Tools"));
uiButSetNFunc(bt, rna_update_cb, MEM_dupallocN(cb), NULL);
@@ -2201,7 +2224,8 @@ static void curvemap_buttons_layout(uiLayout *layout, PointerRNA *ptr, char labe
uiBlockSetNFunc(block, NULL, NULL, NULL);
}
-void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, int levels, int brush)
+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);
@@ -2232,7 +2256,7 @@ void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propn
id = cptr.id.data;
uiBlockSetButLock(block, (id && id->lib), ERROR_LIBDATA_MESSAGE);
- curvemap_buttons_layout(layout, &cptr, type, levels, brush, cb);
+ curvemap_buttons_layout(layout, &cptr, type, levels, brush, neg_slope, cb);
uiBlockClearButLock(block);
@@ -2336,6 +2360,60 @@ void uiTemplateColorPicker(uiLayout *layout, PointerRNA *ptr, const char *propna
}
}
+void uiTemplatePalette(uiLayout *layout, PointerRNA *ptr, const char *propname, int UNUSED(colors))
+{
+ PropertyRNA *prop = RNA_struct_find_property(ptr, propname);
+ PointerRNA cptr;
+ Palette *palette;
+ PaletteColor *color;
+ uiBlock *block;
+ uiLayout *col;
+ int row_cols = 0, col_id = 0;
+ int cols_per_row = MAX2(uiLayoutGetWidth(layout) / UI_UNIT_X, 1);
+
+ if (!prop) {
+ RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname);
+ return;
+ }
+
+ cptr = RNA_property_pointer_get(ptr, prop);
+ if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_Palette))
+ return;
+
+ block = uiLayoutGetBlock(layout);
+
+ palette = cptr.data;
+
+ /* first delete any pending colors */
+ BKE_palette_cleanup(palette);
+
+ color = palette->colors.first;
+
+ col = uiLayoutColumn(layout, true);
+ uiLayoutRow(col, true);
+ uiDefIconButO(block, BUT, "PALETTE_OT_color_add", WM_OP_INVOKE_DEFAULT, ICON_ZOOMIN, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+ uiDefIconButO(block, BUT, "PALETTE_OT_color_delete", WM_OP_INVOKE_DEFAULT, ICON_ZOOMOUT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL);
+
+ col = uiLayoutColumn(layout, true);
+ uiLayoutRow(col, true);
+
+ for (; color; color = color->next) {
+ PointerRNA ptr;
+
+ if (row_cols >= cols_per_row) {
+ uiLayoutRow(col, true);
+ row_cols = 0;
+ }
+
+ RNA_pointer_create(&palette->id, &RNA_PaletteColor, color, &ptr);
+ uiDefButR(block, COLOR, 0, "", 0, 0, UI_UNIT_X, UI_UNIT_Y, &ptr, "color", -1, 0.0, 1.0,
+ UI_PALETTE_COLOR, col_id, "");
+ row_cols++;
+ col_id++;
+ }
+}
+
+
/********************* Layer Buttons Template ************************/
static void handle_layer_buttons(bContext *C, void *arg1, void *arg2)
@@ -2566,8 +2644,8 @@ static void uilist_filter_items_default(struct uiList *ui_list, struct bContext
const char *filter_raw = ui_list->filter_byname;
char *filter = (char *)filter_raw, filter_buff[32], *filter_dyn = NULL;
- bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0;
- bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_ALPHA) != 0;
+ const bool filter_exclude = (ui_list->filter_flag & UILST_FLT_EXCLUDE) != 0;
+ const bool order_by_name = (ui_list->filter_sort_flag & UILST_FLT_SORT_ALPHA) != 0;
int len = RNA_property_collection_length(dataptr, prop);
dyn_data->items_shown = dyn_data->items_len = len;
@@ -2851,11 +2929,11 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
ui_list = MEM_callocN(sizeof(uiList), "uiList");
BLI_strncpy(ui_list->list_id, ui_list_id, sizeof(ui_list->list_id));
BLI_addtail(&ar->ui_lists, ui_list);
+ ui_list->list_grip = -UI_LIST_AUTO_SIZE_THRESHOLD; /* Force auto size by default. */
}
if (!ui_list->dyn_data) {
ui_list->dyn_data = MEM_callocN(sizeof(uiListDyn), "uiList.dyn_data");
- ui_list->list_grip = -UI_LIST_AUTO_SIZE_THRESHOLD; /* Force auto size by default. */
}
dyn_data = ui_list->dyn_data;
@@ -2876,8 +2954,8 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* Filter list items! (not for compact layout, though) */
if (dataptr->data && prop) {
- int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE;
- bool order_reverse = (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0;
+ const int filter_exclude = ui_list->filter_flag & UILST_FLT_EXCLUDE;
+ const bool order_reverse = (ui_list->filter_sort_flag & UILST_FLT_SORT_REVERSE) != 0;
int items_shown, idx = 0;
#if 0
int prev_ii = -1, prev_i;
@@ -3161,7 +3239,7 @@ static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2)
wmOperatorType *ot = arg2;
if (ot)
- WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, NULL);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL);
}
static void operator_search_cb(const bContext *C, void *UNUSED(arg), const char *str, uiSearchItems *items)
@@ -3416,13 +3494,9 @@ static void template_keymap_item_properties(uiLayout *layout, const char *title,
RNA_STRUCT_BEGIN (ptr, prop)
{
- int flag = RNA_property_flag(prop);
- bool is_set = RNA_property_is_set(ptr, prop);
+ const bool is_set = RNA_property_is_set(ptr, prop);
uiBut *but;
- if (flag & PROP_HIDDEN)
- continue;
-
/* recurse for nested properties */
if (RNA_property_type(prop) == PROP_POINTER) {
PointerRNA propptr = RNA_property_pointer_get(ptr, prop);
@@ -3516,7 +3590,7 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P
col = uiLayoutColumn(layout, false);
row = uiLayoutRow(col, false);
- uiItemR(row, &view_transform_ptr, "view_transform", UI_ITEM_R_EXPAND, IFACE_("View"), ICON_NONE);
+ uiItemR(row, &view_transform_ptr, "view_transform", 0, IFACE_("View"), ICON_NONE);
col = uiLayoutColumn(layout, false);
uiItemR(col, &view_transform_ptr, "exposure", 0, NULL, ICON_NONE);
@@ -3527,7 +3601,7 @@ void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), P
col = uiLayoutColumn(layout, false);
uiItemR(col, &view_transform_ptr, "use_curve_mapping", 0, NULL, ICON_NONE);
if (view_settings->flag & COLORMANAGE_VIEW_USE_CURVES)
- uiTemplateCurveMapping(col, &view_transform_ptr, "curve_mapping", 'c', true, 0);
+ uiTemplateCurveMapping(col, &view_transform_ptr, "curve_mapping", 'c', true, false, false);
}
/********************************* Component Menu *************************************/
@@ -3551,8 +3625,7 @@ static uiBlock *component_menu(bContext *C, ARegion *ar, void *args_v)
uiItemR(layout, &args->ptr, args->propname, UI_ITEM_R_EXPAND, "", ICON_NONE);
uiBoundsBlock(block, 6);
- uiBlockSetDirection(block, UI_DOWN);
- uiEndBlock(C, block);
+ uiBlockSetDirection(block, UI_DOWN);
return block;
}
diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c
index 2c958c5028a..008ea84b607 100644
--- a/source/blender/editors/interface/interface_utils.c
+++ b/source/blender/editors/interface/interface_utils.c
@@ -151,7 +151,7 @@ int uiDefAutoButsRNA(uiLayout *layout, PointerRNA *ptr,
const char *name;
int tot = 0;
- assert(ELEM3(label_align, '\0', 'H', 'V'));
+ assert(ELEM(label_align, '\0', 'H', 'V'));
RNA_STRUCT_BEGIN (ptr, prop)
{
@@ -253,7 +253,7 @@ int uiFloatPrecisionCalc(int prec, double value)
static const double max_pow = 10000000.0; /* pow(10, UI_PRECISION_FLOAT_MAX) */
BLI_assert(prec <= UI_PRECISION_FLOAT_MAX);
- BLI_assert(pow10_neg[prec] == pow(10, -prec));
+ BLI_assert(fabs(pow10_neg[prec] - pow(10, -prec)) < 1e-16);
/* check on the number of decimal places need to display the number, this is so 0.00001 is not displayed as 0.00,
* _but_, this is only for small values si 10.0001 will not get the same treatment.
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index b25aac785a7..b7e61400cfa 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -33,6 +33,7 @@
#include <string.h>
#include <assert.h>
+#include "DNA_brush_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
@@ -477,20 +478,24 @@ static void round_box_edges(uiWidgetBase *wt, int roundboxalign, const rcti *rec
/* based on button rect, return scaled array of triangles */
-static void widget_num_tria(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
+static void widget_draw_tria_ex(
+ uiWidgetTrias *tria, const rcti *rect, float triasize, char where,
+ /* input data */
+ const float verts[][2], const int verts_tot,
+ const unsigned int tris[][3], const int tris_tot)
{
float centx, centy, sizex, sizey, minsize;
int a, i1 = 0, i2 = 1;
-
+
minsize = min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
-
+
/* center position and size */
- centx = (float)rect->xmin + 0.5f * minsize;
+ centx = (float)rect->xmin + 0.4f * minsize;
centy = (float)rect->ymin + 0.5f * minsize;
sizex = sizey = -0.5f * triasize * minsize;
if (where == 'r') {
- centx = (float)rect->xmax - 0.5f * minsize;
+ centx = (float)rect->xmax - 0.4f * minsize;
sizex = -sizex;
}
else if (where == 't') {
@@ -502,49 +507,30 @@ static void widget_num_tria(uiWidgetTrias *tria, const rcti *rect, float triasiz
sizex = -sizex;
i2 = 0; i1 = 1;
}
-
- for (a = 0; a < 3; a++) {
- tria->vec[a][0] = sizex * num_tria_vert[a][i1] + centx;
- tria->vec[a][1] = sizey * num_tria_vert[a][i2] + centy;
+
+ for (a = 0; a < verts_tot; a++) {
+ tria->vec[a][0] = sizex * verts[a][i1] + centx;
+ tria->vec[a][1] = sizey * verts[a][i2] + centy;
}
-
- tria->tot = 1;
- tria->index = num_tria_face;
+
+ tria->tot = tris_tot;
+ tria->index = tris;
}
-static void widget_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
+static void widget_num_tria(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
{
- float centx, centy, sizex, sizey, minsize;
- int a, i1 = 0, i2 = 1;
-
- minsize = min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
-
- /* center position and size */
- centx = (float)rect->xmin + 0.5f * minsize;
- centy = (float)rect->ymin + 0.5f * minsize;
- sizex = sizey = -0.5f * triasize * minsize;
+ widget_draw_tria_ex(
+ tria, rect, triasize, where,
+ num_tria_vert, ARRAY_SIZE(num_tria_vert),
+ num_tria_face, ARRAY_SIZE(num_tria_face));
+}
- if (where == 'r') {
- centx = (float)rect->xmax - 0.5f * minsize;
- sizex = -sizex;
- }
- else if (where == 't') {
- centy = (float)rect->ymax - 0.5f * minsize;
- sizey = -sizey;
- i2 = 0; i1 = 1;
- }
- else if (where == 'b') {
- sizex = -sizex;
- i2 = 0; i1 = 1;
- }
-
- for (a = 0; a < 16; a++) {
- tria->vec[a][0] = sizex * scroll_circle_vert[a][i1] + centx;
- tria->vec[a][1] = sizey * scroll_circle_vert[a][i2] + centy;
- }
-
- tria->tot = 14;
- tria->index = scroll_circle_face;
+static void widget_scroll_circle(uiWidgetTrias *tria, const rcti *rect, float triasize, char where)
+{
+ widget_draw_tria_ex(
+ tria, rect, triasize, where,
+ scroll_circle_vert, ARRAY_SIZE(scroll_circle_vert),
+ scroll_circle_face, ARRAY_SIZE(scroll_circle_face));
}
static void widget_trias_draw(uiWidgetTrias *tria)
@@ -863,7 +849,7 @@ static void widget_draw_icon(const uiBut *but, BIFIconID icon, float alpha, cons
height = ICON_DEFAULT_HEIGHT / aspect;
/* calculate blend color */
- if (ELEM4(but->type, TOG, ROW, TOGN, LISTROW)) {
+ if (ELEM(but->type, TOG, ROW, TOGN, LISTROW)) {
if (but->flag & UI_SELECT) {}
else if (but->flag & UI_ACTIVE) {}
else alpha = 0.5f;
@@ -936,45 +922,12 @@ static void ui_text_clip_give_next_off(uiBut *but, const char *str)
but->ofs += bytes;
}
-/**
- * Cut off the start of the text to fit into the width of \a rect
- *
- * \note Sets but->ofs to make sure text is correctly visible.
- * \note Clips right in some cases, this function could be cleaned up.
- */
-static void ui_text_clip_left(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
-{
- /* We are not supposed to use labels with that clipping, so we can always apply margins. */
- const int border = (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
- const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
-
- /* need to set this first */
- uiStyleFontSet(fstyle);
-
- if (fstyle->kerning == 1) /* for BLF_width */
- BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
-
- but->ofs = 0;
- but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr, sizeof(but->drawstr));
-
- if ((okwidth > 0.0f) && (but->strwidth > okwidth)) {
- float strwidth;
- but->ofs = BLF_width_to_rstrlen(fstyle->uifont_id, but->drawstr,
- sizeof(but->drawstr), okwidth, &strwidth);
- but->strwidth = strwidth;
- }
-
- if (fstyle->kerning == 1) {
- BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
- }
-}
-
/* 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)
+ const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
{
float tmp;
int l_end;
@@ -987,19 +940,27 @@ static void ui_text_clip_right_ex(uiFontStyle *fstyle, char *str, const size_t m
if (sep_strwidth / okwidth > 0.2f) {
l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp);
str[l_end] = '\0';
+ if (r_final_len) {
+ *r_final_len = (size_t)l_end;
+ }
}
else {
l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, &tmp);
memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */
+ if (r_final_len) {
+ *r_final_len = (size_t)(l_end + sep_len);
+ }
}
}
/**
* Cut off the middle of the text to fit into the given width.
* Note in case this middle clipping would just remove a few chars, it rather clips right, which is more readable.
+ * 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, const float okwidth, const float minwidth,
- const size_t max_len)
+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 strwidth;
@@ -1018,37 +979,76 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, const float
/* utf8 ellipsis '...', some compilers complain */
const char sep[] = {0xe2, 0x80, 0xa6, 0x0};
const int sep_len = sizeof(sep) - 1;
+ const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
+ float parts_strwidth;
size_t l_end;
- const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
- const float parts_strwidth = ((float)okwidth - sep_strwidth) / 2.0f;
+ char *rpart = NULL, rpart_buf[UI_MAX_DRAW_STR];
+ float rpart_width = 0.0f;
+ size_t rpart_len = 0;
+ size_t final_lpart_len;
+
+ if (rpart_sep) {
+ rpart = strstr(str, rpart_sep);
+
+ if (rpart) {
+ rpart_len = strlen(rpart);
+ rpart_width = BLF_width(fstyle->uifont_id, rpart, rpart_len);
+ okwidth -= rpart_width;
+ strwidth -= rpart_width;
+
+ if (okwidth < 0.0f) {
+ /* Not enough place for actual label, just display protected right part.
+ * Here just for safety, should never happen in real life! */
+ memmove(str, rpart, rpart_len + 1);
+ rpart = NULL;
+ okwidth += rpart_width;
+ strwidth = rpart_width;
+ }
+ }
+ }
+
+ parts_strwidth = (okwidth - sep_strwidth) / 2.0f;
+
+ if (rpart) {
+ strcpy(rpart_buf, rpart);
+ *rpart = '\0';
+ rpart = rpart_buf;
+ }
- if (min_ff(parts_strwidth, strwidth - okwidth) < minwidth) {
+ l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width);
+ if (l_end < 10 || min_ff(parts_strwidth, strwidth - okwidth) < minwidth) {
/* If we really have no place, or we would clip a very small piece of string in the middle,
* only show start of string.
*/
- ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth);
+ ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
}
else {
size_t r_offset, r_len;
- l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, parts_strwidth, &strwidth);
- r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, &strwidth);
- r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'... */
+ r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width);
+ r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'. */
- if (l_end + sep_len + r_len > max_len) {
+ if (l_end + sep_len + r_len + rpart_len > max_len) {
/* Corner case, the str already takes all available mem, and the ellipsis chars would actually
* add more chars...
* Better to just trim one or two letters to the right in this case...
* Note: with a single-char ellipsis, this should never happen! But better be safe here...
*/
- ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth);
+ ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
}
else {
memmove(str + l_end + sep_len, str + r_offset, r_len);
memcpy(str + l_end, sep, sep_len);
+ final_lpart_len = (size_t)(l_end + sep_len + r_len - 1); /* -1 to remove trailing '\0'! */
}
}
+
+ if (rpart) {
+ /* Add back preserved right part to our shorten str. */
+ memcpy(str + final_lpart_len, rpart, rpart_len + 1); /* +1 for trailing '\0'. */
+ }
+
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
}
@@ -1059,6 +1059,9 @@ static float ui_text_clip_middle_ex(uiFontStyle *fstyle, char *str, const float
return strwidth;
}
+/**
+ * Wrapper around ui_text_clip_middle_ex.
+ */
static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
/* No margin for labels! */
@@ -1068,7 +1071,23 @@ 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);
+ but->strwidth = ui_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, NULL);
+}
+
+/**
+ * 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)
+{
+ /* No margin for labels! */
+ const int border = ELEM(but->type, LABEL, MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
+ const float okwidth = (float)max_ii(BLI_rcti_size_x(rect) - border, 0);
+ const size_t max_len = sizeof(but->drawstr);
+ 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);
}
/**
@@ -1248,40 +1267,42 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b
/* text button selection and cursor */
if (but->editstr && but->pos != -1) {
- short t = 0, pos = 0;
- short selsta_tmp, selend_tmp, selsta_draw, selwidth_draw;
+ /* text button selection */
if ((but->selend - but->selsta) > 0) {
- /* text button selection */
- selsta_tmp = but->selsta;
- selend_tmp = but->selend;
+ int selsta_draw, selwidth_draw;
if (drawstr[0] != 0) {
if (but->selsta >= but->ofs) {
- selsta_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, selsta_tmp - but->ofs);
+ selsta_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selsta - but->ofs);
}
else {
selsta_draw = 0;
}
- selwidth_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, selend_tmp - but->ofs);
+ selwidth_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selend - but->ofs);
glColor4ubv((unsigned char *)wcol->item);
- glRects(rect->xmin + selsta_draw, rect->ymin + 2, rect->xmin + selwidth_draw, rect->ymax - 2);
+ glRecti(rect->xmin + selsta_draw,
+ rect->ymin + 2,
+ min_ii(rect->xmin + selwidth_draw, rect->xmax - 2),
+ rect->ymax - 2);
}
}
- else {
- /* text cursor */
- pos = but->pos;
- if (pos >= but->ofs) {
- if (drawstr[0] != 0) {
- t = BLF_width(fstyle->uifont_id, drawstr + but->ofs, pos - but->ofs);
- }
- glColor3f(0.20, 0.6, 0.9);
- glRects(rect->xmin + t, rect->ymin + 2, rect->xmin + t + 2, rect->ymax - 2);
+ /* text cursor */
+ if (but->pos >= but->ofs) {
+ int t;
+ if (drawstr[0] != 0) {
+ t = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs);
+ }
+ else {
+ t = 0;
}
+
+ glColor3f(0.20, 0.6, 0.9);
+ glRecti(rect->xmin + t, rect->ymin + 2, rect->xmin + t + 2, rect->ymax - 2);
}
}
@@ -1443,14 +1464,9 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB
else if (ELEM(but->type, NUM, NUMSLI)) {
ui_text_clip_right_label(fstyle, but, rect);
}
-#if 0
- /* Special hack for non-embossed TEX buttons in uiList (we want them to behave as much as possible as labels). */
- else if ((but->type == TEX) && (but->flag & UI_BUT_LIST_ITEM) && (but->dt & UI_EMBOSSN)) {
- but->ofs = 0;
- }
-#endif
else if ((but->block->flag & UI_BLOCK_LOOP) && (but->type == BUT)) {
- ui_text_clip_left(fstyle, but, rect);
+ /* Clip middle, but protect in all case right part containing the shortcut, if any. */
+ ui_text_clip_middle_protect_right(fstyle, but, rect, "|");
}
else {
ui_text_clip_middle(fstyle, but, rect);
@@ -1608,6 +1624,21 @@ static struct uiWidgetColors wcol_menu_back = {
25, -20
};
+/* pie menus */
+static struct uiWidgetColors wcol_pie_menu = {
+ {10, 10, 10, 200},
+ {25, 25, 25, 230},
+ {140, 140, 140, 255},
+ {45, 45, 45, 230},
+
+ {160, 160, 160, 255},
+ {255, 255, 255, 255},
+
+ 1,
+ 10, -10
+};
+
+
/* tooltip color */
static struct uiWidgetColors wcol_tooltip = {
{0, 0, 0, 255},
@@ -1755,6 +1786,7 @@ void ui_widget_color_init(ThemeUI *tui)
tui->wcol_menu = wcol_menu;
tui->wcol_pulldown = wcol_pulldown;
tui->wcol_menu_back = wcol_menu_back;
+ tui->wcol_pie_menu = wcol_pie_menu;
tui->wcol_tooltip = wcol_tooltip;
tui->wcol_menu_item = wcol_menu_item;
tui->wcol_box = wcol_box;
@@ -1826,7 +1858,9 @@ static void widget_state(uiWidgetType *wt, int state)
if (state & UI_BUT_DRAG_MULTI) {
/* the button isn't SELECT but we're editing this so draw with sel color */
- widget_state_blend(wt->wcol.inner, wt->wcol.inner_sel, 1.0f);
+ copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
+ SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
+ widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.85f);
}
if (state & UI_BUT_NODE_ACTIVE) {
@@ -1901,6 +1935,34 @@ static void widget_state_pulldown(uiWidgetType *wt, int state)
copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
}
+/* special case, pie menu items */
+static void widget_state_pie_menu_item(uiWidgetType *wt, int state)
+{
+ wt->wcol = *(wt->wcol_theme);
+
+ /* active and disabled (not so common) */
+ if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
+ widget_state_blend(wt->wcol.text, wt->wcol.text_sel, 0.5f);
+ /* draw the backdrop at low alpha, helps navigating with keys
+ * when disabled items are active */
+ copy_v4_v4_char(wt->wcol.inner, wt->wcol.item);
+ wt->wcol.inner[3] = 64;
+ }
+ /* regular disabled */
+ else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
+ widget_state_blend(wt->wcol.text, wt->wcol.inner, 0.5f);
+ }
+ /* regular active */
+ else if (state & UI_SELECT) {
+ copy_v4_v4_char(wt->wcol.outline, wt->wcol.inner_sel);
+ copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
+ }
+ else if (state & UI_ACTIVE) {
+ copy_v4_v4_char(wt->wcol.inner, wt->wcol.item);
+ copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel);
+ }
+}
+
/* special case, menu items */
static void widget_state_menu_item(uiWidgetType *wt, int state)
{
@@ -2110,8 +2172,8 @@ static void ui_draw_but_HSVCIRCLE(uiBut *but, uiWidgetColors *wcol, const rcti *
glVertex2f(centx, centy);
for (a = 0; a <= tot; a++, ang += radstep) {
- float si = sin(ang);
- float co = cos(ang);
+ float si = sinf(ang);
+ float co = cosf(ang);
ui_hsvcircle_vals_from_pos(hsv, hsv + 1, rect, centx + co * radius, centy + si * radius);
@@ -2836,6 +2898,24 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
widgetbase_draw(&wtb, wcol);
+ if (but->a1 == UI_PALETTE_COLOR && ((Palette *)but->rnapoin.id.data)->active_color == (int)but->a2) {
+ 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);
+
+ if (bw > 0.5)
+ bw -= 0.5;
+ else
+ bw += 0.5;
+
+ glColor4f(bw, bw, bw, 1.0);
+ glBegin(GL_TRIANGLES);
+ glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.9f * height);
+ glVertex2f(rect->xmin + 0.1f * width, rect->ymin + 0.5f * height);
+ glVertex2f(rect->xmin + 0.5f * width, rect->ymin + 0.9f * height);
+ glEnd();
+ }
}
static void widget_normal(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
@@ -2972,6 +3052,29 @@ static void widget_menu_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(sta
widgetbase_draw(&wtb, wcol);
}
+static void widget_menu_radial_itembut(uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
+{
+ uiWidgetBase wtb;
+ float rad;
+ float fac = but->block->pie_data.alphafac;
+
+ widget_init(&wtb);
+
+ wtb.emboss = 0;
+
+ rad = 0.5f * BLI_rcti_size_y(rect);
+ round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
+
+ wcol->inner[3] *= fac;
+ wcol->inner_sel[3] *= fac;
+ wcol->item[3] *= fac;
+ wcol->text[3] *= fac;
+ wcol->text_sel[3] *= fac;
+ wcol->outline[3] *= fac;
+
+ widgetbase_draw(&wtb, wcol);
+}
+
static void widget_list_itembut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
@@ -3290,6 +3393,12 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type)
wt.wcol_theme = &btheme->tui.wcol_progress;
wt.custom = widget_progressbar;
break;
+
+ case UI_WTYPE_MENU_ITEM_RADIAL:
+ wt.wcol_theme = &btheme->tui.wcol_pie_menu;
+ wt.custom = widget_menu_radial_itembut;
+ wt.state = widget_state_pie_menu_item;
+ break;
}
return &wt;
@@ -3396,6 +3505,9 @@ void ui_draw_but(const bContext *C, ARegion *ar, uiStyle *style, uiBut *but, rct
/* "nothing" */
wt = widget_type(UI_WTYPE_ICON);
}
+ else if (but->dt == UI_EMBOSSR) {
+ wt = widget_type(UI_WTYPE_MENU_ITEM_RADIAL);
+ }
else {
switch (but->type) {
@@ -3648,6 +3760,133 @@ void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
}
}
+static void draw_disk_shaded(
+ float start, float angle,
+ float radius_int, float radius_ext, int subd,
+ const char col1[4], const char col2[4],
+ bool shaded)
+{
+ const float radius_ext_scale = (0.5f / radius_ext); /* 1 / (2 * radius_ext) */
+ int i;
+
+ float s, c;
+ float y1, y2;
+ float fac;
+ unsigned char r_col[4];
+
+ glBegin(GL_TRIANGLE_STRIP);
+
+ s = sinf(start);
+ c = cosf(start);
+
+ y1 = s * radius_int;
+ y2 = s * radius_ext;
+
+ if (shaded) {
+ fac = (y1 + radius_ext) * radius_ext_scale;
+ round_box_shade_col4_r(r_col, col1, col2, fac);
+
+ glColor4ubv(r_col);
+ }
+
+ glVertex2f(c * radius_int, s * radius_int);
+
+ if (shaded) {
+ fac = (y2 + radius_ext) * radius_ext_scale;
+ round_box_shade_col4_r(r_col, col1, col2, fac);
+
+ glColor4ubv(r_col);
+ }
+ glVertex2f(c * radius_ext, s * radius_ext);
+
+ for (i = 1; i < subd; i++) {
+ float a;
+
+ a = start + ((i) / (float)(subd - 1)) * angle;
+ s = sinf(a);
+ c = cosf(a);
+ y1 = s * radius_int;
+ y2 = s * radius_ext;
+
+ if (shaded) {
+ fac = (y1 + radius_ext) * radius_ext_scale;
+ round_box_shade_col4_r(r_col, col1, col2, fac);
+
+ glColor4ubv(r_col);
+ }
+ glVertex2f(c * radius_int, s * radius_int);
+
+ if (shaded) {
+ fac = (y2 + radius_ext) * radius_ext_scale;
+ round_box_shade_col4_r(r_col, col1, col2, fac);
+
+ glColor4ubv(r_col);
+ }
+ glVertex2f(c * radius_ext, s * radius_ext);
+ }
+ glEnd();
+
+}
+
+void ui_draw_pie_center(uiBlock *block)
+{
+ bTheme *btheme = UI_GetTheme();
+ float cx = block->pie_data.pie_center_spawned[0];
+ float cy = block->pie_data.pie_center_spawned[1];
+
+ float *pie_dir = block->pie_data.pie_dir;
+
+ float pie_radius_internal = U.pixelsize * U.pie_menu_threshold;
+ float pie_radius_external = U.pixelsize * (U.pie_menu_threshold + 7.0f);
+
+ int subd = 40;
+
+ float angle = atan2f(pie_dir[1], pie_dir[0]);
+ float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? ((float)M_PI / 2.0f) : ((float)M_PI / 4.0f);
+
+ glPushMatrix();
+ glTranslatef(cx, cy, 0.0f);
+
+ glEnable(GL_BLEND);
+ if (btheme->tui.wcol_pie_menu.shaded) {
+ char col1[4], col2[4];
+ shadecolors4(col1, col2, btheme->tui.wcol_pie_menu.inner, btheme->tui.wcol_pie_menu.shadetop, btheme->tui.wcol_pie_menu.shadedown);
+ draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, col1, col2, true);
+ }
+ else {
+ glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner);
+ draw_disk_shaded(0.0f, (float)(M_PI * 2.0), pie_radius_internal, pie_radius_external, subd, NULL, NULL, false);
+ }
+
+ if (!(block->pie_data.flags & UI_PIE_INVALID_DIR)) {
+ if (btheme->tui.wcol_pie_menu.shaded) {
+ char col1[4], col2[4];
+ shadecolors4(col1, col2, btheme->tui.wcol_pie_menu.inner_sel, btheme->tui.wcol_pie_menu.shadetop, btheme->tui.wcol_pie_menu.shadedown);
+ draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, col1, col2, true);
+ }
+ else {
+ glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.inner_sel);
+ draw_disk_shaded(angle - range / 2.0f, range, pie_radius_internal, pie_radius_external, subd, NULL, NULL, false);
+ }
+ }
+
+ glColor4ubv((GLubyte *)btheme->tui.wcol_pie_menu.outline);
+ glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_internal, subd);
+ glutil_draw_lined_arc(0.0f, (float)M_PI * 2.0f, pie_radius_external, subd);
+
+ if (U.pie_menu_confirm > 0 && !(block->pie_data.flags & (UI_PIE_INVALID_DIR | UI_PIE_CLICK_STYLE))) {
+ float pie_confirm_radius = U.pixelsize * (pie_radius_internal + U.pie_menu_confirm);
+ float pie_confirm_external = U.pixelsize * (pie_radius_internal + U.pie_menu_confirm + 7.0f);
+
+ glColor4ub(btheme->tui.wcol_pie_menu.text_sel[0], btheme->tui.wcol_pie_menu.text_sel[1], btheme->tui.wcol_pie_menu.text_sel[2], 64);
+ draw_disk_shaded(angle - range / 2.0f, range, pie_confirm_radius, pie_confirm_external, subd, NULL, NULL, false);
+ }
+
+ glDisable(GL_BLEND);
+ glPopMatrix();
+}
+
+
uiWidgetColors *ui_tooltip_get_theme(void)
{
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
@@ -3725,7 +3964,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);
+ ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
glColor4ubv((unsigned char *)wt->wcol.text);
uiStyleFontDraw(fstyle, rect, drawstr);
@@ -3800,7 +4039,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);
+ ui_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, NULL);
glColor4ubv((unsigned char *)wt->wcol.text);
uiStyleFontDraw(fstyle, &trect, drawstr);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index 16550327a5e..bcd85333709 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -36,11 +36,10 @@
#include "MEM_guardedalloc.h"
#include "DNA_curve_types.h"
-#include "DNA_userdef_types.h"
#include "DNA_screen_types.h"
#include "DNA_space_types.h"
+#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
-#include "DNA_mesh_types.h" /* init_userdef_factory */
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
@@ -51,7 +50,6 @@
#include "BKE_main.h"
#include "BKE_texture.h"
-
#include "BIF_gl.h"
#include "UI_interface.h"
@@ -92,6 +90,7 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
/* ensure we're not getting a color after running BKE_userdef_free */
BLI_assert(BLI_findindex(&U.themes, theme_active) != -1);
+ BLI_assert(colorid != TH_UNDEFINED);
if (btheme) {
@@ -272,6 +271,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->view_overlay; break;
case TH_WIRE:
cp = ts->wire; break;
+ case TH_WIRE_INNER:
+ cp = ts->syntaxr; break;
case TH_WIRE_EDIT:
cp = ts->wire_edit; break;
case TH_LAMP:
@@ -336,6 +337,8 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->normal; break;
case TH_VNORMAL:
cp = ts->vertex_normal; break;
+ case TH_LNORMAL:
+ cp = ts->loop_normal; break;
case TH_BONE_SOLID:
cp = ts->bone_solid; break;
case TH_BONE_POSE:
@@ -536,6 +539,13 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
cp = ts->preview_stitch_active;
break;
+ case TH_PAINT_CURVE_HANDLE:
+ cp = ts->paint_curve_handle;
+ break;
+ case TH_PAINT_CURVE_PIVOT:
+ cp = ts->paint_curve_pivot;
+ break;
+
case TH_UV_OTHERS:
cp = ts->uv_others;
break;
@@ -773,6 +783,8 @@ static void ui_theme_space_init_handles_color(ThemeSpace *theme_space)
rgba_char_args_set(theme_space->handle_sel_auto, 0xf0, 0xff, 0x40, 255);
rgba_char_args_set(theme_space->handle_sel_vect, 0x40, 0xc0, 0x30, 255);
rgba_char_args_set(theme_space->handle_sel_align, 0xf0, 0x90, 0xa0, 255);
+ rgba_char_args_set(theme_space->handle_vertex, 0x00, 0x00, 0x00, 0xff);
+ rgba_char_args_set(theme_space->handle_vertex_select, 0xff, 0xff, 0, 0xff);
rgba_char_args_set(theme_space->act_spline, 0xdb, 0x25, 0x12, 255);
}
@@ -858,6 +870,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.face_select, 255, 133, 0, 60);
rgba_char_args_set(btheme->tv3d.normal, 0x22, 0xDD, 0xDD, 255);
rgba_char_args_set(btheme->tv3d.vertex_normal, 0x23, 0x61, 0xDD, 255);
+ rgba_char_args_set(btheme->tv3d.loop_normal, 0xDD, 0x23, 0xDD, 255);
rgba_char_args_set(btheme->tv3d.face_dot, 255, 133, 0, 255);
rgba_char_args_set(btheme->tv3d.editmesh_active, 255, 255, 255, 128);
rgba_char_args_set_fl(btheme->tv3d.edge_crease, 0.8, 0, 0.6, 1.0);
@@ -870,6 +883,8 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.title, 0, 0, 0, 255);
rgba_char_args_set(btheme->tv3d.freestyle_edge_mark, 0x7f, 0xff, 0x7f, 255);
rgba_char_args_set(btheme->tv3d.freestyle_face_mark, 0x7f, 0xff, 0x7f, 51);
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
btheme->tv3d.facedot_size = 4;
@@ -1091,6 +1106,7 @@ void ui_theme_init_default(void)
/* space node, re-uses syntax and console color storage */
btheme->tnode = btheme->tv3d;
+ rgba_char_args_set(btheme->tnode.syntaxr, 115, 115, 115, 255); /* wire inner color */
rgba_char_args_set(btheme->tnode.edge_select, 255, 255, 255, 255); /* wire selected */
rgba_char_args_set(btheme->tnode.syntaxl, 155, 155, 155, 160); /* TH_NODE, backdrop */
rgba_char_args_set(btheme->tnode.syntaxn, 100, 100, 100, 255); /* in */
@@ -1128,8 +1144,6 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tclip.path_after, 0x00, 0x00, 0xff, 255);
rgba_char_args_set(btheme->tclip.grid, 0x5e, 0x5e, 0x5e, 255);
rgba_char_args_set(btheme->tclip.cframe, 0x60, 0xc0, 0x40, 255);
- rgba_char_args_set(btheme->tclip.handle_vertex, 0x00, 0x00, 0x00, 0xff);
- rgba_char_args_set(btheme->tclip.handle_vertex_select, 0xff, 0xff, 0, 0xff);
rgba_char_args_set(btheme->tclip.list, 0x66, 0x66, 0x66, 0xff);
rgba_char_args_set(btheme->tclip.strip, 0x0c, 0x0a, 0x0a, 0x80);
rgba_char_args_set(btheme->tclip.strip_select, 0xff, 0x8c, 0x00, 0xff);
@@ -1224,21 +1238,25 @@ void UI_ThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
glColor4ub(r, g, b, a);
}
-/* blend between to theme colors, and set it */
-void UI_ThemeColorBlend(int colorid1, int colorid2, float fac)
+void UI_GetThemeColorBlend3ubv(int colorid1, int colorid2, float fac, unsigned char col[3])
{
- int r, g, b;
const unsigned char *cp1, *cp2;
-
+
cp1 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid1);
cp2 = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid2);
CLAMP(fac, 0.0f, 1.0f);
- r = floorf((1.0f - fac) * cp1[0] + fac * cp2[0]);
- g = floorf((1.0f - fac) * cp1[1] + fac * cp2[1]);
- b = floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
-
- glColor3ub(r, g, b);
+ col[0] = floorf((1.0f - fac) * cp1[0] + fac * cp2[0]);
+ col[1] = floorf((1.0f - fac) * cp1[1] + fac * cp2[1]);
+ col[2] = floorf((1.0f - fac) * cp1[2] + fac * cp2[2]);
+}
+
+/* blend between to theme colors, and set it */
+void UI_ThemeColorBlend(int colorid1, int colorid2, float fac)
+{
+ unsigned char col[3];
+ UI_GetThemeColorBlend3ubv(colorid1, colorid2, fac, col);
+ glColor3ubv(col);
}
/* blend between to theme colors, shade it, and set it */
@@ -2415,9 +2433,47 @@ void init_userdef_do_versions(void)
}
}
- {
+ if (U.versionfile < 271) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set(btheme->tui.wcol_tooltip.text, 255, 255, 255, 255);
+ }
+ }
+
+ if (U.versionfile < 272 || (U.versionfile == 272 && U.subversionfile < 2)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tv3d.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tima.paint_curve_handle, 0.5f, 1.0f, 0.5f, 0.5f);
+ rgba_char_args_set_fl(btheme->tima.paint_curve_pivot, 1.0f, 0.5f, 0.5f, 0.5f);
+ rgba_char_args_set(btheme->tnode.syntaxr, 115, 115, 115, 255);
+ }
+ }
+
+ if (U.versionfile < 271 || (U.versionfile == 271 && U.subversionfile < 5)) {
bTheme *btheme;
+
+ struct uiWidgetColors wcol_pie_menu = {
+ {10, 10, 10, 200},
+ {25, 25, 25, 230},
+ {140, 140, 140, 255},
+ {45, 45, 45, 230},
+
+ {160, 160, 160, 255},
+ {255, 255, 255, 255},
+
+ 1,
+ 10, -10
+ };
+
+ U.pie_menu_radius = 100;
+ U.pie_menu_threshold = 12;
+ U.pie_animation_timeout = 6;
+
for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ btheme->tui.wcol_pie_menu = wcol_pie_menu;
+
ui_theme_space_init_handles_color(&btheme->tclip);
ui_theme_space_init_handles_color(&btheme->tima);
btheme->tima.handle_vertex_size = 5;
@@ -2425,6 +2481,16 @@ void init_userdef_do_versions(void)
}
}
+ if (U.versionfile < 271 || (U.versionfile == 271 && U.subversionfile < 6)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ /* check for (alpha == 0) is safe, then color was never set */
+ if (btheme->tv3d.loop_normal[3] == 0) {
+ rgba_char_args_set(btheme->tv3d.loop_normal, 0xDD, 0x23, 0xDD, 255);
+ }
+ }
+ }
+
if (U.pixelsize == 0.0f)
U.pixelsize = 1.0f;
@@ -2437,26 +2503,3 @@ void init_userdef_do_versions(void)
// XXX reset_autosave();
}
-
-/**
- * Override values in in-memory startup.blend, avoids resaving for small changes.
- */
-void init_userdef_factory(void)
-{
- /* defaults from T37518 */
-
- U.uiflag |= USER_AUTOPERSP;
- U.uiflag |= USER_ZBUF_CURSOR;
- U.uiflag |= USER_QUIT_PROMPT;
- U.uiflag |= USER_CONTINUOUS_MOUSE;
-
- U.versions = 1;
- U.savetime = 2;
-
- {
- Mesh *me;
- for (me = G.main->mesh.first; me; me = me->id.next) {
- me->flag &= ~ME_TWOSIDED;
- }
- }
-}
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index 982e8f1a9fe..d48faa34618 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -384,7 +384,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
* - cur must not fall outside of tot
* - axis locks (zoom and offset) must be maintained
* - zoom must not be excessive (check either sizes or zoom values)
- * - aspect ratio should be respected (NOTE: this is quite closely realted to zoom too)
+ * - aspect ratio should be respected (NOTE: this is quite closely related to zoom too)
*/
/* Step 1: if keepzoom, adjust the sizes of the rects only
@@ -2277,6 +2277,9 @@ typedef struct View2DString {
} col;
rcti rect;
int mval[2];
+
+ /* str is allocated past the end */
+ char str[0];
} View2DString;
/* assumes caches are used correctly, so for time being no local storage in v2d */
@@ -2309,7 +2312,7 @@ void UI_view2d_text_cache_add(View2D *v2d, float x, float y,
v2s->mval[0] = mval[0];
v2s->mval[1] = mval[1];
- memcpy(v2s + 1, str, alloc_len);
+ memcpy(v2s->str, str, alloc_len);
}
}
@@ -2340,7 +2343,7 @@ void UI_view2d_text_cache_add_rectf(View2D *v2d, const rctf *rect_view,
v2s->mval[0] = v2s->rect.xmin;
v2s->mval[1] = v2s->rect.ymin;
- memcpy(v2s + 1, str, alloc_len);
+ memcpy(v2s->str, str, alloc_len);
}
}
@@ -2352,15 +2355,10 @@ void UI_view2d_text_cache_draw(ARegion *ar)
/* investigate using BLF_ascender() */
const float default_height = g_v2d_strings ? BLF_height_default("28", 3) : 0.0f;
-
- // glMatrixMode(GL_PROJECTION);
- // glPushMatrix();
- // glMatrixMode(GL_MODELVIEW);
- // glPushMatrix();
- ED_region_pixelspace(ar);
+
+ wmOrtho2_region_ui(ar);
for (v2s = g_v2d_strings; v2s; v2s = v2s->next) {
- const char *str = (const char *)(v2s + 1);
int xofs = 0, yofs;
yofs = ceil(0.5f * (BLI_rcti_size_y(&v2s->rect) - default_height));
@@ -2372,11 +2370,13 @@ void UI_view2d_text_cache_draw(ARegion *ar)
}
if (v2s->rect.xmin >= v2s->rect.xmax)
- BLF_draw_default((float)v2s->mval[0] + xofs, (float)v2s->mval[1] + yofs, 0.0, str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_default((float)(v2s->mval[0] + xofs), (float)(v2s->mval[1] + yofs), 0.0,
+ v2s->str, BLF_DRAW_STR_DUMMY_MAX);
else {
BLF_clipping_default(v2s->rect.xmin - 4, v2s->rect.ymin - 4, v2s->rect.xmax + 4, v2s->rect.ymax + 4);
BLF_enable_default(BLF_CLIPPING);
- BLF_draw_default(v2s->rect.xmin + xofs, v2s->rect.ymin + yofs, 0.0f, str, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_default(v2s->rect.xmin + xofs, v2s->rect.ymin + yofs, 0.0f,
+ v2s->str, BLF_DRAW_STR_DUMMY_MAX);
BLF_disable_default(BLF_CLIPPING);
}
}
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index e30c6ca61ba..a396893f8f2 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -767,6 +767,8 @@ static int view_zoomin_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static void VIEW2D_OT_zoom_in(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Zoom In";
ot->description = "Zoom in the view";
@@ -778,10 +780,12 @@ static void VIEW2D_OT_zoom_in(wmOperatorType *ot)
ot->poll = view_zoom_poll;
/* rna - must keep these in sync with the other operators */
- RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
- RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
-
+
/* this operator only needs this single callback, where it calls the view_zoom_*() methods */
static int view_zoomout_exec(bContext *C, wmOperator *op)
{
@@ -828,6 +832,8 @@ static int view_zoomout_invoke(bContext *C, wmOperator *op, const wmEvent *event
static void VIEW2D_OT_zoom_out(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Zoom Out";
ot->description = "Zoom out the view";
@@ -839,8 +845,10 @@ static void VIEW2D_OT_zoom_out(wmOperatorType *ot)
ot->poll = view_zoom_poll;
/* rna - must keep these in sync with the other operators */
- RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
- RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float(ot->srna, "zoomfacx", 0, -FLT_MAX, FLT_MAX, "Zoom Factor X", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_float(ot->srna, "zoomfacy", 0, -FLT_MAX, FLT_MAX, "Zoom Factor Y", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/* ********************************************************* */
@@ -1139,6 +1147,7 @@ static int view_zoomdrag_modal(bContext *C, wmOperator *op, const wmEvent *event
static void VIEW2D_OT_zoom(wmOperatorType *ot)
{
+ PropertyRNA *prop;
/* identifiers */
ot->name = "Zoom 2D View";
ot->description = "Zoom in/out the view";
@@ -1156,8 +1165,10 @@ static void VIEW2D_OT_zoom(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
/* rna - must keep these in sync with the other operators */
- RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
- RNA_def_float(ot->srna, "deltay", 0, -FLT_MAX, FLT_MAX, "Delta Y", "", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float(ot->srna, "deltax", 0, -FLT_MAX, FLT_MAX, "Delta X", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_float(ot->srna, "deltay", 0, -FLT_MAX, FLT_MAX, "Delta Y", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/* ********************************************************* */
@@ -1522,6 +1533,7 @@ typedef struct v2dScrollerMove {
short zone; /* -1 is min zoomer, 0 is bar, 1 is max zoomer */ // XXX find some way to provide visual feedback of this (active color?)
float fac; /* view adjustment factor, based on size of region */
+ float fac_round; /* for pixel rounding (avoid visible UI jitter) */
float delta; /* amount moved by mouse on axis of interest */
float scrollbarwidth; /* width of the scrollbar itself, used for page up/down clicks */
@@ -1560,7 +1572,7 @@ enum {
*/
static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_min, int sh_max)
{
- short in_min, in_max, in_bar, out_min, out_max, in_view = 1;
+ bool in_min, in_max, in_bar, out_min, out_max, in_view = 1;
/* firstly, check if
* - 'bubble' fills entire scroller
@@ -1583,9 +1595,9 @@ static short mouse_in_scroller_handle(int mouse, int sc_min, int sc_max, int sh_
/* check if mouse is in or past either handle */
/* TODO: check if these extents are still valid or not */
- in_max = ( (mouse >= (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse <= (sh_max + V2D_SCROLLER_HANDLE_SIZE)) );
- in_min = ( (mouse <= (sh_min + V2D_SCROLLER_HANDLE_SIZE)) && (mouse >= (sh_min - V2D_SCROLLER_HANDLE_SIZE)) );
- in_bar = ( (mouse < (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse > (sh_min + V2D_SCROLLER_HANDLE_SIZE)) );
+ in_max = ((mouse >= (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse <= (sh_max + V2D_SCROLLER_HANDLE_SIZE)));
+ in_min = ((mouse <= (sh_min + V2D_SCROLLER_HANDLE_SIZE)) && (mouse >= (sh_min - V2D_SCROLLER_HANDLE_SIZE)));
+ in_bar = ((mouse < (sh_max - V2D_SCROLLER_HANDLE_SIZE)) && (mouse > (sh_min + V2D_SCROLLER_HANDLE_SIZE)));
out_min = mouse < (sh_min - V2D_SCROLLER_HANDLE_SIZE);
out_max = mouse > (sh_max + V2D_SCROLLER_HANDLE_SIZE);
@@ -1640,7 +1652,10 @@ static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *e
/* horizontal scroller - calculate adjustment factor first */
mask_size = (float)BLI_rcti_size_x(&v2d->hor);
vsm->fac = BLI_rctf_size_x(&tot_cur_union) / mask_size;
-
+
+ /* pixel rounding */
+ vsm->fac_round = (BLI_rctf_size_x(&v2d->cur)) / (float)(BLI_rcti_size_x(&ar->winrct) + 1);
+
/* get 'zone' (i.e. which part of scroller is activated) */
vsm->zone = mouse_in_scroller_handle(event->mval[0],
v2d->hor.xmin, v2d->hor.xmax,
@@ -1659,6 +1674,9 @@ static void scroller_activate_init(bContext *C, wmOperator *op, const wmEvent *e
mask_size = (float)BLI_rcti_size_y(&v2d->vert);
vsm->fac = BLI_rctf_size_y(&tot_cur_union) / mask_size;
+ /* pixel rounding */
+ vsm->fac_round = (BLI_rctf_size_y(&v2d->cur)) / (float)(BLI_rcti_size_y(&ar->winrct) + 1);
+
/* get 'zone' (i.e. which part of scroller is activated) */
vsm->zone = mouse_in_scroller_handle(event->mval[1],
v2d->vert.ymin, v2d->vert.ymax,
@@ -1706,6 +1724,9 @@ static void scroller_activate_apply(bContext *C, wmOperator *op)
/* calculate amount to move view by */
temp = vsm->fac * vsm->delta;
+
+ /* round to pixel */
+ temp = floorf(temp / vsm->fac_round + 0.5f) * vsm->fac_round;
/* type of movement */
switch (vsm->zone) {
diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c
index 4d2ea0e64f4..bbf4447dd72 100644
--- a/source/blender/editors/io/io_collada.c
+++ b/source/blender/editors/io/io_collada.c
@@ -96,7 +96,9 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
int use_object_instantiation;
int sort_by_name;
int export_transformation_type;
- int open_sim;
+ int open_sim;
+
+ int export_count;
if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
BKE_report(op->reports, RPT_ERROR, "No filename given");
@@ -148,33 +150,36 @@ static int wm_collada_export_exec(bContext *C, wmOperator *op)
ED_object_editmode_load(CTX_data_edit_object(C));
-
- if (collada_export(CTX_data_scene(C),
- filepath,
- apply_modifiers,
- export_mesh_type,
- selected,
- include_children,
- include_armatures,
- include_shapekeys,
- deform_bones_only,
-
- active_uv_only,
- include_uv_textures,
- include_material_textures,
- use_texture_copies,
-
- triangulate,
- use_object_instantiation,
- sort_by_name,
- export_transformation_type,
- open_sim))
- {
- return OPERATOR_FINISHED;
+ export_count = collada_export(CTX_data_scene(C),
+ filepath,
+ apply_modifiers,
+ export_mesh_type,
+ selected,
+ include_children,
+ include_armatures,
+ include_shapekeys,
+ deform_bones_only,
+
+ active_uv_only,
+ include_uv_textures,
+ include_material_textures,
+ use_texture_copies,
+
+ triangulate,
+ use_object_instantiation,
+ sort_by_name,
+ export_transformation_type,
+ open_sim);
+
+ if (export_count == 0) {
+ BKE_report(op->reports, RPT_WARNING, "Export file is empty");
+ return OPERATOR_CANCELLED;
}
else {
- BKE_report(op->reports, RPT_WARNING, "Export file not created");
- return OPERATOR_CANCELLED;
+ char buff[100];
+ sprintf(buff, "Exported %d Objects", export_count);
+ BKE_report(op->reports, RPT_INFO, buff);
+ return OPERATOR_FINISHED;
}
}
@@ -250,7 +255,7 @@ static void uiCollada_exportSettings(uiLayout *layout, PointerRNA *imfptr)
row = uiLayoutRow(box, false);
split = uiLayoutSplit(row, 0.6f, UI_LAYOUT_ALIGN_RIGHT);
- uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
+ uiItemL(split, IFACE_("Transformation Type"), ICON_NONE);
uiItemR(split, imfptr, "export_transformation_type_selection", 0, "", ICON_NONE);
row = uiLayoutRow(box, false);
@@ -350,8 +355,8 @@ void WM_OT_collada_export(wmOperatorType *ot)
RNA_def_enum(ot->srna, "export_transformation_type_selection", prop_bc_export_transformation_type, 0,
"Transform", "Transformation type for translation, scale and rotation");
- RNA_def_boolean(ot->srna, "open_sim", 0, "Export for OpenSim",
- "Compatibility mode for OpenSim and compatible online worlds");
+ RNA_def_boolean(ot->srna, "open_sim", 0, "Export to SL/OpenSim",
+ "Compatibility mode for SL, OpenSim and other compatible online worlds");
}
diff --git a/source/blender/editors/mask/CMakeLists.txt b/source/blender/editors/mask/CMakeLists.txt
index b1cf6db3144..033d034cf4e 100644
--- a/source/blender/editors/mask/CMakeLists.txt
+++ b/source/blender/editors/mask/CMakeLists.txt
@@ -25,10 +25,12 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -48,4 +50,6 @@ set(SRC
mask_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_mask "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/mask/SConscript b/source/blender/editors/mask/SConscript
index 9dd521e3a7c..bcbaaa34960 100644
--- a/source/blender/editors/mask/SConscript
+++ b/source/blender/editors/mask/SConscript
@@ -29,14 +29,16 @@ Import ('env')
sources = env.Glob('*.c')
-defs = []
+defs = env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index b816103de13..cb47adbe73e 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -57,12 +57,14 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
struct Mask *mask,
const float normal_co[2],
int threshold, bool feather,
+ float tangent[2],
+ const bool use_deform,
+ const bool use_project,
MaskLayer **masklay_r,
MaskSpline **spline_r,
MaskSplinePoint **point_r,
- float *u_r, float tangent[2],
- const bool use_deform,
- const bool use_project)
+ float *u_r,
+ float *score_r)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -171,6 +173,10 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
*u_r = u;
}
+ if (score_r) {
+ *score_r = dist;
+ }
+
return true;
}
@@ -339,7 +345,9 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
float tangent[2];
float u;
- if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, false, &masklay, &spline, &point, &u, tangent, true, true)) {
+ if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, false, tangent, true, true,
+ &masklay, &spline, &point, &u, NULL))
+ {
MaskSplinePoint *new_point;
int point_index = point - spline->points;
@@ -624,7 +632,9 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op)
if (point)
return OPERATOR_FINISHED;
- if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, true, &masklay, &spline, &point, &u, NULL, true, true)) {
+ if (ED_mask_find_nearest_diff_point(C, mask, co, threshold, true, NULL, true, true,
+ &masklay, &spline, &point, &u, NULL))
+ {
Scene *scene = CTX_data_scene(C);
float w = BKE_mask_point_weight(spline, point, u);
float weight_scalar = BKE_mask_point_weight_scalar(spline, point, u);
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 92d55cc1abb..7e767d8f6c8 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -133,9 +133,12 @@ static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float c
}
static void draw_circle(const float x, const float y,
- const float size, const float xscale, const float yscale)
+ const float size, const bool fill,
+ const float xscale, const float yscale)
{
- static GLuint displist = 0;
+ static GLuint wire_displist = 0;
+ static GLuint fill_displist = 0;
+ GLuint displist = fill ? fill_displist : wire_displist;
/* Initialize round circle shape. */
if (displist == 0) {
@@ -145,11 +148,18 @@ static void draw_circle(const float x, const float y,
glNewList(displist, GL_COMPILE);
qobj = gluNewQuadric();
- gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
+ gluQuadricDrawStyle(qobj, fill ? GLU_FILL : GLU_SILHOUETTE);
gluDisk(qobj, 0, 0.7, 8, 1);
gluDeleteQuadric(qobj);
glEndList();
+
+ if (fill) {
+ fill_displist = displist;
+ }
+ else {
+ wire_displist = displist;
+ }
}
glPushMatrix();
@@ -213,13 +223,13 @@ static void draw_single_handle(const MaskLayer *mask_layer, const MaskSplinePoin
if (point == mask_layer->act_point)
glColor3f(1.0f, 1.0f, 1.0f);
else
- glColor3f(1.0f, 1.0f, 0.0f);
+ UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
}
else {
- glColor3f(0.5f, 0.5f, 0.0f);
+ UI_ThemeColor(TH_HANDLE_VERTEX);
}
- draw_circle(handle_pos[0], handle_pos[1], handle_size, xscale, yscale);
+ draw_circle(handle_pos[0], handle_pos[1], handle_size, false, xscale, yscale);
}
/* return non-zero if spline is selected */
@@ -237,6 +247,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
int i, handle_size, tot_feather_point;
float (*feather_points)[2], (*fp)[2];
+ float min[2], max[2];
if (!spline->tot_point)
return;
@@ -280,10 +291,10 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
if (point == masklay->act_point)
glColor3f(1.0f, 1.0f, 1.0f);
else
- glColor3f(1.0f, 1.0f, 0.0f);
+ UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
}
else {
- glColor3f(0.5f, 0.5f, 0.0f);
+ UI_ThemeColor(TH_HANDLE_VERTEX);
}
glBegin(GL_POINTS);
@@ -302,6 +313,7 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
}
/* control points */
+ INIT_MINMAX2(min, max);
for (i = 0; i < spline->tot_point; i++) {
/* watch it! this is intentionally not the deform array, only check for sel */
@@ -346,14 +358,33 @@ static void draw_spline_points(const bContext *C, MaskLayer *masklay, MaskSpline
if (point == masklay->act_point)
glColor3f(1.0f, 1.0f, 1.0f);
else
- glColor3f(1.0f, 1.0f, 0.0f);
+ UI_ThemeColor(TH_HANDLE_VERTEX_SELECT);
}
else
- glColor3f(0.5f, 0.5f, 0.0f);
+ UI_ThemeColor(TH_HANDLE_VERTEX);
glBegin(GL_POINTS);
glVertex2fv(vert);
glEnd();
+
+ minmax_v2v2_v2(min, max, vert);
+ }
+
+ if (is_spline_sel) {
+ float x = (min[0] + max[0]) / 2.0f;
+ float y = (min[1] + max[1]) / 2.0f;
+ /* TODO(sergey): Remove hardcoded colors. */
+ if (masklay->act_spline == spline) {
+ glColor3ub(255, 255, 255);
+ }
+ else {
+ glColor3ub(255, 255, 0);
+ }
+
+ draw_circle(x, y, 6.0f, true, xscale, yscale);
+
+ glColor3ub(0, 0, 0);
+ draw_circle(x, y, 6.0f, false, xscale, yscale);
}
glPointSize(1.0f);
@@ -742,7 +773,7 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar,
/* w = BLI_rctf_size_x(&v2d->tot); */
- /* h = BLI_rctf_size_y(&v2d->tot);/*/
+ /* h = BLI_rctf_size_y(&v2d->tot); */
zoomx = (float)(BLI_rcti_size_x(&ar->winrct) + 1) / BLI_rctf_size_x(&ar->v2d.cur);
@@ -803,13 +834,14 @@ void ED_mask_draw_region(Mask *mask, ARegion *ar,
/* apply transformation so mask editing tools will assume drawing from the origin in normalized space */
glPushMatrix();
- glTranslatef(x + xofs, y + yofs, 0);
- glScalef(maxdim * zoomx, maxdim * zoomy, 0);
if (stabmat) {
glMultMatrixf(stabmat);
}
+ glTranslatef(x + xofs, y + yofs, 0);
+ glScalef(maxdim * zoomx, maxdim * zoomy, 0);
+
if (do_draw_cb) {
ED_region_draw_cb_draw(C, ar, REGION_DRAW_PRE_VIEW);
}
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index 1acdff8b824..e2eb32e86d9 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -550,6 +550,8 @@ void ED_keymap_mask(wmKeyConfig *keyconf)
/* duplicate */
WM_keymap_add_item(keymap, "MASK_OT_duplicate_move", DKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_item(keymap, "MASK_OT_copy_splines", CKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "MASK_OT_paste_splines", VKEY, KM_PRESS, KM_CTRL, 0);
/* for image editor only */
WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index 6899cf7e6f5..5cdb224ce21 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -44,12 +44,14 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
int threshold, bool feather,
+ float tangent[2],
+ const bool use_deform,
+ const bool use_project,
struct MaskLayer **masklay_r,
struct MaskSpline **spline_r,
struct MaskSplinePoint **point_r,
- float *u_r, float tangent[2],
- const bool use_deform,
- const bool use_project);
+ float *u_r,
+ float *score_r);
void MASK_OT_add_vertex(struct wmOperatorType *ot);
void MASK_OT_add_feather_vertex(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index b7e026ca8e3..93e59f3244e 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -458,7 +458,8 @@ enum {
SLIDE_ACTION_NONE = 0,
SLIDE_ACTION_POINT = 1,
SLIDE_ACTION_HANDLE = 2,
- SLIDE_ACTION_FEATHER = 3
+ SLIDE_ACTION_FEATHER = 3,
+ SLIDE_ACTION_SPLINE = 4
};
typedef struct SlidePointData {
@@ -497,6 +498,108 @@ typedef struct SlidePointData {
float weight, weight_scalar;
} SlidePointData;
+static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2])
+{
+ BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co);
+ ED_clip_point_undistorted_pos(sc, r_co, r_co);
+ BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
+}
+
+static bool spline_under_mouse_get(const bContext *C,
+ Mask *mask, const float co[2],
+ MaskLayer **mask_layer_r,
+ MaskSpline **mask_spline_r)
+{
+ const float threshold = 19.0f;
+ ScrArea *sa = CTX_wm_area(C);
+ SpaceClip *sc = CTX_wm_space_clip(C);
+ MaskLayer *mask_layer;
+ int width, height;
+ float pixel_co[2];
+ float closest_dist_squared;
+ MaskLayer *closest_layer = NULL;
+ MaskSpline *closest_spline = NULL;
+ bool undistort = false;
+ *mask_layer_r = NULL;
+ *mask_spline_r = NULL;
+ ED_mask_get_size(sa, &width, &height);
+ pixel_co[0] = co[0] * width;
+ pixel_co[1] = co[1] * height;
+ if (sc != NULL) {
+ undistort = (sc->clip != NULL) &&
+ (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
+ }
+ for (mask_layer = mask->masklayers.first;
+ mask_layer != NULL;
+ mask_layer = mask_layer->next)
+ {
+ MaskSpline *spline;
+ if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
+ continue;
+ }
+
+ for (spline = mask_layer->splines.first;
+ spline != NULL;
+ spline = spline->next)
+ {
+ MaskSplinePoint *points_array;
+ float min[2], max[2], center[2];
+ float dist_squared;
+ int i;
+ float max_bb_side;
+ if ((spline->flag & SELECT) == 0) {
+ continue;
+ }
+
+ points_array = BKE_mask_spline_point_array(spline);
+ INIT_MINMAX2(min, max);
+ for (i = 0; i < spline->tot_point; i++) {
+ MaskSplinePoint *point_deform = &points_array[i];
+ BezTriple *bezt = &point_deform->bezt;
+
+ float vert[2];
+
+ copy_v2_v2(vert, bezt->vec[1]);
+
+ if (undistort) {
+ mask_point_undistort_pos(sc, vert, vert);
+ }
+
+ minmax_v2v2_v2(min, max, vert);
+ }
+
+ center[0] = (min[0] + max[0]) / 2.0f * width;
+ center[1] = (min[1] + max[1]) / 2.0f * height;
+ dist_squared = len_squared_v2v2(pixel_co, center);
+ max_bb_side = min_ff((max[0] - min[0]) * width, (max[1] - min[1]) * height);
+ if (dist_squared <= max_bb_side * max_bb_side * 0.5f &&
+ (closest_spline == NULL || dist_squared < closest_dist_squared))
+ {
+ closest_layer = mask_layer;
+ closest_spline = spline;
+ closest_dist_squared = dist_squared;
+ }
+ }
+ }
+ if (closest_dist_squared < SQUARE(threshold) && closest_spline != NULL) {
+ float diff_score;
+ if (ED_mask_find_nearest_diff_point(C, mask, co, threshold,
+ false, NULL, true, false,
+ NULL, NULL, NULL, NULL,
+ &diff_score))
+ {
+ if (SQUARE(diff_score) < closest_dist_squared) {
+ return false;
+ }
+ }
+
+ *mask_layer_r = closest_layer;
+ *mask_spline_r = closest_spline;
+ return true;
+ }
+ return false;
+}
+
static bool slide_point_check_initial_feather(MaskSpline *spline)
{
int i;
@@ -607,9 +710,14 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
point = cv_point;
}
- if (action != SLIDE_ACTION_NONE) {
- select_sliding_point(mask, masklay, spline, point, which_handle);
+ if (action == SLIDE_ACTION_NONE) {
+ if (spline_under_mouse_get(C, mask, co, &masklay, &spline)) {
+ action = SLIDE_ACTION_SPLINE;
+ point = NULL;
+ }
+ }
+ if (action != SLIDE_ACTION_NONE) {
customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data");
customdata->event_invoke_type = event->type;
customdata->mask = mask;
@@ -621,12 +729,14 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
customdata->action = action;
customdata->uw = uw;
- customdata->old_h1 = point->bezt.h1;
- customdata->old_h2 = point->bezt.h2;
-
customdata->is_sliding_new_point = RNA_boolean_get(op->ptr, "is_new_point");
- check_sliding_handle_type(point, which_handle);
+ if (customdata->action != SLIDE_ACTION_SPLINE) {
+ customdata->old_h1 = point->bezt.h1;
+ customdata->old_h2 = point->bezt.h2;
+ select_sliding_point(mask, masklay, spline, point, which_handle);
+ check_sliding_handle_type(point, which_handle);
+ }
if (uw) {
float co_uw[2];
@@ -639,7 +749,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
madd_v2_v2v2fl(customdata->prev_feather_coord, co_uw, customdata->no, uw->w * weight_scalar);
}
- else {
+ else if (customdata->action != SLIDE_ACTION_SPLINE) {
BezTriple *bezt = &point->bezt;
customdata->weight = bezt->weight;
@@ -653,10 +763,12 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
customdata->is_initial_feather = slide_point_check_initial_feather(spline);
}
- copy_m3_m3(customdata->vec, point->bezt.vec);
- if (which_handle != MASK_WHICH_HANDLE_NONE) {
- BKE_mask_point_handle(point, which_handle, customdata->orig_handle_coord);
- copy_v2_v2(customdata->prev_handle_coord, customdata->orig_handle_coord);
+ if (customdata->action != SLIDE_ACTION_SPLINE) {
+ copy_m3_m3(customdata->vec, point->bezt.vec);
+ if (which_handle != MASK_WHICH_HANDLE_NONE) {
+ BKE_mask_point_handle(point, which_handle, customdata->orig_handle_coord);
+ copy_v2_v2(customdata->prev_handle_coord, customdata->orig_handle_coord);
+ }
}
customdata->which_handle = which_handle;
@@ -738,7 +850,7 @@ static void cancel_slide_point(SlidePointData *data)
else
data->point->bezt.weight = data->weight;
}
- else {
+ else if (data->action != SLIDE_ACTION_SPLINE) {
copy_m3_m3(data->point->bezt.vec, data->vec);
data->point->bezt.h1 = data->old_h1;
data->point->bezt.h2 = data->old_h2;
@@ -935,6 +1047,20 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
copy_v2_v2(data->prev_feather_coord, offco);
}
}
+ else if (data->action == SLIDE_ACTION_SPLINE) {
+ int i;
+
+ if (data->orig_spline == NULL) {
+ data->orig_spline = BKE_mask_spline_copy(data->spline);
+ }
+
+ for (i = 0; i < data->spline->tot_point; i++) {
+ MaskSplinePoint *point = &data->spline->points[i];
+ add_v2_v2(point->bezt.vec[0], delta);
+ add_v2_v2(point->bezt.vec[1], delta);
+ add_v2_v2(point->bezt.vec[2], delta);
+ }
+ }
WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
DAG_id_tag_update(&data->mask->id, 0);
@@ -970,8 +1096,12 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
free_slide_point_data(op->customdata); /* keep this last! */
return OPERATOR_FINISHED;
}
-
- break;
+ else if (event->type != data->event_invoke_type && event->val == KM_PRESS) {
+ /* pass to ESCKEY */
+ }
+ else {
+ break;
+ }
case ESCKEY:
cancel_slide_point(op->customdata);
@@ -1046,7 +1176,7 @@ static bool slide_spline_curvature_check(bContext *C, const wmEvent *event)
{
Mask *mask = CTX_data_edit_mask(C);
float co[2];
- const float threshold = 19;
+ const float threshold = 19.0f;
ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
@@ -1064,7 +1194,7 @@ static bool slide_spline_curvature_check(bContext *C, const wmEvent *event)
static SlideSplineCurvatureData *slide_spline_curvature_customdata(
bContext *C, const wmEvent *event)
{
- const float threshold = 19;
+ const float threshold = 19.0f;
Mask *mask = CTX_data_edit_mask(C);
SlideSplineCurvatureData *slide_data;
@@ -1077,8 +1207,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(
ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
if (!ED_mask_find_nearest_diff_point(C, mask, co, threshold, false,
+ NULL, true, false,
&mask_layer, &spline, &point, &u,
- NULL, true, false))
+ NULL))
{
return NULL;
}
@@ -2015,6 +2146,8 @@ static int mask_layer_move_exec(bContext *C, wmOperator *op)
mask->masklay_act++;
}
+ WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
+
return OPERATOR_FINISHED;
}
@@ -2075,6 +2208,8 @@ static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
point++;
}
if (end >= start) {
+ int tot_point;
+ int tot_point_shape_start;
MaskSpline *new_spline = BKE_mask_spline_add(mask_layer);
MaskSplinePoint *new_point;
int b;
@@ -2098,15 +2233,29 @@ static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
memcpy(new_spline->points, spline->points + start,
new_spline->tot_point * sizeof(MaskSplinePoint));
+ tot_point = new_spline->tot_point;
+
+ /* animation requires points added one by one */
+ if (mask_layer->splines_shapes.first) {
+ new_spline->tot_point = 0;
+ tot_point_shape_start = BKE_mask_layer_shape_spline_to_index(mask_layer, new_spline);
+ }
+
/* Select points and duplicate their UWs (if needed). */
for (b = 0, new_point = new_spline->points;
- b < new_spline->tot_point;
+ b < tot_point;
b++, new_point++)
{
if (new_point->uw) {
new_point->uw = MEM_dupallocN(new_point->uw);
}
BKE_mask_point_select_set(new_point, true);
+
+
+ if (mask_layer->splines_shapes.first) {
+ new_spline->tot_point++;
+ BKE_mask_layer_shape_changed_add(mask_layer, tot_point_shape_start + b, true, false);
+ }
}
/* Clear cyclic flag if we didn't copy the whole spline. */
@@ -2158,6 +2307,10 @@ static int copy_splines_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
MaskLayer *mask_layer = BKE_mask_layer_active(mask);
+ if (mask_layer == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
BKE_mask_clipboard_copy_from_layer(mask_layer);
return OPERATOR_FINISHED;
@@ -2195,6 +2348,10 @@ static int paste_splines_exec(bContext *C, wmOperator *UNUSED(op))
Mask *mask = CTX_data_edit_mask(C);
MaskLayer *mask_layer = BKE_mask_layer_active(mask);
+ if (mask_layer == NULL) {
+ mask_layer = BKE_mask_layer_new(mask, "");
+ }
+
BKE_mask_clipboard_paste_to_layer(CTX_data_main(C), mask_layer);
/* TODO: only update edited splines */
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index af6f127327c..a4268bddaf5 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -683,7 +683,7 @@ void MASK_OT_select_circle(wmOperatorType *ot)
/* properties */
RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
}
diff --git a/source/blender/editors/mesh/CMakeLists.txt b/source/blender/editors/mesh/CMakeLists.txt
index 8d91b300ff3..db20d42f39d 100644
--- a/source/blender/editors/mesh/CMakeLists.txt
+++ b/source/blender/editors/mesh/CMakeLists.txt
@@ -32,6 +32,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -45,11 +46,13 @@ set(SRC
editmesh_bisect.c
editmesh_extrude.c
editmesh_inset.c
+ editmesh_intersect.c
editmesh_knife.c
editmesh_knife_project.c
editmesh_loopcut.c
editmesh_path.c
editmesh_rip.c
+ editmesh_rip_edge.c
editmesh_select.c
editmesh_tools.c
editmesh_utils.c
@@ -84,4 +87,6 @@ if(WITH_BULLET)
add_definitions(-DWITH_BULLET)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_mesh "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/mesh/SConscript b/source/blender/editors/mesh/SConscript
index 6fa48c12eca..122a7501e58 100644
--- a/source/blender/editors/mesh/SConscript
+++ b/source/blender/editors/mesh/SConscript
@@ -29,11 +29,12 @@ Import ('env')
sources = env.Glob('*.c')
-defs = []
+defs = env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../uvedit',
'../../blenfont',
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
index 5150a703951..87b429f1165 100644
--- a/source/blender/editors/mesh/editface.c
+++ b/source/blender/editors/mesh/editface.c
@@ -204,7 +204,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index,
/* only put face under cursor in array */
mp = &me->mpoly[index];
BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
- BLI_BITMAP_SET(poly_tag, index);
+ BLI_BITMAP_ENABLE(poly_tag, index);
}
else {
/* fill array by selection */
@@ -215,7 +215,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index,
}
else if (mp->flag & ME_FACE_SEL) {
BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
- BLI_BITMAP_SET(poly_tag, a);
+ BLI_BITMAP_ENABLE(poly_tag, a);
}
}
}
@@ -229,13 +229,13 @@ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index,
if (mp->flag & ME_HIDE)
continue;
- if (!BLI_BITMAP_GET(poly_tag, a)) {
+ if (!BLI_BITMAP_TEST(poly_tag, a)) {
mark = false;
ml = me->mloop + mp->loopstart;
for (b = 0; b < mp->totloop; b++, ml++) {
if ((me->medge[ml->e].flag & ME_SEAM) == 0) {
- if (BLI_BITMAP_GET(edge_tag, ml->e)) {
+ if (BLI_BITMAP_TEST(edge_tag, ml->e)) {
mark = true;
break;
}
@@ -243,7 +243,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index,
}
if (mark) {
- BLI_BITMAP_SET(poly_tag, a);
+ BLI_BITMAP_ENABLE(poly_tag, a);
BKE_mesh_poly_edgebitmap_insert(edge_tag, mp, me->mloop + mp->loopstart);
do_it = true;
}
@@ -254,7 +254,7 @@ static void select_linked_tfaces_with_seams(Mesh *me, const unsigned int index,
MEM_freeN(edge_tag);
for (a = 0, mp = me->mpoly; a < me->totpoly; a++, mp++) {
- if (BLI_BITMAP_GET(poly_tag, a)) {
+ if (BLI_BITMAP_TEST(poly_tag, a)) {
BKE_BIT_TEST_SET(mp->flag, select, ME_FACE_SEL);
}
}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 75ba84aaffd..0e48cbcd589 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -73,25 +73,33 @@ typedef struct {
#define HEADER_LENGTH 180
-static void edbm_bevel_update_header(wmOperator *op, bContext *C)
+static void edbm_bevel_update_header(bContext *C, wmOperator *op)
{
- const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Offset: %s, Segments: %d");
+ const char *str = IFACE_("Confirm: (Enter/LMB), Cancel: (Esc/RMB), Mode: %s (M), Clamp Overlap: %s (C), "
+ "Offset: %s, Segments: %d");
char msg[HEADER_LENGTH];
ScrArea *sa = CTX_wm_area(C);
+ Scene *sce = CTX_data_scene(C);
if (sa) {
BevelData *opdata = op->customdata;
char offset_str[NUM_STR_REP_LEN];
+ const char *type_str;
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type");
if (hasNumInput(&opdata->num_input)) {
- outputNumInput(&opdata->num_input, offset_str);
+ outputNumInput(&opdata->num_input, offset_str, &sce->unit);
}
else {
BLI_snprintf(offset_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "offset"));
}
- BLI_snprintf(msg, HEADER_LENGTH, str, offset_str, RNA_int_get(op->ptr, "segments"));
+ RNA_property_enum_name_gettexted(C, op->ptr, prop, RNA_property_enum_get(op->ptr, prop), &type_str);
+
+ BLI_snprintf(msg, HEADER_LENGTH, str, type_str,
+ WM_bool_as_string(RNA_boolean_get(op->ptr, "clamp_overlap")),
+ offset_str, RNA_int_get(op->ptr, "segments"));
ED_area_headerprint(sa, msg);
}
@@ -145,15 +153,21 @@ static bool edbm_bevel_calc(wmOperator *op)
const int segments = RNA_int_get(op->ptr, "segments");
const float profile = RNA_float_get(op->ptr, "profile");
const bool vertex_only = RNA_boolean_get(op->ptr, "vertex_only");
+ const bool clamp_overlap = RNA_boolean_get(op->ptr, "clamp_overlap");
+ int material = RNA_int_get(op->ptr, "material");
/* revert to original mesh */
if (opdata->is_modal) {
EDBM_redo_state_restore(opdata->mesh_backup, em, false);
}
+ if (em->ob)
+ material = CLAMPIS(material, -1, em->ob->totcol - 1);
+
EDBM_op_init(em, &bmop, op,
- "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f",
- BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile);
+ "bevel geom=%hev offset=%f segments=%i vertex_only=%b offset_type=%i profile=%f clamp_overlap=%b "
+ "material=%i",
+ BM_ELEM_SELECT, offset, segments, vertex_only, offset_type, profile, clamp_overlap, material);
BMO_op_exec(em->bm, &bmop);
@@ -253,7 +267,7 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
opdata->initial_length = len_v2(mlen);
opdata->pixel_size = rv3d ? ED_view3d_pixel_size(rv3d, center_3d) : 1.0f;
- edbm_bevel_update_header(op, C);
+ edbm_bevel_update_header(C, op);
if (!edbm_bevel_calc(op)) {
edbm_bevel_cancel(C, op);
@@ -268,44 +282,40 @@ static int edbm_bevel_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static float edbm_bevel_mval_factor(wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
- bool use_dist = true;
- bool is_percent = false;
+ bool use_dist;
+ bool is_percent;
float mdiff[2];
float factor;
mdiff[0] = opdata->mcenter[0] - event->mval[0];
mdiff[1] = opdata->mcenter[1] - event->mval[1];
is_percent = (RNA_enum_get(op->ptr, "offset_type") == BEVEL_AMT_PERCENT);
+ use_dist = !is_percent;
- if (use_dist) {
- factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size;
- }
- else {
- factor = (len_v2(mdiff) - MVAL_PIXEL_MARGIN) / opdata->initial_length;
- factor = factor - 1.0f; /* a different kind of buffer where nothing happens */
- }
+ factor = ((len_v2(mdiff) - MVAL_PIXEL_MARGIN) - opdata->initial_length) * opdata->pixel_size;
/* Fake shift-transform... */
if (event->shift) {
if (opdata->shift_factor < 0.0f) {
opdata->shift_factor = RNA_float_get(op->ptr, "offset");
+ if (is_percent) {
+ opdata->shift_factor /= 100.0f;
+ }
}
factor = (factor - opdata->shift_factor) * 0.1f + opdata->shift_factor;
}
- else if (opdata->shift_factor >= 0.0f)
+ else if (opdata->shift_factor >= 0.0f) {
opdata->shift_factor = -1.0f;
+ }
/* clamp differently based on distance/factor */
if (use_dist) {
if (factor < 0.0f) factor = 0.0f;
}
else {
+ CLAMP(factor, 0.0f, 1.0f);
if (is_percent) {
factor *= 100.0f;
- CLAMP(factor, 0.0f, 100.0f);
- }
- else {
- CLAMP(factor, 0.0f, 1.0f);
}
}
@@ -316,17 +326,16 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
BevelData *opdata = op->customdata;
int segments = RNA_int_get(op->ptr, "segments");
-
- if (event->val == KM_PRESS && hasNumInput(&opdata->num_input)) {
- /* Modal numinput active, try to handle numeric inputs first... */
- if (handleNumInput(C, &opdata->num_input, event)) {
- float value = RNA_float_get(op->ptr, "offset");
- applyNumInput(&opdata->num_input, &value);
- RNA_float_set(op->ptr, "offset", value);
- edbm_bevel_calc(op);
- edbm_bevel_update_header(op, C);
- return OPERATOR_RUNNING_MODAL;
- }
+ const bool has_numinput = hasNumInput(&opdata->num_input);
+
+ /* Modal numinput active, try to handle numeric inputs first... */
+ if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) {
+ float value = RNA_float_get(op->ptr, "offset");
+ applyNumInput(&opdata->num_input, &value);
+ RNA_float_set(op->ptr, "offset", value);
+ edbm_bevel_calc(op);
+ edbm_bevel_update_header(C, op);
+ return OPERATOR_RUNNING_MODAL;
}
else {
bool handled = false;
@@ -337,12 +346,12 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
case MOUSEMOVE:
- if (!hasNumInput(&opdata->num_input)) {
+ if (!has_numinput) {
const float factor = edbm_bevel_mval_factor(op, event);
RNA_float_set(op->ptr, "offset", factor);
edbm_bevel_calc(op);
- edbm_bevel_update_header(op, C);
+ edbm_bevel_update_header(C, op);
handled = true;
}
break;
@@ -367,7 +376,7 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
segments++;
RNA_int_set(op->ptr, "segments", segments);
edbm_bevel_calc(op);
- edbm_bevel_update_header(op, C);
+ edbm_bevel_update_header(C, op);
handled = true;
break;
@@ -379,29 +388,74 @@ static int edbm_bevel_modal(bContext *C, wmOperator *op, const wmEvent *event)
segments = max_ii(segments - 1, 1);
RNA_int_set(op->ptr, "segments", segments);
edbm_bevel_calc(op);
- edbm_bevel_update_header(op, C);
+ edbm_bevel_update_header(C, op);
handled = true;
break;
- }
- if (!handled && event->val == KM_PRESS) {
- /* Modal numinput inactive, try to handle numeric inputs last... */
- if (handleNumInput(C, &opdata->num_input, event)) {
- float value = RNA_float_get(op->ptr, "offset");
- applyNumInput(&opdata->num_input, &value);
- RNA_float_set(op->ptr, "offset", value);
+ case MKEY:
+ if (event->val == KM_RELEASE)
+ break;
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "offset_type");
+ int type = RNA_property_enum_get(op->ptr, prop);
+ type++;
+ if (type > BEVEL_AMT_PERCENT) {
+ type = BEVEL_AMT_OFFSET;
+ }
+ RNA_property_enum_set(op->ptr, prop, type);
+ }
+ /* Update factor accordingly to new offset_type. */
+ if (!has_numinput) {
+ RNA_float_set(op->ptr, "offset", edbm_bevel_mval_factor(op, event));
+ }
edbm_bevel_calc(op);
- edbm_bevel_update_header(op, C);
- return OPERATOR_RUNNING_MODAL;
- }
+ edbm_bevel_update_header(C, op);
+ handled = true;
+ break;
+ case CKEY:
+ if (event->val == KM_RELEASE)
+ break;
+
+ {
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "clamp_overlap");
+ RNA_property_enum_set(op->ptr, prop, !RNA_property_boolean_get(op->ptr, prop));
+ }
+ edbm_bevel_calc(op);
+ edbm_bevel_update_header(C, op);
+ handled = true;
+ break;
+ }
+
+ /* Modal numinput inactive, try to handle numeric inputs last... */
+ if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) {
+ float value = RNA_float_get(op->ptr, "offset");
+ applyNumInput(&opdata->num_input, &value);
+ RNA_float_set(op->ptr, "offset", value);
+ edbm_bevel_calc(op);
+ edbm_bevel_update_header(C, op);
+ return OPERATOR_RUNNING_MODAL;
}
}
return OPERATOR_RUNNING_MODAL;
}
+static void mesh_ot_bevel_offset_range_func(PointerRNA *ptr, PropertyRNA *UNUSED(prop),
+ float *min, float *max, float *softmin, float *softmax)
+{
+ const int offset_type = RNA_enum_get(ptr, "offset_type");
+
+ *min = -FLT_MAX;
+ *max = FLT_MAX;
+ *softmin = 0.0f;
+ *softmax = (offset_type == BEVEL_AMT_PERCENT) ? 100.0f : 1.0f;
+}
+
void MESH_OT_bevel(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
static EnumPropertyItem offset_type_items[] = {
{BEVEL_AMT_OFFSET, "OFFSET", 0, "Offset", "Amount is offset of new edges from original"},
{BEVEL_AMT_WIDTH, "WIDTH", 0, "Width", "Amount is width of new face"},
@@ -426,8 +480,12 @@ void MESH_OT_bevel(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_POINTER | OPTYPE_BLOCKING;
RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures");
- 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, -FLT_MAX, FLT_MAX, "Amount", "", 0.0f, 1.0f);
+ RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func);
RNA_def_int(ot->srna, "segments", 1, 1, 50, "Segments", "Segments for curved edge", 1, 8);
RNA_def_float(ot->srna, "profile", 0.5f, 0.15f, 1.0f, "Profile", "Controls profile shape (0.5 = round)", 0.15f, 1.0f);
- RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex only", "Bevel only vertices");
+ RNA_def_boolean(ot->srna, "vertex_only", false, "Vertex Only", "Bevel only vertices");
+ RNA_def_boolean(ot->srna, "clamp_overlap", false, "Clamp Overlap",
+ "Do not allow beveled edges/vertices to overlap each other");
+ RNA_def_int(ot->srna, "material", -1, -1, INT_MAX, "Material", "Material for bevel faces (-1 means use adjacent faces)", -1, 100);
}
diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c
index 5da33663897..3e403387a67 100644
--- a/source/blender/editors/mesh/editmesh_extrude.c
+++ b/source/blender/editors/mesh/editmesh_extrude.c
@@ -33,6 +33,7 @@
#include "DNA_object_types.h"
#include "BLI_math.h"
+#include "BLI_listbase.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -65,6 +66,75 @@ static void add_normal_aligned(float nor[3], const float add[3])
}
}
+static void edbm_extrude_edge_exclude_mirror(
+ Object *obedit, BMEditMesh *em,
+ const char hflag,
+ BMOperator *op, BMOpSlot *slot_edges_exclude)
+{
+ BMesh *bm = em->bm;
+ ModifierData *md;
+
+ /* If a mirror modifier with clipping is on, we need to adjust some
+ * of the cases above to handle edges on the line of symmetry.
+ */
+ for (md = obedit->modifiers.first; md; md = md->next) {
+ if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
+ MirrorModifierData *mmd = (MirrorModifierData *) md;
+
+ if (mmd->flag & MOD_MIR_CLIPPING) {
+ BMIter iter;
+ BMEdge *edge;
+
+ float mtx[4][4];
+ if (mmd->mirror_ob) {
+ float imtx[4][4];
+ invert_m4_m4(imtx, mmd->mirror_ob->obmat);
+ mul_m4_m4m4(mtx, imtx, obedit->obmat);
+ }
+
+ BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(edge, hflag) &&
+ BM_edge_is_boundary(edge) &&
+ BM_elem_flag_test(edge->l->f, hflag))
+ {
+ float co1[3], co2[3];
+
+ copy_v3_v3(co1, edge->v1->co);
+ copy_v3_v3(co2, edge->v2->co);
+
+ if (mmd->mirror_ob) {
+ mul_v3_m4v3(co1, mtx, co1);
+ mul_v3_m4v3(co2, mtx, co2);
+ }
+
+ if (mmd->flag & MOD_MIR_AXIS_X) {
+ if ((fabsf(co1[0]) < mmd->tolerance) &&
+ (fabsf(co2[0]) < mmd->tolerance))
+ {
+ BMO_slot_map_empty_insert(op, slot_edges_exclude, edge);
+ }
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Y) {
+ if ((fabsf(co1[1]) < mmd->tolerance) &&
+ (fabsf(co2[1]) < mmd->tolerance))
+ {
+ BMO_slot_map_empty_insert(op, slot_edges_exclude, edge);
+ }
+ }
+ if (mmd->flag & MOD_MIR_AXIS_Z) {
+ if ((fabsf(co1[2]) < mmd->tolerance) &&
+ (fabsf(co2[2]) < mmd->tolerance))
+ {
+ BMO_slot_map_empty_insert(op, slot_edges_exclude, edge);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
/* individual face extrude */
/* will use vertex normals for extrusion directions, so *nor is unaffected */
static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
@@ -75,7 +145,10 @@ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const c
BMLoop *l;
BMOperator bmop;
- EDBM_op_init(em, &bmop, op, "extrude_discrete_faces faces=%hf", hflag);
+ EDBM_op_init(
+ em, &bmop, op,
+ "extrude_discrete_faces faces=%hf use_select_history=%b",
+ hflag, true);
/* deselect original verts */
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -101,12 +174,18 @@ static short edbm_extrude_discrete_faces(BMEditMesh *em, wmOperator *op, const c
/* extrudes individual edges */
static short edbm_extrude_edges_indiv(BMEditMesh *em, wmOperator *op, const char hflag, float *UNUSED(nor))
{
+ BMesh *bm = em->bm;
BMOperator bmop;
- EDBM_op_init(em, &bmop, op, "extrude_edge_only edges=%he", hflag);
+ EDBM_op_init(
+ em, &bmop, op,
+ "extrude_edge_only edges=%he use_select_history=%b",
+ hflag, true);
/* deselect original verts */
+ BM_SELECT_HISTORY_BACKUP(bm);
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BM_SELECT_HISTORY_RESTORE(bm);
BMO_op_exec(em->bm, &bmop);
BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "geom.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true);
@@ -123,7 +202,10 @@ static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char
{
BMOperator bmop;
- EDBM_op_init(em, &bmop, op, "extrude_vert_indiv verts=%hv", hflag);
+ EDBM_op_init(
+ em, &bmop, op,
+ "extrude_vert_indiv verts=%hv use_select_history=%b",
+ hflag, true);
/* deselect original verts */
BMO_slot_buffer_hflag_disable(em->bm, bmop.slots_in, "verts", BM_VERT, BM_ELEM_SELECT, true);
@@ -138,82 +220,32 @@ static short edbm_extrude_verts_indiv(BMEditMesh *em, wmOperator *op, const char
return 'g'; /* g is grab */
}
-static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag, float nor[3])
+static short edbm_extrude_edge_ex(
+ Object *obedit, BMEditMesh *em,
+ const char hflag, float nor[3],
+ const bool use_mirror,
+ const bool use_select_history)
{
BMesh *bm = em->bm;
- BMIter iter;
BMOIter siter;
BMOperator extop;
- BMEdge *edge;
BMFace *f;
- ModifierData *md;
BMElem *ele;
- BMOpSlot *slot_edges_exclude;
BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region");
+ BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history);
BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE, hflag);
- slot_edges_exclude = BMO_slot_get(extop.slots_in, "edges_exclude");
+ if (use_mirror) {
+ BMOpSlot *slot_edges_exclude;
+ slot_edges_exclude = BMO_slot_get(extop.slots_in, "edges_exclude");
- /* If a mirror modifier with clipping is on, we need to adjust some
- * of the cases above to handle edges on the line of symmetry.
- */
- md = obedit->modifiers.first;
- for (; md; md = md->next) {
- if ((md->type == eModifierType_Mirror) && (md->mode & eModifierMode_Realtime)) {
- MirrorModifierData *mmd = (MirrorModifierData *) md;
-
- if (mmd->flag & MOD_MIR_CLIPPING) {
- float mtx[4][4];
- if (mmd->mirror_ob) {
- float imtx[4][4];
- invert_m4_m4(imtx, mmd->mirror_ob->obmat);
- mul_m4_m4m4(mtx, imtx, obedit->obmat);
- }
-
- BM_ITER_MESH (edge, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(edge, hflag) &&
- BM_edge_is_boundary(edge) &&
- BM_elem_flag_test(edge->l->f, hflag))
- {
- float co1[3], co2[3];
-
- copy_v3_v3(co1, edge->v1->co);
- copy_v3_v3(co2, edge->v2->co);
-
- if (mmd->mirror_ob) {
- mul_v3_m4v3(co1, mtx, co1);
- mul_v3_m4v3(co2, mtx, co2);
- }
-
- if (mmd->flag & MOD_MIR_AXIS_X) {
- if ((fabsf(co1[0]) < mmd->tolerance) &&
- (fabsf(co2[0]) < mmd->tolerance))
- {
- BMO_slot_map_empty_insert(&extop, slot_edges_exclude, edge);
- }
- }
- if (mmd->flag & MOD_MIR_AXIS_Y) {
- if ((fabsf(co1[1]) < mmd->tolerance) &&
- (fabsf(co2[1]) < mmd->tolerance))
- {
- BMO_slot_map_empty_insert(&extop, slot_edges_exclude, edge);
- }
- }
- if (mmd->flag & MOD_MIR_AXIS_Z) {
- if ((fabsf(co1[2]) < mmd->tolerance) &&
- (fabsf(co2[2]) < mmd->tolerance))
- {
- BMO_slot_map_empty_insert(&extop, slot_edges_exclude, edge);
- }
- }
- }
- }
- }
- }
+ edbm_extrude_edge_exclude_mirror(obedit, em, hflag, &extop, slot_edges_exclude);
}
+ BM_SELECT_HISTORY_BACKUP(bm);
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
+ BM_SELECT_HISTORY_RESTORE(bm);
BMO_op_exec(bm, &extop);
@@ -236,6 +268,13 @@ static short edbm_extrude_edge(Object *obedit, BMEditMesh *em, const char hflag,
return is_zero_v3(nor) ? 'g' : 'n';
}
+static short edbm_extrude_edge(
+ Object *obedit, BMEditMesh *em,
+ const char hflag, float nor[3])
+{
+ return edbm_extrude_edge_ex(obedit, em, hflag, nor, true, true);
+}
+
static short edbm_extrude_vert(Object *obedit, BMEditMesh *em, const char hflag, float nor[3])
{
BMIter iter;
@@ -288,13 +327,12 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op)
mul_m3_v3(tmat, dvec);
for (a = 0; a < steps; a++) {
- edbm_extrude_edge(obedit, em, BM_ELEM_SELECT, nor);
- //BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS, "extrude_face_region geom=%hef", BM_ELEM_SELECT);
- BMO_op_callf(em->bm, BMO_FLAG_DEFAULTS,
- "translate vec=%v verts=%hv",
- dvec, BM_ELEM_SELECT);
- //extrudeflag(obedit, em, SELECT, nor);
- //translateflag(em, SELECT, dvec);
+ edbm_extrude_edge_ex(obedit, em, BM_ELEM_SELECT, nor, false, false);
+
+ BMO_op_callf(
+ em->bm, BMO_FLAG_DEFAULTS,
+ "translate vec=%v verts=%hv",
+ dvec, BM_ELEM_SELECT);
}
EDBM_mesh_normals_update(em);
@@ -693,7 +731,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w
void MESH_OT_dupli_extrude_cursor(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Duplicate or Extrude at 3D Cursor";
+ ot->name = "Duplicate or Extrude to Cursor";
ot->idname = "MESH_OT_dupli_extrude_cursor";
ot->description = "Duplicate and extrude selected vertices, edges or faces towards the mouse cursor";
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index aa3a2c83243..f1c3ca30610 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -85,11 +85,12 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C)
char msg[HEADER_LENGTH];
ScrArea *sa = CTX_wm_area(C);
+ Scene *sce = CTX_data_scene(C);
if (sa) {
char flts_str[NUM_STR_REP_LEN * 2];
if (hasNumInput(&opdata->num_input))
- outputNumInput(&opdata->num_input, flts_str);
+ outputNumInput(&opdata->num_input, flts_str, &sce->unit);
else {
BLI_snprintf(flts_str, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "thickness"));
BLI_snprintf(flts_str + NUM_STR_REP_LEN, NUM_STR_REP_LEN, "%f", RNA_float_get(op->ptr, "depth"));
@@ -213,17 +214,21 @@ static bool edbm_inset_calc(wmOperator *op)
if (use_individual) {
EDBM_op_init(em, &bmop, op,
- "inset_individual faces=%hf use_even_offset=%b use_relative_offset=%b"
+ "inset_individual faces=%hf use_even_offset=%b use_relative_offset=%b "
"use_interpolate=%b thickness=%f depth=%f",
BM_ELEM_SELECT, use_even_offset, use_relative_offset, use_interpolate,
thickness, depth);
}
else {
EDBM_op_init(em, &bmop, op,
- "inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b"
- " use_interpolate=%b thickness=%f depth=%f use_outset=%b use_edge_rail=%b",
+ "inset_region faces=%hf use_boundary=%b use_even_offset=%b use_relative_offset=%b "
+ "use_interpolate=%b thickness=%f depth=%f use_outset=%b use_edge_rail=%b",
BM_ELEM_SELECT, use_boundary, use_even_offset, use_relative_offset, use_interpolate,
thickness, depth, use_outset, use_edge_rail);
+
+ if (use_outset) {
+ BMO_slot_buffer_from_enabled_hflag(em->bm, &bmop, bmop.slots_in, "faces_exclude", BM_FACE, BM_ELEM_HIDDEN);
+ }
}
BMO_op_exec(em->bm, &bmop);
@@ -296,25 +301,24 @@ static int edbm_inset_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
InsetData *opdata = op->customdata;
-
- if (event->val == KM_PRESS && hasNumInput(&opdata->num_input)) {
- /* Modal numinput active, try to handle numeric inputs first... */
- if (handleNumInput(C, &opdata->num_input, event)) {
- float amounts[2] = {RNA_float_get(op->ptr, "thickness"),
- RNA_float_get(op->ptr, "depth")};
- applyNumInput(&opdata->num_input, amounts);
- amounts[0] = max_ff(amounts[0], 0.0f);
- RNA_float_set(op->ptr, "thickness", amounts[0]);
- RNA_float_set(op->ptr, "depth", amounts[1]);
-
- if (edbm_inset_calc(op)) {
- edbm_inset_update_header(op, C);
- return OPERATOR_RUNNING_MODAL;
- }
- else {
- edbm_inset_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
+ const bool has_numinput = hasNumInput(&opdata->num_input);
+
+ /* Modal numinput active, try to handle numeric inputs first... */
+ if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &opdata->num_input, event)) {
+ float amounts[2] = {RNA_float_get(op->ptr, "thickness"),
+ RNA_float_get(op->ptr, "depth")};
+ applyNumInput(&opdata->num_input, amounts);
+ amounts[0] = max_ff(amounts[0], 0.0f);
+ RNA_float_set(op->ptr, "thickness", amounts[0]);
+ RNA_float_set(op->ptr, "depth", amounts[1]);
+
+ if (edbm_inset_calc(op)) {
+ edbm_inset_update_header(op, C);
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ edbm_inset_cancel(C, op);
+ return OPERATOR_CANCELLED;
}
}
else {
@@ -326,7 +330,7 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
case MOUSEMOVE:
- if (!hasNumInput(&opdata->num_input)) {
+ if (!has_numinput) {
float mdiff[2];
float amount;
@@ -454,24 +458,22 @@ static int edbm_inset_modal(bContext *C, wmOperator *op, const wmEvent *event)
break;
}
- if (!handled && event->val == KM_PRESS) {
- /* Modal numinput inactive, try to handle numeric inputs last... */
- if (handleNumInput(C, &opdata->num_input, event)) {
- float amounts[2] = {RNA_float_get(op->ptr, "thickness"),
- RNA_float_get(op->ptr, "depth")};
- applyNumInput(&opdata->num_input, amounts);
- amounts[0] = max_ff(amounts[0], 0.0f);
- RNA_float_set(op->ptr, "thickness", amounts[0]);
- RNA_float_set(op->ptr, "depth", amounts[1]);
-
- if (edbm_inset_calc(op)) {
- edbm_inset_update_header(op, C);
- return OPERATOR_RUNNING_MODAL;
- }
- else {
- edbm_inset_cancel(C, op);
- return OPERATOR_CANCELLED;
- }
+ /* Modal numinput inactive, try to handle numeric inputs last... */
+ if (!handled && event->val == KM_PRESS && handleNumInput(C, &opdata->num_input, event)) {
+ float amounts[2] = {RNA_float_get(op->ptr, "thickness"),
+ RNA_float_get(op->ptr, "depth")};
+ applyNumInput(&opdata->num_input, amounts);
+ amounts[0] = max_ff(amounts[0], 0.0f);
+ RNA_float_set(op->ptr, "thickness", amounts[0]);
+ RNA_float_set(op->ptr, "depth", amounts[1]);
+
+ if (edbm_inset_calc(op)) {
+ edbm_inset_update_header(op, C);
+ return OPERATOR_RUNNING_MODAL;
+ }
+ else {
+ edbm_inset_cancel(C, op);
+ return OPERATOR_CANCELLED;
}
}
}
@@ -512,7 +514,7 @@ void MESH_OT_inset(wmOperatorType *ot)
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");
- RNA_def_boolean(ot->srna, "use_select_inset", true, "Select Outer", "Select the new inset faces");
+ RNA_def_boolean(ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces");
RNA_def_boolean(ot->srna, "use_individual", false, "Individual", "Individual Face Inset");
RNA_def_boolean(ot->srna, "use_interpolate", true, "Interpolate", "Blend face data across the inset");
}
diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c
new file mode 100644
index 00000000000..df6776950d7
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_intersect.c
@@ -0,0 +1,400 @@
+/*
+ * ***** 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/mesh/editmesh_intersect.c
+ * \ingroup edmesh
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+#include "BLI_array.h"
+#include "BLI_linklist_stack.h"
+
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_editmesh.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+
+#include "intern/bmesh_private.h"
+
+#include "mesh_intern.h" /* own include */
+
+#include "tools/bmesh_intersect.h"
+
+
+/* -------------------------------------------------------------------- */
+/* Cut intersections into geometry */
+
+/**
+ * Compare selected with its self.
+ */
+static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data))
+{
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ return 0;
+ }
+ else {
+ return -1;
+ }
+}
+
+/**
+ * Compare selected/unselected.
+ */
+static int bm_face_isect_pair(BMFace *f, void *UNUSED(user_data))
+{
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ return -1;
+ }
+ else if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ return 0;
+ }
+ else {
+ return 1;
+ }
+}
+
+enum {
+ ISECT_SEL = 0,
+ ISECT_SEL_UNSEL = 1,
+};
+
+static EnumPropertyItem isect_mode_items[] = {
+ {ISECT_SEL, "SELECT", 0, "Self Intersect",
+ "Self intersect selected faces"},
+ {ISECT_SEL_UNSEL, "SELECT_UNSELECT", 0, "Selected/Unselected",
+ "Intersect selected with unselected faces"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int edbm_intersect_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ const int mode = RNA_enum_get(op->ptr, "mode");
+ int (*test_fn)(BMFace *, void *);
+ bool use_separate = RNA_boolean_get(op->ptr, "use_separate");
+ const float eps = RNA_float_get(op->ptr, "threshold");
+ bool use_self;
+ bool has_isect;
+
+ switch (mode) {
+ case ISECT_SEL:
+ test_fn = bm_face_isect_self;
+ use_self = true;
+ break;
+ default: /* ISECT_SEL_UNSEL */
+ test_fn = bm_face_isect_pair;
+ use_self = false;
+ break;
+ }
+
+
+ has_isect = BM_mesh_intersect(
+ bm,
+ em->looptris, em->tottri,
+ test_fn, NULL,
+ use_self, use_separate,
+ eps);
+
+
+ if (has_isect) {
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
+
+ if (em->bm->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) {
+ BMIter iter;
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BM_edge_select_set(bm, e, true);
+ }
+ }
+ }
+
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "No intersections found");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_intersect(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Intersect";
+ ot->description = "Cut an intersection into faces";
+ ot->idname = "MESH_OT_intersect";
+
+ /* api callbacks */
+ ot->exec = edbm_intersect_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* props */
+ RNA_def_enum(ot->srna, "mode", isect_mode_items, ISECT_SEL_UNSEL, "Source", "");
+ RNA_def_boolean(ot->srna, "use_separate", true, "Separate", "");
+ RNA_def_float(ot->srna, "threshold", 0.000001f, 0.0, 0.01, "Merge threshold", "", 0.0, 0.001);
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+/* -------------------------------------------------------------------- */
+/* Face Split by Edges */
+
+
+/** \name Face/Edge Split
+ * \{ */
+
+static void bm_face_split_by_edges(BMesh *bm, BMFace *f, const char hflag)
+{
+ BMEdge **edge_net = NULL;
+ BLI_array_declare(edge_net);
+
+ const int f_index = BM_elem_index_get(f);
+
+ BMLoop *l_iter;
+ BMLoop *l_first;
+ BMVert *v;
+
+ BMFace **face_arr;
+ int face_arr_len;
+
+ /* likely this will stay very small
+ * all verts pushed into this stack _must_ have their previous edges set! */
+ BLI_SMALLSTACK_DECLARE(vert_stack, BMVert *);
+ BLI_SMALLSTACK_DECLARE(vert_stack_next, BMVert *);
+
+
+ /* collect all edges */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ BMIter iter;
+ BMEdge *e;
+
+ BM_ITER_ELEM (e, &iter, l_iter->v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e, hflag) &&
+ (BM_elem_index_get(e) == f_index))
+ {
+ v = BM_edge_other_vert(e, l_iter->v);
+ v->e = e;
+
+ BLI_SMALLSTACK_PUSH(vert_stack, v);
+ BLI_array_append(edge_net, e);
+ }
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+
+
+
+ /* now assign all */
+ /* pop free values into the next stack */
+ while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) {
+ BMIter eiter;
+ BMEdge *e_next;
+
+ BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e_next, hflag) &&
+ (BM_elem_index_get(e_next) == -1))
+ {
+ BMVert *v_next;
+ v_next = BM_edge_other_vert(e_next, v);
+ BM_elem_index_set(e_next, f_index);
+ BLI_SMALLSTACK_PUSH(vert_stack_next, v_next);
+ BLI_array_append(edge_net, e_next);
+ }
+ }
+
+ if (BLI_SMALLSTACK_IS_EMPTY(vert_stack)) {
+ BLI_SMALLSTACK_SWAP(vert_stack, vert_stack_next);
+ }
+ }
+
+ BM_face_split_edgenet(bm, f, edge_net, BLI_array_count(edge_net), &face_arr, &face_arr_len);
+ BLI_array_free(edge_net);
+
+ if (face_arr_len) {
+ int i;
+ for (i = 0; i < face_arr_len; i++) {
+ BM_face_select_set(bm, face_arr[i], true);
+ BM_elem_flag_disable(face_arr[i], hflag);
+ }
+ }
+
+ if (face_arr) {
+ MEM_freeN(face_arr);
+ }
+}
+
+static int edbm_face_split_by_edges_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ const char hflag = BM_ELEM_TAG;
+
+ BMVert *v;
+ BMEdge *e;
+ BMFace *f;
+ BMIter iter;
+
+ BLI_SMALLSTACK_DECLARE(loop_stack, BMLoop *);
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_disable(v, hflag);
+ }
+
+ /* edge index is set to -1 then used to assosiate them with faces */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT) && BM_edge_is_wire(e)) {
+ BM_elem_flag_enable(e, hflag);
+
+ BM_elem_flag_enable(e->v1, hflag);
+ BM_elem_flag_enable(e->v2, hflag);
+
+ }
+ else {
+ BM_elem_flag_disable(e, hflag);
+ }
+ BM_elem_index_set(e, -1); /* set_dirty */
+ }
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(f, hflag);
+ }
+ else {
+ BM_elem_flag_disable(f, hflag);
+ }
+ }
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, hflag)) {
+ BMIter viter;
+ BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
+ BMIter liter;
+ BMLoop *l;
+
+ unsigned int loop_stack_len;
+ BMLoop *l_best = NULL;
+
+ BLI_assert(BLI_SMALLSTACK_IS_EMPTY(loop_stack));
+ loop_stack_len = 0;
+
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+ if (BM_elem_flag_test(l->f, hflag)) {
+ BLI_SMALLSTACK_PUSH(loop_stack, l);
+ loop_stack_len++;
+ }
+ }
+
+ if (loop_stack_len == 0) {
+ /* pass */
+ }
+ else if (loop_stack_len == 1) {
+ l_best = BLI_SMALLSTACK_POP(loop_stack);
+ }
+ else {
+ /* complicated case, match the edge with a face-loop */
+
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ float e_dir[3];
+
+ /* we wan't closest to zero */
+ float dot_best = FLT_MAX;
+
+ sub_v3_v3v3(e_dir, v_other->co, v->co);
+ normalize_v3(e_dir);
+
+ while ((l = BLI_SMALLSTACK_POP(loop_stack))) {
+ float dot_test;
+
+ /* Check dot first to save on expensive angle-comparison.
+ * ideal case is 90d difference == 0.0 dot */
+ dot_test = fabsf(dot_v3v3(e_dir, l->f->no));
+ if (dot_test < dot_best) {
+
+ /* check we're in the correct corner (works with convex loops too) */
+ if (angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, v_other->co, l->f->no) <
+ angle_signed_on_axis_v3v3v3_v3(l->prev->v->co, l->v->co, l->next->v->co, l->f->no))
+ {
+ dot_best = dot_test;
+ l_best = l;
+ }
+ }
+ }
+ }
+
+ if (l_best) {
+ BM_elem_index_set(e, BM_elem_index_get(l_best->f)); /* set_dirty */
+ }
+ }
+ }
+ }
+
+ bm->elem_index_dirty |= BM_EDGE;
+
+
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, hflag)) {
+ bm_face_split_by_edges(bm, f, hflag);
+ }
+ }
+
+ EDBM_mesh_normals_update(em);
+ EDBM_update_generic(em, true, true);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void MESH_OT_face_split_by_edges(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Split by Edges";
+ ot->description = "Split faces by loose edges";
+ ot->idname = "MESH_OT_face_split_by_edges";
+
+ /* api callbacks */
+ ot->exec = edbm_face_split_by_edges_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+/** \} */
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 366a8253849..f5a7e82a8a8 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -27,6 +27,8 @@
/** \file blender/editors/mesh/editmesh_knife.c
* \ingroup edmesh
+ *
+ * Interactive editmesh knife tool.
*/
#ifdef _MSC_VER
@@ -71,13 +73,12 @@
#include "mesh_intern.h" /* own include */
-/* this code here is kindof messy. . .I might need to eventually rework it - joeedh */
-
#define KMAXDIST 10 /* max mouse distance from edge before not detecting it */
#define KNIFE_FLT_EPS 0.00001f
#define KNIFE_FLT_EPS_SQUARED (KNIFE_FLT_EPS * KNIFE_FLT_EPS)
#define KNIFE_FLT_EPSBIG 0.0005f
+#define KNIFE_FLT_EPS_PX 0.2f
typedef struct KnifeColors {
unsigned char line[3];
@@ -115,7 +116,7 @@ typedef struct KnifeEdge {
typedef struct KnifeLineHit {
float hit[3], cagehit[3];
- float schit[2];
+ float schit[2]; /* screen coordinates for cagehit */
float l; /* lambda along cut line */
float perc; /* lambda along hit line */
float m; /* depth front-to-back */
@@ -181,6 +182,9 @@ typedef struct KnifeTool_OpData {
BLI_mempool *refs;
float projmat[4][4];
+ float projmat_inv[4][4];
+ /* vector along view z axis (object space, normalized) */
+ float proj_zaxis[3];
KnifeColors colors;
@@ -208,6 +212,9 @@ typedef struct KnifeTool_OpData {
bool ignore_edge_snapping;
bool ignore_vert_snapping;
+ /* use to check if we're currently dragging an angle snapped line */
+ bool is_angle_snapping;
+
enum {
ANGLE_FREE,
ANGLE_0,
@@ -247,6 +254,27 @@ static void knife_project_v2(const KnifeTool_OpData *kcd, const float co[3], flo
ED_view3d_project_float_v2_m4(kcd->ar, co, sco, (float (*)[4])kcd->projmat);
}
+/* use when lambda is in screen-space */
+static void knife_interp_v3_v3v3(
+ const KnifeTool_OpData *kcd,
+ float r_co[3], const float v1[3], const float v2[3], float lambda_ss)
+{
+ if (kcd->is_ortho) {
+ interp_v3_v3v3(r_co, v1, v2, lambda_ss);
+ }
+ else {
+ /* transform into screen-space, interp, then transform back */
+ float v1_ss[3], v2_ss[3];
+
+ mul_v3_project_m4_v3(v1_ss, (float (*)[4])kcd->projmat, v1);
+ mul_v3_project_m4_v3(v2_ss, (float (*)[4])kcd->projmat, v2);
+
+ interp_v3_v3v3(r_co, v1_ss, v2_ss, lambda_ss);
+
+ mul_project_m4_v3((float (*)[4])kcd->projmat_inv, r_co);
+ }
+}
+
static void knife_pos_data_clear(KnifePosData *kpd)
{
zero_v3(kpd->co);
@@ -340,7 +368,7 @@ static KnifeVert *new_knife_vert(KnifeTool_OpData *kcd, const float co[3], const
copy_v3_v3(kfv->co, co);
copy_v3_v3(kfv->cageco, cageco);
- knife_project_v2(kcd, kfv->co, kfv->sco);
+ knife_project_v2(kcd, kfv->cageco, kfv->sco);
return kfv;
}
@@ -441,19 +469,23 @@ static void knife_start_cut(KnifeTool_OpData *kcd)
kcd->prev = kcd->curr;
kcd->curr.is_space = 0; /*TODO: why do we do this? */
- if (kcd->prev.vert == NULL && kcd->prev.edge == NULL && is_zero_v3(kcd->prev.cage)) {
- /* Make prevcage a point on the view ray to mouse closest to a point on model: choose vertex 0 */
+ if (kcd->prev.vert == NULL && kcd->prev.edge == NULL) {
float origin[3], origin_ofs[3];
- BMVert *v0;
+ float ofs_local[3];
+
+ negate_v3_v3(ofs_local, kcd->vc.rv3d->ofs);
+ invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
+ mul_m4_v3(kcd->ob->imat, ofs_local);
knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
- v0 = BM_vert_at_index_find(kcd->em->bm, 0);
- if (v0) {
- closest_to_line_v3(kcd->prev.cage, v0->co, origin_ofs, origin);
- copy_v3_v3(kcd->prev.co, kcd->prev.cage); /*TODO: do we need this? */
- copy_v3_v3(kcd->curr.cage, kcd->prev.cage);
- copy_v3_v3(kcd->curr.co, kcd->prev.co);
+
+ if (!isect_line_plane_v3(kcd->prev.cage, origin, origin_ofs, ofs_local, kcd->proj_zaxis)) {
+ zero_v3(kcd->prev.cage);
}
+
+ copy_v3_v3(kcd->prev.co, kcd->prev.cage); /*TODO: do we need this? */
+ copy_v3_v3(kcd->curr.cage, kcd->prev.cage);
+ copy_v3_v3(kcd->curr.co, kcd->prev.co);
}
}
@@ -483,21 +515,14 @@ static void knife_edge_append_face(KnifeTool_OpData *kcd, KnifeEdge *kfe, BMFace
knife_append_list(kcd, &kfe->faces, f);
}
-static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float co[3], KnifeEdge **newkfe_out)
+static KnifeVert *knife_split_edge(
+ KnifeTool_OpData *kcd, KnifeEdge *kfe,
+ const float co[3], const float cageco[3],
+ KnifeEdge **r_kfe)
{
KnifeEdge *newkfe = new_knife_edge(kcd);
Ref *ref;
BMFace *f;
- float perc, cageco[3], l12;
-
- l12 = len_v3v3(kfe->v1->co, kfe->v2->co);
- if (l12 < KNIFE_FLT_EPS) {
- copy_v3_v3(cageco, kfe->v1->cageco);
- }
- else {
- perc = len_v3v3(co, kfe->v1->co) / l12;
- interp_v3_v3v3(cageco, kfe->v1->cageco, kfe->v2->cageco, perc);
- }
newkfe->v1 = kfe->v1;
newkfe->v2 = new_knife_vert(kcd, co, cageco);
@@ -529,7 +554,7 @@ static KnifeVert *knife_split_edge(KnifeTool_OpData *kcd, KnifeEdge *kfe, float
newkfe->draw = kfe->draw;
newkfe->e = kfe->e;
- *newkfe_out = newkfe;
+ *r_kfe = newkfe;
return newkfe->v2;
}
@@ -667,7 +692,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife
kfe->v1 = lh1->v;
}
else if (lh1->kfe) {
- kfe->v1 = knife_split_edge(kcd, lh1->kfe, lh1->cagehit, &kfe2);
+ kfe->v1 = knife_split_edge(kcd, lh1->kfe, lh1->hit, lh1->cagehit, &kfe2);
lh1->v = kfe->v1; /* record the KnifeVert for this hit */
}
else {
@@ -683,7 +708,7 @@ static void knife_add_single_cut(KnifeTool_OpData *kcd, KnifeLineHit *lh1, Knife
kfe->v2 = lh2->v;
}
else if (lh2->kfe) {
- kfe->v2 = knife_split_edge(kcd, lh2->kfe, lh2->cagehit, &kfe2);
+ kfe->v2 = knife_split_edge(kcd, lh2->kfe, lh2->hit, lh2->cagehit, &kfe2);
lh2->v = kfe->v2; /* future uses of lh2 won't split again */
}
else {
@@ -1068,21 +1093,22 @@ static void knifetool_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
-/* Find intersection of v1-v2 with face f.
- * Only take intersections that are at least face_tol (in screen space) away
+/**
+ * Find intersection of v1-v2 with face f.
+ * Only take intersections that are at least \a face_tol_sq (in screen space) away
* from other intersection elements.
* If v1-v2 is coplanar with f, call that "no intersection though
* it really means "infinite number of intersections".
- * In such a case we should have gotten hits on edges or verts of the face. */
-static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
- const float s[2],
- const float v1[3], const float v2[3],
- BMFace *f,
- const float face_tol,
- float intersectp[3])
+ * In such a case we should have gotten hits on edges or verts of the face.
+ */
+static bool knife_ray_intersect_face(
+ KnifeTool_OpData *kcd,
+ const float s[2], const float v1[3], const float v2[3],
+ BMFace *f, const float face_tol_sq,
+ float hit_co[3], float hit_cageco[3])
{
int tottri, tri_i;
- float lv1[3], lv2[3], lv3[3], raydir[3];
+ float raydir[3];
float tri_norm[3], tri_plane[4];
float se1[2], se2[2];
float d, lambda;
@@ -1098,12 +1124,14 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
BLI_assert(tri_i >= 0 && tri_i < tottri);
for (; tri_i < tottri; tri_i++) {
+ const float *lv1, *lv2, *lv3;
+
tri = kcd->em->looptris[tri_i];
if (tri[0]->f != f)
break;
- copy_v3_v3(lv1, kcd->cagecos[BM_elem_index_get(tri[0]->v)]);
- copy_v3_v3(lv2, kcd->cagecos[BM_elem_index_get(tri[1]->v)]);
- copy_v3_v3(lv3, kcd->cagecos[BM_elem_index_get(tri[2]->v)]);
+ lv1 = kcd->cagecos[BM_elem_index_get(tri[0]->v)];
+ lv2 = kcd->cagecos[BM_elem_index_get(tri[1]->v)];
+ lv3 = kcd->cagecos[BM_elem_index_get(tri[2]->v)];
/* using epsilon test in case ray is directly through an internal
* tesselation edge and might not hit either tesselation tri with
* an exact test;
@@ -1112,24 +1140,29 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd,
/* check if line coplanar with tri */
normal_tri_v3(tri_norm, lv1, lv2, lv3);
plane_from_point_normal_v3(tri_plane, lv1, tri_norm);
- if ((fabsf(dist_squared_to_plane_v3(v1, tri_plane)) < KNIFE_FLT_EPS) &&
- (fabsf(dist_squared_to_plane_v3(v2, tri_plane)) < KNIFE_FLT_EPS))
+ if ((dist_squared_to_plane_v3(v1, tri_plane) < KNIFE_FLT_EPS) &&
+ (dist_squared_to_plane_v3(v2, tri_plane) < KNIFE_FLT_EPS))
{
return false;
}
- copy_v3_v3(intersectp, v1);
- madd_v3_v3fl(intersectp, raydir, lambda);
+ copy_v3_v3(hit_cageco, v1);
+ madd_v3_v3fl(hit_cageco, raydir, lambda);
/* Now check that far enough away from verts and edges */
lst = knife_get_face_kedges(kcd, f);
for (ref = lst->first; ref; ref = ref->next) {
kfe = ref->ref;
knife_project_v2(kcd, kfe->v1->cageco, se1);
knife_project_v2(kcd, kfe->v2->cageco, se2);
- d = dist_to_line_segment_v2(s, se1, se2);
- if (d < face_tol) {
+ d = dist_squared_to_line_segment_v2(s, se1, se2);
+ if (d < face_tol_sq) {
return false;
}
}
+
+ transform_point_by_tri_v3(
+ hit_co, hit_cageco,
+ tri[0]->v->co, tri[1]->v->co, tri[2]->v->co,
+ lv1, lv2, lv3);
return true;
}
}
@@ -1158,6 +1191,13 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa
{
BMFace *f_hit;
+ /* If box clipping on, make sure p is not clipped */
+ if (kcd->vc.rv3d->rflag & RV3D_CLIPPING &&
+ ED_view3d_clipping_test(kcd->vc.rv3d, p, true))
+ {
+ return false;
+ }
+
/* If not cutting through, make sure no face is in front of p */
if (!kcd->cut_through) {
float dist;
@@ -1174,8 +1214,19 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa
madd_v3_v3v3fl(p_ofs, p, view, KNIFE_FLT_EPSBIG * 3.0f);
/* avoid projecting behind the viewpoint */
- if (kcd->is_ortho) {
- dist = FLT_MAX;
+ if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
+ dist = kcd->vc.v3d->far * 2.0f;
+ }
+
+ if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ float view_clip[2][3];
+ /* note: view_clip[0] should never get clipped */
+ copy_v3_v3(view_clip[0], p_ofs);
+ madd_v3_v3v3fl(view_clip[1], p_ofs, view, dist);
+
+ if (clip_segment_v3_plane_n(view_clip[0], view_clip[1], kcd->vc.rv3d->clip_local, 6)) {
+ dist = len_v3v3(p_ofs, view_clip[1]);
+ }
}
/* see if there's a face hit between p1 and the view */
@@ -1184,13 +1235,6 @@ static bool point_is_visible(KnifeTool_OpData *kcd, const float p[3], const floa
return false;
}
- /* If box clipping on, make sure p is not clipped */
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING &&
- ED_view3d_clipping_test(kcd->vc.rv3d, p, true))
- {
- return false;
- }
-
return true;
}
@@ -1208,16 +1252,7 @@ static void clip_to_ortho_planes(float v1[3], float v2[3], float d)
static void set_linehit_depth(KnifeTool_OpData *kcd, KnifeLineHit *lh)
{
- float vnear[3], vfar[3];
-
- ED_view3d_win_to_segment(kcd->ar, kcd->vc.v3d, lh->schit, vnear, vfar, true);
- mul_m4_v3(kcd->ob->imat, vnear);
- if (kcd->is_ortho) {
- if (kcd->ortho_extent == 0.0f)
- calc_ortho_extent(kcd);
- clip_to_ortho_planes(vnear, vfar, kcd->ortho_extent + 10.0f);
- }
- lh->m = len_v3v3(vnear, lh->cagehit);
+ lh->m = dot_m4_v3_row_z(kcd->vc.rv3d->persmatob, lh->cagehit);
}
/* Finds visible (or all, if cutting through) edges that intersects the current screen drag line */
@@ -1241,9 +1276,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
void *val;
float plane_cos[12];
float s[2], se1[2], se2[2], sint[2];
- float p[3], p2[3], r1[3], r2[3];
+ float r1[3], r2[3];
float d, d1, d2, lambda;
- float vert_tol, vert_tol_sq, line_tol, face_tol;
+ float vert_tol, vert_tol_sq;
+ float line_tol, line_tol_sq;
+ float face_tol, face_tol_sq;
+ float eps_scale;
int isect_kind;
unsigned int tot;
int i;
@@ -1288,7 +1326,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
* this gives precision error; rather then solving properly
* (which may involve using doubles everywhere!),
* limit the distance between these points */
- if (kcd->is_ortho) {
+ if (kcd->is_ortho && (kcd->vc.rv3d->persp != RV3D_CAMOB)) {
if (kcd->ortho_extent == 0.0f)
calc_ortho_extent(kcd);
clip_to_ortho_planes(v1, v3, kcd->ortho_extent + 10.0f);
@@ -1346,10 +1384,22 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
/* Now go through the candidates and find intersections */
/* These tolerances, in screen space, are for intermediate hits, as ends are already snapped to screen */
- vert_tol = KNIFE_FLT_EPS * 2000.0f;
- line_tol = KNIFE_FLT_EPS * 2000.0f;
- vert_tol_sq = vert_tol * vert_tol;
+ {
+ /* Scale the epsilon by the zoom level
+ * to compensate for projection imprecision, see T41164 */
+ float zoom_xy[2] = {kcd->vc.rv3d->winmat[0][0],
+ kcd->vc.rv3d->winmat[1][1]};
+ eps_scale = len_v2(zoom_xy);
+ }
+
+ vert_tol = KNIFE_FLT_EPS_PX * eps_scale;
+ line_tol = KNIFE_FLT_EPS_PX * eps_scale;
face_tol = max_ff(vert_tol, line_tol);
+
+ vert_tol_sq = vert_tol * vert_tol;
+ line_tol_sq = line_tol * line_tol;
+ face_tol_sq = face_tol * face_tol;
+
/* Assume these tolerances swamp floating point rounding errors in calculations below */
/* first look for vertex hits */
@@ -1362,7 +1412,7 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
if (point_is_visible(kcd, v->cageco, s, &mats)) {
memset(&hit, 0, sizeof(hit));
hit.v = v;
- copy_v3_v3(hit.hit, v->cageco);
+ copy_v3_v3(hit.hit, v->co);
copy_v3_v3(hit.cagehit, v->cageco);
copy_v2_v2(hit.schit, s);
set_linehit_depth(kcd, &hit);
@@ -1380,35 +1430,39 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
if (isect_kind == -1) {
/* isect_seg_seg_v2 doesn't do tolerance test around ends of s1-s2 */
closest_to_line_segment_v2(sint, s1, se1, se2);
- if (len_squared_v2v2(sint, s1) <= vert_tol_sq)
+ if (len_squared_v2v2(sint, s1) <= line_tol_sq)
isect_kind = 1;
else {
closest_to_line_segment_v2(sint, s2, se1, se2);
- if (len_squared_v2v2(sint, s2) <= vert_tol_sq)
+ if (len_squared_v2v2(sint, s2) <= line_tol_sq)
isect_kind = 1;
}
}
if (isect_kind == 1) {
d1 = len_v2v2(sint, se1);
d2 = len_v2v2(se2, se1);
- if (!(d1 <= vert_tol || d2 <= vert_tol || fabsf(d1 - d2) <= vert_tol)) {
+ if (!(d1 <= line_tol || d2 <= line_tol || fabsf(d1 - d2) <= line_tol)) {
+ float p_cage[3], p_cage_tmp[3];
lambda = d1 / d2;
/* Can't just interpolate between ends of kfe because
* that doesn't work with perspective transformation.
* Need to find 3d intersection of ray through sint */
knife_input_ray_segment(kcd, sint, 1.0f, r1, r2);
- isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p, p2);
- if (isect_kind >= 1 && point_is_visible(kcd, p, sint, &mats)) {
+ isect_kind = isect_line_line_v3(kfe->v1->cageco, kfe->v2->cageco, r1, r2, p_cage, p_cage_tmp);
+ if (isect_kind >= 1 && point_is_visible(kcd, p_cage, sint, &mats)) {
memset(&hit, 0, sizeof(hit));
if (kcd->snap_midpoints) {
/* choose intermediate point snap too */
- mid_v3_v3v3(p, kfe->v1->cageco, kfe->v2->cageco);
+ mid_v3_v3v3(p_cage, kfe->v1->cageco, kfe->v2->cageco);
mid_v2_v2v2(sint, se1, se2);
lambda = 0.5f;
}
hit.kfe = kfe;
- copy_v3_v3(hit.hit, p);
- copy_v3_v3(hit.cagehit, p);
+ transform_point_by_seg_v3(
+ hit.hit, p_cage,
+ kfe->v1->co, kfe->v2->co,
+ kfe->v1->cageco, kfe->v2->cageco);
+ copy_v3_v3(hit.cagehit, p_cage);
copy_v2_v2(hit.schit, sint);
hit.perc = lambda;
set_linehit_depth(kcd, &hit);
@@ -1421,23 +1475,25 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd)
for (val = BLI_smallhash_iternew(&faces, &hiter, (uintptr_t *)&f); val;
val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&f))
{
- if (knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol, p)) {
- if (point_is_visible(kcd, p, s1, &mats)) {
+ float p[3], p_cage[3];
+
+ if (knife_ray_intersect_face(kcd, s1, v1, v3, f, face_tol_sq, p, p_cage)) {
+ if (point_is_visible(kcd, p_cage, s1, &mats)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
copy_v3_v3(hit.hit, p);
- copy_v3_v3(hit.cagehit, p);
+ copy_v3_v3(hit.cagehit, p_cage);
copy_v2_v2(hit.schit, s1);
set_linehit_depth(kcd, &hit);
BLI_array_append(linehits, hit);
}
}
- if (knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol, p)) {
- if (point_is_visible(kcd, p, s2, &mats)) {
+ if (knife_ray_intersect_face(kcd, s2, v2, v4, f, face_tol_sq, p, p_cage)) {
+ if (point_is_visible(kcd, p_cage, s2, &mats)) {
memset(&hit, 0, sizeof(hit));
hit.f = f;
copy_v3_v3(hit.hit, p);
- copy_v3_v3(hit.cagehit, p);
+ copy_v3_v3(hit.cagehit, p_cage);
copy_v2_v2(hit.schit, s2);
set_linehit_depth(kcd, &hit);
BLI_array_append(linehits, hit);
@@ -1597,48 +1653,76 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo
f = knife_find_closest_face(kcd, co, cageco, NULL);
*is_space = !f;
- /* set p to co, in case we don't find anything, means a face cut */
- copy_v3_v3(p, co);
- copy_v3_v3(cagep, cageco);
-
kcd->curr.bmface = f;
if (f) {
const float maxdist_sq = maxdist * maxdist;
KnifeEdge *cure = NULL;
+ float cur_cagep[3];
ListBase *lst;
Ref *ref;
float dis_sq, curdis_sq = FLT_MAX;
+ /* set p to co, in case we don't find anything, means a face cut */
+ copy_v3_v3(p, co);
+ copy_v3_v3(cagep, cageco);
+
knife_project_v2(kcd, cageco, sco);
/* look through all edges associated with this face */
lst = knife_get_face_kedges(kcd, f);
for (ref = lst->first; ref; ref = ref->next) {
KnifeEdge *kfe = ref->ref;
+ float test_cagep[3];
+ float lambda;
/* project edge vertices into screen space */
knife_project_v2(kcd, kfe->v1->cageco, kfe->v1->sco);
knife_project_v2(kcd, kfe->v2->cageco, kfe->v2->sco);
- dis_sq = dist_squared_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
- if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
- if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
- float lambda = line_point_factor_v2(sco, kfe->v1->sco, kfe->v2->sco);
- float vec[3];
+ /* check if we're close enough and calculate 'lambda' */
+ if (kcd->is_angle_snapping) {
+ /* if snapping, check we're in bounds */
+ float sco_snap[2];
+ isect_line_line_v2_point(kfe->v1->sco, kfe->v2->sco, kcd->prev.mval, kcd->curr.mval, sco_snap);
+ lambda = line_point_factor_v2(sco_snap, kfe->v1->sco, kfe->v2->sco);
- interp_v3_v3v3(vec, kfe->v1->cageco, kfe->v2->cageco, lambda);
+ /* be strict about angle-snapping within edge */
+ if ((lambda < 0.0f - KNIFE_FLT_EPSBIG) || (lambda > 1.0f + KNIFE_FLT_EPSBIG)) {
+ continue;
+ }
- if (ED_view3d_clipping_test(kcd->vc.rv3d, vec, true) == 0) {
- cure = kfe;
- curdis_sq = dis_sq;
- }
+ dis_sq = len_squared_v2v2(sco, sco_snap);
+ if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
+ /* we already have 'lambda' */
+ }
+ else {
+ continue;
+ }
+ }
+ else {
+ dis_sq = dist_squared_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
+ if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
+ lambda = line_point_factor_v2(sco, kfe->v1->sco, kfe->v2->sco);
}
else {
- cure = kfe;
- curdis_sq = dis_sq;
+ continue;
}
}
+
+ /* now we have 'lambda' calculated (in screen-space) */
+ knife_interp_v3_v3v3(kcd, test_cagep, kfe->v1->cageco, kfe->v2->cageco, lambda);
+
+ if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
+ /* check we're in the view */
+ if (ED_view3d_clipping_test(kcd->vc.rv3d, test_cagep, true)) {
+ continue;
+ }
+ }
+
+ cure = kfe;
+ curdis_sq = dis_sq;
+ copy_v3_v3(cur_cagep, test_cagep);
}
if (fptr)
@@ -1653,11 +1737,9 @@ static KnifeEdge *knife_find_closest_edge(KnifeTool_OpData *kcd, float p[3], flo
mid_v3_v3v3(cagep, cure->v1->cageco, cure->v2->cageco);
}
else {
- float d;
-
- closest_to_line_segment_v3(cagep, cageco, cure->v1->cageco, cure->v2->cageco);
- d = len_v3v3(cagep, cure->v1->cageco) / len_v3v3(cure->v1->cageco, cure->v2->cageco);
- interp_v3_v3v3(p, cure->v1->co, cure->v2->co, d);
+ float lambda = line_point_factor_v3(cur_cagep, cure->v1->cageco, cure->v2->cageco);
+ copy_v3_v3(cagep, cur_cagep);
+ interp_v3_v3v3(p, cure->v1->co, cure->v2->co, lambda);
}
/* update mouse coordinates to the snapped-to edge's screen coordinates
@@ -1693,9 +1775,6 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
f = knife_find_closest_face(kcd, co, cageco, is_space);
- /* set p to co, in case we don't find anything, means a face cut */
- copy_v3_v3(p, co);
- copy_v3_v3(cagep, cageco);
kcd->curr.bmface = f;
if (f) {
@@ -1705,6 +1784,10 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
KnifeVert *curv = NULL;
float dis_sq, curdis_sq = FLT_MAX;
+ /* set p to co, in case we don't find anything, means a face cut */
+ copy_v3_v3(p, co);
+ copy_v3_v3(cagep, cageco);
+
knife_project_v2(kcd, cageco, sco);
lst = knife_get_face_kedges(kcd, f);
@@ -1717,6 +1800,13 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
knife_project_v2(kcd, kfv->cageco, kfv->sco);
+ /* be strict about angle snapping, the vertex needs to be very close to the angle, or we ignore */
+ if (kcd->is_angle_snapping) {
+ if (dist_squared_to_line_segment_v2(kfv->sco, kcd->prev.mval, kcd->curr.mval) > KNIFE_FLT_EPSBIG) {
+ continue;
+ }
+ }
+
dis_sq = len_squared_v2v2(kfv->sco, sco);
if (dis_sq < curdis_sq && dis_sq < maxdist_sq) {
if (kcd->vc.rv3d->rflag & RV3D_CLIPPING) {
@@ -1764,7 +1854,7 @@ static KnifeVert *knife_find_closest_vert(KnifeTool_OpData *kcd, float p[3], flo
}
/* update both kcd->curr.mval and kcd->mval to snap to required angle */
-static void knife_snap_angle(KnifeTool_OpData *kcd)
+static bool knife_snap_angle(KnifeTool_OpData *kcd)
{
float dx, dy;
float w, abs_tan;
@@ -1772,7 +1862,7 @@ static void knife_snap_angle(KnifeTool_OpData *kcd)
dx = kcd->curr.mval[0] - kcd->prev.mval[0];
dy = kcd->curr.mval[1] - kcd->prev.mval[1];
if (dx == 0.0f && dy == 0.0f)
- return;
+ return false;
if (dx == 0.0f) {
kcd->angle_snapping = ANGLE_90;
@@ -1801,6 +1891,8 @@ static void knife_snap_angle(KnifeTool_OpData *kcd)
}
copy_v2_v2(kcd->mval, kcd->curr.mval);
+
+ return true;
}
/* update active knife edge/vert pointers */
@@ -1810,14 +1902,15 @@ static int knife_update_active(KnifeTool_OpData *kcd)
copy_v2_v2(kcd->curr.mval, kcd->mval);
/* view matrix may have changed, reproject */
- knife_project_v2(kcd, kcd->prev.co, kcd->prev.mval);
+ knife_project_v2(kcd, kcd->prev.cage, kcd->prev.mval);
- if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING)
- knife_snap_angle(kcd);
+ if (kcd->angle_snapping != ANGLE_FREE && kcd->mode == MODE_DRAGGING) {
+ kcd->is_angle_snapping = knife_snap_angle(kcd);
+ }
+ else {
+ kcd->is_angle_snapping = false;
+ }
- /* XXX knife_snap_angle updates the view coordinate mouse values to constrained angles,
- * which current mouse values are set to current mouse values are then used
- * for vertex and edge snap detection, without regard to the exact angle constraint */
kcd->curr.vert = knife_find_closest_vert(kcd, kcd->curr.co, kcd->curr.cage, &kcd->curr.bmface, &kcd->curr.is_space);
if (!kcd->curr.vert) {
@@ -1835,8 +1928,12 @@ static int knife_update_active(KnifeTool_OpData *kcd)
knife_input_ray_segment(kcd, kcd->curr.mval, 1.0f, origin, origin_ofs);
- closest_to_line_v3(kcd->curr.cage, kcd->prev.cage, origin_ofs, origin);
- copy_v3_v3(kcd->curr.co, kcd->curr.cage);
+ if (!isect_line_plane_v3(kcd->curr.cage, origin, origin_ofs, kcd->prev.cage, kcd->proj_zaxis)) {
+ copy_v3_v3(kcd->curr.cage, kcd->prev.cage);
+
+ /* should never fail! */
+ BLI_assert(0);
+ }
}
if (kcd->mode == MODE_DRAGGING) {
@@ -2060,7 +2157,7 @@ static ListBase *find_hole(KnifeTool_OpData *kcd, ListBase *fedges)
static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, ListBase **mainchain,
ListBase **sidechain)
{
- float **fco, **hco;
+ float (*fco)[2], (*hco)[2];
BMVert **fv;
KnifeVert **hv;
KnifeEdge **he;
@@ -2082,8 +2179,8 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
/* Gather 2d projections of hole and face vertex coordinates.
* Use best-axis projection - not completely accurate, maybe revisit */
axis_dominant_v3(&ax, &ay, f->no);
- hco = BLI_memarena_alloc(kcd->arena, nh * sizeof(float *));
- fco = BLI_memarena_alloc(kcd->arena, nf * sizeof(float *));
+ hco = BLI_memarena_alloc(kcd->arena, nh * sizeof(float[2]));
+ fco = BLI_memarena_alloc(kcd->arena, nf * sizeof(float[2]));
hv = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeVert *));
fv = BLI_memarena_alloc(kcd->arena, nf * sizeof(BMVert *));
he = BLI_memarena_alloc(kcd->arena, nh * sizeof(KnifeEdge *));
@@ -2101,7 +2198,6 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
kfv = kfvother;
BLI_assert(kfv == kfe->v1 || kfv == kfe->v2);
}
- hco[i] = BLI_memarena_alloc(kcd->arena, 2 * sizeof(float));
hco[i][0] = kfv->co[ax];
hco[i][1] = kfv->co[ay];
hv[i] = kfv;
@@ -2111,7 +2207,6 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
j = 0;
BM_ITER_ELEM (v, &iter, f, BM_VERTS_OF_FACE) {
- fco[j] = BLI_memarena_alloc(kcd->arena, 2 * sizeof(float));
fco[j][0] = v->co[ax];
fco[j][1] = v->co[ay];
fv[j] = v;
@@ -2203,33 +2298,30 @@ static bool find_hole_chains(KnifeTool_OpData *kcd, ListBase *hole, BMFace *f, L
static bool knife_verts_edge_in_face(KnifeVert *v1, KnifeVert *v2, BMFace *f)
{
- BMLoop *l1, *l2, *l;
- float mid[3];
- BMIter iter;
- int v1inside, v2inside;
+ bool v1_inside, v2_inside;
+ bool v1_inface, v2_inface;
if (!f || !v1 || !v2)
return false;
- l1 = NULL;
- l2 = NULL;
-
/* find out if v1 and v2, if set, are part of the face */
- BM_ITER_ELEM (l, &iter, f, BM_LOOPS_OF_FACE) {
- if (v1->v && l->v == v1->v)
- l1 = l;
- if (v2->v && l->v == v2->v)
- l2 = l;
- }
+ v1_inface = v1->v ? BM_vert_in_face(f, v1->v) : false;
+ v2_inface = v2->v ? BM_vert_in_face(f, v2->v) : false;
/* BM_face_point_inside_test uses best-axis projection so this isn't most accurate test... */
- v1inside = l1 ? 0 : BM_face_point_inside_test(f, v1->co);
- v2inside = l2 ? 0 : BM_face_point_inside_test(f, v2->co);
- if ((l1 && v2inside) || (l2 && v1inside) || (v1inside && v2inside))
+ v1_inside = v1_inface ? false : BM_face_point_inside_test(f, v1->co);
+ v2_inside = v2_inface ? false : BM_face_point_inside_test(f, v2->co);
+ if ((v1_inface && v2_inside) ||
+ (v2_inface && v1_inside) ||
+ (v1_inside && v2_inside))
+ {
return true;
- if (l1 && l2) {
+ }
+
+ if (v1_inface && v2_inface) {
+ float mid[3];
/* Can have case where v1 and v2 are on shared chain between two faces.
- * BM_face_legal_splits does visibility and self-intersection tests,
+ * BM_face_splits_check_legal does visibility and self-intersection tests,
* but it is expensive and maybe a bit buggy, so use a simple
* "is the midpoint in the face" test */
mid_v3_v3v3(mid, v1->co, v2->co);
@@ -2326,12 +2418,12 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
KnifeEdge *kfe;
BMFace *fnew, *fnew2, *fhole;
ListBase *chain, *hole, *sidechain;
- ListBase *fnew_kfedges, *fnew2_kfedges;
Ref *ref, *refnext;
int count, oldcount;
oldcount = BLI_countlist(kfedges);
while ((chain = find_chain(kcd, kfedges)) != NULL) {
+ ListBase fnew_kfedges;
knife_make_chain_cut(kcd, f, chain, &fnew);
if (!fnew) {
return;
@@ -2339,18 +2431,22 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
/* Move kfedges to fnew_kfedges if they are now in fnew.
* The chain edges were removed already */
- fnew_kfedges = knife_empty_list(kcd);
+ BLI_listbase_clear(&fnew_kfedges);
for (ref = kfedges->first; ref; ref = refnext) {
kfe = ref->ref;
refnext = ref->next;
if (knife_edge_in_face(kfe, fnew)) {
BLI_remlink(kfedges, ref);
kfe->basef = fnew;
- knife_append_list(kcd, fnew_kfedges, kfe);
+ BLI_addtail(&fnew_kfedges, ref);
+ }
+ else if (!knife_edge_in_face(kfe, f)) {
+ /* Concave ngon's - this edge might not be in either faces, T41730 */
+ BLI_remlink(kfedges, ref);
}
}
- if (fnew_kfedges->first)
- knife_make_face_cuts(kcd, fnew, fnew_kfedges);
+ if (fnew_kfedges.first)
+ knife_make_face_cuts(kcd, fnew, &fnew_kfedges);
/* find_chain should always remove edges if it returns true,
* but guard against infinite loop anyway */
@@ -2364,6 +2460,8 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
while ((hole = find_hole(kcd, kfedges)) != NULL) {
if (find_hole_chains(kcd, hole, f, &chain, &sidechain)) {
+ ListBase fnew_kfedges, fnew2_kfedges;
+
/* chain goes across f and sidechain comes back
* from the second last vertex to the second vertex.
*/
@@ -2394,28 +2492,28 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe
BM_face_kill(bm, fhole);
/* Move kfedges to either fnew or fnew2 if appropriate.
* The hole edges were removed already */
- fnew_kfedges = knife_empty_list(kcd);
- fnew2_kfedges = knife_empty_list(kcd);
+ BLI_listbase_clear(&fnew_kfedges);
+ BLI_listbase_clear(&fnew2_kfedges);
for (ref = kfedges->first; ref; ref = refnext) {
kfe = ref->ref;
refnext = ref->next;
if (knife_edge_in_face(kfe, fnew)) {
BLI_remlink(kfedges, ref);
kfe->basef = fnew;
- knife_append_list(kcd, fnew_kfedges, kfe);
+ BLI_addtail(&fnew_kfedges, ref);
}
else if (knife_edge_in_face(kfe, fnew2)) {
BLI_remlink(kfedges, ref);
kfe->basef = fnew2;
- knife_append_list(kcd, fnew2_kfedges, kfe);
+ BLI_addtail(&fnew2_kfedges, ref);
}
}
/* We'll skip knife edges that are in the newly formed hole.
* (Maybe we shouldn't have made a hole in the first place?) */
- if (fnew != fhole && fnew_kfedges->first)
- knife_make_face_cuts(kcd, fnew, fnew_kfedges);
- if (fnew2 != fhole && fnew2_kfedges->first)
- knife_make_face_cuts(kcd, fnew2, fnew2_kfedges);
+ if (fnew != fhole && fnew_kfedges.first)
+ knife_make_face_cuts(kcd, fnew, &fnew_kfedges);
+ if (fnew2 != fhole && fnew2_kfedges.first)
+ knife_make_face_cuts(kcd, fnew2, &fnew2_kfedges);
if (f == fhole)
break;
/* find_hole should always remove edges if it returns true,
@@ -2530,7 +2628,11 @@ static void knife_recalc_projmat(KnifeTool_OpData *kcd)
{
invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
ED_view3d_ob_project_mat_get(kcd->ar->regiondata, kcd->ob, kcd->projmat);
- //mul_m4_m4m4(kcd->projmat, kcd->vc.rv3d->winmat, kcd->vc.rv3d->viewmat);
+ 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);
+ normalize_v3(kcd->proj_zaxis);
kcd->is_ortho = ED_view3d_clip_range_get(kcd->vc.v3d, kcd->vc.rv3d,
&kcd->clipsta, &kcd->clipend, true);
diff --git a/source/blender/editors/mesh/editmesh_knife_project.c b/source/blender/editors/mesh/editmesh_knife_project.c
index cc26d6079a9..553c1faa36a 100644
--- a/source/blender/editors/mesh/editmesh_knife_project.c
+++ b/source/blender/editors/mesh/editmesh_knife_project.c
@@ -65,7 +65,7 @@ static LinkNode *knifeproject_poly_from_object(ARegion *ar, Scene *scene, Object
dm = ob->derivedFinal ? ob->derivedFinal : mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
dm_needsFree = false;
}
- else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
+ else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
dm = CDDM_from_curve(ob);
dm_needsFree = true;
}
diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c
index 4ef6c13ec3e..b5508ef8b82 100644
--- a/source/blender/editors/mesh/editmesh_loopcut.c
+++ b/source/blender/editors/mesh/editmesh_loopcut.c
@@ -75,6 +75,9 @@ typedef struct RingSelOpData {
float (*edges)[2][3];
int totedge;
+ float (*points)[3];
+ int totpoint;
+
ViewContext vc;
Object *ob;
@@ -91,9 +94,8 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
{
View3D *v3d = CTX_wm_view3d(C);
RingSelOpData *lcd = arg;
- int i;
- if (lcd->totedge > 0) {
+ if ((lcd->totedge > 0) || (lcd->totpoint > 0)) {
if (v3d && v3d->zbuf)
glDisable(GL_DEPTH_TEST);
@@ -101,12 +103,23 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg)
glMultMatrixf(lcd->ob->obmat);
glColor3ub(255, 0, 255);
- glBegin(GL_LINES);
- for (i = 0; i < lcd->totedge; i++) {
- glVertex3fv(lcd->edges[i][0]);
- glVertex3fv(lcd->edges[i][1]);
+ if (lcd->totedge > 0) {
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, lcd->edges);
+ glDrawArrays(GL_LINES, 0, lcd->totedge * 2);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ }
+
+ if (lcd->totpoint > 0) {
+ glPointSize(3.0f);
+
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glVertexPointer(3, GL_FLOAT, 0, lcd->points);
+ glDrawArrays(GL_POINTS, 0, lcd->totpoint);
+ glDisableClientState(GL_VERTEX_ARRAY);
+
+ glPointSize(1.0f);
}
- glEnd();
glPopMatrix();
if (v3d && v3d->zbuf)
@@ -178,52 +191,43 @@ static void edgering_vcos_get(DerivedMesh *dm, BMVert *v[2][2], float r_cos[2][2
}
}
-static void edgering_sel(RingSelOpData *lcd, int previewlines, bool select)
+static void edgering_vcos_get_pair(DerivedMesh *dm, BMVert *v[2], float r_cos[2][3])
{
- BMEditMesh *em = lcd->em;
- DerivedMesh *dm = EDBM_mesh_deform_dm_get(em);
- BMEdge *eed_start = lcd->eed;
- BMEdge *eed, *eed_last;
- BMVert *v[2][2], *v_last;
- BMWalker walker;
- float (*edges)[2][3] = NULL;
- BLI_array_declare(edges);
- int i, tot = 0;
-
- memset(v, 0, sizeof(v));
-
- if (!eed_start)
- return;
-
- if (lcd->edges) {
- MEM_freeN(lcd->edges);
- lcd->edges = NULL;
- lcd->totedge = 0;
+ if (dm) {
+ int j;
+ for (j = 0; j < 2; j++) {
+ dm->getVertCo(dm, BM_elem_index_get(v[j]), r_cos[j]);
+ }
}
-
- if (!lcd->extend) {
- EDBM_flag_disable_all(lcd->em, BM_ELEM_SELECT);
+ else {
+ int j;
+ for (j = 0; j < 2; j++) {
+ copy_v3_v3(r_cos[j], v[j]->co);
+ }
}
+}
- if (select) {
- BMW_init(&walker, em->bm, BMW_EDGERING,
- BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
- BMW_FLAG_TEST_HIDDEN,
- BMW_NIL_LAY);
-
- for (eed = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
- BM_edge_select_set(em->bm, eed, true);
- }
- BMW_end(&walker);
+static void edgering_preview_free(RingSelOpData *lcd)
+{
+ MEM_SAFE_FREE(lcd->edges);
+ lcd->totedge = 0;
- return;
- }
+ MEM_SAFE_FREE(lcd->points);
+ lcd->totpoint = 0;
+}
- if (dm) {
- BM_mesh_elem_table_ensure(lcd->em->bm, BM_VERT);
- }
+static void edgering_preview_calc_edges(RingSelOpData *lcd, DerivedMesh *dm, const int previewlines)
+{
+ BMesh *bm = lcd->em->bm;
+ BMWalker walker;
+ BMEdge *eed_start = lcd->eed;
+ BMEdge *eed, *eed_last;
+ BMVert *v[2][2] = {{NULL}}, *v_last;
+ float (*edges)[2][3] = NULL;
+ BLI_array_declare(edges);
+ int i, tot = 0;
- BMW_init(&walker, em->bm, BMW_EDGERING,
+ BMW_init(&walker, bm, BMW_EDGERING,
BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
@@ -261,7 +265,7 @@ static void edgering_sel(RingSelOpData *lcd, int previewlines, bool select)
}
eed_last = eed;
}
-
+
if ((eed_last != eed_start) &&
#ifdef BMW_EDGERING_NGON
BM_edge_share_face_check(eed_last, eed_start)
@@ -274,7 +278,7 @@ static void edgering_sel(RingSelOpData *lcd, int previewlines, bool select)
v[1][1] = v[0][1];
edgering_find_order(eed_last, eed_start, v_last, v);
-
+
BLI_array_grow_items(edges, previewlines);
for (i = 1; i <= previewlines; i++) {
@@ -298,15 +302,83 @@ static void edgering_sel(RingSelOpData *lcd, int previewlines, bool select)
lcd->totedge = tot;
}
+static void edgering_preview_calc_points(RingSelOpData *lcd, DerivedMesh *dm, const int previewlines)
+{
+ float v_cos[2][3];
+ float (*points)[3];
+ int i, tot = 0;
+
+ if (dm) {
+ BM_mesh_elem_table_ensure(lcd->em->bm, BM_VERT);
+ }
+
+ points = MEM_mallocN(sizeof(*lcd->points) * previewlines, __func__);
+
+ edgering_vcos_get_pair(dm, &lcd->eed->v1, v_cos);
+
+ for (i = 1; i <= previewlines; i++) {
+ const float fac = (i / ((float)previewlines + 1));
+ interp_v3_v3v3(points[tot], v_cos[0], v_cos[1], fac);
+ tot++;
+ }
+
+ lcd->points = points;
+ lcd->totpoint = previewlines;
+}
+
+static void edgering_preview_calc(RingSelOpData *lcd, const int previewlines)
+{
+ DerivedMesh *dm;
+
+ BLI_assert(lcd->eed != NULL);
+
+ edgering_preview_free(lcd);
+
+ dm = EDBM_mesh_deform_dm_get(lcd->em);
+ if (dm) {
+ BM_mesh_elem_table_ensure(lcd->em->bm, BM_VERT);
+ }
+
+ if (BM_edge_is_wire(lcd->eed)) {
+ edgering_preview_calc_points(lcd, dm, previewlines);
+ }
+ else {
+ edgering_preview_calc_edges(lcd, dm, previewlines);
+ }
+}
+
+static void edgering_select(RingSelOpData *lcd)
+{
+ BMEditMesh *em = lcd->em;
+ BMEdge *eed_start = lcd->eed;
+ BMWalker walker;
+ BMEdge *eed;
+
+ if (!eed_start)
+ return;
+
+ if (!lcd->extend) {
+ EDBM_flag_disable_all(lcd->em, BM_ELEM_SELECT);
+ }
+
+ BMW_init(&walker, em->bm, BMW_EDGERING,
+ BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
+ BMW_FLAG_TEST_HIDDEN,
+ BMW_NIL_LAY);
+
+ for (eed = BMW_begin(&walker, eed_start); eed; eed = BMW_step(&walker)) {
+ BM_edge_select_set(em->bm, eed, true);
+ }
+ BMW_end(&walker);
+}
+
static void ringsel_find_edge(RingSelOpData *lcd, const int previewlines)
{
if (lcd->eed) {
- edgering_sel(lcd, previewlines, false);
+ edgering_preview_calc(lcd, previewlines);
}
- else if (lcd->edges) {
- MEM_freeN(lcd->edges);
- lcd->edges = NULL;
- lcd->totedge = 0;
+ else {
+ edgering_preview_free(lcd);
}
}
@@ -324,26 +396,37 @@ static void ringsel_finish(bContext *C, wmOperator *op)
if (lcd->eed) {
BMEditMesh *em = lcd->em;
+ BMVert *v_eed_orig[2] = {lcd->eed->v1, lcd->eed->v2};
- edgering_sel(lcd, cuts, true);
+ edgering_select(lcd);
if (lcd->do_cut) {
const bool is_macro = (op->opm != NULL);
+ /* a single edge (rare, but better support) */
+ const bool is_single = (BM_edge_is_wire(lcd->eed));
+ const int seltype = is_single ? SUBDIV_SELECT_INNER : SUBDIV_SELECT_LOOPCUT;
+
/* Enable gridfill, so that intersecting loopcut works as one would expect.
* Note though that it will break edgeslide in this specific case.
* See [#31939]. */
BM_mesh_esubdivide(em->bm, BM_ELEM_SELECT,
smoothness, smooth_falloff, true,
0.0f, 0.0f,
- cuts,
- SUBDIV_SELECT_LOOPCUT, SUBD_PATH, 0, true,
+ cuts, seltype, SUBD_PATH, 0, true,
use_only_quads, 0);
/* when used in a macro tessface is already re-recalculated */
EDBM_update_generic(em, (is_macro == false), true);
+ if (is_single) {
+ /* de-select endpoints */
+ BM_vert_select_set(em->bm, v_eed_orig[0], false);
+ BM_vert_select_set(em->bm, v_eed_orig[1], false);
+
+ EDBM_selectmode_flush_ex(lcd->em, SCE_SELECT_VERTEX);
+ }
/* we cant slide multiple edges in vertex select mode */
- if (is_macro && (cuts > 1) && (em->selectmode & SCE_SELECT_VERTEX)) {
+ else if (is_macro && (cuts > 1) && (em->selectmode & SCE_SELECT_VERTEX)) {
EDBM_selectmode_disable(lcd->vc.scene, em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
}
/* force edge slide to edge select mode in in face select mode */
@@ -378,8 +461,7 @@ static void ringsel_exit(bContext *UNUSED(C), wmOperator *op)
/* deactivate the extra drawing stuff in 3D-View */
ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle);
- if (lcd->edges)
- MEM_freeN(lcd->edges);
+ edgering_preview_free(lcd);
ED_region_tag_redraw(lcd->ar);
@@ -555,39 +637,27 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
int cuts = RNA_int_get(op->ptr, "number_cuts");
RingSelOpData *lcd = op->customdata;
bool show_cuts = false;
+ const bool has_numinput = hasNumInput(&lcd->num);
view3d_operator_needs_opengl(C);
/* using the keyboard to input the number of cuts */
- if (event->val == KM_PRESS && hasNumInput(&lcd->num)) {
- /* Modal numinput active, try to handle numeric inputs first... */
- if (handleNumInput(C, &lcd->num, event)) {
- float values[2] = {(float)cuts, smoothness};
- applyNumInput(&lcd->num, values);
-
- /* allow zero so you can backspace and type in a value
- * otherwise 1 as minimum would make more sense */
- cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX);
- smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
-
- RNA_int_set(op->ptr, "number_cuts", cuts);
- ringsel_find_edge(lcd, cuts);
- show_cuts = true;
- RNA_float_set(op->ptr, "smoothness", smoothness);
-
- ED_region_tag_redraw(lcd->ar);
- }
- else {
- switch (event->type) {
- case RETKEY:
- case PADENTER:
- case LEFTMOUSE: /* confirm */ // XXX hardcoded
- return loopcut_finish(lcd, C, op);
- default:
- /* do nothing */;
- break;
- }
- }
+ /* Modal numinput active, try to handle numeric inputs first... */
+ if (event->val == KM_PRESS && has_numinput && handleNumInput(C, &lcd->num, event)) {
+ float values[2] = {(float)cuts, smoothness};
+ applyNumInput(&lcd->num, values);
+
+ /* allow zero so you can backspace and type in a value
+ * otherwise 1 as minimum would make more sense */
+ cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX);
+ smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
+
+ RNA_int_set(op->ptr, "number_cuts", cuts);
+ ringsel_find_edge(lcd, cuts);
+ show_cuts = true;
+ RNA_float_set(op->ptr, "smoothness", smoothness);
+
+ ED_region_tag_redraw(lcd->ar);
}
else {
bool handled = false;
@@ -606,7 +676,7 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
ringsel_exit(C, op);
ED_area_headerprint(CTX_wm_area(C), NULL);
- return OPERATOR_FINISHED;
+ return OPERATOR_CANCELLED;
case ESCKEY:
if (event->val == KM_RELEASE) {
/* cancel */
@@ -663,43 +733,42 @@ static int loopcut_modal(bContext *C, wmOperator *op, const wmEvent *event)
handled = true;
break;
case MOUSEMOVE: /* mouse moved somewhere to select another loop */
- {
- lcd->vc.mval[0] = event->mval[0];
- lcd->vc.mval[1] = event->mval[1];
- loopcut_mouse_move(lcd, cuts);
+ if (!has_numinput) {
+ lcd->vc.mval[0] = event->mval[0];
+ lcd->vc.mval[1] = event->mval[1];
+ loopcut_mouse_move(lcd, cuts);
- ED_region_tag_redraw(lcd->ar);
- handled = true;
+ ED_region_tag_redraw(lcd->ar);
+ handled = true;
+ }
break;
- }
}
- if (!handled && event->val == KM_PRESS) {
- /* Modal numinput inactive, try to handle numeric inputs last... */
- if (handleNumInput(C, &lcd->num, event)) {
- float values[2] = {(float)cuts, smoothness};
- applyNumInput(&lcd->num, values);
-
- /* allow zero so you can backspace and type in a value
- * otherwise 1 as minimum would make more sense */
- cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX);
- smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
-
- RNA_int_set(op->ptr, "number_cuts", cuts);
- ringsel_find_edge(lcd, cuts);
- show_cuts = true;
- RNA_float_set(op->ptr, "smoothness", smoothness);
-
- ED_region_tag_redraw(lcd->ar);
- }
+ /* Modal numinput inactive, try to handle numeric inputs last... */
+ if (!handled && event->val == KM_PRESS && handleNumInput(C, &lcd->num, event)) {
+ float values[2] = {(float)cuts, smoothness};
+ applyNumInput(&lcd->num, values);
+
+ /* allow zero so you can backspace and type in a value
+ * otherwise 1 as minimum would make more sense */
+ cuts = CLAMPIS(values[0], 0, SUBD_CUTS_MAX);
+ smoothness = CLAMPIS(values[1], -SUBD_SMOOTH_MAX, SUBD_SMOOTH_MAX);
+
+ RNA_int_set(op->ptr, "number_cuts", cuts);
+ ringsel_find_edge(lcd, cuts);
+ show_cuts = true;
+ RNA_float_set(op->ptr, "smoothness", smoothness);
+
+ ED_region_tag_redraw(lcd->ar);
}
}
if (show_cuts) {
+ Scene *sce = CTX_data_scene(C);
char buf[64 + NUM_STR_REP_LEN * 2];
char str_rep[NUM_STR_REP_LEN * 2];
if (hasNumInput(&lcd->num)) {
- outputNumInput(&lcd->num, str_rep);
+ outputNumInput(&lcd->num, str_rep, &sce->unit);
}
else {
BLI_snprintf(str_rep, NUM_STR_REP_LEN, "%d", cuts);
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 84952297235..4f149bf2c52 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -217,8 +217,8 @@ static BMEdge *edbm_ripsel_edge_mark_step(BMVert *v, const int uid)
BM_edge_loop_pair(e, &l_a, &l_b); /* no need to check, we know this will be true */
/* so (IS_VISIT_DONE == true) */
- BM_elem_index_set(l_a, uid);
- BM_elem_index_set(l_b, uid);
+ BM_elem_index_set(l_a, uid); /* set_dirty */
+ BM_elem_index_set(l_b, uid); /* set_dirty */
return e;
}
@@ -250,9 +250,10 @@ static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm)
/* initialize loops with dummy invalid index values */
BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- BM_elem_index_set(l, INVALID_UID);
+ BM_elem_index_set(l, INVALID_UID); /* set_dirty */
}
}
+ bm->elem_index_dirty |= BM_LOOP;
/* set contiguous loops ordered 'uid' values for walking after split */
while (true) {
@@ -308,8 +309,7 @@ static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm)
uid_start = uid;
uid = uid_end + bm->totedge;
- BLI_array_grow_one(eloop_pairs);
- lp = &eloop_pairs[BLI_array_count(eloop_pairs) - 1];
+ lp = BLI_array_append_ret(eloop_pairs);
BM_edge_loop_pair(e_last, &lp->l_a, &lp->l_b); /* no need to check, we know this will be true */
@@ -322,8 +322,7 @@ static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm)
}
/* null terminate */
- BLI_array_grow_one(eloop_pairs);
- lp = &eloop_pairs[BLI_array_count(eloop_pairs) - 1];
+ lp = BLI_array_append_ret(eloop_pairs);
lp->l_a = lp->l_b = NULL;
return eloop_pairs;
@@ -794,8 +793,6 @@ static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, const wmEvent *eve
BM_mesh_edgesplit(em->bm, true, true, true);
}
- dist_sq = FLT_MAX;
-
{
/* --- select which vert --- */
BMVert *v_best = NULL;
@@ -994,6 +991,12 @@ static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
+ /* we could support this, but not for now */
+ if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices");
+ return OPERATOR_CANCELLED;
+ }
+
/* note on selection:
* When calling edge split we operate on tagged edges rather then selected
* this is important because the edges to operate on are extended by one,
diff --git a/source/blender/editors/mesh/editmesh_rip_edge.c b/source/blender/editors/mesh/editmesh_rip_edge.c
new file mode 100644
index 00000000000..5daf33fae3b
--- /dev/null
+++ b/source/blender/editors/mesh/editmesh_rip_edge.c
@@ -0,0 +1,252 @@
+/*
+ * ***** 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/mesh/editmesh_rip_edge.c
+ * \ingroup edmesh
+ *
+ * based on mouse cursor position, split of vertices along the closest edge.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+
+#include "BLI_math.h"
+
+#include "BKE_context.h"
+#include "BKE_report.h"
+#include "BKE_editmesh.h"
+
+#include "RNA_define.h"
+#include "RNA_access.h"
+
+#include "WM_types.h"
+
+#include "ED_mesh.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+#include "ED_view3d.h"
+
+#include "bmesh.h"
+
+#include "mesh_intern.h" /* own include */
+
+/* uses total number of selected edges around a vertex to choose how to extend */
+#define USE_TRICKY_EXTEND
+
+static int edbm_rip_edge_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMIter viter;
+ BMVert *v;
+ const float mval_fl[2] = {UNPACK2(event->mval)};
+ float cent_sco[2];
+ int cent_tot;
+ bool changed = false;
+
+ /* mouse direction to view center */
+ float mval_dir[2];
+
+ float projectMat[4][4];
+
+ if (bm->totvertsel == 0)
+ return OPERATOR_CANCELLED;
+
+ ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
+
+ zero_v2(cent_sco);
+ cent_tot = 0;
+
+ /* clear tags and calc screen center */
+ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ float v_sco[2];
+ ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
+
+ add_v2_v2(cent_sco, v_sco);
+ cent_tot += 1;
+ }
+ }
+ mul_v2_fl(cent_sco, 1.0f / (float)cent_tot);
+
+ /* not essential, but gives more expected results with edge selection */
+ if (bm->totedgesel) {
+ /* angle against center can give odd result,
+ * try re-position the center to the closest edge */
+ BMIter eiter;
+ BMEdge *e;
+ float dist_sq_best = len_squared_v2v2(cent_sco, mval_fl);
+
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ float e_sco[2][2];
+ float cent_sco_test[2];
+ float dist_sq_test;
+
+ ED_view3d_project_float_v2_m4(ar, e->v1->co, e_sco[0], projectMat);
+ ED_view3d_project_float_v2_m4(ar, e->v2->co, e_sco[1], projectMat);
+
+ closest_to_line_segment_v2(cent_sco_test, mval_fl, e_sco[0], e_sco[1]);
+ dist_sq_test = len_squared_v2v2(cent_sco_test, mval_fl);
+ if (dist_sq_test < dist_sq_best) {
+ dist_sq_best = dist_sq_test;
+
+ /* we have a new screen center */
+ copy_v2_v2(cent_sco, cent_sco_test);
+ }
+ }
+ }
+ }
+
+ sub_v2_v2v2(mval_dir, mval_fl, cent_sco);
+ normalize_v2(mval_dir);
+
+ /* operate on selected verts */
+ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) {
+ BMIter eiter;
+ BMEdge *e;
+ float v_sco[2];
+
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) &&
+ BM_elem_flag_test(v, BM_ELEM_TAG) == false)
+ {
+ /* Rules for */
+ float angle_best = FLT_MAX;
+ BMEdge *e_best = NULL;
+
+#ifdef USE_TRICKY_EXTEND
+ /* first check if we can select the edge to split based on selection-only */
+ int tot_sel = 0, tot = 0;
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ e_best = e;
+ tot_sel += 1;
+ }
+ tot += 1;
+ }
+ }
+ if (tot_sel != 1) {
+ e_best = NULL;
+ }
+
+ /* only one edge selected, operate on that */
+ if (e_best) {
+ goto found_edge;
+ }
+ /* none selected, fall through and find one */
+ else if (tot_sel == 0) {
+ /* pass */
+ }
+ /* selection not 0 or 1, do nothing */
+ else {
+ goto found_edge;
+ }
+#endif
+ ED_view3d_project_float_v2_m4(ar, v->co, v_sco, projectMat);
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ BMVert *v_other = BM_edge_other_vert(e, v);
+ float v_other_sco[2];
+ float angle_test;
+
+ ED_view3d_project_float_v2_m4(ar, v_other->co, v_other_sco, projectMat);
+
+ /* avoid comparing with view-axis aligned edges (less then a pixel) */
+ if (len_squared_v2v2(v_sco, v_other_sco) > 1.0f) {
+ float v_dir[2];
+
+ sub_v2_v2v2(v_dir, v_other_sco, v_sco);
+ normalize_v2(v_dir);
+
+ angle_test = angle_normalized_v2v2(mval_dir, v_dir);
+
+ if (angle_test < angle_best) {
+ angle_best = angle_test;
+ e_best = e;
+ }
+ }
+ }
+ }
+
+#ifdef USE_TRICKY_EXTEND
+found_edge:
+#endif
+ if (e_best) {
+ const bool e_select = BM_elem_flag_test_bool(e_best, BM_ELEM_SELECT);
+ BMVert *v_new;
+ BMEdge *e_new;
+
+ v_new = BM_edge_split(bm, e_best, v, &e_new, 0.0f);
+
+ BM_vert_select_set(bm, v, false);
+ BM_edge_select_set(bm, e_new, false);
+
+ BM_vert_select_set(bm, v_new, true);
+ if (e_select) {
+ BM_edge_select_set(bm, e_best, true);
+ }
+ BM_elem_flag_enable(v_new, BM_ELEM_TAG); /* prevent further splitting */
+
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ BM_select_history_clear(bm);
+
+ BM_mesh_select_mode_flush(bm);
+
+ EDBM_update_generic(em, true, true);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+
+void MESH_OT_rip_edge(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Extend Vertices";
+ ot->idname = "MESH_OT_rip_edge";
+ ot->description = "Extend vertices along the edge closest to the cursor";
+
+ /* api callbacks */
+ ot->invoke = edbm_rip_edge_invoke;
+ ot->poll = EDBM_view3d_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+}
diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c
index 15bfeea8918..473da4c9756 100644
--- a/source/blender/editors/mesh/editmesh_select.c
+++ b/source/blender/editors/mesh/editmesh_select.c
@@ -66,6 +66,8 @@
#include "UI_resources.h"
+#include "bmesh_tools.h"
+
#include "mesh_intern.h" /* own include */
/* use bmesh operator flags for a few operators */
@@ -213,7 +215,7 @@ bool EDBM_backbuf_border_init(ViewContext *vc, short xmin, short ymin, short xma
a = (xmax - xmin + 1) * (ymax - ymin + 1);
while (a--) {
if (*dr > 0 && *dr <= bm_vertoffs) {
- BLI_BITMAP_SET(selbuf, *dr);
+ BLI_BITMAP_ENABLE(selbuf, *dr);
}
dr++;
}
@@ -230,7 +232,7 @@ bool EDBM_backbuf_check(unsigned int index)
return true;
if (index > 0 && index <= bm_vertoffs)
- return BLI_BITMAP_GET_BOOL(selbuf, index);
+ return BLI_BITMAP_TEST_BOOL(selbuf, index);
return false;
}
@@ -297,7 +299,7 @@ bool EDBM_backbuf_border_mask_init(ViewContext *vc, const int mcords[][2], short
a = (xmax - xmin + 1) * (ymax - ymin + 1);
while (a--) {
if (*dr > 0 && *dr <= bm_vertoffs && *dr_mask == true) {
- BLI_BITMAP_SET(selbuf, *dr);
+ BLI_BITMAP_ENABLE(selbuf, *dr);
}
dr++; dr_mask++;
}
@@ -340,7 +342,7 @@ bool EDBM_backbuf_circle_init(ViewContext *vc, short xs, short ys, short rads)
for (xc = -rads; xc <= rads; xc++, dr++) {
if (xc * xc + yc * yc < radsq) {
if (*dr > 0 && *dr <= bm_vertoffs) {
- BLI_BITMAP_SET(selbuf, *dr);
+ BLI_BITMAP_ENABLE(selbuf, *dr);
}
}
}
@@ -929,6 +931,96 @@ void MESH_OT_select_similar(wmOperatorType *ot)
}
+/* -------------------------------------------------------------------- */
+/* Select Similar Regions */
+
+static int edbm_select_similar_region_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ bool changed = false;
+
+ /* group vars */
+ int *groups_array;
+ int (*group_index)[2];
+ int group_tot;
+ int i;
+
+ if (bm->totfacesel < 2) {
+ BKE_report(op->reports, RPT_ERROR, "No face regions selected");
+ return OPERATOR_CANCELLED;
+ }
+
+ groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
+ group_tot = BM_mesh_calc_face_groups(bm, groups_array, &group_index,
+ NULL, NULL,
+ BM_ELEM_SELECT, BM_VERT);
+
+ BM_mesh_elem_table_ensure(bm, BM_FACE);
+
+ for (i = 0; i < group_tot; i++) {
+ ListBase faces_regions;
+ int tot;
+
+ const int fg_sta = group_index[i][0];
+ const int fg_len = group_index[i][1];
+ int j;
+ BMFace **fg = MEM_mallocN(sizeof(*fg) * fg_len, __func__);
+
+
+ for (j = 0; j < fg_len; j++) {
+ fg[j] = BM_face_at_index(bm, groups_array[fg_sta + j]);
+ }
+
+ tot = BM_mesh_region_match(bm, fg, fg_len, &faces_regions);
+
+ MEM_freeN(fg);
+
+ if (tot) {
+ LinkData *link;
+ while ((link = BLI_pophead(&faces_regions))) {
+ BMFace *f, **faces = link->data;
+ unsigned int i = 0;
+ while ((f = faces[i++])) {
+ BM_face_select_set(bm, f, true);
+ }
+ MEM_freeN(faces);
+ MEM_freeN(link);
+
+ changed = true;
+ }
+ }
+ }
+
+ MEM_freeN(groups_array);
+
+ if (changed) {
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit);
+ }
+ else {
+ BKE_report(op->reports, RPT_WARNING, "No matching face regions found");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_similar_region(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Similar Regions";
+ ot->idname = "MESH_OT_select_similar_region";
+ ot->description = "Select similar face regions to the current selection";
+
+ /* api callbacks */
+ ot->exec = edbm_select_similar_region_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
/* **************** Mode Select *************** */
static int edbm_select_mode_exec(bContext *C, wmOperator *op)
@@ -2039,7 +2131,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op)
BM_elem_flag_set(v, BM_ELEM_TAG, BM_elem_flag_test(v, BM_ELEM_SELECT));
}
- BMW_init(&walker, em->bm, BMW_SHELL,
+ BMW_init(&walker, em->bm, BMW_VERT_SHELL,
BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
@@ -2157,7 +2249,7 @@ static int edbm_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
eed = eve->e;
}
- BMW_init(&walker, bm, BMW_SHELL,
+ BMW_init(&walker, bm, BMW_VERT_SHELL,
BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_TEST_HIDDEN,
BMW_NIL_LAY);
@@ -2433,6 +2525,27 @@ void MESH_OT_select_less(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/**
+ * Check if we're connected to another selected efge.
+ */
+static bool bm_edge_is_select_isolated(BMEdge *e)
+{
+ BMIter viter;
+ BMVert *v;
+
+ BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) {
+ BMIter eiter;
+ BMEdge *e_other;
+
+ BM_ITER_ELEM (e_other, &eiter, v, BM_EDGES_OF_VERT) {
+ if ((e_other != e) && BM_elem_flag_test(e_other, BM_ELEM_SELECT)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
/* 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". */
@@ -2460,8 +2573,10 @@ static void walker_deselect_nth(BMEditMesh *em, int nth, int offset, BMHeader *h
mask_vert = BMO_ELE_TAG;
break;
case BM_EDGE:
+ /* When an edge has no connected-selected edges,
+ * use face-stepping (supports edge-rings) */
itertype = BM_EDGES_OF_MESH;
- walktype = BMW_SHELL;
+ walktype = bm_edge_is_select_isolated((BMEdge *)h_act) ? BMW_FACE_SHELL : BMW_VERT_SHELL;
flushtype = SCE_SELECT_EDGE;
mask_edge = BMO_ELE_TAG;
break;
@@ -2600,6 +2715,8 @@ static int edbm_select_nth_exec(bContext *C, wmOperator *op)
/* 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;
if (edbm_deselect_nth(em, nth, offset) == false) {
BKE_report(op->reports, RPT_ERROR, "Mesh has no active vert/edge/face");
@@ -2782,6 +2899,13 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
BMEdge *e;
BMIter iter;
+ const bool use_wire = RNA_boolean_get(op->ptr, "use_wire");
+ const bool use_boundary = RNA_boolean_get(op->ptr, "use_boundary");
+ const bool use_multi_face = RNA_boolean_get(op->ptr, "use_multi_face");
+ const bool use_non_contiguous = RNA_boolean_get(op->ptr, "use_non_contiguous");
+ const bool use_verts = RNA_boolean_get(op->ptr, "use_verts");
+
+
if (!RNA_boolean_get(op->ptr, "extend"))
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
@@ -2794,15 +2918,30 @@ static int edbm_select_non_manifold_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN) && !BM_vert_is_manifold(v)) {
- BM_vert_select_set(em->bm, v, true);
+ if (use_verts) {
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
+ if (!BM_vert_is_manifold(v)) {
+ BM_vert_select_set(em->bm, v, true);
+ }
+ }
}
}
- BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN) && !BM_edge_is_manifold(e)) {
- BM_edge_select_set(em->bm, e, true);
+ if (use_wire || use_boundary || use_multi_face || use_non_contiguous) {
+ BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ 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)))
+ {
+ /* check we never select perfect edge (in test above) */
+ BLI_assert(!(BM_edge_is_manifold(e) && BM_edge_is_contiguous(e)));
+
+ BM_edge_select_set(em->bm, e, true);
+ }
+ }
}
}
@@ -2829,6 +2968,18 @@ void MESH_OT_select_non_manifold(wmOperatorType *ot)
/* props */
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend the selection");
+ /* edges */
+ RNA_def_boolean(ot->srna, "use_wire", true, "Wire",
+ "Wire edges");
+ RNA_def_boolean(ot->srna, "use_boundary", true, "Boundaries",
+ "Boundary edges");
+ RNA_def_boolean(ot->srna, "use_multi_face", true,
+ "Multiple Faces", "Edges shared by 3+ faces");
+ RNA_def_boolean(ot->srna, "use_non_contiguous", true, "Non Contiguous",
+ "Edges between faces pointing in alternate directions");
+ /* verts */
+ RNA_def_boolean(ot->srna, "use_verts", true, "Vertices",
+ "Vertices connecting multiple face regions");
}
static int edbm_select_random_exec(bContext *C, wmOperator *op)
@@ -3164,7 +3315,7 @@ void MESH_OT_region_to_loop(wmOperatorType *ot)
}
static int loop_find_region(BMLoop *l, int flag,
- SmallHash *fhash, BMFace ***region_out)
+ GSet *visit_face_set, BMFace ***region_out)
{
BMFace **region = NULL;
BMFace **stack = NULL;
@@ -3173,7 +3324,7 @@ static int loop_find_region(BMLoop *l, int flag,
BMFace *f;
BLI_array_append(stack, l->f);
- BLI_smallhash_insert(fhash, (uintptr_t)l->f, NULL);
+ BLI_gset_insert(visit_face_set, l->f);
while (BLI_array_count(stack) > 0) {
BMIter liter1, liter2;
@@ -3187,11 +3338,15 @@ static int loop_find_region(BMLoop *l, int flag,
continue;
BM_ITER_ELEM (l2, &liter2, l1->e, BM_LOOPS_OF_EDGE) {
- if (BLI_smallhash_haskey(fhash, (uintptr_t)l2->f))
+ /* avoids finding same region twice
+ * (otherwise) the logic works fine without */
+ if (BM_elem_flag_test(l2->f, BM_ELEM_TAG)) {
continue;
-
- BLI_array_append(stack, l2->f);
- BLI_smallhash_insert(fhash, (uintptr_t)l2->f, NULL);
+ }
+
+ if (BLI_gset_add(visit_face_set, l2->f)) {
+ BLI_array_append(stack, l2->f);
+ }
}
}
}
@@ -3216,21 +3371,22 @@ static int verg_radial(const void *va, const void *vb)
return 0;
}
+/**
+ * This function leaves faces tagged which are apart of the new region.
+ *
+ * \note faces already tagged are ignored, to avoid finding the same regions twice:
+ * important when we have regions with equal face counts, see: T40309
+ */
static int loop_find_regions(BMEditMesh *em, const bool selbigger)
{
- SmallHash visithash;
+ GSet *visit_face_set;
BMIter iter;
const int edges_len = em->bm->totedgesel;
BMEdge *e, **edges;
- BMFace *f;
int count = 0, i;
- BLI_smallhash_init_ex(&visithash, edges_len);
+ visit_face_set = BLI_gset_ptr_new_ex(__func__, edges_len);
edges = MEM_mallocN(sizeof(*edges) * edges_len, __func__);
-
- BM_ITER_MESH (f, &iter, em->bm, BM_FACES_OF_MESH) {
- BM_elem_flag_disable(f, BM_ELEM_TAG);
- }
i = 0;
BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) {
@@ -3258,10 +3414,10 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger)
continue;
BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
- if (BLI_smallhash_haskey(&visithash, (uintptr_t)l->f))
+ if (BLI_gset_haskey(visit_face_set, l->f))
continue;
-
- c = loop_find_region(l, BM_ELEM_SELECT, &visithash, &region_out);
+
+ c = loop_find_region(l, BM_ELEM_SELECT, visit_face_set, &region_out);
if (!region || (selbigger ? c >= tot : c < tot)) {
/* this region is the best seen so far */
@@ -3296,7 +3452,7 @@ static int loop_find_regions(BMEditMesh *em, const bool selbigger)
}
MEM_freeN(edges);
- BLI_smallhash_release(&visithash);
+ BLI_gset_free(visit_face_set, NULL);
return count;
}
@@ -3310,13 +3466,14 @@ static int edbm_loop_to_region_exec(bContext *C, wmOperator *op)
const bool select_bigger = RNA_boolean_get(op->ptr, "select_bigger");
int a, b;
+
/* find the set of regions with smallest number of total faces */
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
a = loop_find_regions(em, select_bigger);
b = loop_find_regions(em, !select_bigger);
-
- if ((a <= b) ^ select_bigger) {
- loop_find_regions(em, select_bigger);
- }
+
+ BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false);
+ loop_find_regions(em, ((a <= b) != select_bigger) ? select_bigger : !select_bigger);
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 159eac4a275..20c7f4eb521 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -881,12 +881,18 @@ static int edbm_vert_connect_exec(bContext *C, wmOperator *op)
int len;
if (is_pair) {
- if (!EDBM_op_init(em, &bmop, op, "connect_vert_pair verts=%hv", BM_ELEM_SELECT)) {
+ if (!EDBM_op_init(em, &bmop, op,
+ "connect_vert_pair verts=%hv verts_exclude=%hv faces_exclude=%hf",
+ BM_ELEM_SELECT, BM_ELEM_HIDDEN, BM_ELEM_HIDDEN))
+ {
return OPERATOR_CANCELLED;
}
}
else {
- if (!EDBM_op_init(em, &bmop, op, "connect_verts verts=%hv check_degenerate=%b", BM_ELEM_SELECT, true)) {
+ if (!EDBM_op_init(em, &bmop, op,
+ "connect_verts verts=%hv faces_exclude=%hf check_degenerate=%b",
+ BM_ELEM_SELECT, BM_ELEM_HIDDEN, true))
+ {
return OPERATOR_CANCELLED;
}
}
@@ -1019,28 +1025,23 @@ static int edbm_duplicate_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(ob);
BMesh *bm = em->bm;
BMOperator bmop;
- ListBase bm_selected_store = {NULL, NULL};
- /* de-select all would clear otherwise */
- SWAP(ListBase, bm->selected, bm_selected_store);
+ EDBM_op_init(
+ em, &bmop, op,
+ "duplicate geom=%hvef use_select_history=%b",
+ BM_ELEM_SELECT, true);
- EDBM_op_init(em, &bmop, op, "duplicate geom=%hvef", BM_ELEM_SELECT);
-
BMO_op_exec(bm, &bmop);
+
+ /* de-select all would clear otherwise */
+ BM_SELECT_HISTORY_BACKUP(bm);
+
EDBM_flag_disable_all(em, BM_ELEM_SELECT);
BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, true);
/* rebuild editselection */
- bm->selected = bm_selected_store;
-
- if (bm->selected.first) {
- BMOpSlot *slot_vert_map_out = BMO_slot_get(bmop.slots_out, "vert_map.out");
- BMOpSlot *slot_edge_map_out = BMO_slot_get(bmop.slots_out, "edge_map.out");
- BMOpSlot *slot_face_map_out = BMO_slot_get(bmop.slots_out, "face_map.out");
-
- BMO_mesh_selected_remap(bm, slot_vert_map_out, slot_edge_map_out, slot_face_map_out);
- }
+ BM_SELECT_HISTORY_RESTORE(bm);
if (!EDBM_op_finish(em, &bmop, op, true)) {
return OPERATOR_CANCELLED;
@@ -1287,7 +1288,8 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
bool mirrx = false, mirry = false, mirrz = false;
int i, repeat;
float clip_dist = 0.0f;
- bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
+ const float fac = RNA_float_get(op->ptr, "factor");
+ const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
const bool xaxis = RNA_boolean_get(op->ptr, "xaxis");
const bool yaxis = RNA_boolean_get(op->ptr, "yaxis");
@@ -1321,12 +1323,12 @@ static int edbm_do_smooth_vertex_exec(bContext *C, wmOperator *op)
repeat = RNA_int_get(op->ptr, "repeat");
if (!repeat)
repeat = 1;
-
+
for (i = 0; i < repeat; i++) {
if (!EDBM_op_callf(em, op,
- "smooth_vert verts=%hv mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b clip_dist=%f "
- "use_axis_x=%b use_axis_y=%b use_axis_z=%b",
- BM_ELEM_SELECT, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
+ "smooth_vert verts=%hv factor=%f mirror_clip_x=%b mirror_clip_y=%b mirror_clip_z=%b "
+ "clip_dist=%f use_axis_x=%b use_axis_y=%b use_axis_z=%b",
+ BM_ELEM_SELECT, fac, mirrx, mirry, mirrz, clip_dist, xaxis, yaxis, zaxis))
{
return OPERATOR_CANCELLED;
}
@@ -1357,7 +1359,8 @@ void MESH_OT_vertices_smooth(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_int(ot->srna, "repeat", 1, 1, 1000, "Number of times to smooth the mesh", "", 1, 100);
+ 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");
@@ -2424,7 +2427,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2];
/* edit-object needed for matrix, and ar->regiondata for projections to work */
- if (ELEM3(NULL, obedit, ar, ar->regiondata))
+ if (ELEM(NULL, obedit, ar, ar->regiondata))
return OPERATOR_CANCELLED;
if (bm->totvertsel < 2) {
@@ -2460,7 +2463,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op)
if (ED_view3d_project_float_object(ar, bv->co, *sco, V3D_PROJ_TEST_CLIP_NEAR) != V3D_PROJ_RET_OK) {
copy_v2_fl(*sco, FLT_MAX); /* set error value */
}
- BM_elem_index_set(bv, i); /* set_ok */
+ BM_elem_index_set(bv, i); /* set_inline */
sco++;
}
@@ -2783,7 +2786,7 @@ static bool mesh_separate_loose(Main *bmain, Scene *scene, Base *base_old, BMesh
/* Walk from the single vertex, selecting everything connected
* to it */
- BMW_init(&walker, bm_old, BMW_SHELL,
+ BMW_init(&walker, bm_old, BMW_VERT_SHELL,
BMW_MASK_NOP, BMW_MASK_NOP, BMW_MASK_NOP,
BMW_FLAG_NOP,
BMW_NIL_LAY);
@@ -3047,7 +3050,7 @@ static void edbm_fill_grid_prepare(BMesh *bm, int offset, int *r_span, bool span
}
/* set this vertex first */
- BLI_rotatelist_first(verts, v_act_link);
+ BLI_listbase_rotate_first(verts, v_act_link);
BM_edgeloop_edges_get(el_store, edges);
@@ -3479,6 +3482,11 @@ static void edbm_dissolve_prop__use_face_split(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "use_face_split", 0, "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",
+ "Split off face corners instead of merging faces");
+}
static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
{
@@ -3486,9 +3494,14 @@ static int edbm_dissolve_verts_exec(bContext *C, wmOperator *op)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
const bool use_face_split = RNA_boolean_get(op->ptr, "use_face_split");
+ const bool use_boundary_tear = RNA_boolean_get(op->ptr, "use_boundary_tear");
- if (!EDBM_op_callf(em, op, "dissolve_verts verts=%hv use_face_split=%b", BM_ELEM_SELECT, use_face_split))
+ if (!EDBM_op_callf(em, op,
+ "dissolve_verts verts=%hv use_face_split=%b use_boundary_tear=%b",
+ BM_ELEM_SELECT, use_face_split, use_boundary_tear))
+ {
return OPERATOR_CANCELLED;
+ }
EDBM_update_generic(em, true, true);
@@ -3510,6 +3523,7 @@ void MESH_OT_dissolve_verts(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
edbm_dissolve_prop__use_face_split(ot);
+ edbm_dissolve_prop__use_boundary_tear(ot);
}
static int edbm_dissolve_edges_exec(bContext *C, wmOperator *op)
@@ -3621,6 +3635,7 @@ void MESH_OT_dissolve_mode(wmOperatorType *ot)
edbm_dissolve_prop__use_verts(ot);
edbm_dissolve_prop__use_face_split(ot);
+ edbm_dissolve_prop__use_boundary_tear(ot);
}
static int edbm_dissolve_limited_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c
index 758cbd59794..c7d1d883537 100644
--- a/source/blender/editors/mesh/editmesh_utils.c
+++ b/source/blender/editors/mesh/editmesh_utils.c
@@ -1269,7 +1269,7 @@ void EDBM_mesh_reveal(BMEditMesh *em)
/* Use tag flag to remember what was hidden before all is revealed.
* BM_ELEM_HIDDEN --> BM_ELEM_TAG */
-#pragma omp parallel for schedule(dynamic) if (em->bm->totvert + em->bm->totedge + em->bm->totface >= BM_OMP_LIMIT)
+#pragma omp parallel for schedule(static) if (em->bm->totvert + em->bm->totedge + em->bm->totface >= BM_OMP_LIMIT)
for (i = 0; i < 3; i++) {
BMIter iter;
BMElem *ele;
@@ -1328,6 +1328,15 @@ void EDBM_update_generic(BMEditMesh *em, const bool do_tessface, const bool is_d
/* don't keep stale derivedMesh data around, see: [#38872] */
BKE_editmesh_free_derivedmesh(em);
+
+#ifdef DEBUG
+ {
+ BMEditSelection *ese;
+ for (ese = em->bm->selected.first; ese; ese = ese->next) {
+ BLI_assert(BM_elem_flag_test(ese->ele, BM_ELEM_SELECT));
+ }
+ }
+#endif
}
/* poll call for mesh operators requiring a view3d context */
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 83947534d06..68471bfc2ba 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -47,6 +47,7 @@
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_mesh.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_editmesh.h"
@@ -502,6 +503,12 @@ static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op))
if (ED_mesh_uv_texture_add(me, NULL, true) == -1)
return OPERATOR_CANCELLED;
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ Scene *scene = CTX_data_scene(C);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
return OPERATOR_FINISHED;
}
@@ -622,6 +629,12 @@ static int mesh_uv_texture_remove_exec(bContext *C, wmOperator *UNUSED(op))
if (!ED_mesh_uv_texture_remove_active(me))
return OPERATOR_CANCELLED;
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ Scene *scene = CTX_data_scene(C);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
return OPERATOR_FINISHED;
}
@@ -880,17 +893,6 @@ static void mesh_add_verts(Mesh *mesh, int len)
mesh->totvert = totvert;
}
-void ED_mesh_transform(Mesh *me, float mat[4][4])
-{
- int i;
- MVert *mvert = me->mvert;
-
- for (i = 0; i < me->totvert; i++, mvert++)
- mul_m4_v3(mat, mvert->co);
-
- /* don't update normals, caller can do this explicitly */
-}
-
static void mesh_add_edges(Mesh *mesh, int len)
{
CustomData edata;
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 8aea932e93a..6ba91097ec4 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -112,6 +112,10 @@ void MESH_OT_screw(struct wmOperatorType *ot);
/* *** editmesh_inset.c *** */
void MESH_OT_inset(struct wmOperatorType *ot);
+/* *** editmesh_intersect.c *** */
+void MESH_OT_intersect(struct wmOperatorType *ot);
+void MESH_OT_face_split_by_edges(struct wmOperatorType *ot);
+
/* *** editmesh_knife.c *** */
void MESH_OT_knife_tool(struct wmOperatorType *ot);
@@ -128,10 +132,12 @@ void MESH_OT_loopcut(struct wmOperatorType *ot);
/* *** editmesh_rip.c *** */
void MESH_OT_rip(struct wmOperatorType *ot);
+void MESH_OT_rip_edge(struct wmOperatorType *ot);
/* *** editmesh_select.c *** */
void MESH_OT_select_similar(struct wmOperatorType *ot);
+void MESH_OT_select_similar_region(struct wmOperatorType *ot);
void MESH_OT_select_mode(struct wmOperatorType *ot);
void MESH_OT_loop_multi_select(struct wmOperatorType *ot);
void MESH_OT_loop_select(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_navmesh.c b/source/blender/editors/mesh/mesh_navmesh.c
index 433fd176217..440ab14dacd 100644
--- a/source/blender/editors/mesh/mesh_navmesh.c
+++ b/source/blender/editors/mesh/mesh_navmesh.c
@@ -407,7 +407,7 @@ static Object *createRepresentation(bContext *C, struct recast_polyMesh *pmesh,
BM_vert_at_index(em->bm, face[0]),
BM_vert_at_index(em->bm, face[2]),
BM_vert_at_index(em->bm, face[1]), NULL,
- NULL, false);
+ NULL, BM_CREATE_NOP);
/* set navigation polygon idx to the custom layer */
polygonIdx = (int *)CustomData_bmesh_get(&em->bm->pdata, newFace->head.data, CD_RECAST);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index 7c38ef21791..e7dc5a69d53 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -130,6 +130,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_edge_face_add);
WM_operatortype_append(MESH_OT_shortest_path_pick);
WM_operatortype_append(MESH_OT_select_similar);
+ WM_operatortype_append(MESH_OT_select_similar_region);
WM_operatortype_append(MESH_OT_select_mode);
WM_operatortype_append(MESH_OT_loop_multi_select);
WM_operatortype_append(MESH_OT_mark_seam);
@@ -142,6 +143,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_noise);
WM_operatortype_append(MESH_OT_flip_normals);
WM_operatortype_append(MESH_OT_rip);
+ WM_operatortype_append(MESH_OT_rip_edge);
WM_operatortype_append(MESH_OT_blend_from_shape);
WM_operatortype_append(MESH_OT_shape_propagate_to_all);
@@ -169,6 +171,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_bridge_edge_loops);
WM_operatortype_append(MESH_OT_inset);
+ WM_operatortype_append(MESH_OT_intersect);
+ WM_operatortype_append(MESH_OT_face_split_by_edges);
WM_operatortype_append(MESH_OT_poke);
WM_operatortype_append(MESH_OT_wireframe);
WM_operatortype_append(MESH_OT_edge_split);
@@ -239,6 +243,13 @@ void ED_operatormacros_mesh(void)
RNA_enum_set(otmacro->ptr, "proportional", 0);
RNA_boolean_set(otmacro->ptr, "mirror", false);
+ ot = WM_operatortype_append_macro("MESH_OT_rip_edge_move", "Extend Vertices", "Extend vertices and move the result",
+ OPTYPE_UNDO | OPTYPE_REGISTER);
+ WM_operatortype_macro_define(ot, "MESH_OT_rip_edge");
+ otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
+ RNA_enum_set(otmacro->ptr, "proportional", 0);
+ RNA_boolean_set(otmacro->ptr, "mirror", false);
+
ot = WM_operatortype_append_macro("MESH_OT_extrude_region_move", "Extrude Region and Move",
"Extrude region and move result", OPTYPE_UNDO | OPTYPE_REGISTER);
otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region");
@@ -332,7 +343,7 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "MESH_OT_faces_select_linked_flat", FKEY, KM_PRESS, (KM_CTRL | KM_SHIFT | KM_ALT), 0);
- WM_keymap_add_item(keymap, "MESH_OT_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
+ WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_select_similar", GKEY, KM_PRESS, KM_SHIFT, 0);
/* selection mode */
WM_keymap_add_menu(keymap, "VIEW3D_MT_edit_mesh_select_mode", TABKEY, KM_PRESS, KM_CTRL, 0);
@@ -372,6 +383,8 @@ void ED_keymap_mesh(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "MESH_OT_rip_move", VKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "MESH_OT_rip_move_fill", VKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "MESH_OT_rip_edge_move", DKEY, KM_PRESS, KM_ALT, 0);
+
WM_keymap_add_item(keymap, "MESH_OT_merge", MKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "TRANSFORM_OT_shrink_fatten", SKEY, KM_PRESS, KM_ALT, 0);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index d252ae20270..16f4f61f92b 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -999,7 +999,7 @@ static int mirror_facerotation(MFace *a, MFace *b)
return -1;
}
-static int mirror_facecmp(const void *a, const void *b)
+static bool mirror_facecmp(const void *a, const void *b)
{
return (mirror_facerotation((MFace *)a, (MFace *)b) == -1);
}
diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c
index 1441a1ef4c0..f6a54beb8c8 100644
--- a/source/blender/editors/metaball/mball_edit.c
+++ b/source/blender/editors/metaball/mball_edit.c
@@ -191,7 +191,7 @@ enum {
static EnumPropertyItem prop_similar_types[] = {
{SIMMBALL_TYPE, "TYPE", 0, "Type", ""},
{SIMMBALL_RADIUS, "RADIUS", 0, "Radius", ""},
- {SIMMBALL_STIFFNESS, "STIFFNESS", 0, "Stiffness", ""},
+ {SIMMBALL_STIFFNESS, "STIFFNESS", 0, "Stiffness", ""},
{SIMMBALL_ROTATION, "ROTATION", 0, "Rotation", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -594,7 +594,7 @@ bool mouse_mball(bContext *C, const int mval[2], bool extend, bool deselect, boo
rect.ymin = mval[1] - 12;
rect.ymax = mval[1] + 12;
- hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect);
+ hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, true);
/* does startelem exist? */
ml = mb->editelems->first;
@@ -743,28 +743,3 @@ void undo_push_mball(bContext *C, const char *name)
{
undo_editmode_push(C, name, get_data, free_undoMball, undoMball_to_editMball, editMball_to_undoMball, NULL);
}
-
-void ED_mball_transform(MetaBall *mb, float mat[4][4])
-{
- MetaElem *me;
- float quat[4];
- const float scale = mat4_to_scale(mat);
- const float scale_sqrt = sqrtf(scale);
-
- mat4_to_quat(quat, mat);
-
- for (me = mb->elems.first; me; me = me->next) {
- mul_m4_v3(mat, &me->x);
- mul_qt_qtqt(me->quat, quat, me->quat);
- me->rad *= scale;
- /* hrmf, probably elems shouldn't be
- * treating scale differently - campbell */
- if (!MB_TYPE_SIZE_SQUARED(me->type)) {
- mul_v3_fl(&me->expx, scale);
- }
- else {
- mul_v3_fl(&me->expx, scale_sqrt);
- }
- }
- DAG_id_tag_update(&mb->id, 0);
-}
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 1bb35b65918..9b380ff8d48 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -33,10 +33,11 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
-
+ ${GLEW_INCLUDE_PATH}
)
set(SRC
@@ -62,6 +63,8 @@ set(SRC
object_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 99dd8b75609..8972dd7cf08 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -34,6 +34,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
+#include "DNA_camera_types.h"
#include "DNA_curve_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
@@ -83,6 +84,7 @@
#include "BKE_report.h"
#include "BKE_sca.h"
#include "BKE_scene.h"
+#include "BKE_screen.h"
#include "BKE_speaker.h"
#include "BKE_texture.h"
@@ -95,6 +97,7 @@
#include "ED_armature.h"
#include "ED_curve.h"
+#include "ED_lattice.h"
#include "ED_mball.h"
#include "ED_mesh.h"
#include "ED_node.h"
@@ -336,10 +339,7 @@ bool ED_object_add_generic_get_opts(bContext *C, wmOperator *op, const char view
}
else {
Scene *scene = CTX_data_scene(C);
- if (v3d)
- *layer = (v3d->scenelock && !v3d->localvd) ? scene->layact : v3d->layact;
- else
- *layer = scene->layact;
+ *layer = BKE_screen_view3d_layer_active_ex(v3d, scene, false);
for (a = 0; a < 20; a++) {
layer_values[a] = *layer & (1 << a);
}
@@ -446,14 +446,17 @@ Object *ED_object_add_type(bContext *C, int type, const float loc[3], const floa
/* for object add operator */
static int object_add_exec(bContext *C, wmOperator *op)
{
+ Object *ob;
bool enter_editmode;
unsigned int layer;
float loc[3], rot[3];
+ WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
- 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"), loc, rot, enter_editmode, layer);
+ BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
return OPERATOR_FINISHED;
}
@@ -472,6 +475,8 @@ void OBJECT_OT_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* properties */
+ ED_object_add_unit_props(ot);
RNA_def_enum(ot->srna, "type", object_type_items, 0, "Type", "");
ED_object_add_generic_props(ot, true);
@@ -488,32 +493,31 @@ static int effector_add_exec(bContext *C, wmOperator *op)
unsigned int layer;
float loc[3], rot[3];
float mat[4][4];
+ float dia;
+ WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
type = RNA_enum_get(op->ptr, "type");
+ dia = RNA_float_get(op->ptr, "radius");
if (type == PFIELD_GUIDE) {
Curve *cu;
ob = ED_object_add_type(C, OB_CURVE, loc, rot, false, layer);
- if (!ob)
- return OPERATOR_CANCELLED;
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);
ED_object_new_primitive_matrix(C, ob, loc, rot, mat, false);
- BLI_addtail(&cu->editnurb->nurbs, add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, 1));
+ BLI_addtail(&cu->editnurb->nurbs, add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, dia));
if (!enter_editmode)
ED_object_editmode_exit(C, EM_FREEDATA);
}
else {
ob = ED_object_add_type(C, OB_EMPTY, loc, rot, false, layer);
- if (!ob)
- return OPERATOR_CANCELLED;
-
+ 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;
@@ -540,8 +544,10 @@ void OBJECT_OT_effector_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* properties */
ot->prop = RNA_def_enum(ot->srna, "type", field_type_items, 0, "Type", "");
+ ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -552,6 +558,7 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
Object *ob;
+ Camera *cam;
bool enter_editmode;
unsigned int layer;
float loc[3], rot[3];
@@ -572,6 +579,9 @@ static int object_camera_add_exec(bContext *C, wmOperator *op)
}
}
+ cam = ob->data;
+ cam->drawsize = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL);
+
return OPERATOR_FINISHED;
}
@@ -668,6 +678,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
unsigned int layer;
float loc[3], rot[3];
+ WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
@@ -675,6 +686,7 @@ static int object_add_text_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
obedit = ED_object_add_type(C, OB_FONT, 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);
@@ -694,6 +706,9 @@ void OBJECT_OT_text_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -706,9 +721,10 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
bool newob = false;
bool enter_editmode;
unsigned int layer;
- float loc[3], rot[3];
+ float loc[3], rot[3], dia;
bool view_aligned = rv3d && (U.flag & USER_ADD_VIEWALIGNED);
+ WM_operator_view3d_unit_defaults(C, op);
if (!ED_object_add_generic_get_opts(C, op, 'Z', loc, rot, &enter_editmode, &layer, NULL))
return OPERATOR_CANCELLED;
@@ -726,7 +742,8 @@ static int object_armature_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- add_primitive_bone(obedit, view_aligned);
+ dia = RNA_float_get(op->ptr, "radius");
+ ED_armature_edit_bone_add_primitive(obedit, dia, view_aligned);
/* userdef */
if (newob && !enter_editmode)
@@ -750,6 +767,9 @@ void OBJECT_OT_armature_add(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, true);
}
@@ -762,12 +782,14 @@ static int object_empty_add_exec(bContext *C, wmOperator *op)
unsigned int layer;
float loc[3], rot[3];
+ WM_operator_view3d_unit_defaults(C, 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);
BKE_object_empty_draw_type_set(ob, type);
+ BKE_object_obdata_size_init(ob, RNA_float_get(op->ptr, "radius"));
return OPERATOR_FINISHED;
}
@@ -790,6 +812,7 @@ void OBJECT_OT_empty_add(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", object_empty_drawtype_items, 0, "Type", "");
+ ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, false);
}
@@ -899,12 +922,14 @@ static int object_lamp_add_exec(bContext *C, wmOperator *op)
unsigned int layer;
float loc[3], rot[3];
+ WM_operator_view3d_unit_defaults(C, 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);
- la = (Lamp *)ob->data;
+ 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));
@@ -936,6 +961,7 @@ void OBJECT_OT_lamp_add(wmOperatorType *ot)
ot->prop = RNA_def_enum(ot->srna, "type", lamp_type_items, 0, "Type", "");
RNA_def_property_translation_context(ot->prop, BLF_I18NCONTEXT_ID_LAMP);
+ ED_object_add_unit_props(ot);
ED_object_add_generic_props(ot, false);
}
@@ -1470,7 +1496,7 @@ static void convert_ensure_curve_cache(Main *bmain, Scene *scene, Object *ob)
/* Force creation. This is normally not needed but on operator
* redo we might end up with an object which isn't evaluated yet.
*/
- if (ELEM3(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
+ if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) {
BKE_displist_make_curveTypes(scene, ob, false);
}
else if (ob->type == OB_MBALL) {
@@ -2191,6 +2217,7 @@ static int add_named_exec(bContext *C, wmOperator *op)
wmWindow *win = CTX_wm_window(C);
const wmEvent *event = win ? win->eventstate : NULL;
Main *bmain = CTX_data_main(C);
+ View3D *v3d = CTX_wm_view3d(C); /* may be NULL */
Scene *scene = CTX_data_scene(C);
Base *basen, *base;
Object *ob;
@@ -2223,7 +2250,7 @@ static int add_named_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- basen->lay = basen->object->lay = scene->lay;
+ basen->lay = basen->object->lay = BKE_screen_view3d_layer_active(v3d, scene);
basen->object->restrictflag &= ~OB_RESTRICT_VIEW;
if (event) {
@@ -2274,7 +2301,7 @@ static int join_poll(bContext *C)
if (!ob || ob->id.lib) return 0;
- if (ELEM4(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE))
return ED_operator_screenactive(C);
else
return 0;
diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c
index 94574e81b81..b8957514159 100644
--- a/source/blender/editors/object/object_bake.c
+++ b/source/blender/editors/object/object_bake.c
@@ -682,6 +682,7 @@ static void finish_bake_internal(BakeRender *bkr)
}
BKE_image_release_ibuf(ima, ibuf, NULL);
+ DAG_id_tag_update(&ima->id, 0);
}
}
@@ -770,7 +771,7 @@ static int objects_bake_render_modal(bContext *C, wmOperator *UNUSED(op), const
static bool is_multires_bake(Scene *scene)
{
- if (ELEM4(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO))
+ if (ELEM(scene->r.bake_mode, RE_BAKE_NORMALS, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_AO))
return scene->r.bake_flag & R_BAKE_MULTIRES;
return 0;
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 46555f89da9..5746f9efd56 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -51,9 +51,12 @@
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_node.h"
#include "BKE_report.h"
#include "BKE_modifier.h"
#include "BKE_mesh.h"
+#include "BKE_screen.h"
+#include "BKE_depsgraph.h"
#include "RE_engine.h"
#include "RE_pipeline.h"
@@ -73,6 +76,63 @@
#include "object_intern.h"
+
+typedef struct BakeAPIRender {
+ Object *ob;
+ Main *main;
+ Scene *scene;
+ ReportList *reports;
+ ListBase selected_objects;
+
+ ScenePassType pass_type;
+ int margin;
+
+ int save_mode;
+
+ bool is_clear;
+ bool is_split_materials;
+ bool is_automatic_name;
+ bool is_selected_to_active;
+ bool is_cage;
+
+ float cage_extrusion;
+ int normal_space;
+ BakeNormalSwizzle normal_swizzle[3];
+
+ char uv_layer[MAX_CUSTOMDATA_LAYER_NAME];
+ char custom_cage[MAX_NAME];
+ char filepath[FILE_MAX];
+
+ int width;
+ int height;
+ const char *identifier;
+
+ int result;
+ bool ready;
+
+ /* callbacks */
+ Render *render;
+ float *progress;
+ short *do_update;
+
+ /* for redrawing */
+ ScrArea *sa;
+} BakeAPIRender;
+
+/* callbacks */
+
+static void bake_progress_update(void *bjv, float progress)
+{
+ BakeAPIRender *bj = bjv;
+
+ if (bj->progress && *bj->progress != progress) {
+ *bj->progress = progress;
+
+ /* make jobs timer to send notifier */
+ *(bj->do_update) = true;
+ }
+}
+
/* catch esc */
static int bake_modal(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
{
@@ -100,6 +160,16 @@ static int bake_break(void *UNUSED(rjv))
return 0;
}
+
+static void bake_update_image(ScrArea *sa, Image *image)
+{
+ if (sa && sa->spacetype == SPACE_IMAGE) { /* in case the user changed while baking */
+ SpaceImage *sima = sa->spacedata.first;
+ if (sima)
+ sima->image = image;
+ }
+}
+
static bool write_internal_bake_pixels(
Image *image, BakePixel pixel_array[], float *buffer,
const int width, const int height, const int margin,
@@ -109,7 +179,7 @@ static bool write_internal_bake_pixels(
void *lock;
bool is_float;
char *mask_buffer = NULL;
- const int num_pixels = width * height;
+ const size_t num_pixels = (size_t)width * (size_t)height;
ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
@@ -145,7 +215,7 @@ static bool write_internal_bake_pixels(
IMB_buffer_float_from_float(
ibuf->rect_float, buffer, ibuf->channels,
IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
- ibuf->x, ibuf->y, ibuf->x, ibuf->y);
+ ibuf->x, ibuf->y, ibuf->x, ibuf->x);
}
else {
IMB_buffer_byte_from_float(
@@ -158,7 +228,7 @@ static bool write_internal_bake_pixels(
if (is_float) {
IMB_buffer_float_from_float_mask(
ibuf->rect_float, buffer, ibuf->channels,
- ibuf->x, ibuf->y, ibuf->x, ibuf->y, mask_buffer);
+ ibuf->x, ibuf->y, ibuf->x, ibuf->x, mask_buffer);
}
else {
IMB_buffer_byte_from_float_mask(
@@ -191,13 +261,14 @@ static bool write_internal_bake_pixels(
}
/* force OpenGL reload */
-static void reset_images_gpu(BakeImages *bake_images)
+static void refresh_images(BakeImages *bake_images)
{
int i;
for (i = 0; i < bake_images->size; i++) {
Image *ima = bake_images->data[i].image;
if (ima->ok == IMA_OK_LOADED) {
GPU_free_image(ima);
+ DAG_id_tag_update(&ima->id, 0);
}
}
}
@@ -224,7 +295,7 @@ static bool write_external_bake_pixels(
IMB_buffer_float_from_float(
ibuf->rect_float, buffer, ibuf->channels,
IB_PROFILE_LINEAR_RGB, IB_PROFILE_LINEAR_RGB, false,
- ibuf->x, ibuf->y, ibuf->x, ibuf->y);
+ ibuf->x, ibuf->y, ibuf->x, ibuf->x);
}
else {
if (!is_noncolor) {
@@ -242,7 +313,7 @@ static bool write_external_bake_pixels(
/* margins */
if (margin > 0) {
char *mask_buffer = NULL;
- const int num_pixels = width * height;
+ const size_t num_pixels = (size_t)width * (size_t)height;
mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask");
RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer);
@@ -267,44 +338,161 @@ static bool write_external_bake_pixels(
static bool is_noncolor_pass(ScenePassType pass_type)
{
- return ELEM7(pass_type,
- SCE_PASS_Z,
- SCE_PASS_NORMAL,
- SCE_PASS_VECTOR,
- SCE_PASS_INDEXOB,
- SCE_PASS_UV,
- SCE_PASS_RAYHITS,
- SCE_PASS_INDEXMA);
+ return ELEM(pass_type,
+ SCE_PASS_Z,
+ SCE_PASS_NORMAL,
+ SCE_PASS_VECTOR,
+ SCE_PASS_INDEXOB,
+ SCE_PASS_UV,
+ SCE_PASS_RAYHITS,
+ SCE_PASS_INDEXMA);
}
-static bool build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images, ReportList *reports)
+/* if all is good tag image and return true */
+static bool bake_object_check(Object *ob, ReportList *reports)
{
- const int tot_mat = ob->totcol;
- int i, j;
- int tot_images = 0;
+ Image *image;
+ void *lock;
+ int i;
- /* error handling and tag (in case multiple materials share the same image) */
- BKE_main_id_tag_idcode(bmain, ID_IM, false);
+ if (ob->type != OB_MESH) {
+ BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh", ob->id.name + 2);
+ return false;
+ }
+ else {
+ Mesh *me = (Mesh *)ob->data;
- for (i = 0; i < tot_mat; i++) {
- Image *image;
- ED_object_get_active_image(ob, i + 1, &image, NULL, NULL);
+ if (CustomData_get_active_layer_index(&me->ldata, CD_MLOOPUV) == -1) {
+ BKE_reportf(reports, RPT_ERROR,
+ "No active UV layer found in the object \"%s\"", ob->id.name + 2);
+ return false;
+ }
+ }
- if (!image) {
+ for (i = 0; i < ob->totcol; i++) {
+ bNodeTree *ntree = NULL;
+ bNode *node = NULL;
+ ED_object_get_active_image(ob, i + 1, &image, NULL, &node, &ntree);
+
+ if (image) {
+ ImBuf *ibuf;
+
+ if (node) {
+ if (BKE_node_is_connected_to_output(ntree, node)) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Circular dependency for image \"%s\" from object \"%s\"",
+ image->id.name + 2, ob->id.name + 2);
+ }
+ }
+
+ ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
+
+ if (ibuf) {
+ BKE_image_release_ibuf(image, ibuf, lock);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR,
+ "Uninitialized image \"%s\" from object \"%s\"",
+ image->id.name + 2, ob->id.name + 2);
+
+ BKE_image_release_ibuf(image, ibuf, lock);
+ return false;
+ }
+ }
+ else {
if (ob->mat[i]) {
BKE_reportf(reports, RPT_ERROR,
- "No active image found in material %d (%s)", i, ob->mat[i]->id.name + 2);
+ "No active image found in material \"%s\" (%d) for object \"%s\"",
+ ob->mat[i]->id.name + 2, i, ob->id.name + 2);
}
else if (((Mesh *) ob->data)->mat[i]) {
BKE_reportf(reports, RPT_ERROR,
- "No active image found in material %d (%s)", i, ((Mesh *) ob->data)->mat[i]->id.name + 2);
+ "No active image found in material \"%s\" (%d) for object \"%s\"",
+ ((Mesh *) ob->data)->mat[i]->id.name + 2, i, ob->id.name + 2);
}
else {
BKE_reportf(reports, RPT_ERROR,
- "No active image found in material %d", i);
+ "No active image found in material (%d) for object \"%s\"",
+ i, ob->id.name + 2);
+ }
+ return false;
+ }
+
+ image->id.flag |= LIB_DOIT;
+ }
+ return true;
+}
+
+/* before even getting in the bake function we check for some basic errors */
+static bool bake_objects_check(Main *bmain, Object *ob, ListBase *selected_objects,
+ ReportList *reports, const bool is_selected_to_active)
+{
+ CollectionPointerLink *link;
+
+ /* error handling and tag (in case multiple materials share the same image) */
+ BKE_main_id_tag_idcode(bmain, ID_IM, false);
+
+ if (is_selected_to_active) {
+ int tot_objects = 0;
+
+ if (!bake_object_check(ob, reports))
+ return false;
+
+ for (link = selected_objects->first; link; link = link->next) {
+ Object *ob_iter = (Object *)link->ptr.data;
+
+ if (ob_iter == ob)
+ continue;
+
+ if (ELEM(ob_iter->type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL) == false) {
+ BKE_reportf(reports, RPT_ERROR, "Object \"%s\" is not a mesh or can't be converted to a mesh (Curve, Text, Surface or Metaball)", ob_iter->id.name + 2);
+ return false;
}
+ tot_objects += 1;
+ }
+
+ if (tot_objects == 0) {
+ BKE_report(reports, RPT_ERROR, "No valid selected objects");
return false;
}
+ }
+ else {
+ if (BLI_listbase_is_empty(selected_objects)) {
+ BKE_report(reports, RPT_ERROR, "No valid selected objects");
+ return false;
+ }
+
+ for (link = selected_objects->first; link; link = link->next) {
+ if (!bake_object_check(link->ptr.data, reports))
+ return false;
+ }
+ }
+ return true;
+}
+
+/* it needs to be called after bake_objects_check since the image tagging happens there */
+static void bake_images_clear(Main *bmain, const bool is_tangent)
+{
+ Image *image;
+ for (image = bmain->image.first; image; image = image->id.next) {
+ if ((image->id.flag & LIB_DOIT) != 0) {
+ RE_bake_ibuf_clear(image, is_tangent);
+ }
+ }
+}
+
+static void build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images)
+{
+ const int tot_mat = ob->totcol;
+ int i, j;
+ int tot_images = 0;
+
+ /* error handling and tag (in case multiple materials share the same image) */
+ BKE_main_id_tag_idcode(bmain, ID_IM, false);
+
+ for (i = 0; i < tot_mat; i++) {
+ Image *image;
+ ED_object_get_active_image(ob, i + 1, &image, NULL, NULL, NULL);
if ((image->id.flag & LIB_DOIT)) {
for (j = 0; j < i; j++) {
@@ -323,16 +511,15 @@ static bool build_image_lookup(Main *bmain, Object *ob, BakeImages *bake_images,
}
bake_images->size = tot_images;
- return true;
}
/*
* returns the total number of pixels
*/
-static int initialize_internal_images(BakeImages *bake_images, ReportList *reports)
+static size_t initialize_internal_images(BakeImages *bake_images, ReportList *reports)
{
int i;
- int tot_size = 0;
+ size_t tot_size = 0;
for (i = 0; i < bake_images->size; i++) {
ImBuf *ibuf;
@@ -346,11 +533,11 @@ static int initialize_internal_images(BakeImages *bake_images, ReportList *repor
bk_image->height = ibuf->y;
bk_image->offset = tot_size;
- tot_size += ibuf->x * ibuf->y;
+ tot_size += (size_t)ibuf->x * (size_t)ibuf->y;
}
else {
BKE_image_release_ibuf(bk_image->image, ibuf, lock);
- BKE_reportf(reports, RPT_ERROR, "Not initialized image %s", bk_image->image->id.name + 2);
+ BKE_reportf(reports, RPT_ERROR, "Uninitialized image %s", bk_image->image->id.name + 2);
return 0;
}
BKE_image_release_ibuf(bk_image->image, ibuf, lock);
@@ -358,60 +545,28 @@ static int initialize_internal_images(BakeImages *bake_images, ReportList *repor
return tot_size;
}
-typedef struct BakeAPIRender {
- Object *ob;
- Main *main;
- Scene *scene;
- ReportList *reports;
- ListBase selected_objects;
-
- ScenePassType pass_type;
- int margin;
-
- int save_mode;
-
- bool is_clear;
- bool is_split_materials;
- bool is_automatic_name;
- bool use_selected_to_active;
-
- float cage_extrusion;
- int normal_space;
- BakeNormalSwizzle normal_swizzle[3];
-
- char custom_cage[MAX_NAME];
- char filepath[FILE_MAX];
-
- int width;
- int height;
- const char *identifier;
-
- int result;
- bool ready;
-} BakeAPIRender;
-
static int bake(
- Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
+ Render *re, Main *bmain, Scene *scene, Object *ob_low, ListBase *selected_objects, ReportList *reports,
const ScenePassType pass_type, const int margin,
const BakeSaveMode save_mode, const bool is_clear, const bool is_split_materials,
- const bool is_automatic_name, const bool use_selected_to_active,
+ const bool is_automatic_name, const bool is_selected_to_active, const bool is_cage,
const float cage_extrusion, const int normal_space, const BakeNormalSwizzle normal_swizzle[],
const char *custom_cage, const char *filepath, const int width, const int height,
- const char *identifier)
+ const char *identifier, ScrArea *sa, const char *uv_layer)
{
int op_result = OPERATOR_CANCELLED;
bool ok = false;
Object *ob_cage = NULL;
- BakeHighPolyData *highpoly;
+ BakeHighPolyData *highpoly = NULL;
int tot_highpoly;
char restrict_flag_low = ob_low->restrictflag;
- char restrict_flag_cage;
+ char restrict_flag_cage = 0;
Mesh *me_low = NULL;
- Render *re;
+ Mesh *me_cage = NULL;
float *result = NULL;
@@ -421,31 +576,40 @@ static int bake(
const bool is_noncolor = is_noncolor_pass(pass_type);
const int depth = RE_pass_depth(pass_type);
- bool is_highpoly = false;
- bool is_tangent;
-
BakeImages bake_images = {NULL};
- int num_pixels;
+ size_t num_pixels;
int tot_materials;
int i;
- re = RE_NewRender(scene->id.name);
- RE_SetReports(re, NULL);
+ RE_bake_engine_set_engine_parameters(re, bmain, scene);
+
+ if (!RE_bake_has_engine(re)) {
+ BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
+ goto cleanup;
+ }
- is_tangent = pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT;
tot_materials = ob_low->totcol;
+ if (uv_layer && uv_layer[0] != '\0') {
+ Mesh *me = (Mesh *)ob_low->data;
+ if (CustomData_get_named_layer(&me->ldata, CD_MLOOPUV, uv_layer) == -1) {
+ BKE_reportf(reports, RPT_ERROR,
+ "No UV layer named \"%s\" found in the object \"%s\"", uv_layer, ob_low->id.name + 2);
+ goto cleanup;
+ }
+ }
+
if (tot_materials == 0) {
if (is_save_internal) {
BKE_report(reports, RPT_ERROR,
- "No active image found. Add a material or bake to an external file");
+ "No active image found, add a material or bake to an external file");
goto cleanup;
}
else if (is_split_materials) {
BKE_report(reports, RPT_ERROR,
- "No active image found. Add a material or bake without the Split Materials option");
+ "No active image found, add a material or bake without the Split Materials option");
goto cleanup;
}
@@ -456,11 +620,10 @@ static int bake(
}
/* we overallocate in case there is more materials than images */
- bake_images.data = MEM_callocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)");
- bake_images.lookup = MEM_callocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)");
+ bake_images.data = MEM_mallocN(sizeof(BakeImage) * tot_materials, "bake images dimensions (width, height, offset)");
+ bake_images.lookup = MEM_mallocN(sizeof(int) * tot_materials, "bake images lookup (from material to BakeImage)");
- if (!build_image_lookup(bmain, ob_low, &bake_images, reports))
- goto cleanup;
+ build_image_lookup(bmain, ob_low, &bake_images);
if (is_save_internal) {
num_pixels = initialize_internal_images(&bake_images, reports);
@@ -468,15 +631,11 @@ static int bake(
if (num_pixels == 0) {
goto cleanup;
}
-
- if (is_clear) {
- RE_bake_ibuf_clear(&bake_images, is_tangent);
- }
}
else {
/* when saving extenally always use the size specified in the UI */
- num_pixels = width * height * bake_images.size;
+ num_pixels = (size_t)width * (size_t)height * bake_images.size;
for (i = 0; i < bake_images.size; i++) {
bake_images.data[i].width = width;
@@ -492,7 +651,7 @@ static int bake(
}
}
- if (use_selected_to_active) {
+ if (is_selected_to_active) {
CollectionPointerLink *link;
tot_highpoly = 0;
@@ -505,56 +664,48 @@ static int bake(
tot_highpoly ++;
}
- if (tot_highpoly == 0) {
- BKE_report(reports, RPT_ERROR, "No valid selected objects");
- op_result = OPERATOR_CANCELLED;
-
- goto cleanup;
- }
- else {
- is_highpoly = true;
- }
- }
-
- if (custom_cage[0] != '\0') {
- ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2);
+ if (is_cage && custom_cage[0] != '\0') {
+ ob_cage = BLI_findstring(&bmain->object, custom_cage, offsetof(ID, name) + 2);
- /* TODO check if cage object has the same topology (num of triangles and a valid UV) */
- if (ob_cage == NULL || ob_cage->type != OB_MESH) {
- BKE_report(reports, RPT_ERROR, "No valid cage object");
- op_result = OPERATOR_CANCELLED;
-
- goto cleanup;
- }
- else {
- restrict_flag_cage = ob_cage->restrictflag;
+ if (ob_cage == NULL || ob_cage->type != OB_MESH) {
+ BKE_report(reports, RPT_ERROR, "No valid cage object");
+ goto cleanup;
+ }
+ else {
+ restrict_flag_cage = ob_cage->restrictflag;
+ ob_cage->restrictflag |= OB_RESTRICT_RENDER;
+ }
}
}
- RE_bake_engine_set_engine_parameters(re, bmain, scene);
-
- /* blender_test_break uses this global */
- G.is_break = false;
+ pixel_array_low = MEM_mallocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly");
+ result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");
- RE_test_break_cb(re, NULL, bake_break);
+ /* get the mesh as it arrives in the renderer */
+ me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
- pixel_array_low = MEM_callocN(sizeof(BakePixel) * num_pixels, "bake pixels low poly");
- result = MEM_callocN(sizeof(float) * depth * num_pixels, "bake return pixels");
+ /* populate the pixel array with the face data */
+ if ((is_selected_to_active && (ob_cage == NULL) && is_cage) == false)
+ RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images, uv_layer);
+ /* else populate the pixel array with the 'cage' mesh (the smooth version of the mesh) */
- if (is_highpoly) {
+ if (is_selected_to_active) {
CollectionPointerLink *link;
ModifierData *md, *nmd;
ListBase modifiers_tmp, modifiers_original;
- float mat_low[4][4];
int i = 0;
- highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects");
/* prepare cage mesh */
if (ob_cage) {
- me_low = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 1, 0);
- copy_m4_m4(mat_low, ob_cage->obmat);
+ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_cage, 1, 2, 1, 0);
+ if (me_low->totface != me_cage->totface) {
+ BKE_report(reports, RPT_ERROR,
+ "Invalid cage object, the cage mesh must have the same number "
+ "of faces as the active object");
+ goto cleanup;
+ }
}
- else {
+ else if (is_cage) {
modifiers_original = ob_low->modifiers;
BLI_listbase_clear(&modifiers_tmp);
@@ -578,10 +729,12 @@ static int bake(
ob_low->modifiers = modifiers_tmp;
/* get the cage mesh as it arrives in the renderer */
- me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
- copy_m4_m4(mat_low, ob_low->obmat);
+ me_cage = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
+ RE_bake_pixels_populate(me_cage, pixel_array_low, num_pixels, &bake_images, uv_layer);
}
+ highpoly = MEM_callocN(sizeof(BakeHighPolyData) * tot_highpoly, "bake high poly objects");
+
/* populate highpoly array */
for (link = selected_objects->first; link; link = link->next) {
TriangulateModifierData *tmd;
@@ -592,10 +745,8 @@ static int bake(
/* initialize highpoly_data */
highpoly[i].ob = ob_iter;
- highpoly[i].me = NULL;
- highpoly[i].tri_mod = NULL;
highpoly[i].restrict_flag = ob_iter->restrictflag;
- highpoly[i].pixel_array = MEM_callocN(sizeof(BakePixel) * num_pixels, "bake pixels high poly");
+ 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 */
@@ -610,70 +761,71 @@ static int bake(
highpoly[i].ob->restrictflag &= ~OB_RESTRICT_RENDER;
/* lowpoly to highpoly transformation matrix */
- invert_m4_m4(highpoly[i].mat_lowtohigh, highpoly[i].ob->obmat);
- mul_m4_m4m4(highpoly[i].mat_lowtohigh, highpoly[i].mat_lowtohigh, mat_low);
+ 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_m3(highpoly[i].rotmat);
i++;
}
BLI_assert(i == tot_highpoly);
- /* populate the pixel array with the face data */
- RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images);
-
ob_low->restrictflag |= OB_RESTRICT_RENDER;
/* populate the pixel arrays with the corresponding face data for each high poly object */
- RE_bake_pixels_populate_from_objects(
- me_low, pixel_array_low, highpoly, tot_highpoly,
- num_pixels, cage_extrusion);
+ if (!RE_bake_pixels_populate_from_objects(
+ me_low, pixel_array_low, 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");
+ goto cage_cleanup;
+ }
/* the baking itself */
for (i = 0; i < tot_highpoly; i++) {
- if (RE_bake_has_engine(re)) {
- ok = RE_bake_engine(re, highpoly[i].ob, highpoly[i].pixel_array, num_pixels,
- depth, pass_type, result);
- }
- else {
- ok = RE_bake_internal(re, highpoly[i].ob, highpoly[i].pixel_array, num_pixels,
- depth, pass_type, result);
+ ok = RE_bake_engine(re, highpoly[i].ob, highpoly[i].pixel_array, 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;
}
-
- if (!ok)
- break;
}
+cage_cleanup:
/* reverting data back */
- if (ob_cage) {
- ob_cage->restrictflag |= OB_RESTRICT_RENDER;
- }
- else {
+ if ((ob_cage == NULL) && is_cage) {
ob_low->modifiers = modifiers_original;
while ((md = BLI_pophead(&modifiers_tmp))) {
modifier_free(md);
}
}
+
+ if (!ok) {
+ goto cleanup;
+ }
}
else {
- /* get the mesh as it arrives in the renderer */
- me_low = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
-
- /* populate the pixel array with the face data */
- RE_bake_pixels_populate(me_low, pixel_array_low, num_pixels, &bake_images);
-
/* make sure low poly renders */
ob_low->restrictflag &= ~OB_RESTRICT_RENDER;
- if (RE_bake_has_engine(re))
+ if (RE_bake_has_engine(re)) {
ok = RE_bake_engine(re, ob_low, pixel_array_low, num_pixels, depth, pass_type, result);
- else
- ok = RE_bake_internal(re, ob_low, pixel_array_low, num_pixels, depth, pass_type, result);
+ }
+ else {
+ BKE_report(reports, RPT_ERROR, "Current render engine does not support baking");
+ goto cleanup;
+ }
}
/* normal space conversion
* the normals are expected to be in world space, +X +Y +Z */
- if (pass_type == SCE_PASS_NORMAL) {
+ if (ok && pass_type == SCE_PASS_NORMAL) {
switch (normal_space) {
case R_BAKE_SPACE_WORLD:
{
@@ -696,8 +848,8 @@ static int bake(
}
case R_BAKE_SPACE_TANGENT:
{
- if (is_highpoly) {
- RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle);
+ if (is_selected_to_active) {
+ RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_low, normal_swizzle, ob_low->obmat);
}
else {
/* from multiresolution */
@@ -713,9 +865,9 @@ static int bake(
}
me_nores = BKE_mesh_new_from_object(bmain, scene, ob_low, 1, 2, 1, 0);
- RE_bake_pixels_populate(me_nores, pixel_array_low, num_pixels, &bake_images);
+ 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);
+ RE_bake_normal_world_to_tangent(pixel_array_low, num_pixels, depth, result, me_nores, normal_swizzle, ob_low->obmat);
BKE_libblock_free(bmain, me_nores);
if (md)
@@ -729,7 +881,7 @@ static int bake(
}
if (!ok) {
- BKE_report(reports, RPT_ERROR, "Problem baking object map");
+ BKE_reportf(reports, RPT_ERROR, "Problem baking object \"%s\"", ob_low->id.name + 2);
op_result = OPERATOR_CANCELLED;
}
else {
@@ -745,10 +897,12 @@ static int bake(
bk_image->width, bk_image->height,
margin, is_clear, is_noncolor);
+ /* might be read by UI to set active image for display */
+ bake_update_image(sa, bk_image->image);
+
if (!ok) {
- BKE_report(reports, RPT_ERROR,
- "Problem saving the bake map internally, "
- "make sure there is a Texture Image node in the current object material");
+ BKE_reportf(reports, RPT_ERROR,
+ "Problem saving the bake map internally for object \"%s\"", ob_low->id.name + 2);
op_result = OPERATOR_CANCELLED;
}
else {
@@ -798,11 +952,11 @@ static int bake(
margin, &bake->im_format, is_noncolor);
if (!ok) {
- BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\".", name);
+ BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name);
op_result = OPERATOR_CANCELLED;
}
else {
- BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\".", name);
+ BKE_reportf(reports, RPT_INFO, "Baking map written to \"%s\"", name);
op_result = OPERATOR_FINISHED;
}
@@ -814,11 +968,11 @@ static int bake(
}
if (is_save_internal)
- reset_images_gpu(&bake_images);
+ refresh_images(&bake_images);
cleanup:
- if (is_highpoly) {
+ if (highpoly) {
int i;
for (i = 0; i < tot_highpoly; i++) {
highpoly[i].ob->restrictflag = highpoly[i].restrict_flag;
@@ -855,16 +1009,21 @@ cleanup:
if (me_low)
BKE_libblock_free(bmain, me_low);
+ if (me_cage)
+ BKE_libblock_free(bmain, me_cage);
+
return op_result;
}
static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
{
bool is_save_internal;
+ bScreen *sc = CTX_wm_screen(C);
bkr->ob = CTX_data_active_object(C);
bkr->main = CTX_data_main(C);
bkr->scene = CTX_data_scene(C);
+ bkr->sa = sc ? BKE_screen_find_big_area(sc, SPACE_IMAGE, 10) : NULL;
bkr->pass_type = RNA_enum_get(op->ptr, "type");
bkr->margin = RNA_int_get(op->ptr, "margin");
@@ -875,7 +1034,8 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->is_clear = RNA_boolean_get(op->ptr, "use_clear");
bkr->is_split_materials = (!is_save_internal) && RNA_boolean_get(op->ptr, "use_split_materials");
bkr->is_automatic_name = RNA_boolean_get(op->ptr, "use_automatic_name");
- bkr->use_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active");
+ bkr->is_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active");
+ bkr->is_cage = RNA_boolean_get(op->ptr, "use_cage");
bkr->cage_extrusion = RNA_float_get(op->ptr, "cage_extrusion");
bkr->normal_space = RNA_enum_get(op->ptr, "normal_space");
@@ -887,18 +1047,23 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
bkr->height = RNA_int_get(op->ptr, "height");
bkr->identifier = "";
- RNA_string_get(op->ptr, "cage", bkr->custom_cage);
+ RNA_string_get(op->ptr, "uv_layer", bkr->uv_layer);
+
+ RNA_string_get(op->ptr, "cage_object", bkr->custom_cage);
if ((!is_save_internal) && bkr->is_automatic_name) {
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "type");
RNA_property_enum_identifier(C, op->ptr, prop, bkr->pass_type, &bkr->identifier);
}
- if (bkr->use_selected_to_active)
- CTX_data_selected_objects(C, &bkr->selected_objects);
+ CTX_data_selected_objects(C, &bkr->selected_objects);
bkr->reports = op->reports;
+ bkr->result = OPERATOR_CANCELLED;
+
+ bkr->render = RE_NewRender(bkr->scene->id.name);
+
/* XXX hack to force saving to always be internal. Whether (and how) to support
* external saving will be addressed later */
bkr->save_mode = R_BAKE_SAVE_INTERNAL;
@@ -906,33 +1071,104 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr)
static int bake_exec(bContext *C, wmOperator *op)
{
- int result;
+ Render *re;
+ int result = OPERATOR_CANCELLED;
BakeAPIRender bkr = {NULL};
bake_init_api_data(op, C, &bkr);
+ re = bkr.render;
+
+ /* setup new render */
+ RE_test_break_cb(re, NULL, bake_break);
- result = bake(
- bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports,
- bkr.pass_type, bkr.margin, bkr.save_mode,
- bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, bkr.use_selected_to_active,
- bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
- bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier);
+ if (!bake_objects_check(bkr.main, bkr.ob, &bkr.selected_objects, bkr.reports, bkr.is_selected_to_active))
+ return OPERATOR_CANCELLED;
+
+ if (bkr.is_clear) {
+ const bool is_tangent = ((bkr.pass_type == SCE_PASS_NORMAL) && (bkr.normal_space == R_BAKE_SPACE_TANGENT));
+ bake_images_clear(bkr.main, is_tangent);
+ }
+
+ RE_SetReports(re, bkr.reports);
+
+ if (bkr.is_selected_to_active) {
+ result = bake(
+ bkr.render, bkr.main, bkr.scene, bkr.ob, &bkr.selected_objects, bkr.reports,
+ bkr.pass_type, bkr.margin, bkr.save_mode,
+ bkr.is_clear, bkr.is_split_materials, bkr.is_automatic_name, true, bkr.is_cage,
+ bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
+ bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa,
+ bkr.uv_layer);
+ }
+ else {
+ CollectionPointerLink *link;
+ const bool is_clear = bkr.is_clear && BLI_listbase_is_single(&bkr.selected_objects);
+ for (link = bkr.selected_objects.first; link; link = link->next) {
+ Object *ob_iter = link->ptr.data;
+ result = bake(
+ bkr.render, bkr.main, bkr.scene, ob_iter, NULL, bkr.reports,
+ bkr.pass_type, bkr.margin, bkr.save_mode,
+ is_clear, bkr.is_split_materials, bkr.is_automatic_name, false, bkr.is_cage,
+ bkr.cage_extrusion, bkr.normal_space, bkr.normal_swizzle,
+ bkr.custom_cage, bkr.filepath, bkr.width, bkr.height, bkr.identifier, bkr.sa,
+ bkr.uv_layer);
+ }
+ }
+
+ RE_SetReports(re, NULL);
BLI_freelistN(&bkr.selected_objects);
return result;
}
-static void bake_startjob(void *bkv, short *UNUSED(stop), short *UNUSED(do_update), float *UNUSED(progress))
+static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, float *progress)
{
BakeAPIRender *bkr = (BakeAPIRender *)bkv;
- bkr->result = bake(
- bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports,
- bkr->pass_type, bkr->margin, bkr->save_mode,
- bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, bkr->use_selected_to_active,
- bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
- bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier
- );
+ /* setup new render */
+ bkr->do_update = do_update;
+ bkr->progress = progress;
+
+ RE_SetReports(bkr->render, bkr->reports);
+
+ if (!bake_objects_check(bkr->main, bkr->ob, &bkr->selected_objects, bkr->reports, bkr->is_selected_to_active)) {
+ bkr->result = OPERATOR_CANCELLED;
+ return;
+ }
+
+ if (bkr->is_clear) {
+ const bool is_tangent = ((bkr->pass_type == SCE_PASS_NORMAL) && (bkr->normal_space == R_BAKE_SPACE_TANGENT));
+ bake_images_clear(bkr->main, is_tangent);
+ }
+
+ if (bkr->is_selected_to_active) {
+ bkr->result = bake(
+ bkr->render, bkr->main, bkr->scene, bkr->ob, &bkr->selected_objects, bkr->reports,
+ bkr->pass_type, bkr->margin, bkr->save_mode,
+ bkr->is_clear, bkr->is_split_materials, bkr->is_automatic_name, true, bkr->is_cage,
+ bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
+ bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa,
+ bkr->uv_layer);
+ }
+ else {
+ CollectionPointerLink *link;
+ const bool is_clear = bkr->is_clear && BLI_listbase_is_single(&bkr->selected_objects);
+ for (link = bkr->selected_objects.first; link; link = link->next) {
+ Object *ob_iter = link->ptr.data;
+ bkr->result = bake(
+ bkr->render, bkr->main, bkr->scene, ob_iter, NULL, bkr->reports,
+ bkr->pass_type, bkr->margin, bkr->save_mode,
+ is_clear, bkr->is_split_materials, bkr->is_automatic_name, false, bkr->is_cage,
+ bkr->cage_extrusion, bkr->normal_space, bkr->normal_swizzle,
+ bkr->custom_cage, bkr->filepath, bkr->width, bkr->height, bkr->identifier, bkr->sa,
+ bkr->uv_layer);
+
+ if (bkr->result == OPERATOR_CANCELLED)
+ return;
+ }
+ }
+
+ RE_SetReports(bkr->render, NULL);
}
static void bake_freejob(void *bkv)
@@ -980,7 +1216,7 @@ static void bake_set_props(wmOperator *op, Scene *scene)
RNA_property_float_set(op->ptr, prop, bake->cage_extrusion);
}
- prop = RNA_struct_find_property(op->ptr, "cage");
+ prop = RNA_struct_find_property(op->ptr, "cage_object");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_string_set(op->ptr, prop, bake->cage);
}
@@ -1015,6 +1251,11 @@ static void bake_set_props(wmOperator *op, Scene *scene)
RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CLEAR));
}
+ prop = RNA_struct_find_property(op->ptr, "use_cage");
+ if (!RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_CAGE));
+ }
+
prop = RNA_struct_find_property(op->ptr, "use_split_materials");
if (!RNA_property_is_set(op->ptr, prop)) {
RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_SPLIT_MAT));
@@ -1030,6 +1271,7 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
{
wmJob *wm_job;
BakeAPIRender *bkr;
+ Render *re;
Scene *scene = CTX_data_scene(C);
bake_set_props(op, scene);
@@ -1038,10 +1280,15 @@ static int bake_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)
if (WM_jobs_test(CTX_wm_manager(C), scene, WM_JOB_TYPE_OBJECT_BAKE))
return OPERATOR_CANCELLED;
- bkr = MEM_callocN(sizeof(BakeAPIRender), "render bake");
+ bkr = MEM_mallocN(sizeof(BakeAPIRender), "render bake");
/* init bake render */
bake_init_api_data(op, C, bkr);
+ re = bkr->render;
+
+ /* setup new render */
+ RE_test_break_cb(re, NULL, bake_break);
+ RE_progress_cb(re, bkr, bake_progress_update);
/* setup job */
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Texture Bake",
@@ -1089,10 +1336,10 @@ void OBJECT_OT_bake(wmOperatorType *ot)
"Extends the baked result as a post process filter", 0, 64);
RNA_def_boolean(ot->srna, "use_selected_to_active", false, "Selected to Active",
"Bake shading on the surface of selected objects to the active object");
- RNA_def_float(ot->srna, "cage_extrusion", 0.0, 0.0, 1.0, "Cage Extrusion",
- "Distance to use for the inward ray cast when using selected to active", 0.0, 1.0);
- RNA_def_string(ot->srna, "cage", NULL, MAX_NAME, "Cage",
- "Object to use as cage");
+ RNA_def_float(ot->srna, "cage_extrusion", 0.0f, 0.0f, FLT_MAX, "Cage Extrusion",
+ "Distance to use for the inward ray cast when using selected to active", 0.0f, 1.0f);
+ RNA_def_string(ot->srna, "cage_object", NULL, MAX_NAME, "Cage Object",
+ "Object to use as cage, instead of calculating the cage from the active object with cage extrusion");
RNA_def_enum(ot->srna, "normal_space", normal_space_items, R_BAKE_SPACE_TANGENT, "Normal Space",
"Choose normal space for baking");
RNA_def_enum(ot->srna, "normal_r", normal_swizzle_items, R_BAKE_POSX, "R", "Axis to bake in red channel");
@@ -1102,8 +1349,11 @@ void OBJECT_OT_bake(wmOperatorType *ot)
"Choose how to save the baking map");
RNA_def_boolean(ot->srna, "use_clear", false, "Clear",
"Clear Images before baking (only for internal saving)");
+ RNA_def_boolean(ot->srna, "use_cage", false, "Cage",
+ "Cast rays to active object from a cage");
RNA_def_boolean(ot->srna, "use_split_materials", false, "Split Materials",
"Split baked maps per material, using material name in output file (external only)");
RNA_def_boolean(ot->srna, "use_automatic_name", false, "Automatic Name",
"Automatically name the output file with the pass type");
+ RNA_def_string(ot->srna, "uv_layer", NULL, MAX_CUSTOMDATA_LAYER_NAME, "UV Layer", "UV layer to override active");
}
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 85e4bbce8dc..92ed84b7f5e 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -485,7 +485,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
}
/* target checks for specific constraints */
- if (ELEM3(curcon->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO, CONSTRAINT_TYPE_SPLINEIK)) {
+ 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;
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 002bec4ef0b..93956128b84 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -139,7 +139,9 @@ static int object_hide_view_clear_exec(bContext *C, wmOperator *UNUSED(op))
/* XXX need a context loop to handle such cases */
for (base = FIRSTBASE; base; base = base->next) {
if ((base->lay & v3d->lay) && base->object->restrictflag & OB_RESTRICT_VIEW) {
- base->flag |= SELECT;
+ if (!(base->object->restrictflag & OB_RESTRICT_SELECT)) {
+ base->flag |= SELECT;
+ }
base->object->flag = base->flag;
base->object->restrictflag &= ~OB_RESTRICT_VIEW;
changed = true;
@@ -361,6 +363,11 @@ static bool ED_object_editmode_load_ex(Object *obedit, const bool freedata)
if (freedata) free_editMball(obedit);
}
+ /* Tag update so no access to freed data referenced from
+ * derived cache will happen.
+ */
+ DAG_id_tag_update((ID *)obedit->data, 0);
+
return true;
}
@@ -447,7 +454,7 @@ void ED_object_editmode_enter(bContext *C, int flag)
base = scene->basact;
}
- if (ELEM3(NULL, base, base->object, base->object->data)) return;
+ if (ELEM(NULL, base, base->object, base->object->data)) return;
ob = base->object;
@@ -589,7 +596,7 @@ static int editmode_toggle_poll(bContext *C)
if ((ob->restrictflag & OB_RESTRICT_VIEW) && !(ob->mode & OB_MODE_EDIT))
return 0;
- return (ELEM7(ob->type, OB_MESH, OB_ARMATURE, OB_FONT, OB_MBALL, OB_LATTICE, OB_SURF, OB_CURVE));
+ return OB_TYPE_SUPPORT_EDITMODE(ob->type);
}
void OBJECT_OT_editmode_toggle(wmOperatorType *ot)
@@ -760,7 +767,7 @@ static void copy_texture_space(Object *to, Object *ob)
texflag = ((Mesh *)ob->data)->texflag;
poin2 = ((Mesh *)ob->data)->loc;
}
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
texflag = ((Curve *)ob->data)->texflag;
poin2 = ((Curve *)ob->data)->loc;
}
@@ -775,7 +782,7 @@ static void copy_texture_space(Object *to, Object *ob)
((Mesh *)to->data)->texflag = texflag;
poin1 = ((Mesh *)to->data)->loc;
}
- else if (ELEM3(to->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(to->type, OB_CURVE, OB_SURF, OB_FONT)) {
((Curve *)to->data)->texflag = texflag;
poin1 = ((Curve *)to->data)->loc;
}
@@ -1112,7 +1119,7 @@ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object)
/* add/remove modifier as needed */
if (!md) {
if (pd && (pd->shape == PFIELD_SHAPE_SURFACE) && ELEM(pd->forcefield, PFIELD_GUIDE, PFIELD_TEXTURE) == 0)
- if (ELEM4(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE))
+ if (ELEM(object->type, OB_MESH, OB_SURF, OB_FONT, OB_CURVE))
ED_object_modifier_add(NULL, bmain, scene, object, NULL, eModifierType_Surface);
}
else {
@@ -1453,7 +1460,7 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d)
BKE_mesh_texspace_get(ob->data, NULL, NULL, size);
space = size[0] / size[1];
}
- else if (ELEM3(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_FONT, OB_SURF)) {
float size[3];
BKE_curve_texspace_get(ob->data, NULL, NULL, size);
space = size[0] / size[1];
@@ -1500,7 +1507,7 @@ static EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED(
if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) ||
(input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) ||
(input->value == OB_MODE_PARTICLE_EDIT && use_mode_particle_edit) ||
- (ELEM4(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT,
+ (ELEM(input->value, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT,
OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT) && (ob->type == OB_MESH)) ||
(input->value == OB_MODE_OBJECT))
{
@@ -1620,20 +1627,20 @@ static int object_mode_set_exec(bContext *C, wmOperator *op)
/* Exit current mode if it's not the mode we're setting */
if (mode != OB_MODE_OBJECT && (ob->mode != mode || toggle)) {
/* Enter new mode */
- WM_operator_name_call(C, object_mode_op_string(mode), WM_OP_EXEC_REGION_WIN, NULL);
+ ED_object_toggle_modes(C, mode);
}
if (toggle) {
/* Special case for Object mode! */
if (mode == OB_MODE_OBJECT && restore_mode == OB_MODE_OBJECT && ob->restore_mode != OB_MODE_OBJECT) {
- WM_operator_name_call(C, object_mode_op_string(ob->restore_mode), WM_OP_EXEC_REGION_WIN, NULL);
+ ED_object_toggle_modes(C, ob->restore_mode);
}
else if (ob->mode == mode) {
/* For toggling, store old mode so we know what to go back to */
ob->restore_mode = restore_mode;
}
else if (ob->restore_mode != OB_MODE_OBJECT && ob->restore_mode != mode) {
- WM_operator_name_call(C, object_mode_op_string(ob->restore_mode), WM_OP_EXEC_REGION_WIN, NULL);
+ ED_object_toggle_modes(C, ob->restore_mode);
}
}
@@ -1669,24 +1676,12 @@ void OBJECT_OT_mode_set(wmOperatorType *ot)
void ED_object_toggle_modes(bContext *C, int mode)
{
- /* Couldn't we use object_mode_op_string() here?
- * Also, if several bits are set in mode, several toggle ops will be called, is this expected?
- * If so, would be nice to explain why. ;) --mont29
- */
- if (mode & OB_MODE_SCULPT)
- WM_operator_name_call(C, "SCULPT_OT_sculptmode_toggle", WM_OP_EXEC_REGION_WIN, NULL);
- if (mode & OB_MODE_VERTEX_PAINT)
- WM_operator_name_call(C, "PAINT_OT_vertex_paint_toggle", WM_OP_EXEC_REGION_WIN, NULL);
- if (mode & OB_MODE_WEIGHT_PAINT)
- WM_operator_name_call(C, "PAINT_OT_weight_paint_toggle", WM_OP_EXEC_REGION_WIN, NULL);
- if (mode & OB_MODE_TEXTURE_PAINT)
- WM_operator_name_call(C, "PAINT_OT_texture_paint_toggle", WM_OP_EXEC_REGION_WIN, NULL);
- if (mode & OB_MODE_PARTICLE_EDIT)
- WM_operator_name_call(C, "PARTICLE_OT_particle_edit_toggle", WM_OP_EXEC_REGION_WIN, NULL);
- if (mode & OB_MODE_POSE)
- WM_operator_name_call(C, "OBJECT_OT_posemode_toggle", WM_OP_EXEC_REGION_WIN, NULL);
- if (mode & OB_MODE_EDIT)
- WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_EXEC_REGION_WIN, NULL);
+ if (mode != OB_MODE_OBJECT) {
+ const char *opstring = object_mode_op_string(mode);
+ if (opstring) {
+ WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL);
+ }
+ }
}
/************************ Game Properties ***********************/
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 69bd64542f4..20e2e22cdf8 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -74,33 +74,31 @@ static bool group_link_early_exit_check(Group *group, Object *object)
return false;
}
-static bool check_group_contains_object_recursive(Group *group, Object *object)
+static bool check_object_instances_group_recursive(Object *object, Group *group)
{
- GroupObject *group_object;
-
- if ((group->id.flag & LIB_DOIT) == 0) {
- /* Cycle already exists in groups, let's prevent further crappyness */
- return true;
- }
-
- group->id.flag &= ~LIB_DOIT;
-
- for (group_object = group->gobject.first; group_object; group_object = group_object->next) {
- Object *current_object = group_object->ob;
-
- if (current_object == object) {
+ if (object->dup_group) {
+ Group *dup_group = object->dup_group;
+ if ((dup_group->id.flag & LIB_DOIT) == 0) {
+ /* Cycle already exists in groups, let's prevent further crappyness */
return true;
}
-
- if (current_object->dup_group) {
- if (check_group_contains_object_recursive(current_object->dup_group, object)) {
- return true;
+ /* flag the object to identify cyclic dependencies in further dupli groups */
+ dup_group->id.flag &= ~LIB_DOIT;
+
+ if (dup_group == group)
+ return true;
+ else {
+ GroupObject *gob;
+ for (gob = dup_group->gobject.first; gob; gob = gob->next) {
+ if (check_object_instances_group_recursive(gob->ob, group))
+ return true;
}
}
+
+ /* un-flag the object, it's allowed to have the same group multiple times in parallel */
+ dup_group->id.flag |= LIB_DOIT;
}
-
- group->id.flag |= LIB_DOIT;
-
+
return false;
}
@@ -195,7 +193,7 @@ static int objects_add_active_exec(bContext *C, wmOperator *op)
if (group_link_early_exit_check(group, base->object))
continue;
- if (base->object->dup_group != group && !check_group_contains_object_recursive(group, base->object)) {
+ if (!check_object_instances_group_recursive(base->object, group)) {
BKE_group_object_add(group, base->object, scene, base);
updated = true;
}
@@ -498,7 +496,7 @@ static int group_link_exec(bContext *C, wmOperator *op)
* contains our current object.
*/
BKE_main_id_tag_listbase(&bmain->group, true);
- if (ob->dup_group == group || check_group_contains_object_recursive(group, ob)) {
+ if (check_object_instances_group_recursive(ob, group)) {
BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
return OPERATOR_CANCELLED;
}
@@ -565,3 +563,67 @@ void OBJECT_OT_group_remove(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
+
+ if (!group)
+ return OPERATOR_CANCELLED;
+
+ BKE_group_unlink(group);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_group_unlink(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlink Group";
+ ot->idname = "OBJECT_OT_group_unlink";
+ ot->description = "Unlink the group from all objects";
+
+ /* api callbacks */
+ ot->exec = group_unlink_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int select_grouped_exec(bContext *C, wmOperator *UNUSED(op)) /* Select objects in the same group as the active */
+{
+ Group *group = CTX_data_pointer_get_type(C, "group", &RNA_Group).data;
+
+ if (!group)
+ return OPERATOR_CANCELLED;
+
+ CTX_DATA_BEGIN (C, Base *, base, visible_bases)
+ {
+ if (!(base->flag & SELECT) && BKE_group_object_exists(group, base->object)) {
+ ED_base_object_select(base, BA_SELECT);
+ }
+ }
+ CTX_DATA_END;
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void OBJECT_OT_grouped_select(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Grouped";
+ ot->idname = "OBJECT_OT_grouped_select";
+ ot->description = "Select all objects in group";
+
+ /* api callbacks */
+ ot->exec = select_grouped_exec;
+ ot->poll = ED_operator_objectmode;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 6407d2eb8b8..9f9a647c9f1 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -331,6 +331,8 @@ static bool object_hook_index_array(Scene *scene, Object *obedit,
}
case OB_CURVE:
case OB_SURF:
+ load_editNurb(obedit);
+ make_editNurb(obedit);
return return_editcurve_indexar(obedit, r_tot, r_indexar, r_cent);
case OB_LATTICE:
{
@@ -526,8 +528,7 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
invert_m4_m4(ob->imat, ob->obmat);
/* apparently this call goes from right to left... */
- mul_serie_m4(hmd->parentinv, pose_mat, ob->imat, obedit->obmat,
- NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(hmd->parentinv, pose_mat, ob->imat, obedit->obmat);
DAG_relations_tag_update(bmain);
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index fd6b9a1bad0..6fa3caa6172 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -72,6 +72,7 @@ void OBJECT_OT_make_links_scene(struct wmOperatorType *ot);
void OBJECT_OT_make_links_data(struct wmOperatorType *ot);
void OBJECT_OT_move_to_layer(struct wmOperatorType *ot);
void OBJECT_OT_drop_named_material(struct wmOperatorType *ot);
+void OBJECT_OT_unlink_data(struct wmOperatorType *ot);
/* object_edit.c */
void OBJECT_OT_mode_set(struct wmOperatorType *ot);
@@ -251,6 +252,8 @@ void OBJECT_OT_shape_key_move(struct wmOperatorType *ot);
void OBJECT_OT_group_add(struct wmOperatorType *ot);
void OBJECT_OT_group_link(struct wmOperatorType *ot);
void OBJECT_OT_group_remove(struct wmOperatorType *ot);
+void OBJECT_OT_group_unlink(struct wmOperatorType *ot);
+void OBJECT_OT_grouped_select(struct wmOperatorType *ot);
/* object_bake.c */
void OBJECT_OT_bake_image(wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_lattice.c b/source/blender/editors/object/object_lattice.c
index 2af2ca3b0e9..c24a127ed8b 100644
--- a/source/blender/editors/object/object_lattice.c
+++ b/source/blender/editors/object/object_lattice.c
@@ -174,21 +174,6 @@ void load_editLatt(Object *obedit)
}
}
-/*************************** Transform Operator ************************/
-
-void ED_lattice_transform(Lattice *lt, float mat[4][4])
-{
- BPoint *bp = lt->def;
- int a = lt->pntsu * lt->pntsv * lt->pntsw;
-
- while (a--) {
- mul_m4_v3(mat, bp->vec);
- bp++;
- }
-
- DAG_id_tag_update(&lt->id, 0);
-}
-
static void bpoint_select_set(BPoint *bp, bool select)
{
if (select) {
@@ -285,7 +270,7 @@ static int lattice_select_mirror_exec(bContext *C, wmOperator *op)
const int i_flip = BKE_lattice_index_flip(lt, i, flip_uvw[0], flip_uvw[1], flip_uvw[2]);
bp = &lt->def[i];
if (!bp->hide) {
- if (BLI_BITMAP_GET(selpoints, i_flip)) {
+ if (BLI_BITMAP_TEST(selpoints, i_flip)) {
bp->f1 |= SELECT;
}
else {
@@ -338,7 +323,7 @@ static bool lattice_test_bitmap_uvw(Lattice *lt, BLI_bitmap *selpoints, int u, i
else {
int i = BKE_lattice_index_from_uvw(lt, u, v, w);
if (lt->def[i].hide == 0) {
- return (BLI_BITMAP_GET(selpoints, i) != 0) == selected;
+ return (BLI_BITMAP_TEST(selpoints, i) != 0) == selected;
}
return false;
}
diff --git a/source/blender/editors/object/object_lod.c b/source/blender/editors/object/object_lod.c
index a7cc4131a96..48e980015a7 100644
--- a/source/blender/editors/object/object_lod.c
+++ b/source/blender/editors/object/object_lod.c
@@ -29,15 +29,11 @@
* \ingroup edobj
*/
-
#include "DNA_object_types.h"
#include "BKE_context.h"
#include "BKE_object.h"
-#include "ED_screen.h"
-#include "ED_object.h"
-
#include "WM_api.h"
#include "WM_types.h"
@@ -45,6 +41,9 @@
#include "RNA_define.h"
#include "RNA_enum_types.h"
+#include "ED_screen.h"
+#include "ED_object.h"
+
#include "object_intern.h"
static int object_lod_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -69,7 +68,7 @@ void OBJECT_OT_lod_add(wmOperatorType *ot)
/* api callbacks */
ot->exec = object_lod_add_exec;
- ot->poll = ED_operator_objectmode;
+ ot->poll = ED_operator_object_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
@@ -101,7 +100,7 @@ void OBJECT_OT_lod_remove(wmOperatorType *ot)
/* api callbacks */
ot->exec = object_lod_remove_exec;
- ot->poll = ED_operator_objectmode;
+ ot->poll = ED_operator_object_active;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 3e33268704c..b05840b5823 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -98,7 +98,7 @@ ModifierData *ED_object_modifier_add(ReportList *reports, Main *bmain, Scene *sc
ModifierTypeInfo *mti = modifierType_getInfo(type);
/* only geometry objects should be able to get modifiers [#25291] */
- if (!ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ if (!ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2);
return NULL;
}
@@ -1650,9 +1650,9 @@ static void skin_armature_bone_create(Object *skin_ob,
int v;
/* ignore edge if already visited */
- if (BLI_BITMAP_GET(edges_visited, endx))
+ if (BLI_BITMAP_TEST(edges_visited, endx))
continue;
- BLI_BITMAP_SET(edges_visited, endx);
+ BLI_BITMAP_ENABLE(edges_visited, endx);
v = (e->v1 == parent_v ? e->v2 : e->v1);
@@ -1876,7 +1876,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op)
else if (ob->type == OB_MBALL) {
BKE_displist_make_mball(CTX_data_main(C)->eval_ctx, scene, ob);
}
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_displist_make_curveTypes(scene, ob, 0);
}
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index a8f07747d3a..7cf661de52c 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -229,6 +229,8 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_group_add);
WM_operatortype_append(OBJECT_OT_group_link);
WM_operatortype_append(OBJECT_OT_group_remove);
+ WM_operatortype_append(OBJECT_OT_group_unlink);
+ WM_operatortype_append(OBJECT_OT_grouped_select);
WM_operatortype_append(OBJECT_OT_hook_add_selob);
WM_operatortype_append(OBJECT_OT_hook_add_newob);
@@ -241,6 +243,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_bake_image);
WM_operatortype_append(OBJECT_OT_bake);
WM_operatortype_append(OBJECT_OT_drop_named_material);
+ WM_operatortype_append(OBJECT_OT_unlink_data);
WM_operatortype_append(OBJECT_OT_laplaciandeform_bind);
WM_operatortype_append(OBJECT_OT_lod_add);
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 6ff21f75733..8f74278b424 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -128,9 +128,9 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
BPoint *bp;
Object *par;
int a, v1 = 0, v2 = 0, v3 = 0, v4 = 0, nr = 1;
-
+
/* we need 1 to 3 selected vertices */
-
+
if (obedit->type == OB_MESH) {
Mesh *me = obedit->data;
BMEditMesh *em;
@@ -160,7 +160,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
}
else if (ELEM(obedit->type, OB_SURF, OB_CURVE)) {
ListBase *editnurb = object_editcurve_get(obedit);
-
+
cu = obedit->data;
nu = editnurb->first;
@@ -200,7 +200,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
}
else if (obedit->type == OB_LATTICE) {
Lattice *lt = obedit->data;
-
+
a = lt->editlatt->latt->pntsu * lt->editlatt->latt->pntsv * lt->editlatt->latt->pntsw;
bp = lt->editlatt->latt->def;
while (a--) {
@@ -215,28 +215,24 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
bp++;
}
}
-
+
if (v4 || !((v1 && v2 == 0 && v3 == 0) || (v1 && v2 && v3))) {
BKE_report(op->reports, RPT_ERROR, "Select either 1 or 3 vertices to parent to");
return OPERATOR_CANCELLED;
}
-
+
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
if (ob != obedit) {
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
par = obedit->parent;
-
- while (par) {
- if (par == ob) break;
- par = par->parent;
- }
- if (par) {
+
+ if (BKE_object_parent_loop_check(par, ob)) {
BKE_report(op->reports, RPT_ERROR, "Loop in parents");
}
else {
Object workob;
-
+
ob->parent = BASACT->object;
if (v3) {
ob->partype = PARVERT3;
@@ -260,7 +256,7 @@ static int vertex_parent_set_exec(bContext *C, wmOperator *op)
}
}
CTX_DATA_END;
-
+
DAG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT, NULL);
@@ -274,12 +270,12 @@ void OBJECT_OT_vertex_parent_set(wmOperatorType *ot)
ot->name = "Make Vertex Parent";
ot->description = "Parent selected objects to the selected vertices";
ot->idname = "OBJECT_OT_vertex_parent_set";
-
+
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->poll = vertex_parent_set_poll;
ot->exec = vertex_parent_set_exec;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -291,26 +287,26 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
Object *ob = ED_object_active_context(C);
-
+
/* sanity checks */
if (!scene || scene->id.lib || !ob)
return OPERATOR_CANCELLED;
-
+
/* Get object to work on - use a menu if we need to... */
if (ob->dup_group && ob->dup_group->id.lib) {
/* gives menu with list of objects in group */
- //proxy_group_objects_menu(C, op, ob, ob->dup_group);
+ /* proxy_group_objects_menu(C, op, ob, ob->dup_group); */
WM_enum_search_invoke(C, op, event);
return OPERATOR_CANCELLED;
-
}
else if (ob->id.lib) {
uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("OK?"), ICON_QUESTION);
uiLayout *layout = uiPupMenuLayout(pup);
-
+
/* create operator menu item with relevant properties filled in */
- uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
-
+ uiItemFullO_ptr(layout, op->type, op->type->name, ICON_NONE, NULL,
+ WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
+
/* present the menu and be done... */
uiPupMenuEnd(C, pup);
}
@@ -318,7 +314,7 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* error.. cannot continue */
BKE_report(op->reports, RPT_ERROR, "Can only make proxy for a referenced object or group");
}
-
+
/* this invoke just calls another instance of this operator... */
return OPERATOR_CANCELLED;
}
@@ -338,32 +334,32 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
ob = gob;
gob = NULL;
}
-
+
if (ob) {
Object *newob;
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);
-
+
/* set layers OK */
newbase = BASACT; /* BKE_object_add sets active... */
newbase->lay = oldbase->lay;
newob->lay = newbase->lay;
-
+
/* remove base, leave user count of object, it gets linked in BKE_object_make_proxy */
if (gob == NULL) {
BKE_scene_base_unlink(scene, oldbase);
MEM_freeN(oldbase);
}
-
+
BKE_object_make_proxy(newob, ob, gob);
-
+
/* depsgraph flushes are needed for the new data */
DAG_relations_tag_update(bmain);
DAG_id_tag_update(&newob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
@@ -373,12 +369,13 @@ static int make_proxy_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No object to make proxy for");
return OPERATOR_CANCELLED;
}
-
+
return OPERATOR_FINISHED;
}
/* Generic itemf's for operators that take library args */
-static EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
+static EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA *UNUSED(ptr),
+ PropertyRNA *UNUSED(prop), bool *r_free)
{
EnumPropertyItem item_tmp = {0}, *item = NULL;
int totitem = 0;
@@ -410,17 +407,19 @@ void OBJECT_OT_proxy_make(wmOperatorType *ot)
ot->name = "Make Proxy";
ot->idname = "OBJECT_OT_proxy_make";
ot->description = "Add empty object to become local replacement data of a library-linked object";
-
+
/* callbacks */
ot->invoke = make_proxy_invoke;
ot->exec = make_proxy_exec;
ot->poll = ED_operator_object_active;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
- prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object", "Name of lib-linked/grouped object to make a proxy for"); /* XXX, relies on hard coded ID at the moment */
+ /* XXX, relies on hard coded ID at the moment */
+ prop = RNA_def_enum(ot->srna, "object", DummyRNA_DEFAULT_items, 0, "Proxy Object",
+ "Name of lib-linked/grouped object to make a proxy for");
RNA_def_enum_funcs(prop, proxy_group_object_itemf);
RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE);
ot->prop = prop;
@@ -435,24 +434,27 @@ typedef enum eObClearParentTypes {
} eObClearParentTypes;
EnumPropertyItem prop_clear_parent_types[] = {
- {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent", ""},
- {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", ""},
- {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse", ""},
+ {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent",
+ "Completely clear the parenting relationship, including involved modifiers is any"},
+ {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation",
+ "As 'Clear Parent', but keep the current visual transformations of the object"},
+ {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse",
+ "Reset the transform corrections applied to the parenting relationship, does not remove parenting itself"},
{0, NULL, 0, NULL, NULL}
};
/* Helper for ED_object_parent_clear() - Remove deform-modifiers associated with parent */
static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
{
- if (ELEM3(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) {
+ if (ELEM(par->type, OB_ARMATURE, OB_LATTICE, OB_CURVE)) {
ModifierData *md, *mdn;
-
+
/* assume that we only need to remove the first instance of matching deform modifier here */
for (md = ob->modifiers.first; md; md = mdn) {
bool free = false;
-
+
mdn = md->next;
-
+
/* need to match types (modifier + parent) and references */
if ((md->type == eModifierType_Armature) && (par->type == OB_ARMATURE)) {
ArmatureModifierData *amd = (ArmatureModifierData *)md;
@@ -472,7 +474,7 @@ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
free = true;
}
}
-
+
/* free modifier if match */
if (free) {
BLI_remlink(&ob->modifiers, md);
@@ -482,17 +484,17 @@ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par)
}
}
-void ED_object_parent_clear(Object *ob, int type)
+void ED_object_parent_clear(Object *ob, const int type)
{
if (ob->parent == NULL)
return;
-
+
switch (type) {
case CLEAR_PARENT_ALL:
{
/* for deformers, remove corresponding modifiers to prevent a large number of modifiers building up */
object_remove_parent_deform_modifiers(ob, ob->parent);
-
+
/* clear parenting relationship completely */
ob->parent = NULL;
break;
@@ -506,12 +508,15 @@ void ED_object_parent_clear(Object *ob, int type)
}
case CLEAR_PARENT_INVERSE:
{
- /* object stays parented, but the parent inverse (i.e. offset from parent to retain binding state) is cleared */
- unit_m4(ob->parentinv);
+ /* object stays parented, but the parent inverse (i.e. offset from parent to retain binding state)
+ * is cleared. In other words: nothing to do here! */
break;
}
}
-
+
+ /* Always clear parentinv matrix for sake of consistency, see T41950. */
+ unit_m4(ob->parentinv);
+
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
}
@@ -519,7 +524,7 @@ void ED_object_parent_clear(Object *ob, int type)
static int parent_clear_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- int type = RNA_enum_get(op->ptr, "type");
+ const int type = RNA_enum_get(op->ptr, "type");
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
@@ -539,23 +544,26 @@ void OBJECT_OT_parent_clear(wmOperatorType *ot)
ot->name = "Clear Parent";
ot->description = "Clear the object's parenting";
ot->idname = "OBJECT_OT_parent_clear";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = parent_clear_exec;
-
+
ot->poll = ED_operator_object_active_editable;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_parent_types, CLEAR_PARENT_ALL, "Type", "");
}
/* ******************** Make Parent Operator *********************** */
-void ED_object_parent(Object *ob, Object *par, int type, const char *substr)
+void ED_object_parent(Object *ob, Object *par, const int type, const char *substr)
{
+ /* Always clear parentinv matrix for sake of consistency, see T41950. */
+ unit_m4(ob->parentinv);
+
if (!par || BKE_object_parent_loop_check(par, ob)) {
ob->parent = NULL;
ob->partype = PAROBJECT;
@@ -589,21 +597,21 @@ EnumPropertyItem prop_make_parent_types[] = {
{0, NULL, 0, NULL, NULL}
};
-int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par,
- int partype, bool xmirror, bool keep_transform, const int vert_par[3])
+bool ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object *ob, Object *par,
+ int partype, const bool xmirror, const bool keep_transform, const int vert_par[3])
{
bPoseChannel *pchan = NULL;
- int pararm = ELEM4(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
-
+ const bool pararm = ELEM(partype, PAR_ARMATURE, PAR_ARMATURE_NAME, PAR_ARMATURE_ENVELOPE, PAR_ARMATURE_AUTO);
+
DAG_id_tag_update(&par->id, OB_RECALC_OB);
-
+
/* preconditions */
if (partype == PAR_FOLLOW || partype == PAR_PATH_CONST) {
if (par->type != OB_CURVE)
return 0;
else {
Curve *cu = par->data;
-
+
if ((cu->flag & CU_PATH) == 0) {
cu->flag |= CU_PATH | CU_FOLLOW;
BKE_displist_make_curveTypes(scene, par, 0); /* force creation of path data */
@@ -617,12 +625,12 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
/* get or create F-Curve */
bAction *act = verify_adt_action(&cu->id, 1);
FCurve *fcu = verify_fcurve(act, NULL, NULL, "eval_time", 0, 1);
-
+
/* setup dummy 'generator' modifier here to get 1-1 correspondence still working */
if (!fcu->bezt && !fcu->fpt && !fcu->modifiers.first)
add_fmodifier(&fcu->modifiers, FMODIFIER_TYPE_GENERATOR);
}
-
+
/* fall back on regular parenting now (for follow only) */
if (partype == PAR_FOLLOW)
partype = PAR_OBJECT;
@@ -630,17 +638,17 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
}
else if (ELEM(partype, PAR_BONE, PAR_BONE_RELATIVE)) {
pchan = BKE_pose_channel_active(par);
-
+
if (pchan == NULL) {
BKE_report(reports, RPT_ERROR, "No active bone");
- return 0;
+ return false;
}
}
-
+
if (ob != par) {
if (BKE_object_parent_loop_check(par, ob)) {
BKE_report(reports, RPT_ERROR, "Loop in parents");
- return 0;
+ return false;
}
else {
Object workob;
@@ -655,14 +663,16 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
/* set the parent (except for follow-path constraint option) */
if (partype != PAR_PATH_CONST) {
ob->parent = par;
+ /* Always clear parentinv matrix for sake of consistency, see T41950. */
+ unit_m4(ob->parentinv);
}
-
+
/* handle types */
if (pchan)
BLI_strncpy(ob->parsubstr, pchan->name, sizeof(ob->parsubstr));
else
ob->parsubstr[0] = 0;
-
+
if (partype == PAR_PATH_CONST) {
/* don't do anything here, since this is not technically "parenting" */
}
@@ -670,17 +680,18 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
/* partype is now set to PAROBJECT so that invisible 'virtual' modifiers don't need to be created
* NOTE: the old (2.4x) method was to set ob->partype = PARSKEL, creating the virtual modifiers
*/
- ob->partype = PAROBJECT; /* note, dna define, not operator property */
- //ob->partype = PARSKEL; /* note, dna define, not operator property */
-
- /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses
+ ob->partype = PAROBJECT; /* note, dna define, not operator property */
+ /* ob->partype = PARSKEL; */ /* note, dna define, not operator property */
+
+ /* BUT, to keep the deforms, we need a modifier, and then we need to set the object that it uses
* - We need to ensure that the modifier we're adding doesn't already exist, so we check this by
* assuming that the parent is selected too...
*/
- // XXX currently this should only happen for meshes, curves, surfaces, and lattices - this stuff isn't available for metas yet
- if (ELEM5(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
+ /* XXX currently this should only happen for meshes, curves, surfaces,
+ * and lattices - this stuff isn't available for metas yet */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_LATTICE)) {
ModifierData *md;
-
+
switch (partype) {
case PAR_CURVE: /* curve deform */
if (modifiers_isDeformedByCurve(ob) != par) {
@@ -688,6 +699,9 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
if (md) {
((CurveModifierData *)md)->object = par;
}
+ if (par->curve_cache && par->curve_cache->path == NULL) {
+ DAG_id_tag_update(&par->id, OB_RECALC_DATA);
+ }
}
break;
case PAR_LATTICE: /* lattice deform */
@@ -730,21 +744,21 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
else {
ob->partype = PAROBJECT; /* note, dna define, not operator property */
}
-
+
/* constraint */
if (partype == PAR_PATH_CONST) {
bConstraint *con;
bFollowPathConstraint *data;
float cmat[4][4], vec[3];
-
+
con = BKE_constraint_add_for_object(ob, "AutoPath", CONSTRAINT_TYPE_FOLLOWPATH);
-
+
data = con->data;
data->tar = par;
-
+
BKE_constraint_target_matrix_get(scene, con, 0, CONSTRAINT_OBTYPE_OBJECT, NULL, cmat, scene->r.cfra);
sub_v3_v3v3(vec, ob->obmat[3], cmat[3]);
-
+
copy_v3_v3(ob->loc, vec);
}
else if (pararm && (ob->type == OB_MESH) && (par->type == OB_ARMATURE)) {
@@ -760,7 +774,7 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
/* get corrected inverse */
ob->partype = PAROBJECT;
BKE_object_workob_calc_parent(scene, ob, &workob);
-
+
invert_m4_m4(ob->parentinv, workob.obmat);
}
else {
@@ -768,12 +782,12 @@ int ED_object_parent_set(ReportList *reports, Main *bmain, Scene *scene, Object
BKE_object_workob_calc_parent(scene, ob, &workob);
invert_m4_m4(ob->parentinv, workob.obmat);
}
-
+
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
}
}
- return 1;
+ return true;
}
@@ -808,8 +822,8 @@ static int parent_set_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
Object *par = ED_object_active_context(C);
int partype = RNA_enum_get(op->ptr, "type");
- bool xmirror = RNA_boolean_get(op->ptr, "xmirror");
- bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform");
+ const bool xmirror = RNA_boolean_get(op->ptr, "xmirror");
+ const bool keep_transform = RNA_boolean_get(op->ptr, "keep_transform");
bool ok = true;
/* vertex parent (kdtree) */
@@ -828,27 +842,25 @@ static int parent_set_exec(bContext *C, wmOperator *op)
if (tree_tot < (is_tri ? 3 : 1)) {
BKE_report(op->reports, RPT_ERROR, "Not enough vertices for vertex-parent");
ok = false;
- goto cleanup;
}
}
+ if (ok) {
+ /* Non vertex-parent */
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ if (is_vert_par) {
+ parent_set_vert_find(tree, ob, vert_par, is_tri);
+ }
- /* Non vertex-parent */
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
- {
- if (is_vert_par) {
- parent_set_vert_find(tree, ob, vert_par, is_tri);
- }
-
- if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) {
- ok = false;
- break;
+ if (!ED_object_parent_set(op->reports, bmain, scene, ob, par, partype, xmirror, keep_transform, vert_par_p)) {
+ ok = false;
+ break;
+ }
}
+ CTX_DATA_END;
}
- CTX_DATA_END;
-
-cleanup:
if (is_vert_par) {
BLI_kdtree_free(tree);
}
@@ -902,7 +914,7 @@ static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
else if (ob->type == OB_LATTICE) {
uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_LATTICE);
}
-
+
/* vertex parenting */
if (OB_TYPE_SUPPORT_PARVERT(ob->type)) {
uiItemEnumO_ptr(layout, ot, NULL, 0, "type", PAR_VERTEX);
@@ -910,14 +922,14 @@ static int parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent
}
uiPupMenuEnd(C, pup);
-
+
return OPERATOR_CANCELLED;
}
static bool parent_set_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
- int type = RNA_enum_get(ptr, "type");
+ const int type = RNA_enum_get(ptr, "type");
/* Only show XMirror for PAR_ARMATURE_ENVELOPE and PAR_ARMATURE_AUTO! */
if (STREQ(prop_id, "xmirror")) {
@@ -948,22 +960,21 @@ void OBJECT_OT_parent_set(wmOperatorType *ot)
ot->name = "Make Parent";
ot->description = "Set the object's parenting";
ot->idname = "OBJECT_OT_parent_set";
-
+
/* api callbacks */
ot->invoke = parent_set_invoke;
ot->exec = parent_set_exec;
ot->poll = ED_operator_object_active;
ot->ui = parent_set_ui;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
RNA_def_boolean(ot->srna, "xmirror", false, "X Mirror",
"Apply weights symmetrically along X axis, for Envelope/Automatic vertex groups creation");
RNA_def_boolean(ot->srna, "keep_transform", false, "Keep Transform",
"Apply transformation before parenting");
-
}
/* ************ Make Parent Without Inverse Operator ******************* */
@@ -972,9 +983,9 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *par = ED_object_active_context(C);
-
+
DAG_id_tag_update(&par->id, OB_RECALC_OB);
-
+
/* context iterator */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
@@ -986,10 +997,10 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
/* clear inverse matrix and also the object location */
unit_m4(ob->parentinv);
memset(ob->loc, 0, 3 * sizeof(float));
-
+
/* set recalc flags */
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA);
-
+
/* set parenting type for object - object only... */
ob->parent = par;
ob->partype = PAROBJECT; /* note, dna define, not operator property */
@@ -997,10 +1008,10 @@ static int parent_noinv_set_exec(bContext *C, wmOperator *op)
}
}
CTX_DATA_END;
-
+
DAG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -1010,12 +1021,12 @@ void OBJECT_OT_parent_no_inverse_set(wmOperatorType *ot)
ot->name = "Make Parent without Inverse";
ot->description = "Set the object's parenting without setting the inverse parent correction";
ot->idname = "OBJECT_OT_parent_no_inverse_set";
-
+
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->exec = parent_noinv_set_exec;
ot->poll = ED_operator_object_active_editable;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -1040,23 +1051,22 @@ static int object_slow_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
CTX_DATA_END;
WM_event_add_notifier(C, NC_SCENE, scene);
-
+
return OPERATOR_FINISHED;
}
void OBJECT_OT_slow_parent_clear(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Clear Slow Parent";
ot->description = "Clear the object's slow parent";
ot->idname = "OBJECT_OT_slow_parent_clear";
-
+
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->exec = object_slow_parent_clear_exec;
ot->poll = ED_operator_view3d_active;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
@@ -1073,37 +1083,40 @@ static int object_slow_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
ob->partype |= PARSLOW;
DAG_id_tag_update(&ob->id, OB_RECALC_OB);
-
}
CTX_DATA_END;
WM_event_add_notifier(C, NC_SCENE, scene);
-
+
return OPERATOR_FINISHED;
}
void OBJECT_OT_slow_parent_set(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Set Slow Parent";
ot->description = "Set the object's slow parent";
ot->idname = "OBJECT_OT_slow_parent_set";
-
+
/* api callbacks */
ot->invoke = WM_operator_confirm;
ot->exec = object_slow_parent_set_exec;
ot->poll = ED_operator_view3d_active;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/* ******************** Clear Track Operator ******************* */
+enum {
+ CLEAR_TRACK = 1,
+ CLEAR_TRACK_KEEP_TRANSFORM = 2,
+};
+
static EnumPropertyItem prop_clear_track_types[] = {
- {0, "CLEAR", 0, "Clear Track", ""},
- {1, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation (Clear Track)", ""},
+ {CLEAR_TRACK, "CLEAR", 0, "Clear Track", ""},
+ {CLEAR_TRACK_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation (Clear Track)", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1111,7 +1124,7 @@ static EnumPropertyItem prop_clear_track_types[] = {
static int object_track_clear_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- int type = RNA_enum_get(op->ptr, "type");
+ const int type = RNA_enum_get(op->ptr, "type");
if (CTX_data_edit_object(C)) {
BKE_report(op->reports, RPT_ERROR, "Operation cannot be performed in edit mode");
@@ -1120,19 +1133,19 @@ static int object_track_clear_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
bConstraint *con, *pcon;
-
+
/* remove track-object for old track */
ob->track = NULL;
DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
+
/* also remove all tracking constraints */
for (con = ob->constraints.last; con; con = pcon) {
pcon = con->prev;
- if (ELEM3(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK))
+ if (ELEM(con->type, CONSTRAINT_TYPE_TRACKTO, CONSTRAINT_TYPE_LOCKTRACK, CONSTRAINT_TYPE_DAMPTRACK))
BKE_constraint_remove(&ob->constraints, con);
}
-
- if (type == 1)
+
+ if (type == CLEAR_TRACK_KEEP_TRANSFORM)
BKE_object_apply_mat4(ob, ob->obmat, true, true);
}
CTX_DATA_END;
@@ -1149,25 +1162,31 @@ void OBJECT_OT_track_clear(wmOperatorType *ot)
ot->name = "Clear Track";
ot->description = "Clear tracking constraint or flag from object";
ot->idname = "OBJECT_OT_track_clear";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = object_track_clear_exec;
-
+
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
ot->prop = RNA_def_enum(ot->srna, "type", prop_clear_track_types, 0, "Type", "");
}
/************************** Make Track Operator *****************************/
+enum {
+ CREATE_TRACK_DAMPTRACK = 1,
+ CREATE_TRACK_TRACKTO = 2,
+ CREATE_TRACK_LOCKTRACK = 3,
+};
+
static EnumPropertyItem prop_make_track_types[] = {
- {1, "DAMPTRACK", 0, "Damped Track Constraint", ""},
- {2, "TRACKTO", 0, "Track To Constraint", ""},
- {3, "LOCKTRACK", 0, "Lock Track Constraint", ""},
+ {CREATE_TRACK_DAMPTRACK, "DAMPTRACK", 0, "Damped Track Constraint", ""},
+ {CREATE_TRACK_TRACKTO, "TRACKTO", 0, "Track To Constraint", ""},
+ {CREATE_TRACK_LOCKTRACK, "LOCKTRACK", 0, "Lock Track Constraint", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1175,78 +1194,86 @@ static int track_set_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Object *obact = ED_object_active_context(C);
-
- int type = RNA_enum_get(op->ptr, "type");
-
- if (type == 1) {
- bConstraint *con;
- bDampTrackConstraint *data;
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ switch (type) {
+ case CREATE_TRACK_DAMPTRACK:
{
- if (ob != obact) {
- con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK);
+ bConstraint *con;
+ bDampTrackConstraint *data;
- data = con->data;
- data->tar = obact;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
- /* Lamp, Camera and Speaker track differently by default */
- if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
- data->trackflag = TRACK_nZ;
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ if (ob != obact) {
+ con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_DAMPTRACK);
+
+ data = con->data;
+ data->tar = obact;
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ /* Lamp, Camera and Speaker track differently by default */
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ data->trackflag = TRACK_nZ;
+ }
}
}
+ CTX_DATA_END;
+ break;
}
- CTX_DATA_END;
- }
- else if (type == 2) {
- bConstraint *con;
- bTrackToConstraint *data;
-
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ case CREATE_TRACK_TRACKTO:
{
- if (ob != obact) {
- con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO);
+ bConstraint *con;
+ bTrackToConstraint *data;
- data = con->data;
- data->tar = obact;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
- /* Lamp, Camera and Speaker track differently by default */
- if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
- data->reserved1 = TRACK_nZ;
- data->reserved2 = UP_Y;
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ if (ob != obact) {
+ con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_TRACKTO);
+
+ data = con->data;
+ data->tar = obact;
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ /* Lamp, Camera and Speaker track differently by default */
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ data->reserved1 = TRACK_nZ;
+ data->reserved2 = UP_Y;
+ }
}
}
+ CTX_DATA_END;
+ break;
}
- CTX_DATA_END;
- }
- else if (type == 3) {
- bConstraint *con;
- bLockTrackConstraint *data;
-
- CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ case CREATE_TRACK_LOCKTRACK:
{
- if (ob != obact) {
- con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK);
+ bConstraint *con;
+ bLockTrackConstraint *data;
- data = con->data;
- data->tar = obact;
- DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
-
- /* Lamp, Camera and Speaker track differently by default */
- if (ELEM3(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
- data->trackflag = TRACK_nZ;
- data->lockflag = LOCK_Y;
+ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
+ {
+ if (ob != obact) {
+ con = BKE_constraint_add_for_object(ob, "AutoTrack", CONSTRAINT_TYPE_LOCKTRACK);
+
+ data = con->data;
+ data->tar = obact;
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ /* Lamp, Camera and Speaker track differently by default */
+ if (ELEM(ob->type, OB_LAMP, OB_CAMERA, OB_SPEAKER)) {
+ data->trackflag = TRACK_nZ;
+ data->lockflag = LOCK_Y;
+ }
}
}
+ CTX_DATA_END;
+ break;
}
- CTX_DATA_END;
}
-
+
DAG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
-
+
return OPERATOR_FINISHED;
}
@@ -1254,18 +1281,18 @@ void OBJECT_OT_track_set(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Make Track";
- ot->description = "Make the object track another object, either by constraint or old way or locked track";
+ ot->description = "Make the object track another object, using various methods/constraints";
ot->idname = "OBJECT_OT_track_set";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = track_set_exec;
-
+
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", prop_make_track_types, 0, "Type", "");
}
@@ -1287,7 +1314,7 @@ static unsigned int move_to_layer_init(bContext *C, wmOperator *op)
for (a = 0; a < 20; a++)
values[a] = (lay & (1 << a));
-
+
RNA_boolean_set_array(op->ptr, "layers", values);
}
else {
@@ -1320,12 +1347,12 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
View3D *v3d = CTX_wm_view3d(C);
unsigned int lay, local;
/* bool is_lamp = false; */ /* UNUSED */
-
+
lay = move_to_layer_init(C, op);
lay &= 0xFFFFFF;
if (lay == 0) return OPERATOR_CANCELLED;
-
+
if (v3d && v3d->localvd) {
/* now we can move out of localview. */
/* note: layers are set in bases, library objects work for this */
@@ -1353,9 +1380,9 @@ static int move_to_layer_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
}
-
+
/* warning, active object may be hidden now */
-
+
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, scene);
WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, scene);
@@ -1370,15 +1397,15 @@ void OBJECT_OT_move_to_layer(wmOperatorType *ot)
ot->name = "Move to Layer";
ot->description = "Move the object to different layers";
ot->idname = "OBJECT_OT_move_to_layer";
-
+
/* api callbacks */
ot->invoke = move_to_layer_invoke;
ot->exec = move_to_layer_exec;
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
RNA_def_boolean_layer_member(ot->srna, "layers", 20, NULL, "Layer", "");
}
@@ -1390,13 +1417,12 @@ static void link_to_scene(Main *UNUSED(bmain), unsigned short UNUSED(nr))
{
Scene *sce = (Scene *) BLI_findlink(&bmain->scene, G.curscreen->scenenr - 1);
Base *base, *nbase;
-
- if (sce == 0) return;
+
+ if (sce == NULL) return;
if (sce->id.lib) return;
-
+
for (base = FIRSTBASE; base; base = base->next) {
if (TESTBASE(v3d, base)) {
-
nbase = MEM_mallocN(sizeof(Base), "newbase");
*nbase = *base;
BLI_addhead(&(sce->base), nbase);
@@ -1453,48 +1479,45 @@ static int make_links_scene_exec(bContext *C, wmOperator *op)
}
enum {
- MAKE_LINKS_OBDATA = 1,
- MAKE_LINKS_MATERIALS,
- MAKE_LINKS_ANIMDATA,
- MAKE_LINKS_GROUP,
- MAKE_LINKS_DUPLIGROUP,
- MAKE_LINKS_MODIFIERS,
- MAKE_LINKS_FONTS
+ MAKE_LINKS_OBDATA = 1,
+ MAKE_LINKS_MATERIALS = 2,
+ MAKE_LINKS_ANIMDATA = 3,
+ MAKE_LINKS_GROUP = 4,
+ MAKE_LINKS_DUPLIGROUP = 5,
+ MAKE_LINKS_MODIFIERS = 6,
+ MAKE_LINKS_FONTS = 7,
};
-/* Return 1 if make link data is allow, zero otherwise */
-static int allow_make_links_data(const int type, Object *ob_src, Object *ob_dst)
+/* Return true if make link data is allowed, false otherwise */
+static bool allow_make_links_data(const int type, Object *ob_src, Object *ob_dst)
{
switch (type) {
case MAKE_LINKS_OBDATA:
- if (ob_src->type == ob_dst->type && ob_src->type != OB_EMPTY)
- return 1;
+ if (ob_src->type == ob_dst->type && ob_src->type != OB_EMPTY) {
+ return true;
+ }
break;
case MAKE_LINKS_MATERIALS:
- if (OB_TYPE_SUPPORT_MATERIAL(ob_src->type) &&
- OB_TYPE_SUPPORT_MATERIAL(ob_dst->type))
- {
- return 1;
+ if (OB_TYPE_SUPPORT_MATERIAL(ob_src->type) && OB_TYPE_SUPPORT_MATERIAL(ob_dst->type)) {
+ return true;
}
break;
case MAKE_LINKS_ANIMDATA:
case MAKE_LINKS_GROUP:
case MAKE_LINKS_DUPLIGROUP:
- return 1;
+ return true;
case MAKE_LINKS_MODIFIERS:
- if (ob_src->type != OB_EMPTY && ob_dst->type != OB_EMPTY)
- return 1;
+ if (!ELEM(OB_EMPTY, ob_src->type, ob_dst->type)) {
+ return true;
+ }
break;
case MAKE_LINKS_FONTS:
- if ((ob_src->data != ob_dst->data) &&
- (ob_src->type == OB_FONT) &&
- (ob_dst->type == OB_FONT))
- {
- return 1;
+ if ((ob_src->data != ob_dst->data) && (ob_src->type == OB_FONT) && (ob_dst->type == OB_FONT)) {
+ return true;
}
break;
}
- return 0;
+ return false;
}
static int make_links_data_exec(bContext *C, wmOperator *op)
@@ -1635,6 +1658,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op)
DAG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, CTX_wm_view3d(C));
WM_event_add_notifier(C, NC_OBJECT, NULL);
return OPERATOR_FINISHED;
@@ -1679,7 +1703,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/* identifiers */
ot->name = "Link Data";
- ot->description = "Make links from the active object to other selected objects";
+ ot->description = "Apply active object links to other selected objects";
ot->idname = "OBJECT_OT_make_links_data";
/* api callbacks */
@@ -1696,13 +1720,13 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot)
/**************************** Make Single User ********************************/
-static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, int flag, bool copy_groups)
+static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups)
{
Base *base;
Object *ob, *obn;
Group *group, *groupn;
GroupObject *go;
-
+
clear_sca_new_poins(); /* sensor/contr/act */
/* newid may still have some trash from Outliner tree building,
@@ -1713,7 +1737,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, int flag
/* duplicate (must set newid) */
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
-
+
if ((base->flag & flag) == flag) {
if (ob->id.lib == NULL && ob->id.us > 1) {
/* base gets copy of object */
@@ -1760,10 +1784,10 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, int flag
/* group pointers in scene */
BKE_scene_groups_relink(scene);
-
+
ID_NEW(scene->camera);
if (v3d) ID_NEW(v3d->camera);
-
+
/* object and group pointers */
for (base = FIRSTBASE; base; base = base->next) {
BKE_object_relink(base->object);
@@ -1777,7 +1801,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, int flag
void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
{
Base *base;
- bool copy_groups = false;
+ const bool copy_groups = false;
for (base = FIRSTBASE; base; base = base->next) {
if (base->object == ob) base->flag |= OB_DONE;
@@ -1787,11 +1811,11 @@ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob)
single_object_users(bmain, scene, NULL, OB_DONE, copy_groups);
}
-static void new_id_matar(Material **matar, int totcol)
+static void new_id_matar(Material **matar, const int totcol)
{
ID *id;
int a;
-
+
for (a = 0; a < totcol; a++) {
id = (ID *)matar[a];
if (id && id->lib == NULL) {
@@ -1809,12 +1833,12 @@ static void new_id_matar(Material **matar, int totcol)
}
}
-static void single_obdata_users(Main *bmain, Scene *scene, int flag)
+static void single_obdata_users(Main *bmain, Scene *scene, const int flag)
{
Object *ob;
Lamp *la;
Curve *cu;
- //Camera *cam;
+ /* Camera *cam; */
Base *base;
Mesh *me;
Lattice *lat;
@@ -1825,7 +1849,7 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
ob = base->object;
if (ob->id.lib == NULL && (base->flag & flag) == flag) {
id = ob->data;
-
+
if (id && id->us > 1 && id->lib == NULL) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -1886,12 +1910,10 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
id->us--;
id->newid = ob->data;
-
}
-
}
}
-
+
me = bmain->mesh.first;
while (me) {
ID_NEW(me->texcomesh);
@@ -1899,11 +1921,11 @@ static void single_obdata_users(Main *bmain, Scene *scene, int flag)
}
}
-static void single_object_action_users(Scene *scene, int flag)
+static void single_object_action_users(Scene *scene, const int flag)
{
Object *ob;
Base *base;
-
+
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
@@ -1913,27 +1935,26 @@ static void single_object_action_users(Scene *scene, int flag)
}
}
-static void single_mat_users(Scene *scene, int flag, int do_textures)
+static void single_mat_users(Scene *scene, const int flag, const bool do_textures)
{
Object *ob;
Base *base;
Material *ma, *man;
Tex *tex;
int a, b;
-
+
for (base = FIRSTBASE; base; base = base->next) {
ob = base->object;
if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) {
-
for (a = 1; a <= ob->totcol; a++) {
ma = give_current_material(ob, a);
if (ma) {
/* do not test for LIB_NEW: this functions guaranteed delivers single_users! */
-
+
if (ma->id.us > 1) {
man = BKE_material_copy(ma);
BKE_copy_animdata_id_action(&man->id);
-
+
man->id.us = 0;
assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF);
@@ -1959,10 +1980,10 @@ static void single_mat_users(Scene *scene, int flag, int do_textures)
static void do_single_tex_user(Tex **from)
{
Tex *tex, *texn;
-
+
tex = *from;
if (tex == NULL) return;
-
+
if (tex->id.newid) {
*from = (Tex *)tex->id.newid;
id_us_plus(tex->id.newid);
@@ -1984,7 +2005,7 @@ static void single_tex_users_expand(Main *bmain)
Lamp *la;
World *wo;
int b;
-
+
for (ma = bmain->mat.first; ma; ma = ma->id.next) {
if (ma->id.flag & LIB_NEW) {
for (b = 0; b < MAX_MTEX; b++) {
@@ -2025,7 +2046,7 @@ static void single_mat_users_expand(Main *bmain)
MetaBall *mb;
Material *ma;
int a;
-
+
for (ob = bmain->object.first; ob; ob = ob->id.next)
if (ob->id.flag & LIB_NEW)
new_id_matar(ob->mat, ob->totcol);
@@ -2051,7 +2072,7 @@ static void single_mat_users_expand(Main *bmain)
}
/* used for copying scenes */
-void ED_object_single_users(Main *bmain, Scene *scene, bool full, bool copy_groups)
+void ED_object_single_users(Main *bmain, Scene *scene, const bool full, const bool copy_groups)
{
single_object_users(bmain, scene, NULL, 0, copy_groups);
@@ -2072,13 +2093,13 @@ static void make_local_makelocalmaterial(Material *ma)
{
AnimData *adt;
int b;
-
+
id_make_local(&ma->id, false);
-
+
for (b = 0; b < MAX_MTEX; b++)
if (ma->mtex[b] && ma->mtex[b]->tex)
id_make_local(&ma->mtex[b]->tex->id, false);
-
+
adt = BKE_animdata_from_id(&ma->id);
if (adt) BKE_animdata_make_local(adt);
@@ -2086,13 +2107,13 @@ static void make_local_makelocalmaterial(Material *ma)
}
enum {
- MAKE_LOCAL_SELECT_OB,
- MAKE_LOCAL_SELECT_OBDATA,
- MAKE_LOCAL_SELECT_OBDATA_MATERIAL,
- MAKE_LOCAL_ALL
+ MAKE_LOCAL_SELECT_OB = 1,
+ MAKE_LOCAL_SELECT_OBDATA = 2,
+ MAKE_LOCAL_SELECT_OBDATA_MATERIAL = 3,
+ MAKE_LOCAL_ALL = 4,
};
-static bool tag_localizable_looper(void *UNUSED(user_data), ID **id_pointer, int UNUSED(cd_flag))
+static bool tag_localizable_looper(void *UNUSED(user_data), ID **id_pointer, const int UNUSED(cd_flag))
{
if (*id_pointer) {
(*id_pointer)->flag &= ~LIB_DOIT;
@@ -2100,7 +2121,7 @@ static bool tag_localizable_looper(void *UNUSED(user_data), ID **id_pointer, int
return true;
}
-static void tag_localizable_objects(bContext *C, int mode)
+static void tag_localizable_objects(bContext *C, const int mode)
{
Main *bmain = CTX_data_main(C);
Object *object;
@@ -2142,17 +2163,57 @@ static void tag_localizable_objects(bContext *C, int mode)
/* TODO(sergey): Drivers targets? */
}
+/**
+ * Instance indirectly referenced zero user objects,
+ * otherwise they're lost on reload, see T40595.
+ */
+static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene)
+{
+ Object *ob;
+ bool changed = false;
+
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->id.lib && (ob->id.us == 0)) {
+ Base *base;
+
+ ob->id.us = 1;
+
+ /* not essential, but for correctness */
+ id_lib_extern(&ob->id);
+
+ base = BKE_scene_base_add(scene, ob);
+ base->flag |= SELECT;
+ base->object->flag = base->flag;
+ DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME);
+
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
static int make_local_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
AnimData *adt;
ParticleSystem *psys;
Material *ma, ***matarar;
Lamp *la;
ID *id;
- int a, b, mode = RNA_enum_get(op->ptr, "type");
-
+ const int mode = RNA_enum_get(op->ptr, "type");
+ int a, b;
+
if (mode == MAKE_LOCAL_ALL) {
+ /* de-select so the user can differentiate newly instanced from existing objects */
+ BKE_scene_base_deselect_all(scene);
+
+ if (make_local_all__instance_indirect_unused(bmain, scene)) {
+ BKE_report(op->reports, RPT_INFO,
+ "Orphan library objects added to the current scene to avoid loss");
+ }
+
BKE_library_make_local(bmain, NULL, false); /* NULL is all libs */
WM_event_add_notifier(C, NC_WINDOW, NULL);
return OPERATOR_FINISHED;
@@ -2160,7 +2221,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
tag_localizable_objects(C, mode);
BKE_main_id_clear_newpoins(bmain);
-
+
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
if ((ob->id.flag & LIB_DOIT) == 0) {
@@ -2171,7 +2232,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
id_make_local(&ob->id, false);
}
CTX_DATA_END;
-
+
/* maybe object pointers */
CTX_DATA_BEGIN (C, Object *, ob, selected_objects)
{
@@ -2188,12 +2249,12 @@ static int make_local_exec(bContext *C, wmOperator *op)
}
id = ob->data;
-
+
if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) {
id_make_local(id, false);
adt = BKE_animdata_from_id(id);
if (adt) BKE_animdata_make_local(adt);
-
+
/* tag indirect data direct */
matarar = give_matarar(ob);
if (matarar) {
@@ -2233,7 +2294,7 @@ static int make_local_exec(bContext *C, wmOperator *op)
if (ma)
make_local_makelocalmaterial(ma);
}
-
+
matarar = (Material ***)give_matarar(ob);
if (matarar) {
for (a = 0; a < ob->totcol; a++) {
@@ -2266,26 +2327,33 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
ot->name = "Make Local";
ot->description = "Make library linked datablocks local to this file";
ot->idname = "OBJECT_OT_make_local";
-
+
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->exec = make_local_exec;
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-
+
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
}
+enum {
+ /* Be careful with those values, they are used as bitflags in some cases, in others as bool...
+ * See single_object_users, single_obdata_users, single_object_action_users, etc.< */
+ MAKE_SINGLE_USER_ALL = 0,
+ MAKE_SINGLE_USER_SELECTED = SELECT,
+};
+
static int make_single_user_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C); /* ok if this is NULL */
- int flag = RNA_enum_get(op->ptr, "type"); /* 0==ALL, SELECTED==selected objecs */
- bool copy_groups = false;
+ const int flag = RNA_enum_get(op->ptr, "type");
+ const bool copy_groups = false;
bool update_deps = false;
BKE_main_id_clear_newpoins(bmain);
@@ -2332,8 +2400,8 @@ static int make_single_user_exec(bContext *C, wmOperator *op)
void OBJECT_OT_make_single_user(wmOperatorType *ot)
{
static EnumPropertyItem type_items[] = {
- {SELECT, "SELECTED_OBJECTS", 0, "Selected Objects", ""},
- {0, "ALL", 0, "All", ""},
+ {MAKE_SINGLE_USER_SELECTED, "SELECTED_OBJECTS", 0, "Selected Objects", ""},
+ {MAKE_SINGLE_USER_ALL, "ALL", 0, "All", ""},
{0, NULL, 0, NULL, NULL}};
/* identifiers */
@@ -2355,7 +2423,8 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "object", 0, "Object", "Make single user objects");
RNA_def_boolean(ot->srna, "obdata", 0, "Object Data", "Make single user object data");
RNA_def_boolean(ot->srna, "material", 0, "Materials", "Make materials local to each datablock");
- RNA_def_boolean(ot->srna, "texture", 0, "Textures", "Make textures local to each material");
+ RNA_def_boolean(ot->srna, "texture", 0, "Textures",
+ "Make textures local to each material (needs 'Materials' to be set too)");
RNA_def_boolean(ot->srna, "animation", 0, "Object Animation", "Make animation data local to each object");
}
@@ -2364,17 +2433,20 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
Material *ma;
char name[MAX_ID_NAME - 2];
-
+
RNA_string_get(op->ptr, "name", name);
ma = (Material *)BKE_libblock_find_name(ID_MA, name);
if (base == NULL || ma == NULL)
return OPERATOR_CANCELLED;
-
+
assign_material(base->object, ma, 1, BKE_MAT_ASSIGN_USERPREF);
-
+
+ DAG_id_tag_update(&base->object->id, OB_RECALC_OB);
+
+ WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, base->object);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, CTX_wm_view3d(C));
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma);
-
+
return OPERATOR_FINISHED;
}
@@ -2382,19 +2454,70 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
/* assigns to object under cursor, only first material slot */
void OBJECT_OT_drop_named_material(wmOperatorType *ot)
{
-
/* identifiers */
ot->name = "Drop Named Material on Object";
ot->description = "";
ot->idname = "OBJECT_OT_drop_named_material";
-
+
/* api callbacks */
ot->invoke = drop_named_material_invoke;
ot->poll = ED_operator_objectmode;
-
+
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL;
-
+
/* properties */
RNA_def_string(ot->srna, "name", "Material", MAX_ID_NAME - 2, "Name", "Material name to assign");
}
+
+static int object_unlink_data_exec(bContext *C, wmOperator *op)
+{
+ ID *id;
+ PropertyPointerRNA pprop;
+
+ uiIDContextProperty(C, &pprop.ptr, &pprop.prop);
+
+ if (pprop.prop == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Incorrect context for running object data unlink");
+ return OPERATOR_CANCELLED;
+ }
+
+ id = pprop.ptr.id.data;
+
+ if (GS(id->name) == ID_OB) {
+ Object *ob = (Object *)id;
+ if (ob->data) {
+ ID *id_data = ob->data;
+
+ if (GS(id_data->name) == ID_IM) {
+ id_us_min(id_data);
+ ob->data = NULL;
+ }
+ else {
+ BKE_report(op->reports, RPT_ERROR, "Can't unlink this object data");
+ return OPERATOR_CANCELLED;
+ }
+ }
+ }
+
+ RNA_property_update(C, &pprop.ptr, pprop.prop);
+
+ return OPERATOR_FINISHED;
+}
+
+/**
+ * \note Only for empty-image objects, this operator is needed
+ */
+void OBJECT_OT_unlink_data(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Unlink";
+ ot->idname = "OBJECT_OT_unlink_data";
+ ot->description = "";
+
+ /* api callbacks */
+ ot->exec = object_unlink_data_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_INTERNAL;
+}
diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c
index b1a78407491..e295a63848a 100644
--- a/source/blender/editors/object/object_select.c
+++ b/source/blender/editors/object/object_select.c
@@ -315,22 +315,20 @@ static bool object_select_all_by_dup_group(bContext *C, Object *ob)
static bool object_select_all_by_particle(bContext *C, Object *ob)
{
+ ParticleSystem *psys_act = psys_get_current(ob);
bool changed = false;
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
if ((base->flag & SELECT) == 0) {
- /* loop through other, then actives particles*/
+ /* loop through other particles*/
ParticleSystem *psys;
- ParticleSystem *psys_act;
-
+
for (psys = base->object->particlesystem.first; psys; psys = psys->next) {
- for (psys_act = ob->particlesystem.first; psys_act; psys_act = psys_act->next) {
- if (psys->part == psys_act->part) {
- base->flag |= SELECT;
- changed = true;
- break;
- }
+ if (psys->part == psys_act->part) {
+ base->flag |= SELECT;
+ changed = true;
+ break;
}
if (base->flag & SELECT) {
@@ -512,21 +510,36 @@ void OBJECT_OT_select_linked(wmOperatorType *ot)
/*********************** Selected Grouped ********************/
+enum {
+ OBJECT_GRPSEL_CHILDREN_RECURSIVE = 0,
+ OBJECT_GRPSEL_CHILDREN = 1,
+ OBJECT_GRPSEL_PARENT = 2,
+ OBJECT_GRPSEL_SIBLINGS = 3,
+ OBJECT_GRPSEL_TYPE = 4,
+ OBJECT_GRPSEL_LAYER = 5,
+ OBJECT_GRPSEL_GROUP = 6,
+ OBJECT_GRPSEL_HOOK = 7,
+ OBJECT_GRPSEL_PASS = 8,
+ OBJECT_GRPSEL_COLOR = 9,
+ OBJECT_GRPSEL_PROPERTIES = 10,
+ OBJECT_GRPSEL_KEYINGSET = 11,
+ OBJECT_GRPSEL_LAMP_TYPE = 12,
+};
+
static EnumPropertyItem prop_select_grouped_types[] = {
- {1, "CHILDREN_RECURSIVE", 0, "Children", ""},
- {2, "CHILDREN", 0, "Immediate Children", ""},
- {3, "PARENT", 0, "Parent", ""},
- {4, "SIBLINGS", 0, "Siblings", "Shared Parent"},
- {5, "TYPE", 0, "Type", "Shared object type"},
- {6, "LAYER", 0, "Layer", "Shared layers"},
- {7, "GROUP", 0, "Group", "Shared group"},
- {8, "HOOK", 0, "Hook", ""},
- {9, "PASS", 0, "Pass", "Render pass Index"},
- {10, "COLOR", 0, "Color", "Object Color"},
- {11, "PROPERTIES", 0, "Properties", "Game Properties"},
- {12, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"},
- {13, "LAMP_TYPE", 0, "Lamp Type", "Matching lamp types"},
- {14, "PASS_INDEX", 0, "Pass Index", "Matching object pass index"},
+ {OBJECT_GRPSEL_CHILDREN_RECURSIVE, "CHILDREN_RECURSIVE", 0, "Children", ""},
+ {OBJECT_GRPSEL_CHILDREN, "CHILDREN", 0, "Immediate Children", ""},
+ {OBJECT_GRPSEL_PARENT, "PARENT", 0, "Parent", ""},
+ {OBJECT_GRPSEL_SIBLINGS, "SIBLINGS", 0, "Siblings", "Shared Parent"},
+ {OBJECT_GRPSEL_TYPE, "TYPE", 0, "Type", "Shared object type"},
+ {OBJECT_GRPSEL_LAYER, "LAYER", 0, "Layer", "Shared layers"},
+ {OBJECT_GRPSEL_GROUP, "GROUP", 0, "Group", "Shared group"},
+ {OBJECT_GRPSEL_HOOK, "HOOK", 0, "Hook", ""},
+ {OBJECT_GRPSEL_PASS, "PASS", 0, "Pass", "Render pass Index"},
+ {OBJECT_GRPSEL_COLOR, "COLOR", 0, "Color", "Object Color"},
+ {OBJECT_GRPSEL_PROPERTIES, "PROPERTIES", 0, "Properties", "Game Properties"},
+ {OBJECT_GRPSEL_KEYINGSET, "KEYINGSET", 0, "Keying Set", "Objects included in active Keying Set"},
+ {OBJECT_GRPSEL_LAMP_TYPE, "LAMP_TYPE", 0, "Lamp Type", "Matching lamp types"},
{0, NULL, 0, NULL, NULL}
};
@@ -658,7 +671,7 @@ static bool select_grouped_siblings(bContext *C, Object *ob)
CTX_DATA_END;
return changed;
}
-static bool select_similar_lamps(bContext *C, Object *ob)
+static bool select_grouped_lamptype(bContext *C, Object *ob)
{
Lamp *la = ob->data;
@@ -677,20 +690,6 @@ static bool select_similar_lamps(bContext *C, Object *ob)
CTX_DATA_END;
return changed;
}
-static bool select_similar_pass_index(bContext *C, Object *ob)
-{
- bool changed = false;
-
- CTX_DATA_BEGIN (C, Base *, base, selectable_bases)
- {
- if ((base->object->index == ob->index) && !(base->flag & SELECT)) {
- ED_base_object_select(base, BA_SELECT);
- changed = true;
- }
- }
- CTX_DATA_END;
- return changed;
-}
static bool select_grouped_type(bContext *C, Object *ob)
{
bool changed = false;
@@ -754,11 +753,11 @@ static bool select_grouped_color(bContext *C, Object *ob)
static bool objects_share_gameprop(Object *a, Object *b)
{
bProperty *prop;
- /*make a copy of all its properties*/
for (prop = a->prop.first; prop; prop = prop->next) {
- if (BKE_bproperty_object_get(b, prop->name) )
+ if (BKE_bproperty_object_get(b, prop->name)) {
return 1;
+ }
}
return 0;
}
@@ -778,14 +777,29 @@ static bool select_grouped_gameprops(bContext *C, Object *ob)
return changed;
}
-static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob))
+static bool select_grouped_keyingset(bContext *C, Object *UNUSED(ob), ReportList *reports)
{
KeyingSet *ks = ANIM_scene_get_active_keyingset(CTX_data_scene(C));
bool changed = false;
/* firstly, validate KeyingSet */
- if ((ks == NULL) || (ANIM_validate_keyingset(C, NULL, ks) != 0))
- return 0;
+ if (ks == NULL) {
+ BKE_report(reports, RPT_ERROR, "No active Keying Set to use");
+ return false;
+ }
+ else if (ANIM_validate_keyingset(C, NULL, ks) != 0) {
+ if (ks->paths.first == NULL) {
+ if ((ks->flag & KEYINGSET_ABSOLUTE) == 0) {
+ BKE_report(reports, RPT_ERROR,
+ "Use another Keying Set, as the active one depends on the currently "
+ "selected objects or cannot find any targets due to unsuitable context");
+ }
+ else {
+ BKE_report(reports, RPT_ERROR, "Keying Set does not contain any paths");
+ }
+ }
+ return false;
+ }
/* select each object that Keying Set refers to */
/* TODO: perhaps to be more in line with the rest of these, we should only take objects
@@ -818,11 +832,11 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *ob;
- int nr = RNA_enum_get(op->ptr, "type");
+ const int type = RNA_enum_get(op->ptr, "type");
bool changed = false, extend;
extend = RNA_boolean_get(op->ptr, "extend");
-
+
if (extend == 0) {
CTX_DATA_BEGIN (C, Base *, base, visible_bases)
{
@@ -831,38 +845,66 @@ static int object_select_grouped_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
}
-
+
ob = OBACT;
if (ob == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active object");
return OPERATOR_CANCELLED;
}
- if (nr == 13 && ob->type != OB_LAMP) {
- BKE_report(op->reports, RPT_ERROR, "Active object must be a lamp");
- return OPERATOR_CANCELLED;
+ switch (type) {
+ case OBJECT_GRPSEL_CHILDREN_RECURSIVE:
+ changed = select_grouped_children(C, ob, true);
+ break;
+ case OBJECT_GRPSEL_CHILDREN:
+ changed = select_grouped_children(C, ob, false);
+ break;
+ case OBJECT_GRPSEL_PARENT:
+ changed = select_grouped_parent(C);
+ break;
+ case OBJECT_GRPSEL_SIBLINGS:
+ changed = select_grouped_siblings(C, ob);
+ break;
+ case OBJECT_GRPSEL_TYPE:
+ changed = select_grouped_type(C, ob);
+ break;
+ case OBJECT_GRPSEL_LAYER:
+ changed = select_grouped_layer(C, ob);
+ break;
+ case OBJECT_GRPSEL_GROUP:
+ changed = select_grouped_group(C, ob);
+ break;
+ case OBJECT_GRPSEL_HOOK:
+ changed = select_grouped_object_hooks(C, ob);
+ break;
+ case OBJECT_GRPSEL_PASS:
+ changed = select_grouped_index_object(C, ob);
+ break;
+ case OBJECT_GRPSEL_COLOR:
+ changed = select_grouped_color(C, ob);
+ break;
+ case OBJECT_GRPSEL_PROPERTIES:
+ changed = select_grouped_gameprops(C, ob);
+ break;
+ case OBJECT_GRPSEL_KEYINGSET:
+ changed = select_grouped_keyingset(C, ob, op->reports);
+ break;
+ case OBJECT_GRPSEL_LAMP_TYPE:
+ if (ob->type != OB_LAMP) {
+ BKE_report(op->reports, RPT_ERROR, "Active object must be a lamp");
+ break;
+ }
+ changed = select_grouped_lamptype(C, ob);
+ break;
+ default:
+ break;
}
- if (nr == 1) changed |= select_grouped_children(C, ob, 1);
- else if (nr == 2) changed |= select_grouped_children(C, ob, 0);
- else if (nr == 3) changed |= select_grouped_parent(C);
- else if (nr == 4) changed |= select_grouped_siblings(C, ob);
- else if (nr == 5) changed |= select_grouped_type(C, ob);
- else if (nr == 6) changed |= select_grouped_layer(C, ob);
- else if (nr == 7) changed |= select_grouped_group(C, ob);
- else if (nr == 8) changed |= select_grouped_object_hooks(C, ob);
- else if (nr == 9) changed |= select_grouped_index_object(C, ob);
- else if (nr == 10) changed |= select_grouped_color(C, ob);
- else if (nr == 11) changed |= select_grouped_gameprops(C, ob);
- else if (nr == 12) changed |= select_grouped_keyingset(C, ob);
- else if (nr == 13) changed |= select_similar_lamps(C, ob);
- else if (nr == 14) changed |= select_similar_pass_index(C, ob);
-
if (changed) {
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
return OPERATOR_FINISHED;
}
-
+
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c
index 5dd20a76e28..4a24ab66721 100644
--- a/source/blender/editors/object/object_shapekey.c
+++ b/source/blender/editors/object/object_shapekey.c
@@ -301,6 +301,16 @@ static int shape_key_mode_exists_poll(bContext *C)
(BKE_keyblock_from_object(ob) != NULL);
}
+static int shape_key_move_poll(bContext *C)
+{
+ /* Same as shape_key_mode_exists_poll above, but ensure we have at least two shapes! */
+ Object *ob = ED_object_context(C);
+ ID *data = (ob) ? ob->data : NULL;
+ Key *key = BKE_key_from_object(ob);
+
+ return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey > 1);
+}
+
static int shape_key_poll(bContext *C)
{
Object *ob = ED_object_context(C);
@@ -334,7 +344,7 @@ void OBJECT_OT_shape_key_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- RNA_def_boolean(ot->srna, "from_mix", 1, "From Mix", "Create the new shape key from the existing mix of keys");
+ RNA_def_boolean(ot->srna, "from_mix", true, "From Mix", "Create the new shape key from the existing mix of keys");
}
static int shape_key_remove_exec(bContext *C, wmOperator *op)
@@ -482,51 +492,40 @@ void OBJECT_OT_shape_key_mirror(wmOperatorType *ot)
}
+enum {
+ KB_MOVE_TOP = -2,
+ KB_MOVE_UP = -1,
+ KB_MOVE_DOWN = 1,
+ KB_MOVE_BOTTOM = 2,
+};
+
static int shape_key_move_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
- int type = RNA_enum_get(op->ptr, "type");
Key *key = BKE_key_from_object(ob);
+ const int type = RNA_enum_get(op->ptr, "type");
+ const int totkey = key->totkey;
+ const int act_index = ob->shapenr - 1;
+ int new_index;
+
+ switch (type) {
+ case KB_MOVE_TOP:
+ /* Replace the ref key only if we're at the top already (only for relative keys) */
+ new_index = (ELEM(act_index, 0, 1) || key->type == KEY_NORMAL) ? 0 : 1;
+ break;
+ case KB_MOVE_BOTTOM:
+ new_index = totkey - 1;
+ break;
+ case KB_MOVE_UP:
+ case KB_MOVE_DOWN:
+ default:
+ new_index = (totkey + act_index + type) % totkey;
+ break;
+ }
- if (key) {
- KeyBlock *kb, *kb_other;
- int shapenr_act = ob->shapenr - 1;
- int shapenr_swap = shapenr_act + type;
- kb = BLI_findlink(&key->block, shapenr_act);
-
- if ((type == -1 && kb->prev == NULL) || (type == 1 && kb->next == NULL)) {
- return OPERATOR_CANCELLED;
- }
-
- for (kb_other = key->block.first; kb_other; kb_other = kb_other->next) {
- if (kb_other->relative == shapenr_act) {
- kb_other->relative += type;
- }
- else if (kb_other->relative == shapenr_swap) {
- kb_other->relative -= type;
- }
- }
-
- if (type == -1) {
- /* move back */
- kb_other = kb->prev;
- BLI_remlink(&key->block, kb);
- BLI_insertlinkbefore(&key->block, kb_other, kb);
- ob->shapenr--;
- }
- else {
- /* move next */
- kb_other = kb->next;
- BLI_remlink(&key->block, kb);
- BLI_insertlinkafter(&key->block, kb_other, kb);
- ob->shapenr++;
- }
-
- SWAP(float, kb_other->pos, kb->pos); /* for absolute shape keys */
-
- /* First key is refkey, matches interface and BKE_key_sort */
- key->refkey = key->block.first;
+ if (!BKE_keyblock_move(ob, act_index, new_index)) {
+ return OPERATOR_CANCELLED;
}
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
@@ -538,9 +537,11 @@ static int shape_key_move_exec(bContext *C, wmOperator *op)
void OBJECT_OT_shape_key_move(wmOperatorType *ot)
{
static EnumPropertyItem slot_move[] = {
- {-1, "UP", 0, "Up", ""},
- {1, "DOWN", 0, "Down", ""},
- {0, NULL, 0, NULL, NULL}
+ {KB_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
+ {KB_MOVE_UP, "UP", 0, "Up", ""},
+ {KB_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {KB_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
+ { 0, NULL, 0, NULL, NULL }
};
/* identifiers */
@@ -549,7 +550,7 @@ void OBJECT_OT_shape_key_move(wmOperatorType *ot)
ot->description = "Move the active shape key up/down in the list";
/* api callbacks */
- ot->poll = shape_key_mode_poll;
+ ot->poll = shape_key_move_poll;
ot->exec = shape_key_move_exec;
/* flags */
diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c
index 6e59f9f4aea..f19765a5344 100644
--- a/source/blender/editors/object/object_transform.c
+++ b/source/blender/editors/object/object_transform.c
@@ -385,7 +385,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
/* first check if we can execute */
CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects)
{
- if (ELEM6(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) {
+ if (ELEM(ob->type, OB_MESH, OB_ARMATURE, OB_LATTICE, OB_MBALL, OB_CURVE, OB_SURF)) {
ID *obdata = ob->data;
if (ID_REAL_USERS(obdata) > 1) {
BKE_reportf(reports, RPT_ERROR,
@@ -472,27 +472,12 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
/* apply to object data */
if (ob->type == OB_MESH) {
Mesh *me = ob->data;
- MVert *mvert;
- int a;
if (apply_scale)
multiresModifier_scale_disp(scene, ob);
/* adjust data */
- mvert = me->mvert;
- for (a = 0; a < me->totvert; a++, mvert++)
- mul_m4_v3(mat, mvert->co);
-
- if (me->key) {
- KeyBlock *kb;
-
- for (kb = me->key->block.first; kb; kb = kb->next) {
- float *fp = kb->data;
-
- for (a = 0; a < kb->totelem; a++, fp += 3)
- mul_m4_v3(mat, fp);
- }
- }
+ BKE_mesh_transform(me, mat, true);
/* update normals */
BKE_mesh_calc_normals(me);
@@ -502,45 +487,17 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l
}
else if (ob->type == OB_LATTICE) {
Lattice *lt = ob->data;
- BPoint *bp = lt->def;
- int a = lt->pntsu * lt->pntsv * lt->pntsw;
-
- while (a--) {
- mul_m4_v3(mat, bp->vec);
- bp++;
- }
+
+ BKE_lattice_transform(lt, mat, true);
}
else if (ob->type == OB_MBALL) {
MetaBall *mb = ob->data;
- ED_mball_transform(mb, mat);
+ BKE_mball_transform(mb, mat);
}
else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
Curve *cu = ob->data;
-
- Nurb *nu;
- BPoint *bp;
- BezTriple *bezt;
- int a;
-
scale = mat3_to_scale(rsmat);
-
- for (nu = cu->nurb.first; nu; nu = nu->next) {
- if (nu->type == CU_BEZIER) {
- a = nu->pntsu;
- for (bezt = nu->bezt; a--; bezt++) {
- mul_m4_v3(mat, bezt->vec[0]);
- mul_m4_v3(mat, bezt->vec[1]);
- mul_m4_v3(mat, bezt->vec[2]);
- bezt->radius *= scale;
- }
- BKE_nurb_handles_calc(nu);
- }
- else {
- a = nu->pntsu * nu->pntsv;
- for (bp = nu->bp; a--; bp++)
- mul_m4_v3(mat, bp->vec);
- }
- }
+ BKE_curve_transform_ex(cu, mat, true, scale);
}
else if (ob->type == OB_CAMERA) {
MovieClip *clip = BKE_object_movieclip_get(scene, ob, false);
@@ -784,7 +741,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
}
if (ctx_ob_act) {
- BLI_rotatelist_first(&ctx_data_list, (LinkData *)ctx_ob_act);
+ BLI_listbase_rotate_first(&ctx_data_list, (LinkData *)ctx_ob_act);
}
for (tob = bmain->object.first; tob; tob = tob->id.next) {
@@ -1017,7 +974,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
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); /* ommit translation part */
+ mul_mat3_m4_v3(ob_other->obmat, centn); /* 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 ccc3e2e8278..777bbabb6e8 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -62,6 +62,7 @@
#include "BKE_depsgraph.h"
#include "BKE_mesh_mapping.h"
#include "BKE_editmesh.h"
+#include "BKE_modifier.h"
#include "BKE_report.h"
#include "BKE_DerivedMesh.h"
#include "BKE_object_deform.h"
@@ -2301,7 +2302,6 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i
if (dvert_array)
MEM_freeN(dvert_array);
- BLI_SMALLSTACK_FREE(dv_stack);
/* not so efficient to get 'dvert_array' again just so unselected verts are NULL'd */
if (use_mirror) {
@@ -4324,26 +4324,67 @@ static int vgroup_do_remap(Object *ob, const char *name_array, wmOperator *op)
return OPERATOR_FINISHED;
}
-static int vgroup_sort(void *def_a_ptr, void *def_b_ptr)
+static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr)
{
- bDeformGroup *def_a = (bDeformGroup *)def_a_ptr;
- bDeformGroup *def_b = (bDeformGroup *)def_b_ptr;
+ const bDeformGroup *def_a = def_a_ptr;
+ const bDeformGroup *def_b = def_b_ptr;
return BLI_natstrcmp(def_a->name, def_b->name);
}
+/* Sorts the weight groups according to the bone hierarchy of the
+ associated armature (similar to how bones are ordered in the Outliner) */
+static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase)
+{
+ if (bonebase == NULL) {
+ Object *armobj = modifiers_isDeformedByArmature(ob);
+ if (armobj != NULL) {
+ bArmature *armature = armobj->data;
+ bonebase = &armature->bonebase;
+ }
+ }
+
+ if (bonebase != NULL) {
+ Bone *bone;
+ for (bone = bonebase->last; bone; bone = bone->prev) {
+ bDeformGroup *dg = defgroup_find_name(ob, bone->name);
+ vgroup_sort_bone_hierarchy(ob, &bone->childbase);
+
+ if (dg != NULL) {
+ BLI_remlink(&ob->defbase, dg);
+ BLI_addhead(&ob->defbase, dg);
+ }
+ }
+ }
+
+ return;
+}
+
+enum {
+ SORT_TYPE_NAME = 0,
+ SORT_TYPE_BONEHIERARCHY = 1
+};
+
static int vertex_group_sort_exec(bContext *C, wmOperator *op)
{
Object *ob = ED_object_context(C);
char *name_array;
int ret;
+ int sort_type = RNA_enum_get(op->ptr, "sort_type");
/*init remapping*/
name_array = vgroup_init_remap(ob);
/*sort vgroup names*/
- BLI_sortlist(&ob->defbase, vgroup_sort);
-
+ switch (sort_type) {
+ case SORT_TYPE_NAME:
+ BLI_sortlist(&ob->defbase, vgroup_sort_name);
+ break;
+ case SORT_TYPE_BONEHIERARCHY:
+ vgroup_sort_bone_hierarchy(ob, NULL);
+ break;
+ }
+
/*remap vgroup data to map to correct names*/
ret = vgroup_do_remap(ob, name_array, op);
@@ -4359,9 +4400,15 @@ static int vertex_group_sort_exec(bContext *C, wmOperator *op)
void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
{
+ static EnumPropertyItem vgroup_sort_type[] = {
+ {SORT_TYPE_NAME, "NAME", 0, "Name", ""},
+ {SORT_TYPE_BONEHIERARCHY, "BONE_HIERARCHY", 0, "Bone Hierarchy", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
ot->name = "Sort Vertex Groups";
ot->idname = "OBJECT_OT_vertex_group_sort";
- ot->description = "Sort vertex groups alphabetically";
+ ot->description = "Sort vertex groups";
/* api callbacks */
ot->poll = vertex_group_poll;
@@ -4369,6 +4416,8 @@ void OBJECT_OT_vertex_group_sort(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "sort_type", vgroup_sort_type, SORT_TYPE_NAME, "Sort type", "Sort type");
}
static int vgroup_move_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/physics/CMakeLists.txt b/source/blender/editors/physics/CMakeLists.txt
index 892d71befb4..40d555226f3 100644
--- a/source/blender/editors/physics/CMakeLists.txt
+++ b/source/blender/editors/physics/CMakeLists.txt
@@ -23,11 +23,13 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/elbeem/extern
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -64,4 +66,6 @@ if(WITH_BULLET)
add_definitions(-DWITH_BULLET)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_physics "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/physics/SConscript b/source/blender/editors/physics/SConscript
index 9436280de43..983d1c4b4ba 100644
--- a/source/blender/editors/physics/SConscript
+++ b/source/blender/editors/physics/SConscript
@@ -31,20 +31,22 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/rigidbody',
- '#/extern/glew/include',
'#/intern/elbeem/extern',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 3c6bdf86a50..9a3433b0ccf 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -319,7 +319,7 @@ void PE_hide_keys_time(Scene *scene, PTCacheEdit *edit, float cfra)
if (pset->flag & PE_FADE_TIME && pset->selectmode==SCE_SELECT_POINT) {
LOOP_POINTS {
LOOP_KEYS {
- if (fabs(cfra-*key->time) < pset->fade_frames)
+ if (fabsf(cfra - *key->time) < pset->fade_frames)
key->flag &= ~PEK_HIDE;
else {
key->flag |= PEK_HIDE;
@@ -463,7 +463,7 @@ static bool key_inside_circle(PEData *data, float rad, const float co[3], float
dx= data->mval[0] - screen_co[0];
dy= data->mval[1] - screen_co[1];
- dist= sqrt(dx*dx + dy*dy);
+ dist = sqrtf(dx * dx + dy * dy);
if (dist > rad)
return 0;
@@ -616,7 +616,10 @@ static void foreach_mouse_hit_key(PEData *data, ForKeyMatFunc func, int selected
ParticleSystemModifierData *psmd = NULL;
ParticleEditSettings *pset= PE_settings(data->scene);
POINT_P; KEY_K;
- float mat[4][4] = MAT4_UNITY, imat[4][4] = MAT4_UNITY;
+ float mat[4][4], imat[4][4];
+
+ unit_m4(mat);
+ unit_m4(imat);
if (edit->psys)
psmd= psys_get_modifier(data->ob, edit->psys);
@@ -1585,6 +1588,87 @@ void PARTICLE_OT_select_tips(wmOperatorType *ot)
WM_operator_properties_select_action(ot, SEL_SELECT);
}
+/*********************** select random operator ************************/
+
+enum { RAN_HAIR, RAN_POINTS };
+
+static EnumPropertyItem select_random_type_items[] = {
+ {RAN_HAIR, "HAIR", 0, "Hair", ""},
+ {RAN_POINTS, "POINTS", 0, "Points", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static int select_random_exec(bContext *C, wmOperator *op)
+{
+ PEData data;
+ int type;
+ Scene *scene;
+ Object *ob;
+
+ /* used by LOOP_VISIBLE_POINTS, LOOP_VISIBLE_KEYS and LOOP_KEYS */
+ PTCacheEdit *edit;
+ PTCacheEditPoint *point;
+ PTCacheEditKey *key;
+ int p;
+ int k;
+
+ const float randf = RNA_float_get (op->ptr, "percent") / 100.0f;
+
+ type = RNA_enum_get(op->ptr, "type");
+
+ PE_set_data(C, &data);
+ data.select_action = SEL_SELECT;
+ scene = CTX_data_scene(C);
+ ob = CTX_data_active_object(C);
+ edit = PE_get_current(scene, ob);
+
+ switch (type) {
+ case RAN_HAIR:
+ LOOP_VISIBLE_POINTS {
+ int flag = (BLI_frand() < randf) ? SEL_SELECT : SEL_DESELECT;
+ LOOP_KEYS {
+ select_action_apply (point, key, flag);
+ }
+ }
+ break;
+ case RAN_POINTS:
+ LOOP_VISIBLE_POINTS {
+ LOOP_VISIBLE_KEYS {
+ int flag = (BLI_frand() < randf) ? SEL_SELECT : SEL_DESELECT;
+ select_action_apply (point, key, flag);
+ }
+ }
+ break;
+ }
+
+ PE_update_selection(data.scene, data.ob, 1);
+ WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_SELECTED, data.ob);
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_select_random(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Select Random";
+ ot->idname = "PARTICLE_OT_select_random";
+ ot->description = "Select a randomly distributed set of hair or points";
+
+ /* api callbacks */
+ ot->exec = select_random_exec;
+ ot->poll = PE_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_float_percentage (ot->srna, "percent", 50.0f, 0.0f, 100.0f, "Percent",
+ "Percentage (mean) of elements in randomly selected set",
+ 0.0f, 100.0f);
+ ot->prop = RNA_def_enum (ot->srna, "type", select_random_type_items, RAN_HAIR,
+ "Type", "Select either hair or points");
+}
+
/************************ select linked operator ************************/
static int select_linked_exec(bContext *C, wmOperator *op)
@@ -1710,11 +1794,13 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
POINT_P; KEY_K;
- float co[3], mat[4][4] = MAT4_UNITY;
+ float co[3], mat[4][4];
int screen_co[2];
PEData data;
+ unit_m4(mat);
+
if (!PE_start_edit(edit))
return OPERATOR_CANCELLED;
@@ -2927,7 +3013,7 @@ static void brush_cut(PEData *data, int pa_index)
d= dv * rad2 - d*d;
if (d > 0.0f) {
- d= sqrt(d);
+ d= sqrtf(d);
cut_time= -(v0*xo0 + v1*xo1 + d);
@@ -3482,7 +3568,7 @@ static int brush_add(PEData *data, short number)
}
pa->size= 1.0f;
- initialize_particle(pa);
+ initialize_particle(&sim, pa);
reset_particle(&sim, pa, 0.0, 1.0);
point->flag |= PEP_EDIT_RECALC;
if (pe_x_mirror(ob))
@@ -3673,7 +3759,7 @@ static void brush_edit_apply(bContext *C, wmOperator *op, PointerRNA *itemptr)
pset->flag &= ~PE_LOCK_FIRST;
if (((pset->brushtype == PE_BRUSH_ADD) ?
- (sqrt(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0)) || bedit->first)
+ (sqrtf(dx * dx + dy * dy) > pset->brush[PE_BRUSH_ADD].step) : (dx != 0 || dy != 0)) || bedit->first)
{
PEData data= bedit->data;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 25bc2aeed07..5a61f77e5a8 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -633,7 +633,8 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
HairKey *key;
BVHTreeFromMesh bvhtree= {NULL};
BVHTreeNearest nearest;
- MFace *mface, *mf;
+ MFace *mface = NULL, *mf;
+ MEdge *medge = NULL, *me;
MVert *mvert;
DerivedMesh *dm = NULL;
int numverts;
@@ -663,13 +664,23 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
numverts = dm->getNumVerts(dm);
mvert = dm->getVertArray(dm);
- mface = dm->getTessFaceArray(dm);
/* convert to global coordinates */
for (i=0; i<numverts; i++)
mul_m4_v3(ob->obmat, mvert[i].co);
- bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
+ if (dm->getNumTessFaces(dm) != 0) {
+ mface = dm->getTessFaceArray(dm);
+ bvhtree_from_mesh_faces(&bvhtree, dm, 0.0, 2, 6);
+ }
+ else if (dm->getNumEdges(dm) != 0) {
+ medge = dm->getEdgeArray(dm);
+ bvhtree_from_mesh_edges(&bvhtree, dm, 0.0, 2, 6);
+ }
+ else {
+ dm->release(dm);
+ return false;
+ }
for (i=0, pa= psys->particles; i<psys->totpart; i++, pa++) {
key = pa->hair;
@@ -685,21 +696,35 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
continue;
}
- mf = &mface[nearest.index];
+ if (mface) {
+ mf = &mface[nearest.index];
+
+ copy_v3_v3(v[0], mvert[mf->v1].co);
+ copy_v3_v3(v[1], mvert[mf->v2].co);
+ copy_v3_v3(v[2], mvert[mf->v3].co);
+ if (mf->v4) {
+ copy_v3_v3(v[3], mvert[mf->v4].co);
+ interp_weights_poly_v3(pa->fuv, v, 4, nearest.co);
+ }
+ else
+ interp_weights_poly_v3(pa->fuv, v, 3, nearest.co);
+
+ pa->num = nearest.index;
+ pa->num_dmcache = psys_particle_dm_face_lookup(ob, psmd->dm, pa->num, pa->fuv, NULL);
+ }
+ else {
+ me = &medge[nearest.index];
+
+ pa->fuv[1] = line_point_factor_v3(nearest.co,
+ mvert[me->v2].co,
+ mvert[me->v2].co);
+ pa->fuv[0] = 1.0f - pa->fuv[1];
+ pa->fuv[2] = pa->fuv[3] = 0.0f;
- copy_v3_v3(v[0], mvert[mf->v1].co);
- copy_v3_v3(v[1], mvert[mf->v2].co);
- copy_v3_v3(v[2], mvert[mf->v3].co);
- if (mf->v4) {
- copy_v3_v3(v[3], mvert[mf->v4].co);
- interp_weights_poly_v3(pa->fuv, v, 4, nearest.co);
+ pa->num = nearest.index;
+ pa->num_dmcache = -1;
}
- else
- interp_weights_poly_v3(pa->fuv, v, 3, nearest.co);
- pa->num = nearest.index;
- pa->num_dmcache = psys_particle_dm_face_lookup(ob, psmd->dm, pa->num, pa->fuv, NULL);
-
psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
invert_m4_m4(imat, hairmat);
diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c
index 7c49319139b..fb224da6ec4 100644
--- a/source/blender/editors/physics/physics_fluid.c
+++ b/source/blender/editors/physics/physics_fluid.c
@@ -1067,8 +1067,8 @@ static int fluidsimBake(bContext *C, ReportList *reports, Object *fsDomain, shor
WM_jobs_start(CTX_wm_manager(C), wm_job);
}
else {
- short dummy_stop, dummy_do_update;
- float dummy_progress;
+ short dummy_stop = 0, dummy_do_update = 0;
+ float dummy_progress = 0.0f;
/* blocking, use with exec() */
fluidbake_startjob((void *)fb, &dummy_stop, &dummy_do_update, &dummy_progress);
@@ -1259,4 +1259,4 @@ void MANTA_OT_stop_sim(wmOperatorType *ot)
ot->invoke = manta_stop_sim_invoke;
ot->exec = manta_stop_sim_exec;
ot->poll = ED_operator_object_active_editable;
-} \ No newline at end of file
+}
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 2826782c762..7668a850951 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -39,6 +39,7 @@ struct wmOperatorType;
void PARTICLE_OT_select_all(struct wmOperatorType *ot);
void PARTICLE_OT_select_roots(struct wmOperatorType *ot);
void PARTICLE_OT_select_tips(struct wmOperatorType *ot);
+void PARTICLE_OT_select_random(struct wmOperatorType *ot);
void PARTICLE_OT_select_linked(struct wmOperatorType *ot);
void PARTICLE_OT_select_less(struct wmOperatorType *ot);
void PARTICLE_OT_select_more(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index cb4bd5e4dff..1038e8b64e3 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -51,6 +51,7 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_select_all);
WM_operatortype_append(PARTICLE_OT_select_roots);
WM_operatortype_append(PARTICLE_OT_select_tips);
+ WM_operatortype_append(PARTICLE_OT_select_random);
WM_operatortype_append(PARTICLE_OT_select_linked);
WM_operatortype_append(PARTICLE_OT_select_less);
WM_operatortype_append(PARTICLE_OT_select_more);
diff --git a/source/blender/editors/physics/rigidbody_object.c b/source/blender/editors/physics/rigidbody_object.c
index 7ba37bbb76b..13a3d7a523f 100644
--- a/source/blender/editors/physics/rigidbody_object.c
+++ b/source/blender/editors/physics/rigidbody_object.c
@@ -100,10 +100,6 @@ bool ED_rigidbody_object_add(Scene *scene, Object *ob, int type, ReportList *rep
BKE_report(reports, RPT_ERROR, "Can't add Rigid Body to non mesh object");
return false;
}
- if (((Mesh *)ob->data)->totpoly == 0) {
- BKE_report(reports, RPT_ERROR, "Can't create Rigid Body from mesh with no polygons");
- return false;
- }
/* Add rigid body world and group if they don't exist for convenience */
if (rbw == NULL) {
@@ -489,78 +485,6 @@ static EnumPropertyItem *rigidbody_materials_itemf(bContext *UNUSED(C), PointerR
/* ------------------------------------------ */
-/* helper function to calculate volume of rigidbody object */
-// TODO: allow a parameter to specify method used to calculate this?
-static float rigidbody_object_calc_volume(Object *ob)
-{
- RigidBodyOb *rbo = ob->rigidbody_object;
-
- float size[3] = {1.0f, 1.0f, 1.0f};
- float radius = 1.0f;
- float height = 1.0f;
-
- float volume = 0.0f;
-
- /* if automatically determining dimensions, use the Object's boundbox
- * - assume that all quadrics are standing upright on local z-axis
- * - assume even distribution of mass around the Object's pivot
- * (i.e. Object pivot is centralised in boundbox)
- * - boundbox gives full width
- */
- // XXX: all dimensions are auto-determined now... later can add stored settings for this
- BKE_object_dimensions_get(ob, size);
-
- if (ELEM3(rbo->shape, RB_SHAPE_CAPSULE, RB_SHAPE_CYLINDER, RB_SHAPE_CONE)) {
- /* take radius as largest x/y dimension, and height as z-dimension */
- radius = MAX2(size[0], size[1]) * 0.5f;
- height = size[2];
- }
- else if (rbo->shape == RB_SHAPE_SPHERE) {
- /* take radius to the the largest dimension to try and encompass everything */
- radius = max_fff(size[0], size[1], size[2]) * 0.5f;
- }
-
- /* calculate volume as appropriate */
- switch (rbo->shape) {
- case RB_SHAPE_BOX:
- volume = size[0] * size[1] * size[2];
- break;
-
- case RB_SHAPE_SPHERE:
- volume = 4.0f / 3.0f * (float)M_PI * radius * radius * radius;
- break;
-
- /* for now, assume that capsule is close enough to a cylinder... */
- case RB_SHAPE_CAPSULE:
- case RB_SHAPE_CYLINDER:
- volume = (float)M_PI * radius * radius * height;
- break;
-
- case RB_SHAPE_CONE:
- volume = (float)M_PI / 3.0f * radius * radius * height;
- break;
-
- /* for now, all mesh shapes are just treated as boxes...
- * NOTE: this may overestimate the volume, but other methods are overkill
- */
- case RB_SHAPE_CONVEXH:
- case RB_SHAPE_TRIMESH:
- volume = size[0] * size[1] * size[2];
- break;
-
-#if 0 // XXX: not defined yet
- case RB_SHAPE_COMPOUND:
- volume = 0.0f;
- break;
-#endif
- }
-
- /* return the volume calculated */
- return volume;
-}
-
-/* ------------------------------------------ */
-
static int rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op)
{
int material = RNA_enum_get(op->ptr, "material");
@@ -593,7 +517,7 @@ static int rigidbody_objects_calc_mass_exec(bContext *C, wmOperator *op)
/* mass is calculated from the approximate volume of the object,
* and the density of the material we're simulating
*/
- volume = rigidbody_object_calc_volume(ob);
+ BKE_rigidbody_calc_volume(ob, &volume);
mass = volume * density;
/* use RNA-system to change the property and perform all necessary changes */
diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt
index 24015bd4ea3..42dafc076ed 100644
--- a/source/blender/editors/render/CMakeLists.txt
+++ b/source/blender/editors/render/CMakeLists.txt
@@ -32,6 +32,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -64,6 +65,8 @@ if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
endif()
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_FREESTYLE)
list(APPEND INC
../../freestyle
diff --git a/source/blender/editors/render/SConscript b/source/blender/editors/render/SConscript
index 41576f9b485..cbb7988695b 100644
--- a/source/blender/editors/render/SConscript
+++ b/source/blender/editors/render/SConscript
@@ -31,7 +31,8 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/elbeem/extern',
'../include',
'../../blenfont',
@@ -48,7 +49,7 @@ incs = [
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.h
index 8f8cc542821..f9377d576bf 100644
--- a/source/blender/editors/render/render_intern.h
+++ b/source/blender/editors/render/render_intern.h
@@ -72,6 +72,7 @@ void SCENE_OT_freestyle_geometry_modifier_add(struct wmOperatorType *ot);
void SCENE_OT_freestyle_modifier_remove(struct wmOperatorType *ot);
void SCENE_OT_freestyle_modifier_move(struct wmOperatorType *ot);
void SCENE_OT_freestyle_modifier_copy(struct wmOperatorType *ot);
+void SCENE_OT_freestyle_stroke_material_create(struct wmOperatorType *ot);
#endif
diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c
index 9fa312884da..baf25a49f7c 100644
--- a/source/blender/editors/render/render_internal.c
+++ b/source/blender/editors/render/render_internal.c
@@ -35,6 +35,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_threads.h"
#include "BLI_utildefines.h"
#include "PIL_time.h"
@@ -316,10 +317,12 @@ static int screen_render_exec(bContext *C, wmOperator *op)
RE_SetReports(re, op->reports);
+ BLI_begin_threaded_malloc();
if (is_animation)
RE_BlenderAnim(re, mainp, scene, camera_override, lay_override, scene->r.sfra, scene->r.efra, scene->r.frame_step);
else
RE_BlenderFrame(re, mainp, scene, srl, camera_override, lay_override, scene->r.cfra, is_write_still);
+ BLI_end_threaded_malloc();
RE_SetReports(re, NULL);
@@ -1026,6 +1029,10 @@ typedef struct RenderPreview {
RenderEngine *engine;
float viewmat[4][4];
+
+ int start_resolution_divider;
+ int resolution_divider;
+ bool has_freestyle;
} RenderPreview;
static int render_view3d_disprect(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D *rv3d, rcti *disprect)
@@ -1121,19 +1128,52 @@ static void render_view3d_renderinfo_cb(void *rjp, RenderStats *rs)
}
}
+BLI_INLINE void rcti_scale_coords(rcti *scaled_rect, const rcti *rect,
+ const float scale)
+{
+ scaled_rect->xmin = rect->xmin * scale;
+ scaled_rect->ymin = rect->ymin * scale;
+ scaled_rect->xmax = rect->xmax * scale;
+ scaled_rect->ymax = rect->ymax * scale;
+}
+
+static void render_update_resolution(Render *re, const RenderPreview *rp,
+ bool use_border, const rcti *clip_rect)
+{
+ int winx = rp->ar->winx / rp->resolution_divider,
+ winy = rp->ar->winy / rp->resolution_divider;
+ if (use_border) {
+ rcti scaled_cliprct;
+ rcti_scale_coords(&scaled_cliprct, clip_rect,
+ 1.0f / rp->resolution_divider);
+ RE_ChangeResolution(re, winx, winy, &scaled_cliprct);
+ }
+ else {
+ RE_ChangeResolution(re, winx, winy, NULL);
+ }
+
+ if (rp->has_freestyle) {
+ if (rp->resolution_divider == 1) {
+ RE_ChangeModeFlag(re, R_EDGE_FRS, false);
+ }
+ else {
+ RE_ChangeModeFlag(re, R_EDGE_FRS, true);
+ }
+ }
+}
static void render_view3d_startjob(void *customdata, short *stop, short *do_update, float *UNUSED(progress))
{
RenderPreview *rp = customdata;
Render *re;
RenderStats *rstats;
- RenderData rdata;
rctf viewplane;
rcti cliprct;
float clipsta, clipend, pixsize;
bool orth, restore = 0;
char name[32];
int update_flag;
+ bool use_border;
update_flag = rp->engine->job_update_flag;
rp->engine->job_update_flag = 0;
@@ -1161,18 +1201,37 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
rstats = RE_GetStats(re);
+ if (update_flag & PR_UPDATE_VIEW) {
+ Object *object;
+ rp->resolution_divider = rp->start_resolution_divider;
+
+ /* Same as database_init_objects(), loop over all objects.
+ * We might consider de-duplicating the code between this two cases.
+ */
+ for (object = rp->bmain->object.first; object; object = object->id.next) {
+ float mat[4][4];
+ mul_m4_m4m4(mat, rp->viewmat, object->obmat);
+ invert_m4_m4(object->imat_ren, mat);
+ }
+ }
+
+ use_border = render_view3d_disprect(rp->scene, rp->ar, rp->v3d,
+ rp->rv3d, &cliprct);
+
if ((update_flag & (PR_UPDATE_RENDERSIZE | PR_UPDATE_DATABASE)) || rstats->convertdone == 0) {
+ RenderData rdata;
+
/* no osa, blur, seq, layers, 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_VIEWPORT_PREVIEW;
-
+
/* we do use layers, but only active */
rdata.scemode |= R_SINGLE_LAYER;
/* initalize always */
- if (render_view3d_disprect(rp->scene, rp->ar, rp->v3d, rp->rv3d, &cliprct)) {
+ if (use_border) {
rdata.mode |= R_BORDER;
RE_InitState(re, NULL, &rdata, NULL, rp->ar->winx, rp->ar->winy, &cliprct);
}
@@ -1225,8 +1284,34 @@ static void render_view3d_startjob(void *customdata, short *stop, short *do_upda
/* OK, can we enter render code? */
if (rstats->convertdone) {
- RE_TileProcessor(re);
-
+ bool first_time = true;
+ for (;;) {
+ if (first_time == false) {
+ if (restore)
+ RE_DataBase_IncrementalView(re, rp->viewmat, 1);
+
+ rp->resolution_divider /= 2;
+ *do_update = 1;
+
+ render_update_resolution(re, rp, use_border, &cliprct);
+
+ RE_DataBase_IncrementalView(re, rp->viewmat, 0);
+ RE_DataBase_ApplyWindow(re);
+ restore = 1;
+ }
+ else {
+ render_update_resolution(re, rp, use_border, &cliprct);
+ }
+
+ RE_TileProcessor(re);
+
+ first_time = false;
+
+ if (*stop || rp->resolution_divider == 1) {
+ break;
+ }
+ }
+
/* always rotate back */
if (restore)
RE_DataBase_IncrementalView(re, rp->viewmat, 1);
@@ -1322,7 +1407,12 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
wmJob *wm_job;
RenderPreview *rp;
Scene *scene = CTX_data_scene(C);
-
+ ARegion *ar = CTX_wm_region(C);
+ int width = ar->winx, height = ar->winy;
+ int divider = 1;
+ int resolution_threshold = scene->r.preview_start_resolution *
+ scene->r.preview_start_resolution;
+
if (CTX_wm_window(C) == NULL)
return;
if (!render_view3d_flag_changed(engine, C))
@@ -1333,6 +1423,12 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
rp = MEM_callocN(sizeof(RenderPreview), "render preview");
rp->job = wm_job;
+ while (width * height > resolution_threshold) {
+ width = max_ii(1, width / 2);
+ height = max_ii(1, height / 2);
+ divider *= 2;
+ }
+
/* customdata for preview thread */
rp->scene = scene;
rp->engine = engine;
@@ -1341,6 +1437,9 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C)
rp->v3d = rp->sa->spacedata.first;
rp->rv3d = CTX_wm_region_view3d(C);
rp->bmain = CTX_data_main(C);
+ rp->resolution_divider = divider;
+ rp->start_resolution_divider = divider;
+ rp->has_freestyle = scene->r.mode & R_EDGE_FRS;
copy_m4_m4(rp->viewmat, rp->rv3d->viewmat);
/* clear info text */
@@ -1385,24 +1484,42 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
RE_AcquireResultImage(re, &rres);
if (rres.rectf) {
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ View3D *v3d = CTX_wm_view3d(C);
Scene *scene = CTX_data_scene(C);
+ ARegion *ar = CTX_wm_region(C);
bool force_fallback = false;
bool need_fallback = true;
float dither = scene->r.dither_intensity;
-
- /* Dithering is not supported on GLSL yet */
- force_fallback |= dither != 0.0f;
+ float scale_x, scale_y;
+ rcti clip_rect;
+ int xof, yof;
+
+ if (render_view3d_disprect(scene, ar, v3d, rv3d, &clip_rect)) {
+ scale_x = (float) BLI_rcti_size_x(&clip_rect) / rres.rectx;
+ scale_y = (float) BLI_rcti_size_y(&clip_rect) / rres.recty;
+ xof = clip_rect.xmin;
+ yof = clip_rect.ymin;
+ }
+ else {
+ scale_x = (float) ar->winx / rres.rectx;
+ scale_y = (float) ar->winy / rres.recty;
+ xof = rres.xof;
+ yof = rres.yof;
+ }
/* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */
force_fallback |= (U.image_draw_method != IMAGE_DRAW_METHOD_GLSL);
/* Try using GLSL display transform. */
if (force_fallback == false) {
- if (IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, 0.0f, true)) {
+ if (IMB_colormanagement_setup_glsl_draw(&scene->view_settings, &scene->display_settings, dither, true)) {
glEnable(GL_BLEND);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- glaDrawPixelsTex(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_FLOAT,
- GL_NEAREST, rres.rectf);
+ glPixelZoom(scale_x, scale_y);
+ glaDrawPixelsTex(xof, yof, rres.rectx, rres.recty,
+ GL_RGBA, GL_FLOAT, GL_NEAREST, rres.rectf);
+ glPixelZoom(1.0f, 1.0f);
glDisable(GL_BLEND);
IMB_colormanagement_finish_glsl_draw();
@@ -1420,8 +1537,11 @@ void render_view3d_draw(RenderEngine *engine, const bContext *C)
glEnable(GL_BLEND);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- glaDrawPixelsAuto(rres.xof, rres.yof, rres.rectx, rres.recty, GL_RGBA, GL_UNSIGNED_BYTE,
+ glPixelZoom(scale_x, scale_y);
+ glaDrawPixelsAuto(xof, yof, rres.rectx, rres.recty,
+ GL_RGBA, GL_UNSIGNED_BYTE,
GL_NEAREST, display_buffer);
+ glPixelZoom(1.0f, 1.0f);
glDisable(GL_BLEND);
MEM_freeN(display_buffer);
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index c1f8dd89f71..559c86bf48c 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -31,11 +31,10 @@
#include <string.h>
#include <stddef.h>
-#include <GL/glew.h>
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
+#include "BLI_math_color_blend.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
#include "BLI_jitter.h"
@@ -57,6 +56,7 @@
#include "ED_screen.h"
#include "ED_view3d.h"
+#include "ED_gpencil.h"
#include "RE_pipeline.h"
#include "IMB_imbuf_types.h"
@@ -67,6 +67,7 @@
#include "RNA_define.h"
#include "GPU_extensions.h"
+#include "GPU_glew.h"
#include "wm_window.h"
@@ -139,7 +140,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
if (oglrender->is_sequencer) {
SeqRenderData context;
- int chanshown = oglrender->sseq ? oglrender->sseq->chanshown : 0;
+ SpaceSeq *sseq = oglrender->sseq;
+ int chanshown = sseq ? sseq->chanshown : 0;
+ struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_SHOW_GPENCIL)) ? sseq->gpd : NULL;
context = BKE_sequencer_new_render_data(oglrender->bmain->eval_ctx, oglrender->bmain,
scene, oglrender->sizex, oglrender->sizey, 100.0f);
@@ -171,6 +174,33 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
IMB_freeImBuf(linear_ibuf);
}
+
+ if (gpd) {
+ int i;
+ unsigned char *gp_rect;
+
+ GPU_offscreen_bind(oglrender->ofs);
+
+ glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ wmOrtho2(0, sizex, 0, sizey);
+ glTranslatef(sizex / 2, sizey / 2, 0.0f);
+
+ ED_gpencil_draw_ex(gpd, sizex, sizey, scene->r.cfra);
+
+ gp_rect = MEM_mallocN(sizex * sizey * sizeof(unsigned char) * 4, "offscreen rect");
+ GPU_offscreen_read_pixels(oglrender->ofs, GL_UNSIGNED_BYTE, gp_rect);
+
+ 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);
+ }
+ GPU_offscreen_unbind(oglrender->ofs);
+
+ MEM_freeN(gp_rect);
+ }
}
else if (view_context) {
ED_view3d_draw_offscreen_init(scene, v3d);
@@ -340,20 +370,24 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op)
return false;
}
- /* ensure we have a 3d view */
+ /* only one render job at a time */
+ if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER))
+ return false;
- if (!ED_view3d_context_activate(C)) {
- RNA_boolean_set(op->ptr, "view_context", false);
+ if (is_sequencer) {
is_view_context = false;
}
+ else {
+ /* ensure we have a 3d view */
+ if (!ED_view3d_context_activate(C)) {
+ RNA_boolean_set(op->ptr, "view_context", false);
+ is_view_context = false;
+ }
- /* only one render job at a time */
- if (WM_jobs_test(wm, scene, WM_JOB_TYPE_RENDER))
- return false;
-
- if (!is_view_context && scene->camera == NULL) {
- BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
- return false;
+ if (!is_view_context && scene->camera == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Scene has no camera");
+ return false;
+ }
}
if (!is_animation && is_write_still && BKE_imtype_is_movie(scene->r.im_format.imtype)) {
diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.c
index 3401577ee55..0d334082a2b 100644
--- a/source/blender/editors/render/render_ops.c
+++ b/source/blender/editors/render/render_ops.c
@@ -75,6 +75,7 @@ void ED_operatortypes_render(void)
WM_operatortype_append(SCENE_OT_freestyle_modifier_remove);
WM_operatortype_append(SCENE_OT_freestyle_modifier_move);
WM_operatortype_append(SCENE_OT_freestyle_modifier_copy);
+ WM_operatortype_append(SCENE_OT_freestyle_stroke_material_create);
#endif
WM_operatortype_append(TEXTURE_OT_slot_copy);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 4c34c4edba9..450a3b19889 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -88,6 +88,7 @@
#include "PIL_time.h"
#include "RE_pipeline.h"
+#include "RE_engine.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -213,6 +214,12 @@ void ED_preview_init_dbase(void)
#endif
}
+static bool check_engine_supports_textures(Scene *scene)
+{
+ RenderEngineType *type = RE_engines_find(scene->r.engine);
+ return type->flag & RE_USE_TEXTURE_PREVIEW;
+}
+
void ED_preview_free_dbase(void)
{
if (G_pr_main)
@@ -299,10 +306,10 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
sce->r.cfra = scene->r.cfra;
- if (id_type == ID_TE && sp->pr_method == PR_ICON_RENDER) {
- /* force blender internal for texture icons render,
+ if (id_type == ID_TE && !check_engine_supports_textures(scene)) {
+ /* Force blender internal for texture icons and nodes render,
* seems commonly used render engines does not support
- * such kind of rendering
+ * such kind of rendering.
*/
BLI_strncpy(sce->r.engine, "BLENDER_RENDER", sizeof(sce->r.engine));
}
@@ -751,12 +758,6 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs
if (sp->pr_rect)
RE_ResultGet32(re, sp->pr_rect);
}
- else {
- /* validate owner */
- //if (ri->rect == NULL)
- // ri->rect= MEM_mallocN(sizeof(int) * ri->pr_rectx*ri->pr_recty, "BIF_previewrender");
- //RE_ResultGet32(re, ri->rect);
- }
/* unassign the pointers, reset vars */
preview_prepare_scene(sp->scene, NULL, GS(id->name), sp);
@@ -1137,10 +1138,13 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
wmJob *wm_job;
ShaderPreview *sp;
Scene *scene = CTX_data_scene(C);
+ short id_type = GS(id->name);
+ bool use_new_shading = BKE_scene_use_new_shading_nodes(scene);
- /* node previews not supported for cycles */
- if (BKE_scene_use_new_shading_nodes(scene) && method == PR_NODE_RENDER)
+ /* Only texture node preview is supported with Cycles. */
+ if (use_new_shading && method == PR_NODE_RENDER && id_type != ID_TE) {
return;
+ }
wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), owner, "Shader Preview",
WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW);
@@ -1158,10 +1162,12 @@ void ED_preview_shader_job(const bContext *C, void *owner, ID *id, ID *parent, M
/* hardcoded preview .blend for cycles/internal, this should be solved
* once with custom preview .blend path for external engines */
- if (BKE_scene_use_new_shading_nodes(scene))
+ if ((method != PR_NODE_RENDER) && id_type != ID_TE && use_new_shading) {
sp->pr_main = G_pr_main_cycles;
- else
+ }
+ else {
sp->pr_main = G_pr_main;
+ }
if (ob && ob->totcol) copy_v4_v4(sp->col, ob->col);
else sp->col[0] = sp->col[1] = sp->col[2] = sp->col[3] = 1.0f;
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 97f6b346666..6c996bcbd67 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -58,6 +58,7 @@
#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_material.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_texture.h"
@@ -102,8 +103,15 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op))
if (!ob)
return OPERATOR_CANCELLED;
-
+
object_add_material_slot(ob);
+
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ Scene *scene = CTX_data_scene(C);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob);
WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_PREVIEW, ob);
@@ -138,8 +146,15 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Unable to remove material slot in edit mode");
return OPERATOR_CANCELLED;
}
-
+
object_remove_material_slot(ob);
+
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ Scene *scene = CTX_data_scene(C);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+
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_OB_SHADING, ob);
@@ -449,6 +464,14 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op))
* pointer se also increases user, so this compensates it */
tex->id.us--;
+ if (ptr.id.data && GS(((ID *)ptr.id.data)->name) == ID_MA &&
+ RNA_property_pointer_get(&ptr, prop).id.data == NULL)
+ {
+ /* In case we are assigning new texture to a material, and active slot was empty, reset 'use' flag. */
+ Material *ma = (Material *)ptr.id.data;
+ ma->septex &= ~(1 << ma->texact);
+ }
+
RNA_id_pointer_create(&tex->id, &idptr);
RNA_property_pointer_set(&ptr, prop, idptr);
RNA_property_update(C, &ptr, prop);
@@ -590,7 +613,7 @@ void SCENE_OT_render_layer_remove(wmOperatorType *ot)
static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportList *reports)
{
if (!lineset) {
- BKE_report(reports, RPT_ERROR, "No active lineset and associated line style to add the modifier to");
+ BKE_report(reports, RPT_ERROR, "No active lineset and associated line style to manipulate the modifier");
return false;
}
if (!lineset->linestyle) {
@@ -644,6 +667,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op))
BKE_freestyle_module_delete(&srl->freestyleConfig, module);
+ DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -678,6 +702,7 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op)
else {
BKE_freestyle_module_move_down(&srl->freestyleConfig, module);
}
+ DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -714,6 +739,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op))
BKE_freestyle_lineset_add(&srl->freestyleConfig, NULL);
+ DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -752,8 +778,6 @@ static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op))
FRS_copy_active_lineset(&srl->freestyleConfig);
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
-
return OPERATOR_FINISHED;
}
@@ -779,6 +803,7 @@ static int freestyle_lineset_paste_exec(bContext *C, wmOperator *UNUSED(op))
FRS_paste_active_lineset(&srl->freestyleConfig);
+ DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -806,6 +831,7 @@ static int freestyle_lineset_remove_exec(bContext *C, wmOperator *UNUSED(op))
FRS_delete_active_lineset(&srl->freestyleConfig);
+ DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -838,6 +864,7 @@ static int freestyle_lineset_move_exec(bContext *C, wmOperator *op)
else {
FRS_move_active_lineset_down(&srl->freestyleConfig);
}
+ DAG_id_tag_update(&scene->id, 0);
WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
return OPERATOR_FINISHED;
@@ -879,13 +906,13 @@ static int freestyle_linestyle_new_exec(bContext *C, wmOperator *op)
}
if (lineset->linestyle) {
lineset->linestyle->id.us--;
- lineset->linestyle = BKE_copy_linestyle(lineset->linestyle);
+ lineset->linestyle = BKE_linestyle_copy(lineset->linestyle);
}
else {
- lineset->linestyle = BKE_new_linestyle("LineStyle", NULL);
+ lineset->linestyle = BKE_linestyle_new("LineStyle", NULL);
}
-
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ DAG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
}
@@ -916,11 +943,12 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_add_linestyle_color_modifier(lineset->linestyle, type) == NULL) {
+ if (BKE_linestyle_color_modifier_add(lineset->linestyle, NULL, type) == NULL) {
BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type");
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ DAG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
}
@@ -955,11 +983,12 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_add_linestyle_alpha_modifier(lineset->linestyle, type) == NULL) {
+ if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, NULL, type) == NULL) {
BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type");
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ DAG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
}
@@ -994,11 +1023,12 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_add_linestyle_thickness_modifier(lineset->linestyle, type) == NULL) {
+ if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, NULL, type) == NULL) {
BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type");
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ DAG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
}
@@ -1033,11 +1063,12 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- if (BKE_add_linestyle_geometry_modifier(lineset->linestyle, type) == NULL) {
+ if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, NULL, type) == NULL) {
BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type");
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ DAG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
}
@@ -1088,22 +1119,23 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op)
switch (freestyle_get_modifier_type(&ptr)) {
case LS_MODIFIER_TYPE_COLOR:
- BKE_remove_linestyle_color_modifier(lineset->linestyle, modifier);
+ BKE_linestyle_color_modifier_remove(lineset->linestyle, modifier);
break;
case LS_MODIFIER_TYPE_ALPHA:
- BKE_remove_linestyle_alpha_modifier(lineset->linestyle, modifier);
+ BKE_linestyle_alpha_modifier_remove(lineset->linestyle, modifier);
break;
case LS_MODIFIER_TYPE_THICKNESS:
- BKE_remove_linestyle_thickness_modifier(lineset->linestyle, modifier);
+ BKE_linestyle_thickness_modifier_remove(lineset->linestyle, modifier);
break;
case LS_MODIFIER_TYPE_GEOMETRY:
- BKE_remove_linestyle_geometry_modifier(lineset->linestyle, modifier);
+ BKE_linestyle_geometry_modifier_remove(lineset->linestyle, modifier);
break;
default:
BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ DAG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
}
@@ -1137,22 +1169,23 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op)
switch (freestyle_get_modifier_type(&ptr)) {
case LS_MODIFIER_TYPE_COLOR:
- BKE_copy_linestyle_color_modifier(lineset->linestyle, modifier);
+ BKE_linestyle_color_modifier_copy(lineset->linestyle, modifier);
break;
case LS_MODIFIER_TYPE_ALPHA:
- BKE_copy_linestyle_alpha_modifier(lineset->linestyle, modifier);
+ BKE_linestyle_alpha_modifier_copy(lineset->linestyle, modifier);
break;
case LS_MODIFIER_TYPE_THICKNESS:
- BKE_copy_linestyle_thickness_modifier(lineset->linestyle, modifier);
+ BKE_linestyle_thickness_modifier_copy(lineset->linestyle, modifier);
break;
case LS_MODIFIER_TYPE_GEOMETRY:
- BKE_copy_linestyle_geometry_modifier(lineset->linestyle, modifier);
+ BKE_linestyle_geometry_modifier_copy(lineset->linestyle, modifier);
break;
default:
BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ DAG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
}
@@ -1187,22 +1220,23 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op)
switch (freestyle_get_modifier_type(&ptr)) {
case LS_MODIFIER_TYPE_COLOR:
- BKE_move_linestyle_color_modifier(lineset->linestyle, modifier, dir);
+ BKE_linestyle_color_modifier_move(lineset->linestyle, modifier, dir);
break;
case LS_MODIFIER_TYPE_ALPHA:
- BKE_move_linestyle_alpha_modifier(lineset->linestyle, modifier, dir);
+ BKE_linestyle_alpha_modifier_move(lineset->linestyle, modifier, dir);
break;
case LS_MODIFIER_TYPE_THICKNESS:
- BKE_move_linestyle_thickness_modifier(lineset->linestyle, modifier, dir);
+ BKE_linestyle_thickness_modifier_move(lineset->linestyle, modifier, dir);
break;
case LS_MODIFIER_TYPE_GEOMETRY:
- BKE_move_linestyle_geometry_modifier(lineset->linestyle, modifier, dir);
+ BKE_linestyle_geometry_modifier_move(lineset->linestyle, modifier, dir);
break;
default:
BKE_report(op->reports, RPT_ERROR, "The object the data pointer refers to is not a valid modifier");
return OPERATOR_CANCELLED;
}
- WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
+ DAG_id_tag_update(&lineset->linestyle->id, 0);
+ WM_event_add_notifier(C, NC_LINESTYLE, lineset->linestyle);
return OPERATOR_FINISHED;
}
@@ -1231,6 +1265,36 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot)
RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move, UP or DOWN");
}
+static int freestyle_stroke_material_create_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ Scene *scene = CTX_data_scene(C);
+ FreestyleLineStyle *linestyle = BKE_linestyle_active_from_scene(scene);
+
+ if (!linestyle) {
+ BKE_report(op->reports, RPT_ERROR, "No active line style in the current scene");
+ return OPERATOR_CANCELLED;
+ }
+
+ FRS_create_stroke_material(bmain, linestyle);
+
+ return OPERATOR_FINISHED;
+}
+
+void SCENE_OT_freestyle_stroke_material_create(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Create Freestyle Stroke Material";
+ ot->idname = "SCENE_OT_freestyle_stroke_material_create";
+ ot->description = "Create Freestyle stroke material for testing";
+
+ /* api callbacks */
+ ot->exec = freestyle_stroke_material_create_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
#endif /* WITH_FREESTYLE */
static int texture_slot_move_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c
index 94d8d78de1a..df7ca9f11b2 100644
--- a/source/blender/editors/render/render_update.c
+++ b/source/blender/editors/render/render_update.c
@@ -45,6 +45,7 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_icons.h"
#include "BKE_main.h"
@@ -473,15 +474,22 @@ static void image_changed(Main *bmain, Image *ima)
texture_changed(bmain, tex);
}
-static void scene_changed(Main *bmain, Scene *UNUSED(scene))
+static void scene_changed(Main *bmain, Scene *scene)
{
Object *ob;
Material *ma;
/* glsl */
- for (ob = bmain->object.first; ob; ob = ob->id.next)
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
if (ob->gpulamp.first)
GPU_lamp_free(ob);
+
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ BKE_texpaint_slots_refresh_object(scene, ob);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ GPU_drawobject_free(ob->derivedFinal);
+ }
+ }
for (ma = bmain->mat.first; ma; ma = ma->id.next)
if (ma->gpumaterial.first)
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index 0beb5737ec7..ab28f5fa675 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -252,7 +252,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
}
else if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_toggle(C, win, sa);
+ ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt
index 4ff1767f582..413d40b9f9c 100644
--- a/source/blender/editors/screen/CMakeLists.txt
+++ b/source/blender/editors/screen/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -51,4 +52,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_screen "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/screen/SConscript b/source/blender/editors/screen/SConscript
index 28a6cbb02e6..f5442c7ea63 100644
--- a/source/blender/editors/screen/SConscript
+++ b/source/blender/editors/screen/SConscript
@@ -31,7 +31,8 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
@@ -45,7 +46,7 @@ incs = [
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 151764dab6a..e38f3b5bee6 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -63,6 +63,7 @@
#include "BLF_api.h"
#include "UI_interface.h"
+#include "UI_interface_icons.h"
#include "UI_resources.h"
#include "UI_view2d.h"
@@ -107,10 +108,7 @@ static void region_draw_emboss(ARegion *ar, rcti *scirct)
void ED_region_pixelspace(ARegion *ar)
{
- int width = BLI_rcti_size_x(&ar->winrct) + 1;
- int height = BLI_rcti_size_y(&ar->winrct) + 1;
-
- wmOrtho2(-GLA_PIXEL_OFS, (float)width - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, (float)height - GLA_PIXEL_OFS);
+ wmOrtho2_region_pixelspace(ar);
glLoadIdentity();
}
@@ -152,6 +150,45 @@ void ED_area_do_refresh(bContext *C, ScrArea *sa)
}
/**
+ * \brief Corner widget use for quitting fullscreen.
+ */
+static void area_draw_azone_fullscreen(short x1, short y1, short x2, short y2, float alpha)
+{
+ int x = x2 - ((float) x2 - x1) * 0.5f / UI_DPI_FAC;
+ int y = y2 - ((float) y2 - y1) * 0.5f / UI_DPI_FAC;
+
+ /* adjust the icon distance from the corner */
+ x += 36.0f / UI_DPI_FAC;
+ y += 36.0f / UI_DPI_FAC;
+
+ /* draws from the left bottom corner of the icon */
+ x -= UI_DPI_ICON_SIZE;
+ y -= UI_DPI_ICON_SIZE;
+
+ alpha = min_ff(alpha, 0.75f);
+
+ UI_icon_draw_aspect(x, y, ICON_FULLSCREEN_EXIT, 0.7f / UI_DPI_FAC, alpha);
+
+ /* debug drawing :
+ * The click_rect is the same as defined in fullscreen_click_rcti_init
+ * Keep them both in sync */
+
+ if (G.debug_value == 1) {
+ rcti click_rect;
+ float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC;
+ char alpha_debug = 255 * alpha;
+
+ BLI_rcti_init(&click_rect, x, x + icon_size, y, y + icon_size);
+
+ glColor4ub(255, 0, 0, alpha_debug);
+ fdrawbox(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
+ glColor4ub(0, 255, 255, alpha_debug);
+ fdrawline(click_rect.xmin, click_rect.ymin, click_rect.xmax, click_rect.ymax);
+ fdrawline(click_rect.xmin, click_rect.ymax, click_rect.xmax, click_rect.ymin);
+ }
+}
+
+/**
* \brief Corner widgets use for dragging and splitting the view.
*/
static void area_draw_azone(short x1, short y1, short x2, short y2)
@@ -368,6 +405,9 @@ 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);
+ }
}
}
@@ -421,6 +461,8 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
/* note; this sets state, so we can use wmOrtho and friends */
wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, scissor_pad);
+
+ wmOrtho2_region_ui(ar);
UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
@@ -457,8 +499,9 @@ void ED_region_do_draw(bContext *C, ARegion *ar)
uiFreeInactiveBlocks(C, &ar->uiblocks);
- if (sa)
+ if (sa && (win->screen->state != SCREENFULL)) {
region_draw_emboss(ar, &ar->winrct);
+ }
}
/* **********************************
@@ -472,7 +515,8 @@ void ED_region_tag_redraw(ARegion *ar)
* but python scripts can cause this to happen indirectly */
if (ar && !(ar->do_draw & RGN_DRAWING)) {
/* zero region means full region redraw */
- ar->do_draw = RGN_DRAW;
+ ar->do_draw &= ~RGN_DRAW_PARTIAL;
+ ar->do_draw |= RGN_DRAW;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
}
}
@@ -483,12 +527,19 @@ void ED_region_tag_redraw_overlay(ARegion *ar)
ar->do_draw_overlay = RGN_DRAW;
}
+void ED_region_tag_refresh_ui(ARegion *ar)
+{
+ if (ar) {
+ ar->do_draw |= RGN_DRAW_REFRESH_UI;
+ }
+}
+
void ED_region_tag_redraw_partial(ARegion *ar, rcti *rct)
{
if (ar && !(ar->do_draw & RGN_DRAWING)) {
- if (!ar->do_draw) {
+ if (!(ar->do_draw & RGN_DRAW)) {
/* no redraw set yet, set partial region */
- ar->do_draw = RGN_DRAW_PARTIAL;
+ ar->do_draw |= RGN_DRAW_PARTIAL;
ar->drawrct = *rct;
}
else if (ar->drawrct.xmin != ar->drawrct.xmax) {
@@ -560,10 +611,10 @@ static void area_azone_initialize(wmWindow *win, bScreen *screen, ScrArea *sa)
{
AZone *az;
- /* reinitalize entirely, regions add azones too */
+ /* reinitalize entirely, regions and fullscreen add azones too */
BLI_freelistN(&sa->actionzones);
- if (screen->full != SCREENNORMAL) {
+ if (screen->state != SCREENNORMAL) {
return;
}
@@ -595,6 +646,26 @@ static void area_azone_initialize(wmWindow *win, bScreen *screen, ScrArea *sa)
BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
}
+static void fullscreen_azone_initialize(ScrArea *sa, ARegion *ar)
+{
+ AZone *az;
+
+ if (ar->regiontype != RGN_TYPE_WINDOW)
+ return;
+
+ az = (AZone *)MEM_callocN(sizeof(AZone), "fullscreen action zone");
+ BLI_addtail(&(sa->actionzones), az);
+ az->type = AZONE_FULLSCREEN;
+ az->ar = ar;
+ az->alpha = 0.0f;
+
+ az->x1 = ar->winrct.xmax - (AZONEFADEOUT - 1);
+ az->y1 = ar->winrct.ymax - (AZONEFADEOUT - 1);
+ az->x2 = ar->winrct.xmax;
+ az->y2 = ar->winrct.ymax;
+ BLI_rcti_init(&az->rect, az->x1, az->x2, az->y1, az->y2);
+}
+
#define AZONEPAD_EDGE (0.1f * U.widget_unit)
#define AZONEPAD_ICON (0.45f * U.widget_unit)
static void region_azone_edge(AZone *az, ARegion *ar)
@@ -823,25 +894,30 @@ static void region_azone_tria(ScrArea *sa, AZone *az, ARegion *ar)
}
-static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge)
+static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge, const bool is_fullscreen)
{
AZone *az;
+ const bool is_hidden = (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) == 0;
- az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
- BLI_addtail(&(sa->actionzones), az);
- az->type = AZONE_REGION;
- az->ar = ar;
- az->edge = edge;
+ if (is_hidden || !is_fullscreen) {
+ az = (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
+ BLI_addtail(&(sa->actionzones), az);
+ az->type = AZONE_REGION;
+ az->ar = ar;
+ az->edge = edge;
+ }
if (ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
- if (G.debug_value == 3)
- region_azone_icon(sa, az, ar);
- else if (G.debug_value == 2)
- region_azone_tria(sa, az, ar);
- else if (G.debug_value == 1)
- region_azone_tab(sa, az, ar);
- else
- region_azone_tab_plus(sa, az, ar);
+ if (!is_fullscreen) {
+ if (G.debug_value == 3)
+ region_azone_icon(sa, az, ar);
+ else if (G.debug_value == 2)
+ region_azone_tria(sa, az, ar);
+ else if (G.debug_value == 1)
+ region_azone_tab(sa, az, ar);
+ else
+ region_azone_tab_plus(sa, az, ar);
+ }
}
else {
region_azone_edge(az, ar);
@@ -852,18 +928,18 @@ static void region_azone_initialize(ScrArea *sa, ARegion *ar, AZEdge edge)
/* *************************************************************** */
-static void region_azone_add(ScrArea *sa, ARegion *ar, int alignment)
+static void region_azone_add(ScrArea *sa, ARegion *ar, const int alignment, const bool is_fullscreen)
{
/* edge code (t b l r) is along which area edge azone will be drawn */
if (alignment == RGN_ALIGN_TOP)
- region_azone_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT);
+ region_azone_initialize(sa, ar, AE_BOTTOM_TO_TOPLEFT, is_fullscreen);
else if (alignment == RGN_ALIGN_BOTTOM)
- region_azone_initialize(sa, ar, AE_TOP_TO_BOTTOMRIGHT);
+ region_azone_initialize(sa, ar, AE_TOP_TO_BOTTOMRIGHT, is_fullscreen);
else if (alignment == RGN_ALIGN_RIGHT)
- region_azone_initialize(sa, ar, AE_LEFT_TO_TOPRIGHT);
+ region_azone_initialize(sa, ar, AE_LEFT_TO_TOPRIGHT, is_fullscreen);
else if (alignment == RGN_ALIGN_LEFT)
- region_azone_initialize(sa, ar, AE_RIGHT_TO_TOPLEFT);
+ region_azone_initialize(sa, ar, AE_RIGHT_TO_TOPLEFT, is_fullscreen);
}
/* dir is direction to check, not the splitting edge direction! */
@@ -883,38 +959,59 @@ static int rct_fits(rcti *rect, char dir, int size)
/* function checks if some overlapping region was defined before - on same place */
static void region_overlap_fix(ScrArea *sa, ARegion *ar)
{
- ARegion *ar1 = ar->prev;
-
+ ARegion *ar1;
+ const int align = ar->alignment & ~RGN_SPLIT_PREV;
+ int align1 = 0;
+
/* find overlapping previous region on same place */
- while (ar1) {
- if (ar1->overlap) {
- if ((ar1->alignment & RGN_SPLIT_PREV) == 0)
- if (BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL))
- break;
+ for (ar1 = ar->prev; ar1; ar1 = ar1->prev) {
+ if (ar1->overlap && ((ar1->alignment & RGN_SPLIT_PREV) == 0)) {
+ align1 = ar1->alignment;
+ if (BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL)) {
+ if (align1 != align) {
+ /* Left overlapping right or vice-versa, forbid this! */
+ ar->flag |= RGN_FLAG_TOO_SMALL;
+ return;
+ }
+ /* Else, we have our previous region on same side. */
+ break;
+ }
}
- ar1 = ar1->prev;
}
-
+
/* translate or close */
if (ar1) {
- int align1 = ar1->alignment & ~RGN_SPLIT_PREV;
-
if (align1 == RGN_ALIGN_LEFT) {
- if (ar->winrct.xmax + ar1->winx > sa->winx - U.widget_unit)
+ if (ar->winrct.xmax + ar1->winx > sa->winx - U.widget_unit) {
ar->flag |= RGN_FLAG_TOO_SMALL;
- else
+ return;
+ }
+ else {
BLI_rcti_translate(&ar->winrct, ar1->winx, 0);
+ }
}
else if (align1 == RGN_ALIGN_RIGHT) {
- if (ar->winrct.xmin - ar1->winx < U.widget_unit)
+ if (ar->winrct.xmin - ar1->winx < U.widget_unit) {
ar->flag |= RGN_FLAG_TOO_SMALL;
- else
+ return;
+ }
+ else {
BLI_rcti_translate(&ar->winrct, -ar1->winx, 0);
+ }
}
}
-
-
+ /* At this point, 'ar' is in its final position and still open.
+ * Make a final check it does not overlap any previous 'other side' region. */
+ for (ar1 = ar->prev; ar1; ar1 = ar1->prev) {
+ if (ar1->overlap && (ar1->alignment & RGN_SPLIT_PREV) == 0) {
+ if ((ar1->alignment != align) && BLI_rcti_isect(&ar1->winrct, &ar->winrct, NULL)) {
+ /* Left overlapping right or vice-versa, forbid this! */
+ ar->flag |= RGN_FLAG_TOO_SMALL;
+ return;
+ }
+ }
+ }
}
/* overlapping regions only in the following restricted cases */
@@ -923,11 +1020,11 @@ static bool region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar)
if (U.uiflag2 & USER_REGION_OVERLAP) {
if (WM_is_draw_triple(win)) {
if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ)) {
- if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
+ if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
return 1;
}
else if (sa->spacetype == SPACE_IMAGE) {
- if (ELEM4(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW))
+ if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW))
return 1;
}
}
@@ -1160,7 +1257,13 @@ static void region_rect_recursive(wmWindow *win, ScrArea *sa, ARegion *ar, rcti
* must be minimum '4' */
}
else {
- region_azone_add(sa, ar, alignment);
+ if (ELEM(win->screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
+ region_azone_add(sa, ar, alignment, false);
+ }
+ else {
+ region_azone_add(sa, ar, alignment, true);
+ fullscreen_azone_initialize(sa, ar);
+ }
}
region_rect_recursive(win, sa, ar->next, remainder, quad);
@@ -1226,7 +1329,9 @@ static void ed_default_handlers(wmWindowManager *wm, ScrArea *sa, ListBase *hand
/* time space only has this keymap, the others get a boundbox restricted map */
if (sa->spacetype != SPACE_TIME) {
ARegion *ar;
- static rcti rect = {0, 10000, 0, 30}; /* same local check for all areas */
+ /* same local check for all areas */
+ static rcti rect = {0, 10000, 0, -1};
+ rect.ymax = (30 * UI_DPI_FAC);
ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
if (ar) {
WM_event_add_keymap_handler_bb(handlers, keymap, &rect, &ar->winrct);
@@ -1339,10 +1444,6 @@ void ED_region_init(bContext *C, ARegion *ar)
region_subwindow(CTX_wm_window(C), ar);
region_update_rect(ar);
-
- /* UI convention */
- wmOrtho2(-0.01f, ar->winx - 0.01f, -0.01f, ar->winy - 0.01f);
- glLoadIdentity();
}
/* for quick toggle, can skip fades */
@@ -1379,12 +1480,15 @@ void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free)
SpaceType *st;
ARegion *ar;
const char spacetype = sa_dst->spacetype;
+ const short flag_copy = HEADER_NO_PULLDOWN;
sa_dst->headertype = sa_src->headertype;
sa_dst->spacetype = sa_src->spacetype;
sa_dst->type = sa_src->type;
sa_dst->butspacetype = sa_src->butspacetype;
+ sa_dst->flag = (sa_dst->flag & ~flag_copy) | (sa_src->flag & flag_copy);
+
/* area */
if (do_free) {
BKE_spacedata_freelist(&sa_dst->spacedata);
@@ -1759,9 +1863,7 @@ void ED_region_panels(const bContext *C, ARegion *ar, int vertical, const char *
break;
}
}
-
- BLI_SMALLSTACK_FREE(pt_stack);
-
+
/* clear */
if (ar->overlap) {
/* view should be in pixelspace */
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index f31d79ff76b..c095dfe7792 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -50,6 +50,8 @@
#include "IMB_colormanagement.h"
#include "IMB_imbuf_types.h"
+#include "UI_interface.h"
+
#ifndef GL_CLAMP_TO_EDGE
#define GL_CLAMP_TO_EDGE 0x812F
#endif
@@ -222,15 +224,15 @@ void fdrawcheckerboard(float x1, float y1, float x2, float y2)
glDisable(GL_POLYGON_STIPPLE);
}
-void sdrawline(short x1, short y1, short x2, short y2)
+void sdrawline(int x1, int y1, int x2, int y2)
{
- short v[2];
+ int v[2];
glBegin(GL_LINE_STRIP);
v[0] = x1; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x2; v[1] = y2;
- glVertex2sv(v);
+ glVertex2iv(v);
glEnd();
}
@@ -244,25 +246,25 @@ void sdrawline(short x1, short y1, short x2, short y2)
* x1,y1-- x2,y1
*/
-static void sdrawtripoints(short x1, short y1, short x2, short y2)
+static void sdrawtripoints(int x1, int y1, int x2, int y2)
{
- short v[2];
+ int v[2];
v[0] = x1; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x1; v[1] = y2;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x2; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
}
-void sdrawtri(short x1, short y1, short x2, short y2)
+void sdrawtri(int x1, int y1, int x2, int y2)
{
glBegin(GL_LINE_STRIP);
sdrawtripoints(x1, y1, x2, y2);
glEnd();
}
-void sdrawtrifill(short x1, short y1, short x2, short y2)
+void sdrawtrifill(int x1, int y1, int x2, int y2)
{
glBegin(GL_TRIANGLES);
sdrawtripoints(x1, y1, x2, y2);
@@ -270,22 +272,22 @@ void sdrawtrifill(short x1, short y1, short x2, short y2)
}
#endif
-void sdrawbox(short x1, short y1, short x2, short y2)
+void sdrawbox(int x1, int y1, int x2, int y2)
{
- short v[2];
+ int v[2];
glBegin(GL_LINE_STRIP);
v[0] = x1; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x1; v[1] = y2;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x2; v[1] = y2;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x2; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
v[0] = x1; v[1] = y1;
- glVertex2sv(v);
+ glVertex2iv(v);
glEnd();
}
@@ -337,7 +339,7 @@ void sdrawXORline(int x0, int y0, int x1, int y1)
void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
{
- static short old[4][2][2];
+ static int old[4][2][2];
static char flags[4] = {0, 0, 0, 0};
/* with builtin memory, max 4 lines */
@@ -348,8 +350,8 @@ void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
if (nr == -1) { /* flush */
for (nr = 0; nr < 4; nr++) {
if (flags[nr]) {
- glVertex2sv(old[nr][0]);
- glVertex2sv(old[nr][1]);
+ glVertex2iv(old[nr][0]);
+ glVertex2iv(old[nr][1]);
flags[nr] = 0;
}
}
@@ -357,8 +359,8 @@ void sdrawXORline4(int nr, int x0, int y0, int x1, int y1)
else {
if (nr >= 0 && nr < 4) {
if (flags[nr]) {
- glVertex2sv(old[nr][0]);
- glVertex2sv(old[nr][1]);
+ glVertex2iv(old[nr][0]);
+ glVertex2iv(old[nr][1]);
}
old[nr][0][0] = x0;
@@ -1139,3 +1141,40 @@ void cpack(unsigned int x)
(((x) >> 8) & 0xFF),
(((x) >> 16) & 0xFF) );
}
+
+void glaDrawBorderCorners(const rcti *border, float zoomx, float zoomy)
+{
+ float delta_x = 4.0f * UI_DPI_FAC / zoomx;
+ float delta_y = 4.0f * UI_DPI_FAC / zoomy;
+
+ delta_x = min_ff(delta_x, border->xmax - border->xmin);
+ delta_y = min_ff(delta_y, border->ymax - border->ymin);
+
+ /* left bottom corner */
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(border->xmin, border->ymin + delta_y);
+ glVertex2f(border->xmin, border->ymin);
+ glVertex2f(border->xmin + delta_x, border->ymin);
+ glEnd();
+
+ /* left top corner */
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(border->xmin, border->ymax - delta_y);
+ glVertex2f(border->xmin, border->ymax);
+ glVertex2f(border->xmin + delta_x, border->ymax);
+ glEnd();
+
+ /* right bottom corner */
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(border->xmax - delta_x, border->ymin);
+ glVertex2f(border->xmax, border->ymin);
+ glVertex2f(border->xmax, border->ymin + delta_y);
+ glEnd();
+
+ /* right top corner */
+ glBegin(GL_LINE_STRIP);
+ glVertex2f(border->xmax - delta_x, border->ymax);
+ glVertex2f(border->xmax, border->ymax);
+ glVertex2f(border->xmax, border->ymax - delta_y);
+ glEnd();
+}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index f76f76aacaa..9463a702b76 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -378,7 +378,7 @@ ScrArea *area_split(bScreen *sc, ScrArea *sa, char dir, float fac, int merge)
if (split == 0) return NULL;
/* note regarding (fac > 0.5f) checks below.
- * notmally it shouldn't matter which is used since the copy should match the original
+ * normally it shouldn't matter which is used since the copy should match the original
* however with viewport rendering and python console this isn't the case. - campbell */
if (dir == 'h') {
@@ -1009,7 +1009,7 @@ static void scrarea_draw_shape_light(ScrArea *sa, char UNUSED(dir))
glDisable(GL_BLEND);
}
-static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2, short a)
+static void drawscredge_area_draw(int sizex, int sizey, int x1, int y1, int x2, int y2, int a)
{
/* right border area */
if (x2 < sizex - 1)
@@ -1058,7 +1058,7 @@ bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
{
bScreen *newsc;
- if (sc->full != SCREENNORMAL) return NULL; /* XXX handle this case! */
+ if (sc->state != SCREENNORMAL) return NULL; /* XXX handle this case! */
/* make new empty screen: */
newsc = ED_screen_add(win, sc->scene, sc->id.name + 2);
@@ -1485,7 +1485,7 @@ void ED_screen_set(bContext *C, bScreen *sc)
return;
- if (sc->full) { /* find associated full */
+ if (sc->state == SCREENFULL) { /* find associated full */
bScreen *sc1;
for (sc1 = bmain->screen.first; sc1; sc1 = sc1->id.next) {
ScrArea *sa = sc1->areabase.first;
@@ -1586,7 +1586,7 @@ void ED_screen_delete(bContext *C, bScreen *sc)
int delete = 1;
/* don't allow deleting temp fullscreens for now */
- if (sc->full == SCREENFULL) {
+ if (ELEM(sc->state, SCREENMAXIMIZED, SCREENFULL)) {
return;
}
@@ -1730,11 +1730,11 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
ScrArea *newsa = NULL;
if (!sa || sa->full == NULL) {
- newsa = ED_screen_full_toggle(C, win, sa);
+ newsa = ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
}
if (!newsa) {
- if (sa->full) {
+ if (sa->full && (screen->state == SCREENMAXIMIZED)) {
/* if this has been called from the temporary info header generated in
* temp fullscreen layouts, find the correct fullscreen area to change
* to create a new space inside */
@@ -1760,7 +1760,7 @@ void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
ED_area_prevspace(C, sa);
if (sa->full)
- ED_screen_full_toggle(C, win, sa);
+ ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
}
/* restore a screen / area back to default operation, after temp fullscreen modes */
@@ -1768,6 +1768,8 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
{
wmWindow *win = CTX_wm_window(C);
SpaceLink *sl = sa->spacedata.first;
+ bScreen *screen = CTX_wm_screen(C);
+ short state = (screen ? screen->state : SCREENMAXIMIZED);
/* if fullscreen area has a secondary space (such as a file browser or fullscreen render
* overlaid on top of a existing setup) then return to the previous space */
@@ -1785,23 +1787,23 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
ED_screen_full_prevspace(C, sa);
}
else
- ED_screen_full_toggle(C, win, sa);
+ ED_screen_state_toggle(C, win, sa, state);
}
else if (sl->spacetype == SPACE_FILE) {
ED_screen_full_prevspace(C, sa);
}
else {
- ED_screen_full_toggle(C, win, sa);
+ ED_screen_state_toggle(C, win, sa, state);
}
}
/* otherwise just tile the area again */
else {
- ED_screen_full_toggle(C, win, sa);
+ ED_screen_state_toggle(C, win, sa, state);
}
}
-/* this function toggles: if area is full then the parent will be restored */
-ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
+/* this function toggles: if area is maximized/full then the parent will be restored */
+ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *sa, const short state)
{
bScreen *sc, *oldscreen;
ARegion *ar;
@@ -1812,23 +1814,20 @@ ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
* are no longer in the same screen */
for (ar = sa->regionbase.first; ar; ar = ar->next)
uiFreeBlocks(C, &ar->uiblocks);
-
+
/* prevent hanging header prints */
ED_area_headerprint(sa, NULL);
}
if (sa && sa->full) {
+ /* restoring back to SCREENNORMAL */
ScrArea *old;
- /*short fulltype;*/ /*UNUSED*/
sc = sa->full; /* the old screen to restore */
oldscreen = win->screen; /* the one disappearing */
- /*fulltype = sc->full;*/
- sc->full = 0;
+ sc->state = SCREENNORMAL;
- /* removed: SCREENAUTOPLAY exception here */
-
/* find old area */
for (old = sc->areabase.first; old; old = old->next)
if (old->full) break;
@@ -1838,6 +1837,13 @@ ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
return NULL;
}
+ if (state == SCREENFULL) {
+ /* restore the old side panels/header visibility */
+ for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ ar->flag = ar->flagfullscreen;
+ }
+ }
+
ED_area_data_swap(old, sa);
if (sa->flag & AREA_TEMP_INFO) sa->flag &= ~AREA_TEMP_INFO;
old->full = NULL;
@@ -1853,44 +1859,66 @@ ScrArea *ED_screen_full_toggle(bContext *C, wmWindow *win, ScrArea *sa)
}
else {
+ /* change from SCREENNORMAL to new state */
ScrArea *newa;
char newname[MAX_ID_NAME - 2];
oldscreen = win->screen;
- /* nothing wrong with having only 1 area, as far as I can see...
- * is there only 1 area? */
-#if 0
- if (oldscreen->areabase.first == oldscreen->areabase.last)
- return NULL;
-#endif
-
- oldscreen->full = SCREENFULL;
- BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "full");
+ oldscreen->state = state;
+ BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal");
sc = ED_screen_add(win, oldscreen->scene, newname);
- sc->full = SCREENFULL; // XXX
+ sc->state = state;
/* timer */
sc->animtimer = oldscreen->animtimer;
oldscreen->animtimer = NULL;
- /* returns the top small area */
- newa = area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
- ED_area_newspace(C, newa, SPACE_INFO);
-
/* use random area when we have no active one, e.g. when the
* mouse is outside of the window and we open a file browser */
if (!sa)
sa = oldscreen->areabase.first;
- /* copy area */
- newa = newa->prev;
- ED_area_data_swap(newa, sa);
- sa->flag |= AREA_TEMP_INFO;
+ if (state == SCREENMAXIMIZED) {
+ /* returns the top small area */
+ newa = area_split(sc, (ScrArea *)sc->areabase.first, 'h', 0.99f, 1);
+ ED_area_newspace(C, newa, SPACE_INFO);
+
+ /* copy area */
+ newa = newa->prev;
+ ED_area_data_swap(newa, sa);
+ sa->flag |= AREA_TEMP_INFO;
+
+ sa->full = oldscreen;
+ newa->full = oldscreen;
+ newa->next->full = oldscreen; // XXX
+ }
+ else if (state == SCREENFULL) {
+ newa = (ScrArea *)sc->areabase.first;
+
+ /* copy area */
+ ED_area_data_swap(newa, sa);
+ newa->flag = sa->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */
+
+ /* temporarily hide the side panels/header */
+ for (ar = newa->regionbase.first; ar; ar = ar->next) {
+ ar->flagfullscreen = ar->flag;
+
+ if (ELEM(ar->regiontype,
+ RGN_TYPE_UI,
+ RGN_TYPE_HEADER,
+ RGN_TYPE_TOOLS))
+ {
+ ar->flag |= RGN_FLAG_HIDDEN;
+ }
+ }
- sa->full = oldscreen;
- newa->full = oldscreen;
- newa->next->full = oldscreen; // XXX
+ sa->full = oldscreen;
+ newa->full = oldscreen;
+ }
+ else {
+ BLI_assert(false);
+ }
ED_screen_set(C, sc);
}
diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h
index 9e0421b6e99..79036d3356f 100644
--- a/source/blender/editors/screen/screen_intern.h
+++ b/source/blender/editors/screen/screen_intern.h
@@ -36,6 +36,8 @@ struct wmWindow;
struct Scene;
#define AZONESPOT (0.6f * U.widget_unit)
+#define AZONEFADEIN (5.0f * U.widget_unit) /* when azone is totally visible */
+#define AZONEFADEOUT (6.5f * U.widget_unit) /* when we start seeing the azone */
/* area.c */
void ED_area_data_copy(ScrArea *sa_dst, ScrArea *sa_src, const bool do_free);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 8b6a1b22a5c..a4a7580c058 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -129,13 +129,31 @@ static int screen_active_editable(bContext *C)
{
if (ED_operator_screenactive(C)) {
/* no full window splitting allowed */
- if (CTX_wm_screen(C)->full != SCREENNORMAL)
+ if (CTX_wm_screen(C)->state != SCREENNORMAL)
return 0;
return 1;
}
return 0;
}
+static ARegion *screen_find_region_type(bContext *C, int type)
+{
+ ARegion *ar = CTX_wm_region(C);
+
+ /* find the header region
+ * - try context first, but upon failing, search all regions in area...
+ */
+ if ((ar == NULL) || (ar->regiontype != type)) {
+ ScrArea *sa = CTX_wm_area(C);
+ ar = BKE_area_find_region_type(sa, type);
+ }
+ else {
+ ar = NULL;
+ }
+
+ return ar;
+}
+
/* when mouse is over area-edge */
int ED_operator_screen_mainwinactive(bContext *C)
{
@@ -166,7 +184,7 @@ int ED_operator_objectmode(bContext *C)
return 0;
/* add a check for ob->mode too? */
- if (obact && obact->mode)
+ if (obact && (obact->mode != OB_MODE_OBJECT))
return 0;
return 1;
@@ -201,7 +219,7 @@ int ED_operator_animview_active(bContext *C)
{
if (ED_operator_areaactive(C)) {
SpaceLink *sl = (SpaceLink *)CTX_wm_space_data(C);
- if (sl && (ELEM5(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME)))
+ if (sl && (ELEM(sl->spacetype, SPACE_SEQ, SPACE_ACTION, SPACE_NLA, SPACE_IPO, SPACE_TIME)))
return true;
}
@@ -267,7 +285,6 @@ int ED_operator_node_editable(bContext *C)
return 0;
}
-/* XXX rename */
int ED_operator_graphedit_active(bContext *C)
{
return ed_spacetype_test(C, SPACE_IPO);
@@ -612,6 +629,24 @@ static int actionzone_area_poll(bContext *C)
return 0;
}
+/* the debug drawing of the click_rect is in area_draw_azone_fullscreen, keep both in sync */
+static void fullscreen_click_rcti_init(rcti *rect, const short x1, const short y1, const short x2, const short y2)
+{
+ int x = x2 - ((float) x2 - x1) * 0.5f / UI_DPI_FAC;
+ int y = y2 - ((float) y2 - y1) * 0.5f / UI_DPI_FAC;
+ float icon_size = UI_DPI_ICON_SIZE + 7 * UI_DPI_FAC;
+
+ /* adjust the icon distance from the corner */
+ x += 36.0f / UI_DPI_FAC;
+ y += 36.0f / UI_DPI_FAC;
+
+ /* draws from the left bottom corner of the icon */
+ x -= UI_DPI_ICON_SIZE;
+ y -= UI_DPI_ICON_SIZE;
+
+ BLI_rcti_init(rect, x, x + icon_size, y, y + icon_size);
+}
+
AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2])
{
AZone *az = NULL;
@@ -628,6 +663,42 @@ AZone *is_in_area_actionzone(ScrArea *sa, const int xy[2])
else if (az->type == AZONE_REGION) {
break;
}
+ else if (az->type == AZONE_FULLSCREEN) {
+ int mouse_radius, spot_radius, fadein_radius, fadeout_radius;
+ rcti click_rect;
+
+ fullscreen_click_rcti_init(&click_rect, az->x1, az->y1, az->x2, az->y2);
+
+ if (BLI_rcti_isect_pt_v(&click_rect, xy)) {
+ az->alpha = 1.0f;
+ }
+ else {
+ mouse_radius = (xy[0] - az->x2) * (xy[0] - az->x2) + (xy[1] - az->y2) * (xy[1] - az->y2);
+ spot_radius = AZONESPOT * AZONESPOT;
+ fadein_radius = AZONEFADEIN * AZONEFADEIN;
+ fadeout_radius = AZONEFADEOUT * AZONEFADEOUT;
+
+ if (mouse_radius < spot_radius) {
+ az->alpha = 1.0f;
+ }
+ else if (mouse_radius < fadein_radius) {
+ az->alpha = 1.0f;
+ }
+ else if (mouse_radius < fadeout_radius) {
+ az->alpha = 1.0f - ((float)(mouse_radius - fadein_radius)) / ((float)(fadeout_radius - fadein_radius));
+ }
+ else {
+ az->alpha = 0.0f;
+ }
+
+ /* fade in/out but no click */
+ az = NULL;
+ }
+
+ /* XXX force redraw to show/hide the action zone */
+ ED_area_tag_redraw(sa);
+ break;
+ }
}
}
@@ -655,8 +726,11 @@ static void actionzone_apply(bContext *C, wmOperator *op, int type)
if (type == AZONE_AREA)
event.type = EVT_ACTIONZONE_AREA;
+ else if (type == AZONE_FULLSCREEN)
+ event.type = EVT_ACTIONZONE_FULLSCREEN;
else
event.type = EVT_ACTIONZONE_REGION;
+
event.val = 0;
event.customdata = op->customdata;
event.customdatafree = true;
@@ -681,8 +755,8 @@ static int actionzone_invoke(bContext *C, wmOperator *op, const wmEvent *event)
sad->x = event->x; sad->y = event->y;
/* region azone directly reacts on mouse clicks */
- if (sad->az->type == AZONE_REGION) {
- actionzone_apply(C, op, AZONE_REGION);
+ if (ELEM(sad->az->type, AZONE_REGION, AZONE_FULLSCREEN)) {
+ actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
return OPERATOR_FINISHED;
}
@@ -1463,7 +1537,7 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int dir;
/* no full window splitting allowed */
- if (sc->full != SCREENNORMAL)
+ if (sc->state != SCREENNORMAL)
return OPERATOR_CANCELLED;
if (event->type == EVT_ACTIONZONE_AREA) {
@@ -2232,8 +2306,8 @@ static void SCREEN_OT_marker_jump(wmOperatorType *ot)
static bool screen_set_is_ok(bScreen *screen, bScreen *screen_prev)
{
- return ((screen->winid == 0) &&
- (screen->full == 0) &&
+ return ((screen->winid == 0) &&
+ (screen->state == SCREENNORMAL) &&
(screen != screen_prev) &&
(screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT)));
}
@@ -2304,10 +2378,11 @@ static void SCREEN_OT_screen_set(wmOperatorType *ot)
/* function to be called outside UI context, or for redo */
-static int screen_full_area_exec(bContext *C, wmOperator *UNUSED(op))
+static int screen_maximize_area_exec(bContext *C, wmOperator *op)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *sa = NULL;
+ const bool hide_panels = RNA_boolean_get(op->ptr, "use_hide_panels");
/* search current screen for 'fullscreen' areas */
/* prevents restoring info header, when mouse is over it */
@@ -2315,25 +2390,41 @@ static int screen_full_area_exec(bContext *C, wmOperator *UNUSED(op))
if (sa->full) break;
}
- if (sa == NULL) sa = CTX_wm_area(C);
+ if (sa == NULL) {
+ sa = CTX_wm_area(C);
+ }
- ED_screen_full_toggle(C, CTX_wm_window(C), sa);
+ if (hide_panels) {
+ if (!ELEM(screen->state, SCREENNORMAL, SCREENFULL)) {
+ return OPERATOR_CANCELLED;
+ }
+ ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENFULL);
+ }
+ else {
+ if (!ELEM(screen->state, SCREENNORMAL, SCREENMAXIMIZED)) {
+ return OPERATOR_CANCELLED;
+ }
+ ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
+ }
+
return OPERATOR_FINISHED;
}
static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
{
- ot->name = "Toggle Full Screen";
- ot->description = "Toggle display selected area as fullscreen";
+ PropertyRNA *prop;
+
+ ot->name = "Toggle Fullscreen Area";
+ ot->description = "Toggle display selected area as fullscreen/maximized";
ot->idname = "SCREEN_OT_screen_full_area";
- ot->exec = screen_full_area_exec;
+ ot->exec = screen_maximize_area_exec;
ot->poll = ED_operator_areaactive;
ot->flag = 0;
-
-}
-
+ prop = RNA_def_boolean(ot->srna, "use_hide_panels", false, "Hide Panels", "Hide all the panels");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
/* ************** join area operator ********************************************** */
@@ -3028,23 +3119,44 @@ static void SCREEN_OT_region_flip(wmOperatorType *ot)
ot->flag = 0;
}
+/* ************** header operator ***************************** */
+static int header_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ ARegion *ar = screen_find_region_type(C, RGN_TYPE_HEADER);
+
+ if (ar == NULL) {
+ return OPERATOR_CANCELLED;
+ }
+
+ ar->flag ^= RGN_FLAG_HIDDEN;
+
+ ED_area_tag_redraw(CTX_wm_area(C));
+
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+static void SCREEN_OT_header(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Header";
+ ot->description = "Display header";
+ ot->idname = "SCREEN_OT_header";
+
+ /* api callbacks */
+ ot->exec = header_exec;
+}
+
/* ************** header flip operator ***************************** */
/* flip a header region alignment */
static int header_flip_exec(bContext *C, wmOperator *UNUSED(op))
{
- ARegion *ar = CTX_wm_region(C);
-
- /* find the header region
- * - try context first, but upon failing, search all regions in area...
- */
- if ((ar == NULL) || (ar->regiontype != RGN_TYPE_HEADER)) {
- ScrArea *sa = CTX_wm_area(C);
- ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER);
+ ARegion *ar = screen_find_region_type(C, RGN_TYPE_HEADER);
- /* don't do anything if no region */
- if (ar == NULL)
- return OPERATOR_CANCELLED;
+ if (ar == NULL) {
+ return OPERATOR_CANCELLED;
}
/* copied from SCREEN_OT_region_flip */
@@ -3221,6 +3333,16 @@ static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
}
}
+ else if (regiontype == RGN_TYPE_CHANNELS) {
+ switch (spacetype) {
+ case SPACE_IPO:
+ case SPACE_ACTION:
+ case SPACE_NLA:
+ if (redraws & TIME_ALL_ANIM_WIN)
+ return 1;
+ break;
+ }
+ }
else if (regiontype == RGN_TYPE_UI) {
if (spacetype == SPACE_CLIP) {
/* Track Preview button is on Properties Editor in SpaceClip,
@@ -3936,6 +4058,7 @@ void ED_operatortypes_screen(void)
WM_operatortype_append(SCREEN_OT_region_scale);
WM_operatortype_append(SCREEN_OT_region_flip);
WM_operatortype_append(SCREEN_OT_header_flip);
+ WM_operatortype_append(SCREEN_OT_header);
WM_operatortype_append(SCREEN_OT_header_toggle_menus);
WM_operatortype_append(SCREEN_OT_header_toolbox);
WM_operatortype_append(SCREEN_OT_screen_set);
@@ -4038,6 +4161,7 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_verify_item(keymap, "SCREEN_OT_area_options", RIGHTMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "SCREEN_OT_header", F9KEY, KM_PRESS, KM_ALT, 0);
/* Header Editing ------------------------------------------------ */
keymap = WM_keymap_find(keyconf, "Header", 0, 0);
@@ -4057,6 +4181,11 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
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);
@@ -4155,7 +4284,8 @@ void ED_keymap_screen(wmKeyConfig *keyconf)
/* dropbox for entire window */
lb = WM_dropboxmap_find("Window", 0, 0);
WM_dropbox_add(lb, "WM_OT_open_mainfile", open_file_drop_poll, open_file_drop_copy);
-
+ WM_dropbox_add(lb, "UI_OT_drop_color", UI_drop_color_poll, UI_drop_color_copy);
+
keymap_modal_set(keyconf);
}
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt
index 79ce4f879b7..0fa5f2d9837 100644
--- a/source/blender/editors/sculpt_paint/CMakeLists.txt
+++ b/source/blender/editors/sculpt_paint/CMakeLists.txt
@@ -32,6 +32,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -40,6 +41,7 @@ set(INC_SYS
set(SRC
paint_cursor.c
+ paint_curve.c
paint_hide.c
paint_image.c
paint_image_2d.c
@@ -63,4 +65,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_sculpt_paint "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/sculpt_paint/SConscript b/source/blender/editors/sculpt_paint/SConscript
index b0118fbbf53..233f562fcc7 100644
--- a/source/blender/editors/sculpt_paint/SConscript
+++ b/source/blender/editors/sculpt_paint/SConscript
@@ -29,11 +29,12 @@ Import ('env')
sources = env.Glob('*.c')
-defs = []
+defs = env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../uvedit',
'../../blenfont',
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index b1e4696cd02..e27ef705fad 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -44,6 +44,7 @@
#include "BKE_brush.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
#include "BKE_image.h"
#include "BKE_node.h"
#include "BKE_paint.h"
@@ -58,6 +59,8 @@
#include "ED_view3d.h"
+#include "UI_resources.h"
+
#include "paint_intern.h"
/* still needed for sculpt_stroke_get_location, should be
* removed eventually (TODO) */
@@ -518,14 +521,15 @@ static int project_brush_radius(ViewContext *vc,
}
}
-static int sculpt_get_brush_geometry(bContext *C, ViewContext *vc,
- int x, int y, int *pixel_radius,
- float location[3])
+static bool sculpt_get_brush_geometry(
+ bContext *C, ViewContext *vc,
+ int x, int y, int *pixel_radius,
+ float location[3])
{
Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
float mouse[2];
- int hit;
+ bool hit;
mouse[0] = x;
mouse[1] = y;
@@ -756,7 +760,7 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
ViewContext *vc, int x, int y, float zoom, PaintMode mode)
{
/* color means that primary brush texture is colured and secondary is used for alpha/mask control */
- bool col = ELEM3(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false;
+ bool col = ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX) ? true : false;
OverlayControlFlags flags = BKE_paint_get_overlay_flags();
/* save lots of GL state
* TODO: check on whether all of these are needed? */
@@ -791,6 +795,138 @@ static void paint_draw_alpha_overlay(UnifiedPaintSettings *ups, Brush *brush,
glPopAttrib();
}
+
+BLI_INLINE void draw_tri_point(float *co, float width, bool selected)
+{
+ float w = width / 2.0f;
+ if (selected)
+ UI_ThemeColor4(TH_VERTEX_SELECT);
+ else
+ UI_ThemeColor4(TH_PAINT_CURVE_PIVOT);
+
+ glLineWidth(3.0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(co[0], co[1] + w);
+ glVertex2f(co[0] - w, co[1] - w);
+ glVertex2f(co[0] + w, co[1] - w);
+ glEnd();
+
+ glColor4f(1.0, 1.0, 1.0, 0.5);
+ glLineWidth(1.0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(co[0], co[1] + w);
+ glVertex2f(co[0] - w, co[1] - w);
+ glVertex2f(co[0] + w, co[1] - w);
+ glEnd();
+}
+
+BLI_INLINE void draw_rect_point(float *co, float width, bool selected)
+{
+ float w = width / 2.0f;
+ if (selected)
+ UI_ThemeColor4(TH_VERTEX_SELECT);
+ else
+ UI_ThemeColor4(TH_PAINT_CURVE_HANDLE);
+ glLineWidth(3.0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(co[0] + w, co[1] + w);
+ glVertex2f(co[0] - w, co[1] + w);
+ glVertex2f(co[0] - w, co[1] - w);
+ glVertex2f(co[0] + w, co[1] - w);
+ glEnd();
+
+ glColor4f(1.0, 1.0, 1.0, 0.5);
+ glLineWidth(1.0);
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(co[0] + w, co[1] + w);
+ glVertex2f(co[0] - w, co[1] + w);
+ glVertex2f(co[0] - w, co[1] - w);
+ glVertex2f(co[0] + w, co[1] - w);
+ glEnd();
+}
+
+
+BLI_INLINE void draw_bezier_handle_lines(BezTriple *bez)
+{
+ short line1[] = {0, 1};
+ short line2[] = {1, 2};
+
+ glVertexPointer(2, GL_FLOAT, 3 * sizeof(float), bez->vec);
+ glColor4f(0.0, 0.0, 0.0, 0.5);
+ glLineWidth(3.0);
+ glDrawArrays(GL_LINE_STRIP, 0, 3);
+
+ glLineWidth(1.0);
+ if (bez->f1 || bez->f2)
+ UI_ThemeColor4(TH_VERTEX_SELECT);
+ else
+ glColor4f(1.0, 1.0, 1.0, 0.5);
+ glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line1);
+ if (bez->f3 || bez->f2)
+ UI_ThemeColor4(TH_VERTEX_SELECT);
+ else
+ glColor4f(1.0, 1.0, 1.0, 0.5);
+ glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, line2);
+}
+
+static void paint_draw_curve_cursor(Brush *brush)
+{
+ if (brush->paint_curve && brush->paint_curve->points) {
+ int i;
+ PaintCurve *pc = brush->paint_curve;
+ PaintCurvePoint *cp = pc->points;
+
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glEnableClientState(GL_VERTEX_ARRAY);
+
+ /* draw the bezier handles and the curve segment between the current and next point */
+ for (i = 0; i < pc->tot_points - 1; i++, cp++) {
+ int j;
+ PaintCurvePoint *cp_next = cp + 1;
+ float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ /* use color coding to distinguish handles vs curve segments */
+ draw_bezier_handle_lines(&cp->bez);
+ draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
+ draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
+ draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
+
+ for (j = 0; j < 2; j++)
+ BKE_curve_forward_diff_bezier(
+ cp->bez.vec[1][j],
+ cp->bez.vec[2][j],
+ cp_next->bez.vec[0][j],
+ cp_next->bez.vec[1][j],
+ data + j, PAINT_CURVE_NUM_SEGMENTS, sizeof(float[2]));
+
+ glVertexPointer(2, GL_FLOAT, 0, data);
+ glLineWidth(3.0);
+ glColor4f(0.0, 0.0, 0.0, 0.5);
+ glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
+
+ glLineWidth(1.0);
+ glColor4f(0.9, 0.9, 1.0, 0.5);
+ glDrawArrays(GL_LINE_STRIP, 0, PAINT_CURVE_NUM_SEGMENTS + 1);
+ }
+
+ /* draw last line segment */
+ draw_bezier_handle_lines(&cp->bez);
+ draw_tri_point(&cp->bez.vec[1][0], 10.0, cp->bez.f2);
+ draw_rect_point(&cp->bez.vec[0][0], 8.0, cp->bez.f1 || cp->bez.f2);
+ draw_rect_point(&cp->bez.vec[2][0], 8.0, cp->bez.f3 || cp->bez.f2);
+
+ glLineWidth(1.0);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ glDisableClientState(GL_VERTEX_ARRAY);
+ }
+}
+
/* Special actions taken when paint cursor goes over mesh */
/* TODO: sculpt only for now */
static void paint_cursor_on_hit(UnifiedPaintSettings *ups, Brush *brush, ViewContext *vc,
@@ -848,6 +984,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
zoomx = max_ff(zoomx, zoomy);
mode = BKE_paintmode_get_active_from_context(C);
+ /* skip everything and draw brush here */
+ if (brush->flag & BRUSH_CURVE) {
+ paint_draw_curve_cursor(brush);
+ return;
+ }
+
/* set various defaults */
translation[0] = x;
translation[1] = y;
@@ -857,8 +999,11 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* don't calculate rake angles while a stroke is active because the rake variables are global and
* we may get interference with the stroke itself. For line strokes, such interference is visible */
- if (!ups->stroke_active && (brush->flag & BRUSH_RAKE))
- paint_calculate_rake_rotation(ups, translation);
+ if (!ups->stroke_active) {
+ if (brush->flag & BRUSH_RAKE)
+ /* here, translation contains the mouse coordinates. */
+ paint_calculate_rake_rotation(ups, translation);
+ }
/* draw overlay */
paint_draw_alpha_overlay(ups, brush, &vc, x, y, zoomx, mode);
@@ -867,7 +1012,8 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
* special mode of drawing will go away */
if ((mode == PAINT_SCULPT) && vc.obact->sculpt) {
float location[3];
- int pixel_radius, hit;
+ int pixel_radius;
+ bool hit;
/* test if brush is over the mesh */
hit = sculpt_get_brush_geometry(C, &vc, x, y, &pixel_radius, location);
@@ -878,9 +1024,9 @@ 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 ((!(brush->flag & BRUSH_INVERTED) ^
+ if ((!(ups->draw_inverted) ^
!(brush->flag & BRUSH_DIR_IN)) &&
- ELEM5(brush->sculpt_tool, SCULPT_TOOL_DRAW,
+ ELEM(brush->sculpt_tool, SCULPT_TOOL_DRAW,
SCULPT_TOOL_INFLATE, SCULPT_TOOL_CLAY,
SCULPT_TOOL_PINCH, SCULPT_TOOL_CREASE))
{
@@ -890,12 +1036,12 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused))
/* only do if brush is over the mesh */
if (hit)
paint_cursor_on_hit(ups, brush, &vc, location);
+ }
- if (ups->draw_anchored) {
- final_radius = ups->anchored_size;
- translation[0] = ups->anchored_initial_mouse[0];
- translation[1] = ups->anchored_initial_mouse[1];
- }
+ if (ups->draw_anchored) {
+ final_radius = ups->anchored_size;
+ translation[0] = ups->anchored_initial_mouse[0];
+ translation[1] = ups->anchored_initial_mouse[1];
}
/* make lines pretty */
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
new file mode 100644
index 00000000000..8c7c3b102e3
--- /dev/null
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -0,0 +1,787 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/sculpt_paint/paint_curve.c
+ * \ingroup edsculpt
+ */
+
+#include <string.h>
+#include <limits.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_brush_types.h"
+#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_context.h"
+#include "BKE_main.h"
+#include "BKE_paint.h"
+
+#include "BLI_math_vector.h"
+#include "BLI_string.h"
+
+#include "ED_paint.h"
+#include "ED_view3d.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "RNA_access.h"
+#include "RNA_define.h"
+
+#include "UI_view2d.h"
+
+#include "paint_intern.h"
+
+#define PAINT_CURVE_SELECT_THRESHOLD 40.0f
+#define PAINT_CURVE_POINT_SELECT(pcp, i) (*(&pcp->bez.f1 + i) = SELECT)
+
+
+int paint_curve_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ Paint *p;
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ SpaceImage *sima;
+
+ if (rv3d && !(ob && ((ob->mode & OB_MODE_ALL_PAINT) != 0)))
+ return false;
+
+ sima = CTX_wm_space_image(C);
+
+ if (sima && sima->mode != SI_MODE_PAINT)
+ return false;
+
+ p = BKE_paint_get_active_from_context(C);
+
+ if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
+ return true;
+ }
+
+ return false;
+}
+
+/* Paint Curve Undo*/
+
+typedef struct UndoCurve {
+ struct UndoImageTile *next, *prev;
+
+ PaintCurvePoint *points; /* points of curve */
+ int tot_points;
+ int active_point;
+
+ char idname[MAX_ID_NAME]; /* name instead of pointer*/
+} UndoCurve;
+
+static void paintcurve_undo_restore(bContext *C, ListBase *lb)
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ UndoCurve *uc;
+ PaintCurve *pc = NULL;
+
+ if (p->brush) {
+ pc = p->brush->paint_curve;
+ }
+
+ if (!pc)
+ return;
+
+ uc = (UndoCurve *)lb->first;
+
+ if (strncmp(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname))) == 0) {
+ SWAP(PaintCurvePoint *, pc->points, uc->points);
+ SWAP(int, pc->tot_points, uc->tot_points);
+ SWAP(int, pc->add_index, uc->active_point);
+ }
+}
+
+static void paintcurve_undo_delete(ListBase *lb)
+{
+ UndoCurve *uc;
+ uc = (UndoCurve *)lb->first;
+
+ if (uc->points)
+ MEM_freeN(uc->points);
+ uc->points = NULL;
+}
+
+
+static void paintcurve_undo_begin(bContext *C, wmOperator *op, PaintCurve *pc)
+{
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ ListBase *lb = NULL;
+ int undo_stack_id;
+ UndoCurve *uc;
+
+ switch (mode) {
+ case PAINT_TEXTURE_2D:
+ case PAINT_TEXTURE_PROJECTIVE:
+ undo_stack_id = UNDO_PAINT_IMAGE;
+ break;
+
+ case PAINT_SCULPT:
+ undo_stack_id = UNDO_PAINT_MESH;
+ break;
+
+ default:
+ /* do nothing, undo is handled by global */
+ return;
+ }
+
+
+ ED_undo_paint_push_begin(undo_stack_id, op->type->name,
+ paintcurve_undo_restore, paintcurve_undo_delete, NULL);
+ lb = undo_paint_push_get_list(undo_stack_id);
+
+ uc = MEM_callocN(sizeof(*uc), "Undo_curve");
+
+ lb->first = uc;
+
+ BLI_strncpy(uc->idname, pc->id.name, sizeof(uc->idname));
+ uc->tot_points = pc->tot_points;
+ uc->active_point = pc->add_index;
+ uc->points = MEM_dupallocN(pc->points);
+
+ undo_paint_push_count_alloc(undo_stack_id, sizeof(*uc) + sizeof(*pc->points) * pc->tot_points);
+
+ ED_undo_paint_push_end(undo_stack_id);
+}
+#define SEL_F1 (1 << 0)
+#define SEL_F2 (1 << 1)
+#define SEL_F3 (1 << 2)
+
+/* returns 0, 1, or 2 in point according to handle 1, pivot or handle 2 */
+static PaintCurvePoint *paintcurve_point_get_closest(PaintCurve *pc, const float pos[2], bool ignore_pivot, const float threshold, char *point)
+{
+ PaintCurvePoint *pcp, *closest = NULL;
+ int i;
+ float dist, closest_dist = FLT_MAX;
+
+ for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+ dist = len_manhattan_v2v2(pos, pcp->bez.vec[0]);
+ if (dist < threshold) {
+ if (dist < closest_dist) {
+ closest = pcp;
+ closest_dist = dist;
+ if (point)
+ *point = SEL_F1;
+ }
+ }
+ if (!ignore_pivot) {
+ dist = len_manhattan_v2v2(pos, pcp->bez.vec[1]);
+ if (dist < threshold) {
+ if (dist < closest_dist) {
+ closest = pcp;
+ closest_dist = dist;
+ if (point)
+ *point = SEL_F2;
+ }
+ }
+ }
+ dist = len_manhattan_v2v2(pos, pcp->bez.vec[2]);
+ if (dist < threshold) {
+ if (dist < closest_dist) {
+ closest = pcp;
+ closest_dist = dist;
+ if (point)
+ *point = SEL_F3;
+ }
+ }
+ }
+
+ return closest;
+}
+
+static int paintcurve_point_co_index(char sel)
+{
+ char i = 0;
+ while (sel != 1) {
+ sel >>= 1;
+ i++;
+ }
+ return i;
+}
+
+/******************* Operators *********************************/
+
+static int paintcurve_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Main *bmain = CTX_data_main(C);
+
+ if (p && p->brush) {
+ p->brush->paint_curve = BKE_paint_curve_add(bmain, "PaintCurve");
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINTCURVE_OT_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Paint Curve";
+ ot->description = "Add new paint curve";
+ ot->idname = "PAINTCURVE_OT_new";
+
+ /* api callbacks */
+ ot->exec = paintcurve_new_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static void paintcurve_point_add(bContext *C, wmOperator *op, const int loc[2])
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = p->brush;
+ Main *bmain = CTX_data_main(C);
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ float vec[3] = {loc[0], loc[1], 0.0};
+ int add_index;
+ int i;
+
+ pc = br->paint_curve;
+ if (!pc) {
+ br->paint_curve = pc = BKE_paint_curve_add(bmain, "PaintCurve");
+ }
+
+ paintcurve_undo_begin(C, op, pc);
+
+ pcp = MEM_mallocN((pc->tot_points + 1) * sizeof(PaintCurvePoint), "PaintCurvePoint");
+ add_index = pc->add_index;
+
+ if (pc->points) {
+ if (add_index > 0)
+ memcpy(pcp, pc->points, add_index * sizeof(PaintCurvePoint));
+ if (add_index < pc->tot_points)
+ memcpy(pcp + add_index + 1, pc->points + add_index, (pc->tot_points - add_index) * sizeof(PaintCurvePoint));
+
+ MEM_freeN(pc->points);
+ }
+ pc->points = pcp;
+ pc->tot_points++;
+
+ /* initialize new point */
+ memset(&pcp[add_index], 0, sizeof(PaintCurvePoint));
+ copy_v3_v3(pcp[add_index].bez.vec[0], vec);
+ copy_v3_v3(pcp[add_index].bez.vec[1], vec);
+ copy_v3_v3(pcp[add_index].bez.vec[2], vec);
+
+ /* last step, clear selection from all bezier handles expect the next */
+ 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;
+
+ WM_paint_cursor_tag_redraw(window, ar);
+}
+
+
+static int paintcurve_add_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int loc[2] = {event->mval[0], event->mval[1]};
+ paintcurve_point_add(C, op, loc);
+ RNA_int_set_array(op->ptr, "location", loc);
+ return OPERATOR_FINISHED;
+}
+
+static int paintcurve_add_point_exec(bContext *C, wmOperator *op)
+{
+ int loc[2];
+
+ if (RNA_struct_property_is_set(op->ptr, "location")) {
+ RNA_int_get_array(op->ptr, "location", loc);
+ paintcurve_point_add(C, op, loc);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void PAINTCURVE_OT_add_point(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Paint Curve Point";
+ ot->description = "Add new paint curve point";
+ ot->idname = "PAINTCURVE_OT_add_point";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_add_point_invoke;
+ ot->exec = paintcurve_add_point_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
+ "Location", "Location of vertex in area space", 0, SHRT_MAX);
+}
+
+static int paintcurve_delete_point_exec(bContext *C, wmOperator *op)
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = p->brush;
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ int i;
+ int tot_del = 0;
+ pc = br->paint_curve;
+
+ if (!pc || pc->tot_points == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ paintcurve_undo_begin(C, op, pc);
+
+#define DELETE_TAG 2
+
+ for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+ if ((pcp->bez.f1 & SELECT) || (pcp->bez.f2 & SELECT) || (pcp->bez.f3 & SELECT)) {
+ pcp->bez.f2 |= DELETE_TAG;
+ tot_del++;
+ }
+ }
+
+ if (tot_del > 0) {
+ int j = 0;
+ int new_tot = pc->tot_points - tot_del;
+ PaintCurvePoint *points_new = NULL;
+ if (new_tot > 0)
+ points_new = MEM_mallocN(new_tot * sizeof(PaintCurvePoint), "PaintCurvePoint");
+
+ for (i = 0, pcp = pc->points; i < pc->tot_points; i++, pcp++) {
+ if (!(pcp->bez.f2 & DELETE_TAG)) {
+ points_new[j] = pc->points[i];
+
+ if ((i + 1) == pc->add_index) {
+ pc->add_index = j + 1;
+ }
+ j++;
+ }
+ else if ((i + 1) == pc->add_index) {
+ /* prefer previous point */
+ pc->add_index = j;
+ }
+ }
+ MEM_freeN(pc->points);
+
+ pc->points = points_new;
+ pc->tot_points = new_tot;
+ }
+
+#undef DELETE_TAG
+
+ WM_paint_cursor_tag_redraw(window, ar);
+
+ return OPERATOR_FINISHED;
+}
+
+
+void PAINTCURVE_OT_delete_point(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Paint Curve Point";
+ ot->description = "Add new paint curve point";
+ ot->idname = "PAINTCURVE_OT_delete_point";
+
+ /* api callbacks */
+ ot->exec = paintcurve_delete_point_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+
+static bool paintcurve_point_select(bContext *C, wmOperator *op, const int loc[2], bool toggle, bool extend)
+{
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+ Paint *p = BKE_paint_get_active_from_context(C);
+ Brush *br = p->brush;
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ int i;
+ const float loc_fl[2] = {UNPACK2(loc)};
+
+ pc = br->paint_curve;
+
+ if (!pc)
+ return false;
+
+ paintcurve_undo_begin(C, op, pc);
+
+ pcp = pc->points;
+
+ if (toggle) {
+ char select = 0;
+ bool selected = false;
+
+ for (i = 0; i < pc->tot_points; i++) {
+ if (pcp[i].bez.f1 || pcp[i].bez.f2 || pcp[i].bez.f3) {
+ selected = true;
+ break;
+ }
+ }
+
+ if (!selected) {
+ select = SELECT;
+ }
+
+ for (i = 0; i < pc->tot_points; i++) {
+ pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = select;
+ }
+ }
+ else {
+ PaintCurvePoint *pcp;
+ char selflag;
+
+ pcp = paintcurve_point_get_closest(pc, loc_fl, false, PAINT_CURVE_SELECT_THRESHOLD, &selflag);
+
+ if (pcp) {
+ pc->add_index = (pcp - pc->points) + 1;
+
+ if (selflag == SEL_F2) {
+ if (extend)
+ pcp->bez.f2 ^= SELECT;
+ else
+ pcp->bez.f2 |= SELECT;
+ }
+ else if (selflag == SEL_F1) {
+ if (extend)
+ pcp->bez.f1 ^= SELECT;
+ else
+ pcp->bez.f1 |= SELECT;
+ }
+ else if (selflag == SEL_F3) {
+ if (extend)
+ pcp->bez.f3 ^= SELECT;
+ else
+ pcp->bez.f3 |= SELECT;
+ }
+ }
+
+ /* clear selection for unselected points if not extending and if a point has been selected */
+ if (!extend && pcp) {
+ for (i = 0; i < pc->tot_points; i++) {
+ pc->points[i].bez.f1 = pc->points[i].bez.f2 = pc->points[i].bez.f3 = 0;
+
+ if ((pc->points + i) == pcp) {
+ char index = paintcurve_point_co_index(selflag);
+ PAINT_CURVE_POINT_SELECT(pcp, index);
+ }
+ }
+ }
+
+ if (!pcp)
+ return false;
+ }
+
+ WM_paint_cursor_tag_redraw(window, ar);
+
+ return true;
+}
+
+
+static int paintcurve_select_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int loc[2] = {UNPACK2(event->mval)};
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ if (paintcurve_point_select(C, op, loc, toggle, extend)) {
+ RNA_int_set_array(op->ptr, "location", loc);
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static int paintcurve_select_point_exec(bContext *C, wmOperator *op)
+{
+ int loc[2];
+
+ if (RNA_struct_property_is_set(op->ptr, "location")) {
+ bool toggle = RNA_boolean_get(op->ptr, "toggle");
+ bool extend = RNA_boolean_get(op->ptr, "extend");
+ RNA_int_get_array(op->ptr, "location", loc);
+ if (paintcurve_point_select(C, op, loc, toggle, extend))
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void PAINTCURVE_OT_select(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Select Paint Curve Point";
+ ot->description = "Select a paint curve point";
+ ot->idname = "PAINTCURVE_OT_select";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_select_point_invoke;
+ ot->exec = paintcurve_select_point_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ /* properties */
+ RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, SHRT_MAX,
+ "Location", "Location of vertex in area space", 0, SHRT_MAX);
+ prop = RNA_def_boolean(ot->srna, "toggle", false, "Toggle", "(De)select all");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+typedef struct PointSlideData {
+ PaintCurvePoint *pcp;
+ char select;
+ int initial_loc[2];
+ float point_initial_loc[3][2];
+ int event;
+ bool align;
+} PointSlideData;
+
+static int paintcurve_slide_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Paint *p = BKE_paint_get_active_from_context(C);
+ const float loc_fl[2] = {UNPACK2(event->mval)};
+ char select;
+ int i;
+ bool do_select = RNA_boolean_get(op->ptr, "select");
+ bool align = RNA_boolean_get(op->ptr, "align");
+ Brush *br = p->brush;
+ PaintCurve *pc = br->paint_curve;
+ PaintCurvePoint *pcp;
+
+ if (!pc)
+ return OPERATOR_PASS_THROUGH;
+
+ if (do_select) {
+ pcp = paintcurve_point_get_closest(pc, loc_fl, align, PAINT_CURVE_SELECT_THRESHOLD, &select);
+ }
+ else {
+ 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) {
+ pcp = &pc->points[i];
+ select = SEL_F3;
+ break;
+ }
+ }
+ }
+
+
+ if (pcp) {
+ ARegion *ar = CTX_wm_region(C);
+ wmWindow *window = CTX_wm_window(C);
+ PointSlideData *psd = MEM_mallocN(sizeof(PointSlideData), "PointSlideData");
+ copy_v2_v2_int(psd->initial_loc, event->mval);
+ psd->event = event->type;
+ psd->pcp = pcp;
+ psd->select = paintcurve_point_co_index(select);
+ for (i = 0; i < 3; i++) {
+ copy_v2_v2(psd->point_initial_loc[i], pcp->bez.vec[i]);
+ }
+ psd->align = align;
+ op->customdata = psd;
+
+ if (do_select)
+ paintcurve_undo_begin(C, op, pc);
+
+ /* first, clear all selection from points */
+ for (i = 0; i < pc->tot_points; i++)
+ pc->points[i].bez.f1 = pc->points[i].bez.f3 = pc->points[i].bez.f2 = 0;
+
+ /* only select the active point */
+ PAINT_CURVE_POINT_SELECT(pcp, psd->select);
+ pc->add_index = (pcp - pc->points) + 1;
+
+ WM_event_add_modal_handler(C, op);
+ WM_paint_cursor_tag_redraw(window, ar);
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ return OPERATOR_PASS_THROUGH;
+}
+
+static int paintcurve_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ PointSlideData *psd = op->customdata;
+
+ if (event->type == psd->event && event->val == KM_RELEASE) {
+ MEM_freeN(psd);
+ return OPERATOR_FINISHED;
+ }
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ {
+ ARegion *ar = CTX_wm_region(C);
+ wmWindow *window = CTX_wm_window(C);
+ float diff[2] = {event->mval[0] - psd->initial_loc[0],
+ event->mval[1] - psd->initial_loc[1]};
+ if (psd->select == 1) {
+ int i;
+ for (i = 0; i < 3; i++)
+ add_v2_v2v2(psd->pcp->bez.vec[i], diff, psd->point_initial_loc[i]);
+ }
+ else {
+ add_v2_v2(diff, psd->point_initial_loc[psd->select]);
+ copy_v2_v2(psd->pcp->bez.vec[psd->select], diff);
+
+ if (psd->align) {
+ char opposite = (psd->select == 0) ? 2 : 0;
+ sub_v2_v2v2(diff, psd->pcp->bez.vec[1], psd->pcp->bez.vec[psd->select]);
+ add_v2_v2v2(psd->pcp->bez.vec[opposite], psd->pcp->bez.vec[1], diff);
+ }
+ }
+ WM_paint_cursor_tag_redraw(window, ar);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+
+void PAINTCURVE_OT_slide(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Slide Paint Curve Point";
+ ot->description = "Select and slide paint curve point";
+ ot->idname = "PAINTCURVE_OT_slide";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_slide_invoke;
+ ot->modal = paintcurve_slide_modal;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "align", false, "Align Handles", "Aligns opposite point handle during transform");
+ RNA_def_boolean(ot->srna, "select", true, "Select", "Attempt to select a point handle before transform");
+}
+
+static int paintcurve_draw_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ const char *name;
+
+ switch (mode) {
+ case PAINT_TEXTURE_2D:
+ case PAINT_TEXTURE_PROJECTIVE:
+ name = "PAINT_OT_image_paint";
+ break;
+ case PAINT_WEIGHT:
+ name = "PAINT_OT_weight_paint";
+ break;
+ case PAINT_VERTEX:
+ name = "PAINT_OT_vertex_paint";
+ break;
+ case PAINT_SCULPT:
+ name = "SCULPT_OT_brush_stroke";
+ break;
+ default:
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ return WM_operator_name_call(C, name, WM_OP_INVOKE_DEFAULT, NULL);
+}
+
+void PAINTCURVE_OT_draw(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Draw Curve";
+ ot->description = "Draw curve";
+ ot->idname = "PAINTCURVE_OT_draw";
+
+ /* api callbacks */
+ ot->exec = paintcurve_draw_exec;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+}
+
+static int paintcurve_cursor_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+
+ switch (mode) {
+ case PAINT_TEXTURE_2D:
+ {
+ ARegion *ar = CTX_wm_region(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ float location[2];
+
+ if (!sima)
+ return OPERATOR_CANCELLED;
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &location[0], &location[1]);
+ copy_v2_v2(sima->cursor, location);
+ WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL);
+ break;
+ }
+ default:
+ ED_view3d_cursor3d_update(C, event->mval);
+ break;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PAINTCURVE_OT_cursor(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Place Cursor";
+ ot->description = "Place cursor";
+ ot->idname = "PAINTCURVE_OT_cursor";
+
+ /* api callbacks */
+ ot->invoke = paintcurve_cursor_invoke;
+ ot->poll = paint_curve_poll;
+
+ /* flags */
+ ot->flag = 0;
+}
diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c
index 3d860145f59..f1c91d0fcb5 100644
--- a/source/blender/editors/sculpt_paint/paint_hide.c
+++ b/source/blender/editors/sculpt_paint/paint_hide.c
@@ -192,14 +192,14 @@ static void partialvis_update_grids(Object *ob,
/* skip grid element if not in the effected area */
if (is_effected(area, planes, co, mask)) {
/* set or clear the hide flag */
- BLI_BITMAP_MODIFY(gh, y * key.grid_size + x,
+ BLI_BITMAP_SET(gh, y * key.grid_size + x,
action == PARTIALVIS_HIDE);
any_changed = true;
}
/* keep track of whether any elements are still hidden */
- if (BLI_BITMAP_GET(gh, y * key.grid_size + x))
+ if (BLI_BITMAP_TEST(gh, y * key.grid_size + x))
any_hidden = true;
else
any_visible = true;
@@ -252,14 +252,14 @@ static void partialvis_update_bmesh_verts(BMesh *bm,
}
}
-static void partialvis_update_bmesh_faces(GSet *faces, PartialVisAction action)
+static void partialvis_update_bmesh_faces(GSet *faces)
{
GSetIterator gs_iter;
GSET_ITER (gs_iter, faces) {
BMFace *f = BLI_gsetIterator_getKey(&gs_iter);
- if ((action == PARTIALVIS_HIDE) && paint_is_bmesh_face_hidden(f))
+ if (paint_is_bmesh_face_hidden(f))
BM_elem_flag_enable(f, BM_ELEM_HIDDEN);
else
BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
@@ -301,7 +301,7 @@ static void partialvis_update_bmesh(Object *ob,
&any_visible);
/* finally loop over node faces and tag the ones that are fully hidden */
- partialvis_update_bmesh_faces(faces, action);
+ partialvis_update_bmesh_faces(faces);
if (any_changed) {
BKE_pbvh_node_mark_rebuild_draw(node);
@@ -329,7 +329,7 @@ static void clip_planes_from_rect(bContext *C,
view3d_set_viewcontext(C, &vc);
view3d_get_transformation(vc.ar, vc.rv3d, vc.obact, &mats);
ED_view3d_clipping_calc(&bb, clip_planes, &mats, rect);
- mul_m4_fl(clip_planes, -1.0f);
+ negate_m4(clip_planes);
}
/* If mode is inside, get all PBVH nodes that lie at least partially
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index 5e2bdcb3c93..021822793ff 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -43,6 +43,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_threads.h"
#include "PIL_time.h"
@@ -56,12 +57,18 @@
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_brush.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_node.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
+#include "BKE_scene.h"
+#include "BKE_texture.h"
+#include "BKE_colortools.h"
#include "BKE_editmesh.h"
@@ -69,8 +76,8 @@
#include "ED_image.h"
#include "ED_object.h"
+#include "ED_paint.h"
#include "ED_screen.h"
-#include "ED_sculpt.h"
#include "ED_view3d.h"
#include "WM_api.h"
@@ -81,6 +88,10 @@
#include "RNA_enum_types.h"
#include "GPU_draw.h"
+#include "GPU_buffers.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
#include "IMB_colormanagement.h"
@@ -102,14 +113,27 @@ typedef struct UndoImageTile {
int x, y;
+ Image *ima;
short source, use_float;
char gen_type;
+ bool valid;
} UndoImageTile;
/* this is a static resource for non-globality,
* Maybe it should be exposed as part of the
* paint operation, but for now just give a public interface */
static ImagePaintPartialRedraw imapaintpartial = {0, 0, 0, 0, 0};
+static SpinLock undolock;
+
+void image_undo_init_locks(void)
+{
+ BLI_spin_init(&undolock);
+}
+
+void image_undo_end_locks(void)
+{
+ BLI_spin_end(&undolock);
+}
ImagePaintPartialRedraw *get_imapaintpartial(void)
{
@@ -122,26 +146,53 @@ void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr)
}
/* UNDO */
+typedef enum {
+ COPY = 0,
+ RESTORE = 1,
+ RESTORE_COPY = 2
+} CopyMode;
-static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, int restore)
+static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, CopyMode mode)
{
- /* copy or swap contents of tile->rect and region in ibuf->rect */
- IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
- tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+ if (mode == COPY) {
+ /* copy or swap contents of tile->rect and region in ibuf->rect */
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
- if (ibuf->rect_float) {
- SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
}
else {
- SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
- }
-
- if (restore)
+ if (mode == RESTORE_COPY)
+ IMB_rectcpy(tmpibuf, ibuf, 0, 0, tile->x * IMAPAINT_TILE_SIZE,
+ tile->y * IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+ /* swap to the tmpbuf for easy copying */
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+
IMB_rectcpy(ibuf, tmpibuf, tile->x * IMAPAINT_TILE_SIZE,
tile->y * IMAPAINT_TILE_SIZE, 0, 0, IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE);
+
+ if (mode == RESTORE) {
+ if (ibuf->rect_float) {
+ SWAP(float *, tmpibuf->rect_float, tile->rect.fp);
+ }
+ else {
+ SWAP(unsigned int *, tmpibuf->rect, tile->rect.uint);
+ }
+ }
+ }
}
-void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask)
+void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsigned short **mask, bool validate)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
@@ -160,6 +211,8 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
*mask = tile->mask;
}
+ if (validate)
+ tile->valid = true;
return tile->rect.pt;
}
@@ -170,7 +223,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)
+void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile, int y_tile, unsigned short **mask, bool **valid, bool proj)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
UndoImageTile *tile;
@@ -179,10 +232,14 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
void *data;
/* check if tile is already pushed */
- data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, NULL);
- if (data)
- return data;
-
+
+ /* in projective painting we keep accounting of tiles, so if we need one pushed, just push! */
+ if (!proj) {
+ data = image_undo_find_tile(ima, ibuf, x_tile, y_tile, mask, true);
+ if (data)
+ return data;
+ }
+
if (*tmpibuf == NULL)
*tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, IB_rectfloat | IB_rect);
@@ -191,6 +248,11 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
tile->x = x_tile;
tile->y = y_tile;
+ /* add mask explicitly here */
+ if (mask)
+ *mask = tile->mask = MEM_callocN(sizeof(unsigned short) * IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE,
+ "UndoImageTile.mask");
+
allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
allocsize *= (ibuf->rect_float) ? sizeof(float) : sizeof(char);
tile->rect.pt = MEM_mapallocN(allocsize, "UndeImageTile.rect");
@@ -200,12 +262,23 @@ void *image_undo_push_tile(Image *ima, ImBuf *ibuf, ImBuf **tmpibuf, int x_tile,
tile->gen_type = ima->gen_type;
tile->source = ima->source;
tile->use_float = use_float;
+ tile->valid = true;
+ tile->ima = ima;
- undo_copy_tile(tile, *tmpibuf, ibuf, 0);
- undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
+ if (valid)
+ *valid = &tile->valid;
+ undo_copy_tile(tile, *tmpibuf, ibuf, COPY);
+
+ if (proj)
+ BLI_spin_lock(&undolock);
+
+ undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, allocsize);
BLI_addtail(lb, tile);
-
+
+ if (proj)
+ BLI_spin_unlock(&undolock);
+
return tile->rect.pt;
}
@@ -222,6 +295,33 @@ void image_undo_remove_masks(void)
}
}
+static void image_undo_restore_runtime(ListBase *lb)
+{
+ ImBuf *ibuf, *tmpibuf;
+ UndoImageTile *tile;
+
+ tmpibuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32,
+ IB_rectfloat | IB_rect);
+
+ for (tile = lb->first; tile; tile = tile->next) {
+ Image *ima = tile->ima;
+ ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
+
+ undo_copy_tile(tile, tmpibuf, ibuf, RESTORE);
+
+ GPU_free_image(ima); /* force OpenGL reload (maybe partial update will operate better?) */
+ if (ibuf->rect_float)
+ ibuf->userflags |= IB_RECT_INVALID; /* force recreate of char rect */
+ if (ibuf->mipmap[0])
+ ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
+ ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ }
+
+ IMB_freeImBuf(tmpibuf);
+}
+
void ED_image_undo_restore(bContext *C, ListBase *lb)
{
Main *bmain = CTX_data_main(C);
@@ -247,7 +347,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
if (ima && ibuf && strcmp(tile->ibufname, ibuf->name) != 0) {
/* current ImBuf filename was changed, probably current frame
- * was changed when paiting on image sequence, rather than storing
+ * was changed when painting on image sequence, rather than storing
* full image user (which isn't so obvious, btw) try to find ImBuf with
* matched file name in list of already loaded images */
@@ -273,7 +373,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
continue;
}
- undo_copy_tile(tile, tmpibuf, ibuf, 1);
+ undo_copy_tile(tile, tmpibuf, ibuf, RESTORE_COPY);
GPU_free_image(ima); /* force OpenGL reload */
if (ibuf->rect_float)
@@ -282,6 +382,8 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
ibuf->userflags |= IB_MIPMAP_INVALID; /* force mipmap recreatiom */
ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
+ DAG_id_tag_update(&ima->id, 0);
+
BKE_image_release_ibuf(ima, ibuf, NULL);
}
@@ -296,6 +398,42 @@ void ED_image_undo_free(ListBase *lb)
MEM_freeN(tile->rect.pt);
}
+static void image_undo_end(void)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ UndoImageTile *tile;
+ int deallocsize = 0;
+ int allocsize = IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE * 4;
+
+ /* first dispose of invalid tiles (may happen due to drag dot for instance) */
+ for (tile = lb->first; tile;) {
+ if (!tile->valid) {
+ UndoImageTile *tmp_tile = tile->next;
+ deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char));
+ MEM_freeN(tile->rect.pt);
+ BLI_freelinkN (lb, tile);
+ tile = tmp_tile;
+ }
+ else {
+ tile = tile->next;
+ }
+ }
+
+ /* don't forget to remove the size of deallocated tiles */
+ undo_paint_push_count_alloc(UNDO_PAINT_IMAGE, -deallocsize);
+
+ ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+}
+
+static void image_undo_invalidate(void)
+{
+ UndoImageTile *tile;
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+
+ for (tile = lb->first; tile; tile = tile->next)
+ tile->valid = false;
+}
+
/* Imagepaint Partial Redraw & Dirty Region */
void ED_imapaint_clear_partial_redraw(void)
@@ -344,7 +482,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);
+ image_undo_push_tile(ima, ibuf, &tmpibuf, tx, ty, NULL, NULL, false);
ibuf->userflags |= IB_BITMAPDIRTY;
@@ -373,6 +511,79 @@ void imapaint_image_update(SpaceImage *sima, Image *image, ImBuf *ibuf, short te
}
}
+/* paint blur kernels. Projective painting enforces use of a 2x2 kernel due to lagging */
+BlurKernel *paint_new_blur_kernel(Brush *br, bool proj)
+{
+ int i, j;
+ BlurKernel *kernel = MEM_mallocN(sizeof(BlurKernel), "blur kernel");
+ float radius;
+ int side;
+ BlurKernelType type = br->blur_mode;
+
+ if (proj) {
+ radius = 0.5f;
+
+ side = kernel->side = 2;
+ kernel->side_squared = kernel->side * kernel->side;
+ kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data");
+ kernel->pixel_len = radius;
+ }
+ else {
+ if (br->blur_kernel_radius <= 0)
+ br->blur_kernel_radius = 1;
+
+ radius = br->blur_kernel_radius;
+
+ side = kernel->side = radius * 2 + 1;
+ kernel->side_squared = kernel->side * kernel->side;
+ kernel->wdata = MEM_mallocN(sizeof(float) * kernel->side_squared, "blur kernel data");
+ kernel->pixel_len = br->blur_kernel_radius;
+ }
+
+ switch (type) {
+ case KERNEL_BOX:
+ for (i = 0; i < kernel->side_squared; i++)
+ kernel->wdata[i] = 1.0;
+ break;
+
+ case KERNEL_GAUSSIAN:
+ {
+ /* at 3.0 standard deviations distance, kernel is about zero */
+ float standard_dev = radius / 3.0f;
+
+ /* make the necessary adjustment to the value for use in the normal distribution formula */
+ standard_dev = -standard_dev * standard_dev * 2;
+
+ for (i = 0; i < side; i++) {
+ for (j = 0; j < side; j++) {
+ float idist = radius - i;
+ float jdist = radius - j;
+ float value = exp((idist * idist + jdist * jdist) / standard_dev);
+
+ kernel->wdata[i + j * side] = value;
+ }
+ }
+
+ break;
+ }
+
+ default:
+ printf("unidentified kernel type, aborting\n");
+ MEM_freeN(kernel->wdata);
+ MEM_freeN(kernel);
+ return NULL;
+ break;
+ }
+
+ return kernel;
+}
+
+void paint_delete_blur_kernel(BlurKernel *kernel)
+{
+ if (kernel->wdata)
+ MEM_freeN(kernel->wdata);
+}
+
/************************ image paint poll ************************/
static Brush *image_paint_brush(bContext *C)
@@ -385,11 +596,12 @@ static Brush *image_paint_brush(bContext *C)
static int image_paint_poll(bContext *C)
{
- Object *obact = CTX_data_active_object(C);
+ Object *obact;
if (!image_paint_brush(C))
return 0;
+ obact = CTX_data_active_object(C);
if ((obact && obact->mode & OB_MODE_TEXTURE_PAINT) && CTX_wm_region_view3d(C)) {
return 1;
}
@@ -432,11 +644,57 @@ typedef struct PaintOperation {
void *custom_paint;
float prevmouse[2];
+ float startmouse[2];
double starttime;
+ void *cursor;
ViewContext vc;
} PaintOperation;
+bool paint_use_opacity_masking(Brush *brush)
+{
+ return (brush->flag & BRUSH_AIRBRUSH) ||
+ (brush->flag & BRUSH_DRAG_DOT) ||
+ (brush->flag & BRUSH_ANCHORED) ||
+ (brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
+ (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) ||
+ (brush->imagepaint_tool == PAINT_TOOL_FILL) ||
+ (brush->flag & BRUSH_USE_GRADIENT) ||
+ (brush->mtex.tex && !ELEM(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)) ?
+ false : true;
+}
+
+void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance,
+ float pressure, float color[3], struct ColorManagedDisplay *display)
+{
+ if (invert)
+ copy_v3_v3(color, BKE_brush_secondary_color_get(scene, br));
+ else {
+ if (br->flag & BRUSH_USE_GRADIENT) {
+ switch (br->gradient_stroke_mode) {
+ case BRUSH_GRADIENT_PRESSURE:
+ do_colorband(br->gradient, pressure, color);
+ break;
+ case BRUSH_GRADIENT_SPACING_REPEAT:
+ {
+ float coord = fmod(distance / br->gradient_spacing, 1.0);
+ do_colorband(br->gradient, coord, color);
+ break;
+ }
+ case BRUSH_GRADIENT_SPACING_CLAMP:
+ {
+ do_colorband(br->gradient, distance / br->gradient_spacing, color);
+ break;
+ }
+ }
+ }
+ else
+ copy_v3_v3(color, BKE_brush_color_get(scene, br));
+ }
+ if (color_correction)
+ IMB_colormanagement_display_to_scene_linear_v3(color, display);
+}
+
void paint_brush_init_tex(Brush *brush)
{
/* init mtex nodes */
@@ -462,26 +720,56 @@ void paint_brush_exit_tex(Brush *brush)
}
}
+static void gradient_draw_line(bContext *UNUSED(C), int x, int y, void *customdata)
+{
+ PaintOperation *pop = (PaintOperation *)customdata;
+
+ if (pop) {
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+
+ glLineWidth(4.0);
+ glColor4ub(0, 0, 0, 255);
+ sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
+ glLineWidth(2.0);
+ glColor4ub(255, 255, 255, 255);
+ sdrawline(x, y, pop->startmouse[0], pop->startmouse[1]);
+ glLineWidth(1.0);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ }
+}
-static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mouse[2])
+
+static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, const float mouse[2])
{
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
PaintOperation *pop = MEM_callocN(sizeof(PaintOperation), "PaintOperation"); /* caller frees */
+ Brush *brush = BKE_paint_brush(&settings->imapaint.paint);
int mode = RNA_enum_get(op->ptr, "mode");
view3d_set_viewcontext(C, &pop->vc);
- pop->prevmouse[0] = mouse[0];
- pop->prevmouse[1] = mouse[1];
+ copy_v2_v2(pop->prevmouse, mouse);
+ copy_v2_v2(pop->startmouse, mouse);
/* initialize from context */
if (CTX_wm_region_view3d(C)) {
+ Object *ob = OBACT;
+ bool uvs, mat, tex, stencil;
+ if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, &stencil)) {
+ BKE_paint_data_warning(op->reports, uvs, mat, tex, stencil);
+ MEM_freeN(pop);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ return NULL;
+ }
pop->mode = PAINT_MODE_3D_PROJECT;
- pop->custom_paint = paint_proj_new_stroke(C, OBACT, pop->prevmouse, mode);
+ pop->custom_paint = paint_proj_new_stroke(C, ob, mouse, mode);
}
else {
pop->mode = PAINT_MODE_2D;
- pop->custom_paint = paint_2d_new_stroke(C, op);
+ pop->custom_paint = paint_2d_new_stroke(C, op, mode);
}
if (!pop->custom_paint) {
@@ -489,54 +777,75 @@ static PaintOperation *texture_paint_init(bContext *C, wmOperator *op, float mou
return NULL;
}
+ if ((brush->imagepaint_tool == PAINT_TOOL_FILL) && (brush->flag & BRUSH_USE_GRADIENT)) {
+ pop->cursor = WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, gradient_draw_line, pop);
+ }
+
settings->imapaint.flag |= IMAGEPAINT_DRAWING;
ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- ED_image_undo_restore, ED_image_undo_free);
-
- {
- UnifiedPaintSettings *ups = &settings->unified_paint_settings;
- ups->stroke_active = true;
- }
+ ED_image_undo_restore, ED_image_undo_free, NULL);
return pop;
}
+/* restore painting image to previous state. Used for anchored and drag-dot style brushes*/
+static void paint_stroke_restore(void)
+{
+ ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_IMAGE);
+ image_undo_restore_runtime(lb);
+ image_undo_invalidate();
+}
+
static void paint_stroke_update_step(bContext *C, struct PaintStroke *stroke, PointerRNA *itemptr)
{
PaintOperation *pop = paint_stroke_mode_data(stroke);
Scene *scene = CTX_data_scene(C);
- Brush *brush = BKE_paint_brush(&scene->toolsettings->imapaint.paint);
+ ToolSettings *toolsettings = CTX_data_tool_settings(C);
+ UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
+ Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
+
+ float alphafac = (brush->flag & BRUSH_ACCUMULATE) ? ups->overlap_factor : 1.0f;
/* initial brush values. Maybe it should be considered moving these to stroke system */
- float startsize = (float)BKE_brush_size_get(scene, brush);
float startalpha = BKE_brush_alpha_get(scene, brush);
float mouse[2];
float pressure;
+ float size;
+ float distance = paint_stroke_distance_get(stroke);
int eraser;
RNA_float_get_array(itemptr, "mouse", mouse);
pressure = RNA_float_get(itemptr, "pressure");
eraser = RNA_boolean_get(itemptr, "pen_flip");
+ size = max_ff(1.0f, RNA_float_get(itemptr, "size"));
+
+ /* stroking with fill tool only acts on stroke end */
+ if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ copy_v2_v2(pop->prevmouse, mouse);
+ return;
+ }
if (BKE_brush_use_alpha_pressure(scene, brush))
- BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure));
- if (BKE_brush_use_size_pressure(scene, brush))
- BKE_brush_size_set(scene, brush, (int)max_ff(1.0f, startsize * pressure));
+ BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * pressure * alphafac));
+ else
+ BKE_brush_alpha_set(scene, brush, max_ff(0.0f, startalpha * alphafac));
+
+ if ((brush->flag & BRUSH_DRAG_DOT) || (brush->flag & BRUSH_ANCHORED)) {
+ paint_stroke_restore();
+ }
if (pop->mode == PAINT_MODE_3D_PROJECT) {
- paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse);
+ paint_proj_stroke(C, pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
}
else {
- paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser);
+ paint_2d_stroke(pop->custom_paint, pop->prevmouse, mouse, eraser, pressure, distance, size);
}
- pop->prevmouse[0] = mouse[0];
- pop->prevmouse[1] = mouse[1];
+ copy_v2_v2(pop->prevmouse, mouse);
/* restore brush values */
BKE_brush_alpha_set(scene, brush, startalpha);
- BKE_brush_size_set(scene, brush, startsize);
}
static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, bool final)
@@ -554,11 +863,41 @@ static void paint_stroke_redraw(const bContext *C, struct PaintStroke *stroke, b
static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
{
Scene *scene = CTX_data_scene(C);
- ToolSettings *settings = scene->toolsettings;
+ ToolSettings *toolsettings = scene->toolsettings;
PaintOperation *pop = paint_stroke_mode_data(stroke);
+ Brush *brush = BKE_paint_brush(&toolsettings->imapaint.paint);
+
+ toolsettings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
- settings->imapaint.flag &= ~IMAGEPAINT_DRAWING;
+ if (brush->imagepaint_tool == PAINT_TOOL_FILL) {
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ if (pop->mode == PAINT_MODE_2D) {
+ paint_2d_gradient_fill(C, brush, pop->startmouse, pop->prevmouse, pop->custom_paint);
+ }
+ else {
+ paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, paint_stroke_flipped(stroke),
+ 1.0, 0.0, BKE_brush_size_get(scene, brush));
+ /* two redraws, one for GPU update, one for notification */
+ paint_proj_redraw(C, pop->custom_paint, false);
+ paint_proj_redraw(C, pop->custom_paint, true);
+ }
+ }
+ else {
+ if (pop->mode == PAINT_MODE_2D) {
+ float color[3];
+ srgb_to_linearrgb_v3_v3(color, BKE_brush_color_get(scene, brush));
+ paint_2d_bucket_fill(C, color, brush, pop->prevmouse, pop->custom_paint);
+ }
+ else {
+ paint_proj_stroke(C, pop->custom_paint, pop->startmouse, pop->prevmouse, paint_stroke_flipped(stroke),
+ 1.0, 0.0, BKE_brush_size_get(scene, brush));
+ /* two redraws, one for GPU update, one for notification */
+ paint_proj_redraw(C, pop->custom_paint, false);
+ paint_proj_redraw(C, pop->custom_paint, true);
+ }
+ }
+ }
if (pop->mode == PAINT_MODE_3D_PROJECT) {
paint_proj_stroke_done(pop->custom_paint);
}
@@ -566,7 +905,11 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
paint_2d_stroke_done(pop->custom_paint);
}
- ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+ if (pop->cursor) {
+ WM_paint_cursor_end(CTX_wm_manager(C), pop->cursor);
+ }
+
+ image_undo_end();
/* duplicate warning, see texpaint_init */
#if 0
@@ -576,43 +919,41 @@ static void paint_stroke_done(const bContext *C, struct PaintStroke *stroke)
BKE_reportf(op->reports, RPT_WARNING, "Packed MultiLayer files cannot be painted: %s", pop->s.warnpackedfile);
#endif
MEM_freeN(pop);
-
- {
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
- ups->stroke_active = false;
- }
-}
-
-static bool paint_stroke_test_start(bContext *UNUSED(C), wmOperator *UNUSED(op), const float UNUSED(mouse[2]))
-{
- return true;
}
-
-static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+static bool paint_stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
{
PaintOperation *pop;
- float mouse[2];
- int retval;
/* TODO Should avoid putting this here. Instead, last position should be requested
* from stroke system. */
- mouse[0] = event->mval[0];
- mouse[1] = event->mval[1];
if (!(pop = texture_paint_init(C, op, mouse))) {
- return OPERATOR_CANCELLED;
+ return false;
}
- op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start,
+ paint_stroke_set_mode_data(op->customdata, pop);
+
+ return true;
+}
+
+
+static int paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ int retval;
+
+ op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start,
paint_stroke_update_step,
paint_stroke_redraw,
paint_stroke_done, event->type);
- paint_stroke_set_mode_data(op->customdata, pop);
+
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
/* add modal handler */
WM_event_add_modal_handler(C, op);
- retval = op->type->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
@@ -637,12 +978,10 @@ static int paint_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- op->customdata = paint_stroke_new(C, NULL, paint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, paint_stroke_test_start,
paint_stroke_update_step,
paint_stroke_redraw,
paint_stroke_done, 0);
- paint_stroke_set_mode_data(op->customdata, pop);
-
/* frees op->customdata */
paint_stroke_exec(C, op);
@@ -651,12 +990,6 @@ static int paint_exec(bContext *C, wmOperator *op)
void PAINT_OT_image_paint(wmOperatorType *ot)
{
- static EnumPropertyItem stroke_mode_items[] = {
- {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"},
- {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
- {0}
- };
-
/* identifiers */
ot->name = "Image Paint";
ot->idname = "PAINT_OT_image_paint";
@@ -672,11 +1005,7 @@ void PAINT_OT_image_paint(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_BLOCKING;
- RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL,
- "Paint Stroke Mode",
- "Action taken when a paint stroke is made");
-
- RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ paint_stroke_operator_properties(ot);
}
@@ -686,9 +1015,9 @@ int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
if (!rv3d) {
SpaceImage *sima = CTX_wm_space_image(C);
- ARegion *ar = CTX_wm_region(C);
if (sima->mode == SI_MODE_PAINT) {
+ ARegion *ar = CTX_wm_region(C);
ED_space_image_get_zoom(sima, ar, zoomx, zoomy);
return 1;
@@ -847,17 +1176,39 @@ void PAINT_OT_grab_clone(wmOperatorType *ot)
typedef struct {
bool show_cursor;
short event_type;
-} SampleColorData;
+ float initcolor[3];
+ bool sample_palette;
+} SampleColorData;
+
+
+static void sample_color_update_header(SampleColorData *data, bContext *C)
+{
+#define HEADER_LENGTH 150
+ char msg[HEADER_LENGTH];
+ ScrArea *sa = CTX_wm_area(C);
+
+ if (sa) {
+ BLI_snprintf(msg, HEADER_LENGTH,
+ "Sample color for %s",
+ !data->sample_palette ?
+ "Brush. Use Left Click to sample for palette instead" :
+ "Palette. Use Left Click to sample more colors");
+ ED_area_headerprint(sa, msg);
+ }
+
+#undef HEADER_LENGTH
+}
static int sample_color_exec(bContext *C, wmOperator *op)
{
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
ARegion *ar = CTX_wm_region(C);
wmWindow *win = CTX_wm_window(C);
bool show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
int location[2];
-
+ bool use_palette;
paint->flags &= ~PAINT_SHOW_BRUSH;
/* force redraw without cursor */
@@ -865,7 +1216,9 @@ static int sample_color_exec(bContext *C, wmOperator *op)
WM_redraw_windows(C);
RNA_int_get_array(op->ptr, "location", location);
- paint_sample_color(C, ar, location[0], location[1]);
+ use_palette = RNA_boolean_get(op->ptr, "palette");
+
+ paint_sample_color(C, ar, location[0], location[1], mode == PAINT_TEXTURE_PROJECTIVE, use_palette);
if (show_cursor) {
paint->flags |= PAINT_SHOW_BRUSH;
@@ -878,7 +1231,9 @@ static int sample_color_exec(bContext *C, wmOperator *op)
static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Scene *scene = CTX_data_scene(C);
Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
SampleColorData *data = MEM_mallocN(sizeof(SampleColorData), "sample color custom data");
ARegion *ar = CTX_wm_region(C);
@@ -886,18 +1241,24 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
data->event_type = event->type;
data->show_cursor = ((paint->flags & PAINT_SHOW_BRUSH) != 0);
+ copy_v3_v3(data->initcolor, BKE_brush_color_get(scene, brush));
+ data->sample_palette = false;
op->customdata = data;
paint->flags &= ~PAINT_SHOW_BRUSH;
+ sample_color_update_header(data, C);
+
+ WM_event_add_modal_handler(C, op);
+
/* force redraw without cursor */
WM_paint_cursor_tag_redraw(win, ar);
WM_redraw_windows(C);
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1]);
+
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false);
WM_cursor_modal_set(win, BC_EYEDROPPER_CURSOR);
- WM_event_add_modal_handler(C, op);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
return OPERATOR_RUNNING_MODAL;
@@ -905,17 +1266,27 @@ static int sample_color_invoke(bContext *C, wmOperator *op, const wmEvent *event
static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
+ Scene *scene = CTX_data_scene(C);
SampleColorData *data = op->customdata;
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
if ((event->type == data->event_type) && (event->val == KM_RELEASE)) {
+ ScrArea *sa = CTX_wm_area(C);
+
if (data->show_cursor) {
paint->flags |= PAINT_SHOW_BRUSH;
}
+ if (data->sample_palette) {
+ BKE_brush_color_set(scene, brush, data->initcolor);
+ RNA_boolean_set(op->ptr, "palette", true);
+ }
WM_cursor_modal_restore(CTX_wm_window(C));
MEM_freeN(data);
+ ED_area_headerprint(sa, NULL);
+
return OPERATOR_FINISHED;
}
@@ -924,10 +1295,23 @@ static int sample_color_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ARegion *ar = CTX_wm_region(C);
RNA_int_set_array(op->ptr, "location", event->mval);
- paint_sample_color(C, ar, event->mval[0], event->mval[1]);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, false);
WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
break;
}
+
+ case LEFTMOUSE:
+ if (event->val == KM_PRESS) {
+ ARegion *ar = CTX_wm_region(C);
+ RNA_int_set_array(op->ptr, "location", event->mval);
+ paint_sample_color(C, ar, event->mval[0], event->mval[1], mode == PAINT_TEXTURE_PROJECTIVE, true);
+ if (!data->sample_palette) {
+ data->sample_palette = true;
+ sample_color_update_header(data, C);
+ }
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush);
+ }
+ break;
}
return OPERATOR_RUNNING_MODAL;
@@ -956,6 +1340,7 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
/* properties */
RNA_def_int_vector(ot->srna, "location", 2, NULL, 0, INT_MAX, "Location", "Cursor location in region coordinates", 0, 16384);
+ RNA_def_boolean(ot->srna, "palette", 0, "Palette", "Add color to palette");
}
/******************** texture paint toggle operator ********************/
@@ -979,7 +1364,6 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
const int mode_flag = OB_MODE_TEXTURE_PAINT;
const bool is_mode_set = (ob->mode & mode_flag) != 0;
- Mesh *me;
if (!is_mode_set) {
if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) {
@@ -987,8 +1371,6 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
}
}
- me = BKE_mesh_from_object(ob);
-
if (ob->mode & mode_flag) {
ob->mode &= ~mode_flag;
@@ -999,12 +1381,47 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
toggle_paint_cursor(C, 0);
}
else {
+ bScreen *sc;
+ Main *bmain = CTX_data_main(C);
+ Image *ima = NULL;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+
+ /* This has to stay here to regenerate the texture paint
+ * cache in case we are loading a file */
+ BKE_texpaint_slots_refresh_object(scene, ob);
+
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+
+ /* entering paint mode also sets image to editors */
+ if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ Material *ma = give_current_material(ob, ob->actcol); /* set the current material active paint slot on image editor */
+
+ if (ma && ma->texpaintslot)
+ ima = ma->texpaintslot[ma->paint_active_slot].ima;
+ }
+ else if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ ima = imapaint->canvas;
+ }
+
+ if (ima) {
+ 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) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ if (!sima->pin)
+ ED_space_image_set(sima, scene, scene->obedit, ima);
+ }
+ }
+ }
+ }
+ }
+
ob->mode |= mode_flag;
- if (me->mtface == NULL)
- me->mtface = CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT,
- NULL, me->totface);
-
BKE_paint_init(&scene->toolsettings->imapaint.paint, PAINT_CURSOR_TEXTURE_PAINT);
if (U.glreslimit != 0)
@@ -1014,7 +1431,7 @@ static int texture_paint_toggle_exec(bContext *C, wmOperator *op)
toggle_paint_cursor(C, 1);
}
- DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ GPU_drawobject_free(ob->derivedFinal);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene);
return OPERATOR_FINISHED;
@@ -1035,6 +1452,65 @@ void PAINT_OT_texture_paint_toggle(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+
+static int brush_colors_flip_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
+ Brush *br = image_paint_brush(C);
+ if (ups->flag & UNIFIED_PAINT_COLOR) {
+ swap_v3_v3(ups->rgb, ups->secondary_rgb);
+ }
+ else if (br) {
+ swap_v3_v3(br->rgb, br->secondary_rgb);
+ }
+ WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, br);
+
+ return OPERATOR_FINISHED;
+}
+
+static int brush_colors_flip_poll(bContext *C)
+{
+ if (image_paint_poll(C)) {
+ Brush *br = image_paint_brush(C);
+ if (br->imagepaint_tool == PAINT_TOOL_DRAW)
+ return 1;
+ }
+
+ return 0;
+}
+
+void PAINT_OT_brush_colors_flip(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Brush Colors Flip";
+ ot->idname = "PAINT_OT_brush_colors_flip";
+ ot->description = "Toggle foreground and background brush colors";
+
+ /* api callbacks */
+ ot->exec = brush_colors_flip_exec;
+ ot->poll = brush_colors_flip_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+void ED_imapaint_bucket_fill(struct bContext *C, float color[3], wmOperator *op)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
+
+ ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
+ ED_image_undo_restore, ED_image_undo_free, NULL);
+
+ paint_2d_bucket_fill(C, color, NULL, NULL, NULL);
+
+ ED_undo_paint_push_end(UNDO_PAINT_IMAGE);
+
+ DAG_id_tag_update(&ima->id, 0);
+}
+
+
static int texture_paint_poll(bContext *C)
{
if (texture_paint_toggle_poll(C))
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 667b487d4b1..ea0e30a6635 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -40,14 +40,21 @@
#include "BLI_math.h"
+#include "BLI_rect.h"
+#include "BLI_math_color_blend.h"
+#include "BLI_stack.h"
+#include "BLI_bitmap.h"
+
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
#include "BKE_brush.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_texture.h"
+#include "ED_paint.h"
#include "ED_screen.h"
-#include "ED_sculpt.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -69,24 +76,25 @@
/* Defines and Structs */
typedef struct BrushPainterCache {
- int size; /* size override, if 0 uses 2*BKE_brush_size_get(brush) */
-
bool use_float; /* need float imbuf? */
bool use_color_correction; /* use color correction for float */
- bool use_masking; /* use masking? */
+ bool invert;
bool is_texbrush;
bool is_maskbrush;
- int lastsize;
- float lastalpha;
- float lastjitter;
+ int lastdiameter;
float last_tex_rotation;
float last_mask_rotation;
+ float last_pressure;
ImBuf *ibuf;
ImBuf *texibuf;
- unsigned short *mask;
+ unsigned short *curve_mask;
+ unsigned short *tex_mask;
+ unsigned short *tex_mask_old;
+ unsigned int tex_mask_old_w;
+ unsigned int tex_mask_old_h;
} BrushPainterCache;
typedef struct BrushPainter {
@@ -136,43 +144,42 @@ typedef struct ImagePaintState {
int do_facesel;
bool need_redraw;
+
+ BlurKernel *blurkernel;
} ImagePaintState;
-static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush)
+static BrushPainter *brush_painter_2d_new(Scene *scene, Brush *brush, bool invert)
{
BrushPainter *painter = MEM_callocN(sizeof(BrushPainter), "BrushPainter");
painter->brush = brush;
painter->scene = scene;
painter->firsttouch = 1;
- painter->cache.lastsize = -1; /* force ibuf create in refresh */
+ painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
+ painter->cache.invert = invert;
return painter;
}
-static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction, bool use_masking)
+static void brush_painter_2d_require_imbuf(BrushPainter *painter, bool use_float, bool use_color_correction)
{
Brush *brush = painter->brush;
if ((painter->cache.use_float != use_float)) {
if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
- if (painter->cache.mask) MEM_freeN(painter->cache.mask);
+ if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
+ if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
+ if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
painter->cache.ibuf = NULL;
- painter->cache.mask = NULL;
- painter->cache.lastsize = -1; /* force ibuf create in refresh */
- }
-
- if (painter->cache.use_float != use_float) {
- if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
- painter->cache.texibuf = NULL;
- painter->cache.lastsize = -1; /* force ibuf create in refresh */
+ painter->cache.curve_mask = NULL;
+ painter->cache.tex_mask = NULL;
+ painter->cache.lastdiameter = -1; /* force ibuf create in refresh */
}
painter->cache.use_float = use_float;
painter->cache.use_color_correction = use_float && use_color_correction;
- painter->cache.use_masking = use_masking;
painter->cache.is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
painter->cache.is_maskbrush = (brush->mask_mtex.tex) ? true : false;
}
@@ -181,7 +188,9 @@ static void brush_painter_2d_free(BrushPainter *painter)
{
if (painter->cache.ibuf) IMB_freeImBuf(painter->cache.ibuf);
if (painter->cache.texibuf) IMB_freeImBuf(painter->cache.texibuf);
- if (painter->cache.mask) MEM_freeN(painter->cache.mask);
+ if (painter->cache.curve_mask) MEM_freeN(painter->cache.curve_mask);
+ if (painter->cache.tex_mask) MEM_freeN(painter->cache.tex_mask);
+ if (painter->cache.tex_mask_old) MEM_freeN(painter->cache.tex_mask_old);
MEM_freeN(painter);
}
@@ -192,41 +201,177 @@ static void brush_imbuf_tex_co(rctf *mapping, int x, int y, float texco[3])
texco[2] = 0.0f;
}
-/* create a mask with the falloff strength and optionally brush alpha */
-static unsigned short *brush_painter_mask_new(BrushPainter *painter, int size)
+/* create a mask with the mask texture */
+static unsigned short *brush_painter_mask_ibuf_new(BrushPainter *painter, int size)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
- bool use_masking = painter->cache.use_masking;
-
- float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush);
- int radius = BKE_brush_size_get(scene, brush);
- int xoff = -size * 0.5f + 0.5f;
- int yoff = -size * 0.5f + 0.5f;
+ rctf mask_mapping = painter->mask_mapping;
+ struct ImagePool *pool = painter->pool;
+ float texco[3];
unsigned short *mask, *m;
- int x, y;
+ int x, y, thread = 0;
- mask = MEM_callocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
+ mask = MEM_mallocN(sizeof(unsigned short) * size * size, "brush_painter_mask");
m = mask;
for (y = 0; y < size; y++) {
for (x = 0; x < size; x++, m++) {
+ float res;
+ brush_imbuf_tex_co(&mask_mapping, x, y, texco);
+ res = BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
+ *m = (unsigned short)(65535.0f * res);
+ }
+ }
+
+ return mask;
+}
+
+/* update rectangular section of the brush image */
+static void brush_painter_mask_imbuf_update(
+ BrushPainter *painter, unsigned short *tex_mask_old,
+ int origx, int origy, int w, int h, int xt, int yt, int diameter)
+{
+ Scene *scene = painter->scene;
+ Brush *brush = painter->brush;
+ rctf tex_mapping = painter->mask_mapping;
+ struct ImagePool *pool = painter->pool;
+ unsigned short res;
+
+ bool use_texture_old = (tex_mask_old != NULL);
+
+ int x, y, thread = 0;
+
+ unsigned short *tex_mask = painter->cache.tex_mask;
+ unsigned short *tex_mask_cur = painter->cache.tex_mask_old;
+
+ /* fill pixels */
+ for (y = origy; y < h; y++) {
+ for (x = origx; x < w; x++) {
+ /* sample texture */
+ float texco[3];
+
+ /* handle byte pixel */
+ unsigned short *b = tex_mask + (y * diameter + x);
+ unsigned short *t = tex_mask_cur + (y * diameter + x);
+
+ if (!use_texture_old) {
+ brush_imbuf_tex_co(&tex_mapping, x, y, texco);
+ res = (unsigned short)(65535.0f * BKE_brush_sample_masktex(scene, brush, texco, thread, pool));
+ }
+
+ /* read from old texture buffer */
+ if (use_texture_old) {
+ res = *(tex_mask_old + ((y - origy + yt) * painter->cache.tex_mask_old_w + (x - origx + xt)));
+ }
+
+ /* write to new texture mask */
+ *t = res;
+ /* write to mask image buffer */
+ *b = res;
+ }
+ }
+}
+
+
+/**
+ * Update the brush mask image by trying to reuse the cached texture result.
+ * This can be considerably faster for brushes that change size due to pressure or
+ * textures that stick to the surface where only part of the pixels are new
+ */
+static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
+{
+ BrushPainterCache *cache = &painter->cache;
+ unsigned short *tex_mask_old;
+ int destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
+
+ /* create brush image buffer if it didn't exist yet */
+ if (!cache->tex_mask)
+ cache->tex_mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+
+ /* create new texture image buffer with coordinates relative to old */
+ tex_mask_old = cache->tex_mask_old;
+ cache->tex_mask_old = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+
+ if (tex_mask_old) {
+ ImBuf maskibuf;
+ ImBuf maskibuf_old;
+ maskibuf.x = maskibuf.y = diameter;
+ maskibuf_old.x = cache->tex_mask_old_w;
+ maskibuf_old.y = cache->tex_mask_old_h;
+
+ srcx = srcy = 0;
+ w = cache->tex_mask_old_w;
+ h = cache->tex_mask_old_h;
+ destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2);
+ desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2);
+
+ /* hack, use temporary rects so that clipping works */
+ IMB_rectclip(&maskibuf, &maskibuf_old, &destx, &desty, &srcx, &srcy, &w, &h);
+ }
+ else {
+ srcx = srcy = 0;
+ destx = desty = 0;
+ w = h = 0;
+ }
+
+ x1 = min_ii(destx, diameter);
+ y1 = min_ii(desty, diameter);
+ x2 = min_ii(destx + w, diameter);
+ y2 = min_ii(desty + h, diameter);
+
+ /* blend existing texture in new position */
+ if ((x1 < x2) && (y1 < y2))
+ brush_painter_mask_imbuf_update(painter, tex_mask_old, x1, y1, x2, y2, srcx, srcy, diameter);
+
+ if (tex_mask_old)
+ MEM_freeN(tex_mask_old);
+
+ /* sample texture in new areas */
+ if ((0 < x1) && (0 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, 0, 0, x1, diameter, 0, 0, diameter);
+ if ((x2 < diameter) && (0 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, x2, 0, diameter, diameter, 0, 0, diameter);
+ if ((x1 < x2) && (0 < y1))
+ brush_painter_mask_imbuf_update(painter, NULL, x1, 0, x2, y1, 0, 0, diameter);
+ if ((x1 < x2) && (y2 < diameter))
+ brush_painter_mask_imbuf_update(painter, NULL, x1, y2, x2, diameter, 0, 0, diameter);
+
+ /* through with sampling, now update sizes */
+ cache->tex_mask_old_w = diameter;
+ cache->tex_mask_old_h = diameter;
+}
+
+/* create a mask with the falloff strength */
+static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter, int diameter, float radius)
+{
+ Brush *brush = painter->brush;
+
+ int xoff = -diameter * 0.5f + 0.5f;
+ int yoff = -diameter * 0.5f + 0.5f;
+
+ unsigned short *mask, *m;
+ int x, y;
+
+ mask = MEM_mallocN(sizeof(unsigned short) * diameter * diameter, "brush_painter_mask");
+ m = mask;
+
+ for (y = 0; y < diameter; y++) {
+ for (x = 0; x < diameter; x++, m++) {
float xy[2] = {x + xoff, y + yoff};
float len = len_v2(xy);
- float strength = alpha;
-
- strength *= BKE_brush_curve_strength_clamp(brush, len, radius);
- *m = (unsigned short)(65535.0f * strength);
+ *m = (unsigned short)(65535.0f * BKE_brush_curve_strength_clamp(brush, len, radius));
}
}
return mask;
}
+
/* create imbuf with brush color */
-static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
+static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size, float pressure, float distance)
{
Scene *scene = painter->scene;
Brush *brush = painter->brush;
@@ -235,19 +380,11 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
rctf tex_mapping = painter->tex_mapping;
- rctf mask_mapping = painter->mask_mapping;
struct ImagePool *pool = painter->pool;
- bool use_masking = painter->cache.use_masking;
bool use_color_correction = painter->cache.use_color_correction;
bool use_float = painter->cache.use_float;
bool is_texbrush = painter->cache.is_texbrush;
- bool is_maskbrush = painter->cache.is_maskbrush;
-
- float alpha = (use_masking) ? 1.0f : BKE_brush_alpha_get(scene, brush);
- int radius = BKE_brush_size_get(scene, brush);
- int xoff = -size * 0.5f + 0.5f;
- int yoff = -size * 0.5f + 0.5f;
int x, y, thread = 0;
float brush_rgb[3];
@@ -257,11 +394,7 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
/* get brush color */
if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
- copy_v3_v3(brush_rgb, brush->rgb);
-
- if (use_color_correction) {
- IMB_colormanagement_display_to_scene_linear_v3(brush_rgb, display);
- }
+ paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, distance, pressure, brush_rgb, display);
}
else {
brush_rgb[0] = 1.0f;
@@ -278,30 +411,17 @@ static ImBuf *brush_painter_imbuf_new(BrushPainter *painter, int size)
if (is_texbrush) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
+ mul_v3_v3(rgba, brush_rgb);
/* TODO(sergey): Support texture paint color space. */
if (!use_float) {
IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
}
- mul_v3_v3(rgba, brush_rgb);
}
else {
copy_v3_v3(rgba, brush_rgb);
rgba[3] = 1.0f;
}
- if (is_maskbrush) {
- brush_imbuf_tex_co(&mask_mapping, x, y, texco);
- rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
- }
-
- /* when not using masking, multiply in falloff and strength */
- if (!use_masking) {
- float xy[2] = {x + xoff, y + yoff};
- float len = len_v2(xy);
-
- rgba[3] *= alpha * BKE_brush_curve_strength_clamp(brush, len, radius);
- }
-
if (use_float) {
/* write to float pixel */
float *dstf = ibuf->rect_float + (y * size + x) * 4;
@@ -332,14 +452,11 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
struct ColorManagedDisplay *display = IMB_colormanagement_display_get_named(display_device);
rctf tex_mapping = painter->tex_mapping;
- rctf mask_mapping = painter->mask_mapping;
struct ImagePool *pool = painter->pool;
- bool use_masking = painter->cache.use_masking;
bool use_color_correction = painter->cache.use_color_correction;
bool use_float = painter->cache.use_float;
bool is_texbrush = painter->cache.is_texbrush;
- bool is_maskbrush = painter->cache.is_maskbrush;
bool use_texture_old = (oldtexibuf != NULL);
int x, y, thread = 0;
@@ -347,15 +464,10 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
ImBuf *ibuf = painter->cache.ibuf;
ImBuf *texibuf = painter->cache.texibuf;
- unsigned short *mask = painter->cache.mask;
/* get brush color */
if (brush->imagepaint_tool == PAINT_TOOL_DRAW) {
- copy_v3_v3(brush_rgb, brush->rgb);
-
- if (use_color_correction) {
- IMB_colormanagement_display_to_scene_linear_v3(brush_rgb, display);
- }
+ paint_brush_color_get(scene, brush, use_color_correction, painter->cache.invert, 0.0, 1.0, brush_rgb, display);
}
else {
brush_rgb[0] = 1.0f;
@@ -363,7 +475,7 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
brush_rgb[2] = 1.0f;
}
- /* fill pixes */
+ /* fill pixels */
for (y = origy; y < h; y++) {
for (x = origx; x < w; x++) {
/* sample texture and multiply with brush color */
@@ -373,21 +485,16 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
if (is_texbrush) {
brush_imbuf_tex_co(&tex_mapping, x, y, texco);
BKE_brush_sample_tex_3D(scene, brush, texco, rgba, thread, pool);
+ mul_v3_v3(rgba, brush_rgb);
/* TODO(sergey): Support texture paint color space. */
if (!use_float) {
IMB_colormanagement_scene_linear_to_display_v3(rgba, display);
}
- mul_v3_v3(rgba, brush_rgb);
}
else {
copy_v3_v3(rgba, brush_rgb);
rgba[3] = 1.0f;
}
-
- if (is_maskbrush) {
- brush_imbuf_tex_co(&mask_mapping, x, y, texco);
- rgba[3] *= BKE_brush_sample_masktex(scene, brush, texco, thread, pool);
- }
}
if (use_float) {
@@ -404,12 +511,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
/* write to new texture buffer */
copy_v4_v4(tf, rgba);
- /* if not using masking, multiply in the mask now */
- if (!use_masking) {
- unsigned short *m = mask + (y * ibuf->x + x);
- rgba[3] *= *m * (1.0f / 65535.0f);
- }
-
/* output premultiplied float image, mf was already premultiplied */
mul_v3_v3fl(bf, rgba, rgba[3]);
bf[3] = rgba[3];
@@ -438,12 +539,6 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
t[2] = crgba[2];
t[3] = crgba[3];
- /* if not using masking, multiply in the mask now */
- if (!use_masking) {
- unsigned short *m = mask + (y * ibuf->x + x);
- crgba[3] = (crgba[3] * (*m)) / 65535;
- }
-
/* write to brush image buffer */
b[0] = crgba[0];
b[1] = crgba[1];
@@ -457,14 +552,11 @@ static void brush_painter_imbuf_update(BrushPainter *painter, ImBuf *oldtexibuf,
/* update the brush image by trying to reuse the cached texture result. this
* can be considerably faster for brushes that change size due to pressure or
* textures that stick to the surface where only part of the pixels are new */
-static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2])
+static void brush_painter_imbuf_partial_update(BrushPainter *painter, const float pos[2], int diameter)
{
- const Scene *scene = painter->scene;
- Brush *brush = painter->brush;
BrushPainterCache *cache = &painter->cache;
ImBuf *oldtexibuf, *ibuf;
int imbflag, destx, desty, srcx, srcy, w, h, x1, y1, x2, y2;
- int diameter = 2 * BKE_brush_size_get(scene, brush);
/* create brush image buffer if it didn't exist yet */
imbflag = (cache->use_float) ? IB_rectfloat : IB_rect;
@@ -478,10 +570,10 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa
if (oldtexibuf) {
srcx = srcy = 0;
- destx = (int)painter->lastpaintpos[0] - (int)pos[0];
- desty = (int)painter->lastpaintpos[1] - (int)pos[1];
w = oldtexibuf->x;
h = oldtexibuf->y;
+ destx = (int)painter->lastpaintpos[0] - (int)pos[0] + (diameter / 2 - w / 2);
+ desty = (int)painter->lastpaintpos[1] - (int)pos[1] + (diameter / 2 - h / 2);
IMB_rectclip(cache->texibuf, oldtexibuf, &destx, &desty, &srcx, &srcy, &w, &h);
}
@@ -514,7 +606,7 @@ static void brush_painter_imbuf_partial_update(BrushPainter *painter, const floa
brush_painter_imbuf_update(painter, NULL, x1, y2, x2, ibuf->y, 0, 0);
}
-static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping)
+static void brush_painter_2d_tex_mapping(ImagePaintState *s, int diameter, const float startpos[2], const float pos[2], const float mouse[2], int mapmode, rctf *mapping)
{
float invw = 1.0f / (float)s->canvas->x;
float invh = 1.0f / (float)s->canvas->y;
@@ -522,19 +614,19 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const flo
int ipos[2];
/* find start coordinate of brush in canvas */
- ipos[0] = (int)floorf((pos[0] - size / 2) + 1.0f);
- ipos[1] = (int)floorf((pos[1] - size / 2) + 1.0f);
+ ipos[0] = (int)floorf((pos[0] - diameter / 2) + 1.0f);
+ ipos[1] = (int)floorf((pos[1] - diameter / 2) + 1.0f);
if (mapmode == MTEX_MAP_MODE_STENCIL) {
/* map from view coordinates of brush to region coordinates */
UI_view2d_view_to_region(s->v2d, ipos[0] * invw, ipos[1] * invh, &xmin, &ymin);
- UI_view2d_view_to_region(s->v2d, (ipos[0] + size) * invw, (ipos[1] + size) * invh, &xmax, &ymax);
+ UI_view2d_view_to_region(s->v2d, (ipos[0] + diameter) * invw, (ipos[1] + diameter) * invh, &xmax, &ymax);
/* output mapping from brush ibuf x/y to region coordinates */
mapping->xmin = xmin;
mapping->ymin = ymin;
- mapping->xmax = (xmax - xmin) / (float)size;
- mapping->ymax = (ymax - ymin) / (float)size;
+ mapping->xmax = (xmax - xmin) / (float)diameter;
+ mapping->ymax = (ymax - ymin) / (float)diameter;
}
else if (mapmode == MTEX_MAP_MODE_3D) {
/* 3D mapping, just mapping to canvas 0..1 */
@@ -545,104 +637,126 @@ static void brush_painter_2d_tex_mapping(ImagePaintState *s, int size, const flo
}
else if (ELEM(mapmode, MTEX_MAP_MODE_VIEW, MTEX_MAP_MODE_RANDOM)) {
/* view mapping */
- mapping->xmin = mouse[0] - size * 0.5f + 0.5f;
- mapping->ymin = mouse[1] - size * 0.5f + 0.5f;
+ mapping->xmin = mouse[0] - diameter * 0.5f + 0.5f;
+ mapping->ymin = mouse[1] - diameter * 0.5f + 0.5f;
mapping->xmax = 1.0f;
mapping->ymax = 1.0f;
}
else /* if (mapmode == MTEX_MAP_MODE_TILED) */ {
- mapping->xmin = -size * 0.5f + 0.5f + (int)pos[0] - (int)startpos[0];
- mapping->ymin = -size * 0.5f + 0.5f + (int)pos[1] - (int)startpos[1];
+ mapping->xmin = (int)(-diameter * 0.5) + (int)pos[0] - (int)startpos[0];
+ mapping->ymin = (int)(-diameter * 0.5) + (int)pos[1] - (int)startpos[1];
mapping->xmax = 1.0f;
mapping->ymax = 1.0f;
}
}
-static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2])
+static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *painter, const float pos[2], const float mouse[2], float pressure, float distance, float size)
{
const Scene *scene = painter->scene;
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
Brush *brush = painter->brush;
BrushPainterCache *cache = &painter->cache;
- const int diameter = 2 * BKE_brush_size_get(scene, brush);
- const int size = (cache->size) ? cache->size : diameter;
- const float alpha = BKE_brush_alpha_get(scene, brush);
- const bool use_masking = painter->cache.use_masking;
+ const int diameter = 2 * size;
bool do_random = false;
bool do_partial_update = false;
- bool do_view = false;
+ bool update_color = (brush->flag & BRUSH_USE_GRADIENT) &&
+ ((ELEM(brush->gradient_stroke_mode,
+ BRUSH_GRADIENT_SPACING_REPEAT,
+ BRUSH_GRADIENT_SPACING_CLAMP)) ||
+ (cache->last_pressure != pressure));
float tex_rotation = -brush->mtex.rot;
float mask_rotation = -brush->mask_mtex.rot;
+ painter->pool = BKE_image_pool_new();
+
/* determine how can update based on textures used */
if (painter->cache.is_texbrush) {
if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
- do_view = true;
tex_rotation += ups->brush_rotation;
}
else if (brush->mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
do_random = true;
- else
+ else if (!((brush->flag & BRUSH_ANCHORED) || update_color))
do_partial_update = true;
- brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse,
+ brush_painter_2d_tex_mapping(s, diameter, painter->startpaintpos, pos, mouse,
brush->mtex.brush_map_mode, &painter->tex_mapping);
}
if (painter->cache.is_maskbrush) {
+ bool renew_maxmask = false;
+ bool do_partial_update_mask = false;
+ /* invalidate case for all mapping modes */
if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_VIEW) {
- do_view = true;
mask_rotation += ups->brush_rotation;
}
- else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- do_random = true;
- else
- do_partial_update = true;
+ else if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM) {
+ renew_maxmask = true;
+ }
+ else if (!(brush->flag & BRUSH_ANCHORED)) {
+ do_partial_update_mask = true;
+ renew_maxmask = true;
+ }
+ /* explicilty disable partial update even if it has been enabled above */
+ if (brush->mask_pressure) {
+ do_partial_update_mask = false;
+ renew_maxmask = true;
+ }
+
+ if ((diameter != cache->lastdiameter) ||
+ (mask_rotation != cache->last_mask_rotation) ||
+ renew_maxmask)
+ {
+ if (cache->tex_mask) {
+ MEM_freeN(cache->tex_mask);
+ cache->tex_mask = NULL;
+ }
- brush_painter_2d_tex_mapping(s, size, painter->startpaintpos, pos, mouse,
- brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
+ brush_painter_2d_tex_mapping(s, diameter, painter->startpaintpos, pos, mouse,
+ brush->mask_mtex.brush_map_mode, &painter->mask_mapping);
+
+ if (do_partial_update_mask)
+ brush_painter_mask_imbuf_partial_update(painter, pos, diameter);
+ else
+ cache->tex_mask = brush_painter_mask_ibuf_new(painter, diameter);
+ cache->last_mask_rotation = mask_rotation;
+ }
}
- if (do_view || do_random)
- do_partial_update = false;
+ /* curve mask can only change if the size changes */
+ if (diameter != cache->lastdiameter) {
+ if (cache->curve_mask) {
+ MEM_freeN(cache->curve_mask);
+ cache->curve_mask = NULL;
+ }
- painter->pool = BKE_image_pool_new();
+ cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size);
+ }
/* detect if we need to recreate image brush buffer */
- if (diameter != cache->lastsize ||
- alpha != cache->lastalpha ||
- brush->jitter != cache->lastjitter ||
- tex_rotation != cache->last_tex_rotation ||
- mask_rotation != cache->last_mask_rotation ||
- do_random)
+ if ((diameter != cache->lastdiameter) ||
+ (tex_rotation != cache->last_tex_rotation) ||
+ do_random ||
+ update_color)
{
if (cache->ibuf) {
IMB_freeImBuf(cache->ibuf);
cache->ibuf = NULL;
}
- if (cache->mask) {
- MEM_freeN(cache->mask);
- cache->mask = NULL;
- }
if (do_partial_update) {
- /* do partial update of texture + recreate mask */
- cache->mask = brush_painter_mask_new(painter, size);
- brush_painter_imbuf_partial_update(painter, pos);
+ /* do partial update of texture */
+ brush_painter_imbuf_partial_update(painter, pos, diameter);
}
else {
- /* create brush and mask from scratch */
- if (use_masking)
- cache->mask = brush_painter_mask_new(painter, size);
- cache->ibuf = brush_painter_imbuf_new(painter, size);
+ /* create brush from scratch */
+ cache->ibuf = brush_painter_imbuf_new(painter, diameter, pressure, distance);
}
- cache->lastsize = diameter;
- cache->lastalpha = alpha;
- cache->lastjitter = brush->jitter;
+ cache->lastdiameter = diameter;
cache->last_tex_rotation = tex_rotation;
- cache->last_mask_rotation = mask_rotation;
+ cache->last_pressure = pressure;
}
else if (do_partial_update) {
/* do only partial update of texture */
@@ -650,7 +764,7 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, BrushPainter *pai
int dy = (int)painter->lastpaintpos[1] - (int)pos[1];
if ((dx != 0) || (dy != 0)) {
- brush_painter_imbuf_partial_update(painter, pos);
+ brush_painter_imbuf_partial_update(painter, pos, diameter);
}
}
@@ -703,7 +817,7 @@ static void paint_2d_ibuf_rgb_set(ImBuf *ibuf, int x, int y, const bool is_torus
}
}
-static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus)
+static float paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus, float w)
{
float inrgb[4];
@@ -716,16 +830,23 @@ static int paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, flo
paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb);
}
+ mul_v4_fl(inrgb, w);
add_v4_v4(outrgb, inrgb);
- return 1;
+ return w;
}
-static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool is_torus)
+static void paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short is_torus)
{
- int x, y, count, xi, yi, xo, yo;
+ bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
+ float threshold = s->brush->sharp_threshold;
+ int x, y, xi, yi, xo, yo, xk, yk;
+ float count;
int out_off[2], in_off[2], dim[2];
+ int diff_pos[2];
float outrgb[4];
+ float rgba[4];
+ BlurKernel *kernel = s->blurkernel;
dim[0] = ibufb->x;
dim[1] = ibufb->y;
@@ -741,28 +862,52 @@ static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool
return;
}
+ /* find offset inside mask buffers to sample them */
+ sub_v2_v2v2_int(diff_pos, out_off, in_off);
+
for (y = 0; y < dim[1]; y++) {
for (x = 0; x < dim[0]; x++) {
/* get input pixel */
xi = in_off[0] + x;
yi = in_off[1] + y;
- count = 1;
- paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb);
+ count = 0.0;
+ paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, rgba);
+ zero_v4(outrgb);
- count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus);
- count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus);
- count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus);
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ count += paint_2d_ibuf_add_if(ibuf, xi + xk - kernel->pixel_len,
+ yi + yk - kernel->pixel_len, outrgb, is_torus,
+ kernel->wdata[xk + yk * kernel->side]);
+ }
+ }
- count += paint_2d_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus);
- count += paint_2d_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus);
+ if (count > 0.0f) {
+ mul_v4_fl(outrgb, 1.0f / (float)count);
- count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus);
- count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus);
- count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus);
+ if (sharpen) {
+ /* subtract blurred image from normal image gives high pass filter */
+ sub_v3_v3v3(outrgb, rgba, outrgb);
- mul_v4_fl(outrgb, 1.0f / (float)count);
+ /* 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);
+ if (fabsf(outrgb[0]) > threshold) {
+ float mask = BKE_brush_alpha_get(s->scene, s->brush);
+ float alpha = rgba[3];
+ rgba[3] = outrgb[3] = mask;
+ /* add to enhance edges */
+ blend_color_add_float(outrgb, rgba, outrgb);
+ outrgb[3] = alpha;
+ }
+ else
+ copy_v4_v4(outrgb, rgba);
+ }
+ }
+ else
+ copy_v4_v4(outrgb, rgba);
/* write into brush buffer */
xo = out_off[0] + x;
yo = out_off[1] + y;
@@ -830,10 +975,10 @@ static void paint_2d_lift_smear(ImBuf *ibuf, ImBuf *ibufb, int *pos)
tot = paint_2d_torus_split_region(region, ibufb, ibuf);
for (a = 0; a < tot; a++)
- IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, 0, region[a].destx, region[a].desty,
+ IMB_rectblend(ibufb, ibufb, ibuf, NULL, NULL, NULL, 0, region[a].destx, region[a].desty,
region[a].destx, region[a].desty,
region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, IMB_BLEND_COPY_RGB);
+ region[a].width, region[a].height, IMB_BLEND_COPY_RGB, false);
}
static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
@@ -844,10 +989,10 @@ static ImBuf *paint_2d_lift_clone(ImBuf *ibuf, ImBuf *ibufb, int *pos)
ImBuf *clonebuf = IMB_allocImBuf(w, h, ibufb->planes, ibufb->flags);
IMB_rectclip(clonebuf, ibuf, &destx, &desty, &srcx, &srcy, &w, &h);
- IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
- IMB_BLEND_COPY_ALPHA);
- IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
- IMB_BLEND_COPY_RGB);
+ IMB_rectblend(clonebuf, clonebuf, ibufb, NULL, NULL, NULL, 0, destx, desty, destx, desty, destx, desty, w, h,
+ IMB_BLEND_COPY_ALPHA, false);
+ IMB_rectblend(clonebuf, clonebuf, ibuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, w, h,
+ IMB_BLEND_COPY_RGB, false);
return clonebuf;
}
@@ -858,17 +1003,16 @@ static void paint_2d_convert_brushco(ImBuf *ibufb, const float pos[2], int ipos[
ipos[1] = (int)floorf((pos[1] - ibufb->y / 2) + 1.0f);
}
-static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const float lastpos[2], const float pos[2])
+static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *curveb, unsigned short *texmaskb, const float lastpos[2], const float pos[2])
{
ImagePaintState *s = ((ImagePaintState *)state);
- ImBuf *clonebuf = NULL, *frombuf, *tmpbuf = NULL;
+ ImBuf *clonebuf = NULL, *frombuf;
ImagePaintRegion region[4];
short torus = s->brush->flag & BRUSH_TORUS;
short blend = s->blend;
const float *offset = s->brush->clone.offset;
float liftpos[2];
- float brush_alpha = BKE_brush_alpha_get(s->scene, s->brush);
- unsigned short mask_max = (unsigned short)(brush_alpha * 65535.0f);
+ float mask_max = BKE_brush_alpha_get(s->scene, s->brush);
int bpos[2], blastpos[2], bliftpos[2];
int a, tot;
@@ -876,7 +1020,7 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f
/* lift from canvas */
if (s->tool == PAINT_TOOL_SOFTEN) {
- paint_2d_lift_soften(s->canvas, ibufb, bpos, torus);
+ paint_2d_lift_soften(s, s->canvas, ibufb, bpos, torus);
}
else if (s->tool == PAINT_TOOL_SMEAR) {
if (lastpos[0] == pos[0] && lastpos[1] == pos[1])
@@ -903,9 +1047,6 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f
paint_2d_set_region(region, bpos[0], bpos[1], 0, 0, frombuf->x, frombuf->y);
tot = 1;
}
-
- if (s->do_masking)
- tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
/* blend into canvas */
for (a = 0; a < tot; a++) {
@@ -916,11 +1057,14 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f
if (s->do_masking) {
/* masking, find original pixels tiles from undo buffer to composite over */
int tilex, tiley, tilew, tileh, tx, ty;
+ ImBuf *tmpbuf;
imapaint_region_tiles(s->canvas, region[a].destx, region[a].desty,
region[a].width, region[a].height,
&tilex, &tiley, &tilew, &tileh);
-
+
+ tmpbuf = IMB_allocImBuf(IMAPAINT_TILE_SIZE, IMAPAINT_TILE_SIZE, 32, 0);
+
for (ty = tiley; ty <= tileh; ty++) {
for (tx = tilex; tx <= tilew; tx++) {
/* retrieve original pixels + mask from undo buffer */
@@ -929,31 +1073,32 @@ static int paint_2d_op(void *state, ImBuf *ibufb, unsigned short *maskb, const f
int origy = region[a].desty - ty * IMAPAINT_TILE_SIZE;
if (s->canvas->rect_float)
- tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
+ tmpbuf->rect_float = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
else
- tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask);
+ tmpbuf->rect = image_undo_find_tile(s->image, s->canvas, tx, ty, &mask, false);
IMB_rectblend(s->canvas, tmpbuf, frombuf, mask,
- maskb, mask_max,
+ curveb, texmaskb, mask_max,
region[a].destx, region[a].desty,
origx, origy,
region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, blend);
+ region[a].width, region[a].height, blend, ((s->brush->flag & BRUSH_ACCUMULATE) != 0));
}
}
+
+ IMB_freeImBuf(tmpbuf);
}
else {
/* no masking, composite brush directly onto canvas */
- IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, NULL, 0,
+ IMB_rectblend(s->canvas, s->canvas, frombuf, NULL, curveb, texmaskb, mask_max,
region[a].destx, region[a].desty,
region[a].destx, region[a].desty,
region[a].srcx, region[a].srcy,
- region[a].width, region[a].height, blend);
+ region[a].width, region[a].height, blend, false);
}
}
if (clonebuf) IMB_freeImBuf(clonebuf);
- if (tmpbuf) IMB_freeImBuf(tmpbuf);
return 1;
}
@@ -1003,10 +1148,7 @@ static int paint_2d_canvas_set(ImagePaintState *s, Image *ima)
}
/* set masking */
- s->do_masking = (s->brush->flag & BRUSH_AIRBRUSH ||
- (s->brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
- (s->brush->mtex.tex && !ELEM3(s->brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)))
- ? false : true;
+ s->do_masking = paint_use_opacity_masking(s->brush);
return 1;
}
@@ -1016,11 +1158,15 @@ static void paint_2d_canvas_free(ImagePaintState *s)
BKE_image_release_ibuf(s->image, s->canvas, NULL);
BKE_image_release_ibuf(s->brush->clone.image, s->clonecanvas, NULL);
- if (s->do_masking)
- image_undo_remove_masks();
+ if (s->blurkernel) {
+ paint_delete_blur_kernel(s->blurkernel);
+ MEM_freeN(s->blurkernel);
+ }
+
+ image_undo_remove_masks();
}
-void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser)
+void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], const bool eraser, float pressure, float distance, float size)
{
float newuv[2], olduv[2];
ImagePaintState *s = ps;
@@ -1063,17 +1209,17 @@ void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], in
/* OCIO_TODO: float buffers are now always linear, so always use color correction
* this should probably be changed when texture painting color space is supported
*/
- brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data, s->do_masking);
+ brush_painter_2d_require_imbuf(painter, (ibuf->rect_float != NULL), !is_data);
- brush_painter_2d_refresh_cache(s, painter, newuv, mval);
+ brush_painter_2d_refresh_cache(s, painter, newuv, mval, pressure, distance, size);
- if (paint_2d_op(s, painter->cache.ibuf, painter->cache.mask, olduv, newuv))
+ if (paint_2d_op(s, painter->cache.ibuf, painter->cache.curve_mask, painter->cache.tex_mask, olduv, newuv))
s->need_redraw = true;
BKE_image_release_ibuf(s->image, ibuf, NULL);
}
-void *paint_2d_new_stroke(bContext *C, wmOperator *op)
+void *paint_2d_new_stroke(bContext *C, wmOperator *op, int mode)
{
Scene *scene = CTX_data_scene(C);
ToolSettings *settings = scene->toolsettings;
@@ -1102,10 +1248,14 @@ void *paint_2d_new_stroke(bContext *C, wmOperator *op)
return NULL;
}
+ if (brush->imagepaint_tool == PAINT_TOOL_SOFTEN) {
+ s->blurkernel = paint_new_blur_kernel(brush, false);
+ }
+
paint_brush_init_tex(s->brush);
/* create painter */
- s->painter = brush_painter_2d_new(scene, s->brush);
+ s->painter = brush_painter_2d_new(scene, s->brush, mode == BRUSH_STROKE_INVERT);
return s;
}
@@ -1134,6 +1284,7 @@ void paint_2d_redraw(const bContext *C, void *ps, bool final)
/* compositor listener deals with updating */
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, s->image);
+ DAG_id_tag_update(&s->image->id, 0);
}
else {
if (!s->sima || !s->sima->lock)
@@ -1153,3 +1304,335 @@ void paint_2d_stroke_done(void *ps)
MEM_freeN(s);
}
+
+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;
+
+ if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
+ return;
+
+ coordinate = y_px * ibuf->x + x_px;
+
+ if (!BLI_BITMAP_TEST(touched, coordinate)) {
+ float color_f[4];
+ unsigned char *color_b = (unsigned char *)(ibuf->rect + coordinate);
+ rgba_uchar_to_float(color_f, color_b);
+
+ if (compare_len_squared_v3v3(color_f, color, threshold_sq)) {
+ BLI_stack_push(stack, &coordinate);
+ }
+ BLI_BITMAP_SET(touched, coordinate, true);
+ }
+}
+
+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;
+
+ if (x_px >= ibuf->x || x_px < 0 || y_px >= ibuf->y || y_px < 0)
+ return;
+
+ coordinate = 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)) {
+ BLI_stack_push(stack, &coordinate);
+ }
+ BLI_BITMAP_SET(touched, coordinate, true);
+ }
+}
+
+/* this function expects linear space color values */
+void paint_2d_bucket_fill(
+ const bContext *C, const float color[3], Brush *br,
+ const float mouse_init[2],
+ void *ps)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
+
+ ImagePaintState *s = ps;
+
+ ImBuf *ibuf;
+ int x_px, y_px;
+ unsigned int color_b;
+ float color_f[4];
+ float strength = br ? br->alpha : 1.0f;
+
+ bool do_float;
+
+ if (!ima)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+
+ if (!ibuf)
+ return;
+
+ do_float = (ibuf->rect_float != NULL);
+ /* first check if our image is float. If it is not we should correct the color to
+ * be in gamma space. strictly speaking this is not correct, but blender does not paint
+ * byte images in linear space */
+ if (!do_float) {
+ linearrgb_to_srgb_uchar3((unsigned char *)&color_b, color);
+ *(((char *)&color_b) + 3) = strength * 255;
+ }
+ else {
+ copy_v3_v3(color_f, color);
+ color_f[3] = strength;
+ }
+
+ 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);
+
+ 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);
+ }
+ }
+ }
+ 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);
+ }
+ }
+ }
+ }
+ else {
+ /* second case, start sweeping the neighboring pixels, looking for pixels whose
+ * value is within the brush fill threshold from the fill color */
+ BLI_Stack *stack;
+ BLI_bitmap *touched;
+ int coordinate;
+ int width = ibuf->x;
+ float image_init[2];
+ int minx = ibuf->x, miny = ibuf->y, maxx = 0, maxy = 0;
+ float pixel_color[4];
+ float threshold_sq = br->fill_threshold * br->fill_threshold;
+
+ UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
+
+ x_px = image_init[0] * ibuf->x;
+ y_px = image_init[1] * ibuf->y;
+
+ if (x_px >= ibuf->x || x_px < 0 || y_px > ibuf->y || y_px < 0) {
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+ return;
+ }
+
+ /* change image invalidation method later */
+ ED_imapaint_dirty_region(ima, ibuf, 0, 0, ibuf->x, ibuf->y);
+
+ stack = BLI_stack_new(sizeof(int), __func__);
+ touched = BLI_BITMAP_NEW(ibuf->x * ibuf->y, "bucket_fill_bitmap");
+
+ coordinate = (y_px * ibuf->x + x_px);
+
+ if (do_float) {
+ copy_v4_v4(pixel_color, ibuf->rect_float + 4 * coordinate);
+ }
+ else {
+ int pixel_color_b = *(ibuf->rect + coordinate);
+ rgba_uchar_to_float(pixel_color, (unsigned char *)&pixel_color_b);
+ }
+
+ BLI_stack_push(stack, &coordinate);
+ BLI_BITMAP_SET(touched, coordinate, true);
+
+ if (do_float) {
+ while (!BLI_stack_is_empty(stack)) {
+ BLI_stack_pop(stack, &coordinate);
+
+ IMB_blend_color_float(ibuf->rect_float + 4 * (coordinate),
+ ibuf->rect_float + 4 * (coordinate),
+ color_f, br->blend);
+
+ /* reconstruct the coordinates here */
+ x_px = coordinate % width;
+ y_px = coordinate / width;
+
+ paint_2d_fill_add_pixel_float(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_float(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+
+ if (x_px > maxx)
+ maxx = x_px;
+ if (x_px < minx)
+ minx = x_px;
+ if (y_px > maxy)
+ maxy = y_px;
+ if (x_px > miny)
+ miny = y_px;
+ }
+ }
+ else {
+ while (!BLI_stack_is_empty(stack)) {
+ BLI_stack_pop(stack, &coordinate);
+
+ IMB_blend_color_byte((unsigned char *)(ibuf->rect + coordinate),
+ (unsigned char *)(ibuf->rect + coordinate),
+ (unsigned char *)&color_b, br->blend);
+
+ /* reconstruct the coordinates here */
+ x_px = coordinate % width;
+ y_px = coordinate / width;
+
+ paint_2d_fill_add_pixel_byte(x_px - 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px - 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px - 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px + 1, y_px - 1, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px + 1, y_px, ibuf, stack, touched, pixel_color, threshold_sq);
+ paint_2d_fill_add_pixel_byte(x_px + 1, y_px + 1, ibuf, stack, touched, pixel_color, threshold_sq);
+
+ if (x_px > maxx)
+ maxx = x_px;
+ if (x_px < minx)
+ minx = x_px;
+ if (y_px > maxy)
+ maxy = y_px;
+ if (x_px > miny)
+ miny = y_px;
+ }
+ }
+
+ MEM_freeN(touched);
+ BLI_stack_free(stack);
+ }
+
+ imapaint_image_update(sima, ima, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+}
+
+void paint_2d_gradient_fill(
+ const bContext *C, Brush *br,
+ const float mouse_init[2], const float mouse_final[2],
+ void *ps)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima = sima->image;
+ ImagePaintState *s = ps;
+
+ ImBuf *ibuf;
+ int x_px, y_px;
+ unsigned int color_b;
+ float color_f[4];
+ float image_init[2], image_final[2];
+ float tangent[2];
+ float line_len_sq_inv, line_len;
+
+ bool do_float;
+
+ if (!ima)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, &sima->iuser, NULL);
+
+ if (!ibuf)
+ return;
+
+ UI_view2d_region_to_view(s->v2d, mouse_final[0], mouse_final[1], &image_final[0], &image_final[1]);
+ UI_view2d_region_to_view(s->v2d, mouse_init[0], mouse_init[1], &image_init[0], &image_init[1]);
+
+ image_final[0] *= ibuf->x;
+ image_final[1] *= ibuf->y;
+
+ image_init[0] *= ibuf->x;
+ image_init[1] *= ibuf->y;
+
+ /* some math to get needed gradient variables */
+ sub_v2_v2v2(tangent, image_final, image_init);
+ line_len = len_squared_v2(tangent);
+ line_len_sq_inv = 1.0f / line_len;
+ line_len = sqrtf(line_len);
+
+ 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);
+
+ if (do_float) {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ float f;
+ float p[2] = {x_px - image_init[0], y_px - image_init[1]};
+
+ switch (br->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR:
+ {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+ do_colorband(br->gradient, f, color_f);
+ /* 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),
+ color_f, br->blend);
+ }
+ }
+ }
+ else {
+ for (x_px = 0; x_px < ibuf->x; x_px++) {
+ for (y_px = 0; y_px < ibuf->y; y_px++) {
+ float f;
+ float p[2] = {x_px - image_init[0], y_px - image_init[1]};
+
+ switch (br->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR:
+ {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+
+ do_colorband(br->gradient, f, color_f);
+ 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),
+ (unsigned char *)&color_b, br->blend);
+ }
+ }
+ }
+
+ imapaint_image_update(sima, ima, ibuf, false);
+ ED_imapaint_clear_partial_redraw();
+
+ BKE_image_release_ibuf(ima, ibuf, NULL);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+}
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 492857bd0bb..791c1b3ada1 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -48,33 +48,46 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "PIL_time.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
#include "DNA_brush_types.h"
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "BKE_camera.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_idprop.h"
#include "BKE_brush.h"
#include "BKE_image.h"
#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
+#include "BKE_node.h"
#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_scene.h"
+#include "BKE_texture.h"
#include "UI_view2d.h"
+#include "UI_interface.h"
+#include "ED_image.h"
+#include "ED_mesh.h"
+#include "ED_node.h"
+#include "ED_paint.h"
#include "ED_screen.h"
-#include "ED_sculpt.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -88,6 +101,7 @@
#include "RNA_enum_types.h"
#include "GPU_draw.h"
+#include "GPU_buffers.h"
#include "IMB_colormanagement.h"
@@ -134,9 +148,14 @@ BLI_INLINE unsigned char f_to_char(const float val)
#define PROJ_FACE_NOSEAM3 (1 << 6)
#define PROJ_FACE_NOSEAM4 (1 << 7)
+/* face winding */
+#define PROJ_FACE_WINDING_INIT 1
+#define PROJ_FACE_WINDING_CW 2
+
#define PROJ_SRC_VIEW 1
#define PROJ_SRC_IMAGE_CAM 2
#define PROJ_SRC_IMAGE_VIEW 3
+#define PROJ_SRC_VIEW_FILL 4
#define PROJ_VIEW_DATA_ID "view_data"
#define PROJ_VIEW_DATA_SIZE (4 * 4 + 4 * 4 + 3) /* viewmat + winmat + clipsta + clipend + is_ortho */
@@ -158,6 +177,9 @@ BLI_INLINE unsigned char f_to_char(const float val)
/* vert flags */
#define PROJ_VERT_CULL 1
+/* to avoid locking in tile initialization */
+#define TILE_PENDING SET_INT_IN_POINTER(-1)
+
/* This is mainly a convenience struct used so we can keep an array of images we use
* Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread
* because 'partRedrawRect' and 'touch' values would not be thread safe */
@@ -165,7 +187,10 @@ typedef struct ProjPaintImage {
Image *ima;
ImBuf *ibuf;
ImagePaintPartialRedraw *partRedrawRect;
- void **undoRect; /* only used to build undo tiles after painting */
+ volatile void **undoRect; /* only used to build undo tiles during painting */
+ 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;
} ProjPaintImage;
@@ -177,9 +202,14 @@ typedef struct ProjPaintState {
Scene *scene;
int source; /* PROJ_SRC_**** */
+ /* the paint color. It can change depending of inverted mode or not */
+ float paint_color[3];
+ float paint_color_linear[3];
+
Brush *brush;
short tool, blend, mode;
int orig_brush_size;
+ float brush_size;
Object *ob;
/* end similarities with ImagePaintState */
@@ -190,10 +220,15 @@ typedef struct ProjPaintState {
MVert *dm_mvert;
MFace *dm_mface;
- MTFace *dm_mtface;
- MTFace *dm_mtface_clone; /* other UV map, use for cloning between layers */
+ 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;
+ float stencil_value;
+
/* projection painting only */
MemArena *arena_mt[BLENDER_MAX_THREADS]; /* for multithreading, the first item is sometimes used for non threaded cases too */
LinkNode **bucketRect; /* screen sized 2D array, each pixel has a linked list of ProjPixel's */
@@ -201,6 +236,7 @@ typedef struct ProjPaintState {
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
@@ -226,6 +262,8 @@ typedef struct ProjPaintState {
bool do_layer_clone;
bool do_layer_stencil;
bool do_layer_stencil_inv;
+ bool do_stencil_brush;
+ bool do_material_slots;
bool do_occlude; /* Use raytraced occlusion? - ortherwise will paint right through to the back*/
bool do_backfacecull; /* ignore faces with normals pointing away, skips a lot of raycasts if your normals are correctly flipped */
@@ -240,7 +278,6 @@ typedef struct ProjPaintState {
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 */
- bool is_maskbrush_tiled; /* mask brush is applied after masking */
#ifndef PROJ_DEBUG_NOSEAMBLEED
float seam_bleed_px;
#endif
@@ -264,6 +301,10 @@ typedef struct ProjPaintState {
/* redraw */
bool need_redraw;
+
+ BlurKernel *blurkernel;
+
+ SpinLock *tile_lock;
} ProjPaintState;
typedef union pixelPointer {
@@ -285,14 +326,16 @@ typedef struct ProjPixel {
* 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;
+ 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;
- PixelStore origColor;
+ PixelPointer origColor;
PixelStore newColor;
PixelPointer pixel;
@@ -305,33 +348,51 @@ typedef struct ProjPixelClone {
PixelStore clonepx;
} ProjPixelClone;
-/* blur, store surrounding colors */
-#define PROJ_PIXEL_SOFTEN_TOT 4
-/* blur picking offset (in screenspace) */
-#define PROJ_PIXEL_SOFTEN_OFS_PX 1.0f
+/* undo tile pushing */
+typedef struct {
+ SpinLock *lock;
+ bool masked;
+ unsigned short tile_width;
+ ImBuf **tmpibuf;
+ ProjPaintImage *pjima;
+} TileInfo;
-static const float proj_pixel_soften_v2[PROJ_PIXEL_SOFTEN_TOT][2] = {
- {-PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f},
- { 0.0f, -PROJ_PIXEL_SOFTEN_OFS_PX},
- { 0.0f, PROJ_PIXEL_SOFTEN_OFS_PX},
- { PROJ_PIXEL_SOFTEN_OFS_PX, 0.0f},
-};
/* Finish projection painting structs */
-static Image *project_paint_face_image(const ProjPaintState *ps, MTFace *dm_mtface, int face_index)
+static TexPaintSlot *project_paint_face_paint_slot(const ProjPaintState *ps, int face_index)
{
- Image *ima;
+ MFace *mf = ps->dm_mface + face_index;
+ Material *ma = ps->dm->mat[mf->mat_nr];
+ return ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
+}
- if (ps->do_new_shading_nodes) { /* cached BKE_scene_use_new_shading_nodes result */
- MFace *mf = ps->dm_mface + face_index;
- ED_object_get_active_image(ps->ob, mf->mat_nr + 1, &ima, NULL, NULL);
+static Image *project_paint_face_paint_image(const ProjPaintState *ps, int face_index)
+{
+ if (ps->do_stencil_brush) {
+ return ps->stencil_ima;
}
else {
- ima = dm_mtface[face_index].tpage;
+ MFace *mf = ps->dm_mface + face_index;
+ Material *ma = ps->dm->mat[mf->mat_nr];
+ TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_active_slot : NULL;
+ return slot ? slot->ima : ps->canvas_ima;
}
+}
- return ima;
+static TexPaintSlot *project_paint_face_clone_slot(const ProjPaintState *ps, int face_index)
+{
+ MFace *mf = ps->dm_mface + face_index;
+ Material *ma = ps->dm->mat[mf->mat_nr];
+ return ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
+}
+
+static Image *project_paint_face_clone_image(const ProjPaintState *ps, int face_index)
+{
+ MFace *mf = ps->dm_mface + face_index;
+ Material *ma = ps->dm->mat[mf->mat_nr];
+ TexPaintSlot *slot = ma ? ma->texpaintslot + ma->paint_clone_slot : NULL;
+ return slot ? slot->ima : ps->clone_ima;
}
/* fast projection bucket array lookup, use the safe version for bound checking */
@@ -472,8 +533,8 @@ static int project_paint_PickFace(const ProjPaintState *ps, const float pt[2], f
static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, float *x, float *y)
{
/* use */
- *x = (float)fmodf(uv[0], 1.0f);
- *y = (float)fmodf(uv[1], 1.0f);
+ *x = fmodf(uv[0], 1.0f);
+ *y = fmodf(uv[1], 1.0f);
if (*x < 0.0f) *x += 1.0f;
if (*y < 0.0f) *y += 1.0f;
@@ -500,7 +561,7 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
if (face_index == -1)
return 0;
- tf = ps->dm_mtface + face_index;
+ tf = *(ps->dm_mtface + face_index);
if (side == 0) {
interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[1], tf->uv[2], w);
@@ -509,8 +570,9 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
interp_v2_v2v2v2(uv, tf->uv[0], tf->uv[2], tf->uv[3], w);
}
- ima = project_paint_face_image(ps, ps->dm_mtface, face_index);
+ ima = project_paint_face_paint_image(ps, face_index);
ibuf = BKE_image_get_first_ibuf(ima); /* we must have got the imbuf before getting here */
+ if (!ibuf) return 0;
if (interp) {
float x, y;
@@ -757,11 +819,11 @@ static int line_isect_x(const float p1[2], const float p2[2], const float x_leve
static bool cmp_uv(const float vec2a[2], const float vec2b[2])
{
/* if the UV's are not between 0.0 and 1.0 */
- float xa = (float)fmodf(vec2a[0], 1.0f);
- float ya = (float)fmodf(vec2a[1], 1.0f);
+ float xa = fmodf(vec2a[0], 1.0f);
+ float ya = fmodf(vec2a[1], 1.0f);
- float xb = (float)fmodf(vec2b[0], 1.0f);
- float yb = (float)fmodf(vec2b[1], 1.0f);
+ float xb = fmodf(vec2b[0], 1.0f);
+ float yb = fmodf(vec2b[1], 1.0f);
if (xa < 0.0f) xa += 1.0f;
if (ya < 0.0f) ya += 1.0f;
@@ -835,6 +897,21 @@ static bool pixel_bounds_array(float (*uv)[2], rcti *bounds_px, const int ibuf_x
#ifndef PROJ_DEBUG_NOSEAMBLEED
+static void project_face_winding_init(const ProjPaintState *ps, const int face_index)
+{
+ /* detect the winding of faces in uv space */
+ MTFace *tf = ps->dm_mtface[face_index];
+ float winding = cross_tri_v2(tf->uv[0], tf->uv[1], tf->uv[2]);
+
+ if (ps->dm_mface[face_index].v4)
+ winding += cross_tri_v2(tf->uv[2], tf->uv[3], tf->uv[0]);
+
+ if (winding > 0)
+ ps->faceWindingFlags[face_index] |= PROJ_FACE_WINDING_CW;
+
+ ps->faceWindingFlags[face_index] |= PROJ_FACE_WINDING_INIT;
+}
+
/* This function returns 1 if this face has a seam along the 2 face-vert indices
* 'orig_i1_fidx' and 'orig_i2_fidx' */
static bool check_seam(const ProjPaintState *ps,
@@ -848,7 +925,7 @@ static bool check_seam(const ProjPaintState *ps,
MFace *mf;
MTFace *tf;
const MFace *orig_mf = ps->dm_mface + orig_face;
- const MTFace *orig_tf = ps->dm_mtface + orig_face;
+ const MTFace *orig_tf = ps->dm_mtface[orig_face];
/* vert indices from face vert order indices */
i1 = (*(&orig_mf->v1 + orig_i1_fidx));
@@ -870,23 +947,37 @@ static bool check_seam(const ProjPaintState *ps,
/* Only need to check if 'i2_fidx' is valid because we know i1_fidx is the same vert on both faces */
if (i2_fidx != -1) {
- Image *tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
- Image *orig_tpage = project_paint_face_image(ps, ps->dm_mtface, orig_face);
+ Image *tpage = project_paint_face_paint_image(ps, face_index);
+ Image *orig_tpage = project_paint_face_paint_image(ps, orig_face);
BLI_assert(i1_fidx != -1);
/* This IS an adjacent face!, now lets check if the UVs are ok */
- tf = ps->dm_mtface + face_index;
+ tf = ps->dm_mtface[face_index];
/* set up the other face */
*other_face = face_index;
- *orig_fidx = (i1_fidx < i2_fidx) ? i1_fidx : i2_fidx;
+
+ /* we check if difference is 1 here, else we might have a case of edge 2-0 or 3-0 for quads */
+ *orig_fidx = (i1_fidx < i2_fidx && (i2_fidx - i1_fidx == 1)) ? i1_fidx : i2_fidx;
+
+ /* initialize face winding if needed */
+ if ((ps->faceWindingFlags[face_index] & PROJ_FACE_WINDING_INIT) == 0)
+ project_face_winding_init(ps, face_index);
/* first test if they have the same image */
if ((orig_tpage == tpage) &&
cmp_uv(orig_tf->uv[orig_i1_fidx], tf->uv[i1_fidx]) &&
- cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]) )
+ cmp_uv(orig_tf->uv[orig_i2_fidx], tf->uv[i2_fidx]))
{
+ /* if faces don't have the same winding in uv space,
+ * they are on the same side so edge is boundary */
+ if ((ps->faceWindingFlags[face_index] & PROJ_FACE_WINDING_CW) !=
+ (ps->faceWindingFlags[orig_face] & PROJ_FACE_WINDING_CW))
+ {
+ return 1;
+ }
+
// printf("SEAM (NONE)\n");
return 0;
@@ -1016,6 +1107,10 @@ static void project_face_seams_init(const ProjPaintState *ps, const int face_ind
int fidx1 = is_quad ? 3 : 2;
int fidx2 = 0; /* next fidx in the face (0,1,2,3) -> (1,2,3,0) or (0,1,2) -> (1,2,0) for a tri */
+ /* initialize face winding if needed */
+ if ((ps->faceWindingFlags[face_index] & PROJ_FACE_WINDING_INIT) == 0)
+ project_face_winding_init(ps, face_index);
+
do {
if ((ps->faceSeamFlags[face_index] & (1 << fidx1 | 16 << fidx1)) == 0) {
if (check_seam(ps, face_index, fidx1, fidx2, &other_face, &other_fidx)) {
@@ -1132,7 +1227,7 @@ static float project_paint_uvpixel_mask(
if (ps->do_layer_stencil) {
/* another UV maps image is masking this one's */
ImBuf *ibuf_other;
- Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_stencil, face_index);
+ Image *other_tpage = ps->stencil_ima;
const MTFace *tf_other = ps->dm_mtface_stencil + face_index;
if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
@@ -1260,24 +1355,70 @@ static int project_paint_pixel_sizeof(const short tool)
}
}
+static int project_paint_undo_subtiles(const TileInfo *tinf, int tx, int ty)
+{
+ ProjPaintImage *pjIma = tinf->pjima;
+ int tile_index = tx + ty * tinf->tile_width;
+ bool generate_tile = false;
+
+ /* double check lock to avoid locking */
+ if (UNLIKELY(!pjIma->undoRect[tile_index])) {
+ if (tinf->lock)
+ BLI_spin_lock(tinf->lock);
+ if (LIKELY(!pjIma->undoRect[tile_index])) {
+ pjIma->undoRect[tile_index] = TILE_PENDING;
+ generate_tile = true;
+ }
+ if (tinf->lock)
+ BLI_spin_unlock(tinf->lock);
+ }
+
+
+ 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);
+ }
+ else {
+ undorect = image_undo_push_tile(pjIma->ima, pjIma->ibuf, tinf->tmpibuf, tx, ty, NULL, &pjIma->valid[tile_index], true);
+ }
+
+ pjIma->ibuf->userflags |= IB_BITMAPDIRTY;
+ /* tile ready, publish */
+ if (tinf->lock)
+ BLI_spin_lock(tinf->lock);
+ pjIma->undoRect[tile_index] = undorect;
+ if (tinf->lock)
+ BLI_spin_unlock(tinf->lock);
+
+ }
+
+ return tile_index;
+}
/* run this function when we know a bucket's, face's pixel can be initialized,
* return the ProjPixel which is added to 'ps->bucketRect[bucket_index]' */
static ProjPixel *project_paint_uvpixel_init(
const ProjPaintState *ps,
MemArena *arena,
- const ImBuf *ibuf,
+ const TileInfo *tinf,
int x_px, int y_px,
const float mask,
const int face_index,
- const int image_index,
const float pixelScreenCo[4],
const float world_spaceCo[3],
const int side,
const float w[3])
{
ProjPixel *projPixel;
-
+ int x_tile, y_tile;
+ int x_round, y_round;
+ int tile_offset;
+ /* volatile is important here to ensure pending check is not optimized away by compiler*/
+ volatile int tile_index;
+
+ ProjPaintImage *projima = tinf->pjima;
+ ImBuf *ibuf = projima->ibuf;
/* wrap pixel location */
x_px = mod_i(x_px, ibuf->x);
@@ -1285,19 +1426,36 @@ static ProjPixel *project_paint_uvpixel_init(
BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool));
projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof);
+
+ /* calculate the undo tile offset of the pixel, used to store the original
+ * pixel color and accumulated mask if any */
+ x_tile = x_px >> IMAPAINT_TILE_BITS;
+ y_tile = y_px >> IMAPAINT_TILE_BITS;
+
+ x_round = x_tile * IMAPAINT_TILE_SIZE;
+ y_round = y_tile * IMAPAINT_TILE_SIZE;
//memset(projPixel, 0, size);
+ tile_offset = (x_px - x_round) + (y_px - y_round) * IMAPAINT_TILE_SIZE;
+ tile_index = project_paint_undo_subtiles(tinf, x_tile, y_tile);
+
+ /* other thread may be initializing the tile so wait here */
+ while (projima->undoRect[tile_index] == TILE_PENDING)
+ ;
+
+ BLI_assert(tile_index < (IMAPAINT_TILE_NUMBER(ibuf->x) * IMAPAINT_TILE_NUMBER(ibuf->y)));
+ BLI_assert(tile_offset < (IMAPAINT_TILE_SIZE * IMAPAINT_TILE_SIZE));
+
+ projPixel->valid = projima->valid[tile_index];
+
if (ibuf->rect_float) {
projPixel->pixel.f_pt = ibuf->rect_float + ((x_px + y_px * ibuf->x) * 4);
- projPixel->origColor.f[0] = projPixel->pixel.f_pt[0];
- projPixel->origColor.f[1] = projPixel->pixel.f_pt[1];
- projPixel->origColor.f[2] = projPixel->pixel.f_pt[2];
- projPixel->origColor.f[3] = projPixel->pixel.f_pt[3];
+ projPixel->origColor.f_pt = (float *)projima->undoRect[tile_index] + 4 * tile_offset;
zero_v4(projPixel->newColor.f);
}
else {
- projPixel->pixel.ch_pt = ((unsigned char *)ibuf->rect + ((x_px + y_px * ibuf->x) * 4));
- projPixel->origColor.uint = *projPixel->pixel.uint_pt;
+ projPixel->pixel.ch_pt = (unsigned char *)(ibuf->rect + (x_px + y_px * ibuf->x));
+ projPixel->origColor.uint_pt = (unsigned int *)projima->undoRect[tile_index] + tile_offset;
projPixel->newColor.uint = 0;
}
@@ -1312,7 +1470,10 @@ static ProjPixel *project_paint_uvpixel_init(
projPixel->y_px = y_px;
projPixel->mask = (unsigned short)(mask * 65535);
- projPixel->mask_accum = 0;
+ if (ps->do_masking)
+ projPixel->mask_accum = projima->maskRect[tile_index] + tile_offset;
+ else
+ projPixel->mask_accum = NULL;
/* which bounding box cell are we in?, needed for undo */
projPixel->bb_cell_index = ((int)(((float)x_px / (float)ibuf->x) * PROJ_BOUNDBOX_DIV)) +
@@ -1322,8 +1483,8 @@ static ProjPixel *project_paint_uvpixel_init(
if (ps->tool == PAINT_TOOL_CLONE) {
if (ps->dm_mtface_clone) {
ImBuf *ibuf_other;
- Image *other_tpage = project_paint_face_image(ps, ps->dm_mtface_clone, face_index);
- const MTFace *tf_other = ps->dm_mtface_clone + face_index;
+ Image *other_tpage = project_paint_face_clone_image(ps, face_index);
+ const MTFace *tf_other = ps->dm_mtface_clone[face_index];
if (other_tpage && (ibuf_other = BKE_image_acquire_ibuf(other_tpage, NULL, NULL))) {
/* BKE_image_acquire_ibuf - TODO - this may be slow */
@@ -1346,6 +1507,7 @@ static ProjPixel *project_paint_uvpixel_init(
project_face_pixel(tf_other, ibuf_other, w, side, NULL, rgba);
premul_to_straight_v4(rgba);
linearrgb_to_srgb_uchar3(((ProjPixelClone *)projPixel)->clonepx.ch, rgba);
+ ((ProjPixelClone *)projPixel)->clonepx.ch[3] = rgba[3] * 255;
}
else { /* char to char */
project_face_pixel(tf_other, ibuf_other, w, side, ((ProjPixelClone *)projPixel)->clonepx.ch, NULL);
@@ -1387,7 +1549,8 @@ static ProjPixel *project_paint_uvpixel_init(
if (ibuf->rect_float) projPixel->pixel.f_pt[0] = 0;
else projPixel->pixel.ch_pt[0] = 0;
#endif
- projPixel->image_index = image_index;
+ /* pointer arithmetics */
+ projPixel->image_index = projima - ps->projImages;
return projPixel;
}
@@ -2095,15 +2258,24 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot
/* One of the most important function for projection painting, since it selects the pixels to be added into each bucket.
* initialize pixels from this face where it intersects with the bucket_index, optionally initialize pixels for removing seams */
-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, rctf *bucket_bounds, const ImBuf *ibuf, const short clamp_u, const short clamp_v)
+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, rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf, const short clamp_u, const short clamp_v)
{
/* Projection vars, to get the 3D locations into screen space */
MemArena *arena = ps->arena_mt[thread_index];
LinkNode **bucketPixelNodes = ps->bucketRect + bucket_index;
LinkNode *bucketFaceNodes = ps->bucketFaces[bucket_index];
+ bool threaded = (ps->thread_tot > 1);
+
+ TileInfo tinf = {
+ ps->tile_lock,
+ ps->do_masking,
+ IMAPAINT_TILE_NUMBER(ibuf->x),
+ tmpibuf,
+ ps->projImages + image_index
+ };
const MFace *mf = ps->dm_mface + face_index;
- const MTFace *tf = ps->dm_mtface + face_index;
+ const MTFace *tf = ps->dm_mtface[face_index];
/* UV/pixel seeking data */
int x; /* Image X-Pixel */
@@ -2147,8 +2319,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
/* Use tf_uv_pxoffset instead of tf->uv so we can offset the UV half a pixel
* this is done so we can avoid offsetting all the pixels by 0.5 which causes
* problems when wrapping negative coords */
- xhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf;
- yhalfpx = (0.5f + (PROJ_GEOM_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf;
+ xhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 3.0f))) / ibuf_xf;
+ yhalfpx = (0.5f + (PROJ_PIXEL_TOLERANCE * (1.0f / 4.0f))) / ibuf_yf;
/* Note about (PROJ_GEOM_TOLERANCE/x) above...
* Needed to add this offset since UV coords are often quads aligned to pixels.
@@ -2222,6 +2394,10 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
CLAMP(bounds_px.ymax, 0, ibuf->y);
}
+ /*
+ project_paint_undo_tiles_init(&bounds_px, ps->projImages + image_index, tmpibuf,
+ tile_width, threaded, ps->do_masking);
+ */
/* clip face and */
has_isect = 0;
@@ -2264,8 +2440,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if (mask > 0.0f) {
BLI_linklist_prepend_arena(
bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index,
- image_index, pixelScreenCo, wco, side, w),
+ project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index,
+ pixelScreenCo, wco, side, w),
arena
);
}
@@ -2297,7 +2473,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if (ps->seam_bleed_px > 0.0f) {
int face_seam_flag;
- if (ps->thread_tot > 1)
+ if (threaded)
BLI_lock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
face_seam_flag = ps->faceSeamFlags[face_index];
@@ -2315,7 +2491,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if ((face_seam_flag & (PROJ_FACE_SEAM1 | PROJ_FACE_SEAM2 | PROJ_FACE_SEAM3 | PROJ_FACE_SEAM4)) == 0) {
- if (ps->thread_tot > 1)
+ if (threaded)
BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
}
@@ -2340,7 +2516,7 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
uv_image_outset(tf_uv_pxoffset, outset_uv, ps->seam_bleed_px, ibuf->x, ibuf->y, mf->v4 != 0);
/* ps->faceSeamUVs cant be modified when threading, now this is done we can unlock */
- if (ps->thread_tot > 1)
+ if (threaded)
BLI_unlock_thread(LOCK_CUSTOM1); /* Other threads could be modifying these vars */
vCoSS[0] = ps->screenCoords[mf->v1];
@@ -2484,7 +2660,8 @@ static void project_paint_face_init(const ProjPaintState *ps, const int thread_i
if (mask > 0.0f) {
BLI_linklist_prepend_arena(
bucketPixelNodes,
- project_paint_uvpixel_init(ps, arena, ibuf, x, y, mask, face_index, image_index, pixelScreenCo, wco, side, w),
+ project_paint_uvpixel_init(ps, arena, &tinf, x, y, mask, face_index,
+ pixelScreenCo, wco, side, w),
arena
);
}
@@ -2553,6 +2730,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
ImBuf *ibuf = NULL;
Image *tpage_last = NULL, *tpage;
Image *ima = NULL;
+ ImBuf *tmpibuf = NULL;
if (ps->image_tot == 1) {
/* Simple loop, no context switching */
@@ -2560,7 +2738,7 @@ 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, 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, bucket_bounds, ibuf, &tmpibuf, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
}
}
else {
@@ -2570,7 +2748,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
face_index = GET_INT_FROM_POINTER(node->link);
/* Image context switching */
- tpage = project_paint_face_image(ps, ps->dm_mtface, face_index);
+ tpage = project_paint_face_paint_image(ps, face_index);
if (tpage_last != tpage) {
tpage_last = tpage;
@@ -2584,10 +2762,13 @@ 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, ima->tpageflag & IMA_CLAMP_U, ima->tpageflag & IMA_CLAMP_V);
+ 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);
}
}
+ if (tmpibuf)
+ IMB_freeImBuf(tmpibuf);
+
ps->bucketFlags[bucket_index] |= PROJ_BUCKET_INIT;
}
@@ -2735,11 +2916,17 @@ static void project_paint_begin(ProjPaintState *ps)
ProjPaintImage *projIma;
Image *tpage_last = NULL, *tpage;
+ TexPaintSlot *slot_last = NULL, *slot = NULL;
+ TexPaintSlot *slot_last_clone = NULL, *slot_clone;
/* Face vars */
MPoly *mpoly_orig;
MFace *mf;
- MTFace *tf;
+ MTFace **tf;
+ MTFace *tf_base;
+
+ MTFace **tf_clone;
+ MTFace *tf_clone_base = NULL;
int a, i; /* generic looping vars */
int image_index = -1, face_index;
@@ -2785,7 +2972,7 @@ static void project_paint_begin(ProjPaintState *ps)
ps->dm_release = true;
}
- if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE) ) {
+ if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE)) {
if (ps->dm_release)
ps->dm->release(ps->dm);
@@ -2794,13 +2981,15 @@ static void project_paint_begin(ProjPaintState *ps)
return;
}
- ps->dm_mvert = ps->dm->getVertArray(ps->dm);
- ps->dm_mface = ps->dm->getTessFaceArray(ps->dm);
- ps->dm_mtface = ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE);
+ DM_update_materials(ps->dm, ps->ob);
ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
ps->dm_totface = ps->dm->getNumTessFaces(ps->dm);
+ ps->dm_mvert = ps->dm->getVertArray(ps->dm);
+ ps->dm_mface = ps->dm->getTessFaceArray(ps->dm);
+ ps->dm_mtface = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces");
+
if (ps->do_face_sel) {
index_mf_to_mpoly = ps->dm->getTessFaceDataArray(ps->dm, CD_ORIGINDEX);
index_mp_to_orig = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX);
@@ -2816,32 +3005,36 @@ static void project_paint_begin(ProjPaintState *ps)
}
/* use clone mtface? */
-
-
- /* Note, use the original mesh for getting the clone and mask layer index
- * this avoids re-generating the derived mesh just to get the new index */
if (ps->do_layer_clone) {
- //int layer_num = CustomData_get_clone_layer(&ps->dm->faceData, CD_MTFACE);
- int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
- if (layer_num != -1)
- ps->dm_mtface_clone = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
-
- if (ps->dm_mtface_clone == NULL || ps->dm_mtface_clone == ps->dm_mtface) {
- ps->do_layer_clone = false;
- ps->dm_mtface_clone = NULL;
- }
+ ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces");
}
- if (ps->do_layer_stencil) {
+ if (ps->do_layer_stencil || ps->do_stencil_brush) {
//int layer_num = CustomData_get_stencil_layer(&ps->dm->faceData, CD_MTFACE);
int layer_num = CustomData_get_stencil_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
if (layer_num != -1)
ps->dm_mtface_stencil = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
- if (ps->dm_mtface_stencil == NULL || ps->dm_mtface_stencil == ps->dm_mtface) {
- ps->do_layer_stencil = false;
- ps->dm_mtface_stencil = NULL;
+ if (ps->dm_mtface_stencil == NULL) {
+ /* get active instead */
+ ps->dm_mtface_stencil = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
}
+
+ if (ps->do_stencil_brush)
+ tf_base = ps->dm_mtface_stencil;
+ }
+
+ if (ps->do_layer_clone) {
+ int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
+
+ if (layer_num != -1)
+ tf_clone_base = CustomData_get_layer_n(&ps->dm->faceData, CD_MTFACE, layer_num);
+
+ if (tf_clone_base == NULL) {
+ /* get active instead */
+ tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ }
+
}
/* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
@@ -3038,6 +3231,7 @@ static void project_paint_begin(ProjPaintState *ps)
if (ps->seam_bleed_px > 0.0f) {
ps->vertFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces");
ps->faceSeamFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags");
+ ps->faceWindingFlags = (char *)MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceWindindFlags");
ps->faceSeamUVs = MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs");
}
#endif
@@ -3055,6 +3249,13 @@ static void project_paint_begin(ProjPaintState *ps)
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);
+ }
+
+ 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");
}
@@ -3116,7 +3317,60 @@ static void project_paint_begin(ProjPaintState *ps)
is_face_sel = true;
}
- if (is_face_sel && (tpage = project_paint_face_image(ps, ps->dm_mtface, face_index))) {
+ if (!ps->do_stencil_brush) {
+ slot = project_paint_face_paint_slot(ps, face_index);
+ /* all faces should have a valid slot, reassert here */
+ if (slot == NULL) {
+ tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ tpage = ps->canvas_ima;
+ }
+ else {
+ if (slot != slot_last) {
+ if (!slot->uvname || !(tf_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot->uvname)))
+ tf_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ slot_last = slot;
+ }
+
+ /* don't allow using the same inage for painting and stencilling */
+ if (slot->ima == ps->stencil_ima)
+ continue;
+
+ tpage = slot->ima;
+ }
+ }
+ else {
+ tpage = ps->stencil_ima;
+ }
+
+ *tf = tf_base + face_index;
+
+ if (ps->do_layer_clone) {
+ if (ps->do_material_slots) {
+ slot_clone = project_paint_face_clone_slot(ps, face_index);
+ /* all faces should have a valid slot, reassert here */
+ if (ELEM(slot_clone, NULL, slot))
+ continue;
+ }
+ else if (ps->clone_ima == ps->canvas_ima)
+ continue;
+
+ tf_clone = ps->dm_mtface_clone + face_index;
+
+ if (ps->do_material_slots) {
+ if (slot_clone != slot_last_clone) {
+ if (!slot->uvname || !(tf_clone_base = CustomData_get_layer_named(&ps->dm->faceData, CD_MTFACE, slot_clone->uvname)))
+ tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ slot_last_clone = slot_clone;
+ }
+ }
+
+ *tf_clone = tf_clone_base + face_index;
+ }
+
+ /* tfbase here should be non-null! */
+ BLI_assert (tf_base != NULL);
+
+ if (is_face_sel && tpage) {
const float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL;
v1coSS = ps->screenCoords[mf->v1];
@@ -3214,10 +3468,19 @@ static void project_paint_begin(ProjPaintState *ps)
projIma = ps->projImages = (ProjPaintImage *)BLI_memarena_alloc(arena, sizeof(ProjPaintImage) * ps->image_tot);
for (node = image_LinkList, i = 0; node; node = node->next, i++, projIma++) {
+ int size;
projIma->ima = node->link;
projIma->touch = 0;
projIma->ibuf = BKE_image_acquire_ibuf(projIma->ima, NULL, NULL);
- projIma->partRedrawRect = BLI_memarena_calloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ size = sizeof(void **) * IMAPAINT_TILE_NUMBER(projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(projIma->ibuf->y);
+ projIma->partRedrawRect = BLI_memarena_alloc(arena, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ memset(projIma->partRedrawRect, 0, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ projIma->undoRect = (volatile void **) BLI_memarena_alloc(arena, size);
+ memset(projIma->undoRect, 0, size);
+ projIma->maskRect = (unsigned short **) BLI_memarena_alloc(arena, size);
+ memset(projIma->maskRect, 0, size);
+ projIma->valid = (bool **) BLI_memarena_alloc(arena, size);
+ memset(projIma->valid, 0, size);
}
/* we have built the array, discard the linked list */
@@ -3244,95 +3507,12 @@ static void project_paint_end(ProjPaintState *ps)
int a;
ProjPaintImage *projIma;
- /* build undo data from original pixel colors */
- if (U.uiflag & USER_GLOBALUNDO) {
- ProjPixel *projPixel;
- ImBuf *tmpibuf = NULL, *tmpibuf_float = NULL;
- LinkNode *pixel_node;
- void *tilerect;
- MemArena *arena = ps->arena_mt[0]; /* threaded arena re-used for non threaded case */
-
- int bucket_tot = (ps->buckets_x * ps->buckets_y); /* we could get an X/Y but easier to loop through all possible buckets */
- int bucket_index;
- int tile_index;
- int x_round, y_round;
- int x_tile, y_tile;
- int is_float = -1;
-
- /* context */
- ProjPaintImage *last_projIma;
- int last_image_index = -1;
- int last_tile_width = 0;
-
- for (a = 0, last_projIma = ps->projImages; a < ps->image_tot; a++, last_projIma++) {
- int size = sizeof(void **) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x) * IMAPAINT_TILE_NUMBER(last_projIma->ibuf->y);
- last_projIma->undoRect = (void **) BLI_memarena_calloc(arena, size);
- last_projIma->ibuf->userflags |= IB_BITMAPDIRTY;
- }
-
- for (bucket_index = 0; bucket_index < bucket_tot; bucket_index++) {
- /* loop through all pixels */
- for (pixel_node = ps->bucketRect[bucket_index]; pixel_node; pixel_node = pixel_node->next) {
-
- /* ok we have a pixel, was it modified? */
- projPixel = (ProjPixel *)pixel_node->link;
-
- if (last_image_index != projPixel->image_index) {
- /* set the context */
- last_image_index = projPixel->image_index;
- last_projIma = ps->projImages + last_image_index;
- last_tile_width = IMAPAINT_TILE_NUMBER(last_projIma->ibuf->x);
- is_float = last_projIma->ibuf->rect_float ? 1 : 0;
- }
-
-
- if ((is_float == 0 && projPixel->origColor.uint != *projPixel->pixel.uint_pt) ||
- (is_float == 1 &&
- (projPixel->origColor.f[0] != projPixel->pixel.f_pt[0] ||
- projPixel->origColor.f[1] != projPixel->pixel.f_pt[1] ||
- projPixel->origColor.f[2] != projPixel->pixel.f_pt[2] ||
- projPixel->origColor.f[3] != projPixel->pixel.f_pt[3]))
- )
- {
-
- x_tile = projPixel->x_px >> IMAPAINT_TILE_BITS;
- y_tile = projPixel->y_px >> IMAPAINT_TILE_BITS;
-
- x_round = x_tile * IMAPAINT_TILE_SIZE;
- y_round = y_tile * IMAPAINT_TILE_SIZE;
-
- tile_index = x_tile + y_tile * last_tile_width;
-
- if (last_projIma->undoRect[tile_index] == NULL) {
- /* add the undo tile from the modified image, then write the original colors back into it */
- tilerect = last_projIma->undoRect[tile_index] = image_undo_push_tile(last_projIma->ima, last_projIma->ibuf, is_float ? (&tmpibuf_float) : (&tmpibuf), x_tile, y_tile);
- }
- else {
- tilerect = last_projIma->undoRect[tile_index];
- }
-
- /* This is a BIT ODD, but overwrite the undo tiles image info with this pixels original color
- * because allocating the tiles along the way slows down painting */
-
- if (is_float) {
- float *rgba_fp = (float *)tilerect + (((projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE)) * 4;
- copy_v4_v4(rgba_fp, projPixel->origColor.f);
- }
- else {
- ((unsigned int *)tilerect)[(projPixel->x_px - x_round) + (projPixel->y_px - y_round) * IMAPAINT_TILE_SIZE] = projPixel->origColor.uint;
- }
- }
- }
- }
-
- if (tmpibuf) IMB_freeImBuf(tmpibuf);
- if (tmpibuf_float) IMB_freeImBuf(tmpibuf_float);
- }
- /* done calculating undo data */
+ 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);
}
BKE_image_release_ibuf(ps->reproject_image, ps->reproject_ibuf, NULL);
@@ -3341,15 +3521,29 @@ 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();
#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);
}
#endif
+ if (ps->blurkernel) {
+ paint_delete_blur_kernel(ps->blurkernel);
+ MEM_freeN(ps->blurkernel);
+ }
+
if (ps->vertFlags) MEM_freeN(ps->vertFlags);
for (a = 0; a < ps->thread_tot; a++) {
@@ -3442,7 +3636,7 @@ static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
{
if (ps->source == PROJ_SRC_VIEW) {
float min_brush[2], max_brush[2];
- const float radius = (float)BKE_brush_size_get(ps->scene, ps->brush);
+ const float radius = ps->brush_size;
/* so we don't have a bucket bounds that is way too small to paint into */
// if (radius < 1.0f) radius = 1.0f; // this doesn't work yet :/
@@ -3480,7 +3674,7 @@ static bool project_bucket_iter_init(ProjPaintState *ps, const float mval_f[2])
static bool project_bucket_iter_next(ProjPaintState *ps, int *bucket_index, rctf *bucket_bounds, const float mval[2])
{
- const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
+ const int diameter = 2 * ps->brush_size;
if (ps->thread_tot > 1)
BLI_lock_thread(LOCK_CUSTOM1);
@@ -3542,7 +3736,7 @@ static void do_projectpaint_clone(ProjPaintState *ps, ProjPixel *projPixel, floa
clone_rgba[3] = (unsigned char)(clone_pt[3] * mask);
if (ps->do_masking) {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, clone_rgba, ps->blend);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, clone_rgba, ps->blend);
}
else {
IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, clone_rgba, ps->blend);
@@ -3560,7 +3754,7 @@ static void do_projectpaint_clone_f(ProjPaintState *ps, ProjPixel *projPixel, fl
mul_v4_v4fl(clone_rgba, clone_pt, mask);
if (ps->do_masking) {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, clone_rgba, ps->blend);
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, clone_rgba, ps->blend);
}
else {
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, clone_rgba, ps->blend);
@@ -3598,42 +3792,58 @@ static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, fl
BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
}
-/* do_projectpaint_soften for float & byte
- */
-static float inv_pow2(float f)
-{
- f = 1.0f - f;
- f = f * f;
- return 1.0f - f;
-}
-
static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, float mask,
MemArena *softenArena, LinkNode **softenPixels)
{
- unsigned int accum_tot = 0;
- unsigned int i;
-
+ float accum_tot = 0.0f;
+ int xk, yk;
+ BlurKernel *kernel = ps->blurkernel;
float *rgba = projPixel->newColor.f;
- /* sigh, mask values tend to need to be a _lot_ stronger with blur */
- mask = inv_pow2(mask);
-
/* rather then painting, accumulate surrounding colors */
zero_v4(rgba);
- for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) {
- float co_ofs[2];
- float rgba_tmp[4];
- sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]);
- if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
- add_v4_v4(rgba, rgba_tmp);
- accum_tot++;
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ float rgba_tmp[4];
+ float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
+
+ add_v2_v2(co_ofs, projPixel->projCoSS);
+
+ if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
+ float weight = kernel->wdata[xk + yk * kernel->side];
+ mul_v4_fl(rgba_tmp, weight);
+ add_v4_v4(rgba, rgba_tmp);
+ accum_tot += weight;
+ }
}
}
if (LIKELY(accum_tot != 0)) {
mul_v4_fl(rgba, 1.0f / (float)accum_tot);
- blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask);
+
+ if (ps->mode == BRUSH_STROKE_INVERT) {
+ /* subtract blurred image from normal image gives high pass filter */
+ sub_v3_v3v3(rgba, projPixel->pixel.f_pt, 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);
+ if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
+ float alpha = projPixel->pixel.f_pt[3];
+ projPixel->pixel.f_pt[3] = rgba[3] = mask;
+
+ /* add to enhance edges */
+ blend_color_add_float(rgba, projPixel->pixel.f_pt, rgba);
+ rgba[3] = alpha;
+ }
+ else
+ return;
+ }
+ else {
+ blend_color_interpolate_float(rgba, rgba, projPixel->pixel.f_pt, mask);
+ }
+
BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
}
}
@@ -3641,24 +3851,27 @@ static void do_projectpaint_soften_f(ProjPaintState *ps, ProjPixel *projPixel, f
static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, float mask,
MemArena *softenArena, LinkNode **softenPixels)
{
- unsigned int accum_tot = 0;
- unsigned int i;
-
+ float accum_tot = 0;
+ int xk, yk;
+ BlurKernel *kernel = ps->blurkernel;
float rgba[4]; /* convert to byte after */
- /* sigh, mask values tend to need to be a _lot_ stronger with blur */
- mask = inv_pow2(mask);
-
/* rather then painting, accumulate surrounding colors */
zero_v4(rgba);
- for (i = 0; i < PROJ_PIXEL_SOFTEN_TOT; i++) {
- float co_ofs[2];
- float rgba_tmp[4];
- sub_v2_v2v2(co_ofs, projPixel->projCoSS, proj_pixel_soften_v2[i]);
- if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
- add_v4_v4(rgba, rgba_tmp);
- accum_tot++;
+ for (yk = 0; yk < kernel->side; yk++) {
+ for (xk = 0; xk < kernel->side; xk++) {
+ float rgba_tmp[4];
+ float co_ofs[2] = {2.0f * xk - 1.0f, 2.0f * yk - 1.0f};
+
+ add_v2_v2(co_ofs, projPixel->projCoSS);
+
+ if (project_paint_PickColor(ps, co_ofs, rgba_tmp, NULL, true)) {
+ float weight = kernel->wdata[xk + yk * kernel->side];
+ mul_v4_fl(rgba_tmp, weight);
+ add_v4_v4(rgba, rgba_tmp);
+ accum_tot += weight;
+ }
}
}
@@ -3666,9 +3879,34 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
unsigned char *rgba_ub = projPixel->newColor.ch;
mul_v4_fl(rgba, 1.0f / (float)accum_tot);
- premul_float_to_straight_uchar(rgba_ub, rgba);
- blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask);
+ if (ps->mode == BRUSH_STROKE_INVERT) {
+ float rgba_pixel[4];
+
+ straight_uchar_to_premul_float(rgba_pixel, projPixel->pixel.ch_pt);
+
+ /* subtract blurred image from normal image gives high pass filter */
+ 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);
+ if (fabsf(rgba[0]) > ps->brush->sharp_threshold) {
+ float alpha = rgba_pixel[3];
+ rgba[3] = rgba_pixel[3] = mask;
+
+ /* add to enhance edges */
+ blend_color_add_float(rgba, rgba_pixel, rgba);
+
+ rgba[3] = alpha;
+ premul_float_to_straight_uchar(rgba_ub, rgba);
+ }
+ else
+ return;
+ }
+ else {
+ premul_float_to_straight_uchar(rgba_ub, rgba);
+ blend_color_interpolate_byte(rgba_ub, rgba_ub, projPixel->pixel.ch_pt, mask);
+ }
BLI_linklist_prepend_arena(softenPixels, (void *)projPixel, softenArena);
}
}
@@ -3678,7 +3916,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const
float rgb[3];
unsigned char rgba_ub[4];
- copy_v3_v3(rgb, ps->brush->rgb);
+ copy_v3_v3(rgb, ps->paint_color);
if (ps->is_texbrush) {
mul_v3_v3(rgb, texrgb);
@@ -3690,7 +3928,7 @@ static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const
rgba_ub[3] = f_to_char(mask);
if (ps->do_masking) {
- IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch, rgba_ub, ps->blend);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
}
else {
IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
@@ -3701,7 +3939,7 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, con
{
float rgba[4];
- srgb_to_linearrgb_v3_v3(rgba, ps->brush->rgb);
+ copy_v3_v3(rgba, ps->paint_color_linear);
if (ps->is_texbrush)
mul_v3_v3(rgba, texrgb);
@@ -3710,13 +3948,42 @@ static void do_projectpaint_draw_f(ProjPaintState *ps, ProjPixel *projPixel, con
rgba[3] = mask;
if (ps->do_masking) {
- IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f, rgba, ps->blend);
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
+ }
+ else {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
+ }
+}
+
+static void do_projectpaint_mask(ProjPaintState *ps, ProjPixel *projPixel, float mask)
+{
+ unsigned char rgba_ub[4];
+ rgba_ub[0] = rgba_ub[1] = rgba_ub[2] = ps->stencil_value * 255.0f;
+ rgba_ub[3] = f_to_char(mask);
+
+ if (ps->do_masking) {
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt, rgba_ub, ps->blend);
+ }
+ else {
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->pixel.ch_pt, rgba_ub, ps->blend);
+ }
+}
+
+static void do_projectpaint_mask_f(ProjPaintState *ps, ProjPixel *projPixel, float mask)
+{
+ float rgba[4];
+ rgba[0] = rgba[1] = rgba[2] = ps->stencil_value;
+ rgba[3] = mask;
+
+ if (ps->do_masking) {
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt, rgba, ps->blend);
}
else {
IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->pixel.f_pt, rgba, ps->blend);
}
}
+
/* run this for single and multithreaded painting */
static void *do_projectpaint_thread(void *ph_v)
{
@@ -3750,7 +4017,7 @@ static void *do_projectpaint_thread(void *ph_v)
float co[2];
unsigned short mask_short;
const float brush_alpha = BKE_brush_alpha_get(ps->scene, brush);
- const float brush_radius = (float)BKE_brush_size_get(ps->scene, brush);
+ 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;
@@ -3800,32 +4067,108 @@ static void *do_projectpaint_thread(void *ph_v)
}
/* end copy */
- if (is_floatbuf) {
- /* re-project buffer is assumed byte - TODO, allow float */
- bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
- projPixel->projCoSS[0], projPixel->projCoSS[1]);
- if (projPixel->newColor.ch[3]) {
- float newColor_f[4];
- float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+ /* fill tools */
+ if (ps->source == PROJ_SRC_VIEW_FILL) {
+ if (brush->flag & BRUSH_USE_GRADIENT) {
+ /* these could probably be cached instead of being done per pixel */
+ float tangent[2];
+ float line_len_sq_inv, line_len;
+ float f;
+ float color_f[4];
+ float p[2] = {projPixel->projCoSS[0] - lastpos[0], projPixel->projCoSS[1] - lastpos[1]};
+
+ sub_v2_v2v2(tangent, pos, lastpos);
+ line_len = len_squared_v2(tangent);
+ line_len_sq_inv = 1.0f / line_len;
+ line_len = sqrtf(line_len);
+
+ switch (brush->gradient_fill_mode) {
+ case BRUSH_GRADIENT_LINEAR:
+ {
+ f = dot_v2v2(p, tangent) * line_len_sq_inv;
+ break;
+ }
+ case BRUSH_GRADIENT_RADIAL:
+ {
+ f = len_v2(p) / line_len;
+ break;
+ }
+ }
+ do_colorband(brush->gradient, f, color_f);
+ color_f[3] *= ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha;
+
+ if (is_floatbuf) {
+ /* convert to premultipied */
+ mul_v3_fl(color_f, color_f[3]);
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt,
+ color_f, ps->blend);
+ }
+ else {
+ linearrgb_to_srgb_v3_v3(color_f, color_f);
+ rgba_float_to_uchar(projPixel->newColor.ch, color_f);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
+ projPixel->newColor.ch, ps->blend);
+ }
+ }
+ else {
+ if (is_floatbuf) {
+ float newColor_f[4];
+ newColor_f[3] = ((float)projPixel->mask) * (1.0f / 65535.0f) * brush->alpha;
+ copy_v3_v3(newColor_f, ps->paint_color_linear);
- straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch);
- IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, true, ps->reproject_ibuf->rect_colorspace);
- mul_v4_v4fl(newColor_f, newColor_f, mask);
+ IMB_blend_color_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt,
+ newColor_f, ps->blend);
+ }
+ else {
+ float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+ projPixel->newColor.ch[3] = mask * 255 * brush->alpha;
- blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f,
- newColor_f);
+ rgb_float_to_uchar(projPixel->newColor.ch, ps->paint_color);
+ IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
+ projPixel->newColor.ch, ps->blend);
+ }
+ }
+
+ 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];
}
+
+ last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
+ last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px);
+ last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px);
+
+ last_partial_redraw_cell->x2 = max_ii(last_partial_redraw_cell->x2, (int)projPixel->x_px + 1);
+ last_partial_redraw_cell->y2 = max_ii(last_partial_redraw_cell->y2, (int)projPixel->y_px + 1);
}
else {
- /* re-project buffer is assumed byte - TODO, allow float */
- bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
- projPixel->projCoSS[0], projPixel->projCoSS[1]);
- if (projPixel->newColor.ch[3]) {
- float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
- projPixel->newColor.ch[3] *= mask;
-
- blend_color_mix_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch,
- projPixel->newColor.ch);
+ if (is_floatbuf) {
+ /* re-project buffer is assumed byte - TODO, allow float */
+ bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
+ projPixel->projCoSS[0], projPixel->projCoSS[1]);
+ if (projPixel->newColor.ch[3]) {
+ float newColor_f[4];
+ float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+
+ straight_uchar_to_premul_float(newColor_f, projPixel->newColor.ch);
+ IMB_colormanagement_colorspace_to_scene_linear_v4(newColor_f, true, ps->reproject_ibuf->rect_colorspace);
+ mul_v4_v4fl(newColor_f, newColor_f, mask);
+
+ blend_color_mix_float(projPixel->pixel.f_pt, projPixel->origColor.f_pt,
+ newColor_f);
+ }
+ }
+ else {
+ /* re-project buffer is assumed byte - TODO, allow float */
+ bicubic_interpolation_color(ps->reproject_ibuf, projPixel->newColor.ch, NULL,
+ projPixel->projCoSS[0], projPixel->projCoSS[1]);
+ if (projPixel->newColor.ch[3]) {
+ float mask = ((float)projPixel->mask) * (1.0f / 65535.0f);
+ projPixel->newColor.ch[3] *= mask;
+
+ blend_color_mix_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
+ projPixel->newColor.ch);
+ }
}
}
}
@@ -3847,7 +4190,7 @@ static void *do_projectpaint_thread(void *ph_v)
if (falloff > 0.0f) {
float texrgb[3];
- float mask = falloff;
+ float mask;
if (ps->do_masking) {
/* masking to keep brush contribution to a pixel limited. note we do not do
@@ -3856,20 +4199,24 @@ static void *do_projectpaint_thread(void *ph_v)
*
* Instead we use a formula that adds up but approaches brush_alpha slowly
* and never exceeds it, which gives nice smooth results. */
- float mask_accum = projPixel->mask_accum;
+ float mask_accum = *projPixel->mask_accum;
+ float max_mask = brush_alpha * falloff * 65535.0f;
if (ps->is_maskbrush) {
float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
- CLAMP(texmask, 0.0f, 1.0f);
- mask = mask_accum + (brush_alpha * texmask * 65535.0f - mask_accum) * mask;
- }
- else {
- mask = mask_accum + (brush_alpha * 65535.0f - mask_accum) * mask;
+ max_mask *= texmask;
}
+
+ if (brush->flag & BRUSH_ACCUMULATE)
+ mask = mask_accum + max_mask;
+ else
+ mask = mask_accum + (max_mask - mask_accum * falloff);
+
+ mask = min_ff(mask, 65535.0f);
mask_short = (unsigned short)mask;
- if (mask_short > projPixel->mask_accum) {
- projPixel->mask_accum = mask_short;
+ if (mask_short > *projPixel->mask_accum) {
+ *projPixel->mask_accum = mask_short;
mask = mask_short * (1.0f / 65535.0f);
}
else {
@@ -3878,7 +4225,7 @@ static void *do_projectpaint_thread(void *ph_v)
}
}
else {
- mask *= brush_alpha;
+ mask = brush_alpha * falloff;
if (ps->is_maskbrush) {
float texmask = BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
CLAMP(texmask, 0.0f, 1.0f);
@@ -3907,10 +4254,6 @@ static void *do_projectpaint_thread(void *ph_v)
mask *= texrgba[3];
}
- if (ps->is_maskbrush_tiled) {
- mask *= BKE_brush_sample_masktex(ps->scene, ps->brush, projPixel->projCoSS, thread_index, pool);
- }
-
/* extra mask for normal, layer stencil, .. */
mask *= ((float)projPixel->mask) * (1.0f / 65535.0f);
@@ -3926,6 +4269,9 @@ static void *do_projectpaint_thread(void *ph_v)
}
/* end copy */
+ /* validate undo tile, since we will modify t*/
+ *projPixel->valid = true;
+
last_partial_redraw_cell = last_projIma->partRedrawRect + projPixel->bb_cell_index;
last_partial_redraw_cell->x1 = min_ii(last_partial_redraw_cell->x1, (int)projPixel->x_px);
last_partial_redraw_cell->y1 = min_ii(last_partial_redraw_cell->y1, (int)projPixel->y_px);
@@ -3949,6 +4295,10 @@ static void *do_projectpaint_thread(void *ph_v)
if (is_floatbuf) do_projectpaint_soften_f(ps, projPixel, mask, softenArena, &softenPixels_f);
else do_projectpaint_soften(ps, projPixel, mask, softenArena, &softenPixels);
break;
+ case PAINT_TOOL_MASK:
+ if (is_floatbuf) do_projectpaint_mask_f(ps, projPixel, mask);
+ else do_projectpaint_mask(ps, projPixel, mask);
+ break;
default:
if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, texrgb, mask);
else do_projectpaint_draw(ps, projPixel, texrgb, mask);
@@ -3957,8 +4307,8 @@ static void *do_projectpaint_thread(void *ph_v)
}
if (lock_alpha) {
- if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f[3];
- else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch[3];
+ if (is_floatbuf) projPixel->pixel.f_pt[3] = projPixel->origColor.f_pt[3];
+ else projPixel->pixel.ch_pt[3] = projPixel->origColor.ch_pt[3];
}
/* done painting */
@@ -4076,14 +4426,20 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
}
-void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const float pos[2])
+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)
{
ProjPaintState *ps = pps;
+ 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) {
- Scene *scene = ps->scene;
View3D *v3d = ps->v3d;
float *cursor = ED_view3d_cursor3d_get(scene, v3d);
int mval_i[2] = {(int)pos[0], (int)pos[1]};
@@ -4098,6 +4454,25 @@ void paint_proj_stroke(bContext *C, void *pps, const float prev_pos[2], const fl
return;
}
+ /* handle gradient and inverted stroke color here */
+ if (ps->tool == PAINT_TOOL_DRAW) {
+ paint_brush_color_get(scene, brush, false, ps->mode == BRUSH_STROKE_INVERT, distance, pressure, ps->paint_color, NULL);
+ srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ else if (ps->tool == PAINT_TOOL_FILL) {
+ copy_v3_v3(ps->paint_color, BKE_brush_color_get(scene, brush));
+ srgb_to_linearrgb_v3_v3(ps->paint_color_linear, ps->paint_color);
+ }
+ else if (ps->tool == PAINT_TOOL_MASK) {
+ ps->stencil_value = brush->weight;
+
+ if ((ps->mode == BRUSH_STROKE_INVERT) ^
+ ((scene->toolsettings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0))
+ {
+ ps->stencil_value = 1.0f - ps->stencil_value;
+ }
+ }
+
/* continue adding to existing partial redraw rects until redraw */
if (!ps->need_redraw) {
for (a = 0; a < ps->image_tot; a++)
@@ -4122,30 +4497,24 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
Brush *brush = ps->brush;
ps->tool = brush->imagepaint_tool;
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) ?
+ BRUSH_STROKE_INVERT : BRUSH_STROKE_NORMAL);
+
+ ps->blurkernel = paint_new_blur_kernel(brush, true);
+ }
/* disable for 3d mapping also because painting on mirrored mesh can create "stripes" */
- ps->do_masking = (brush->flag & BRUSH_AIRBRUSH ||
- (brush->imagepaint_tool == PAINT_TOOL_SMEAR) ||
- (brush->mtex.tex && !ELEM3(brush->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D)))
- ? false : true;
+ ps->do_masking = paint_use_opacity_masking(brush);
ps->is_texbrush = (brush->mtex.tex && brush->imagepaint_tool == PAINT_TOOL_DRAW) ? true : false;
- ps->is_maskbrush = false;
- ps->is_maskbrush_tiled = false;
- if (brush->mask_mtex.tex) {
- if (ELEM(brush->mask_mtex.brush_map_mode, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_TILED)) {
- ps->is_maskbrush_tiled = true;
- }
- else {
- ps->is_maskbrush = true;
- }
- }
+ ps->is_maskbrush = (brush->mask_mtex.tex) ? true : false;
}
else {
/* brush may be NULL*/
ps->do_masking = false;
ps->is_texbrush = false;
ps->is_maskbrush = false;
- ps->is_maskbrush_tiled = false;
}
/* sizeof(ProjPixel), since we alloc this a _lot_ */
@@ -4160,17 +4529,33 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
ps->scene = scene;
ps->ob = ob; /* allow override of active object */
+ ps->do_material_slots = (settings->imapaint.mode == IMAGEPAINT_MODE_MATERIAL);
+ ps->stencil_ima = settings->imapaint.stencil;
+ ps->canvas_ima = (!ps->do_material_slots) ?
+ settings->imapaint.canvas : NULL;
+ ps->clone_ima = (!ps->do_material_slots) ?
+ settings->imapaint.clone : NULL;
+
/* setup projection painting data */
- ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1;
- ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1;
- ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1;
+ if (ps->tool != PAINT_TOOL_FILL) {
+ ps->do_backfacecull = (settings->imapaint.flag & IMAGEPAINT_PROJECT_BACKFACE) ? 0 : 1;
+ ps->do_occlude = (settings->imapaint.flag & IMAGEPAINT_PROJECT_XRAY) ? 0 : 1;
+ ps->do_mask_normal = (settings->imapaint.flag & IMAGEPAINT_PROJECT_FLAT) ? 0 : 1;
+ }
+ else {
+ ps->do_backfacecull = ps->do_occlude = ps->do_mask_normal = 0;
+ }
ps->do_new_shading_nodes = BKE_scene_use_new_shading_nodes(scene); /* only cache the value */
if (ps->tool == PAINT_TOOL_CLONE)
ps->do_layer_clone = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_CLONE) ? 1 : 0;
- ps->do_layer_stencil = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? 1 : 0;
- ps->do_layer_stencil_inv = (settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) ? 1 : 0;
+
+ ps->do_stencil_brush = (ps->brush && ps->brush->imagepaint_tool == PAINT_TOOL_MASK);
+ /* deactivate stenciling for the stencil brush :) */
+ ps->do_layer_stencil = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) &&
+ !(ps->do_stencil_brush) && ps->stencil_ima);
+ ps->do_layer_stencil_inv = ((settings->imapaint.flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) != 0);
#ifndef PROJ_DEBUG_NOSEAMBLEED
@@ -4198,6 +4583,7 @@ 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");
+
project_state_init(C, ob, ps, mode);
if (ps->tool == PAINT_TOOL_CLONE && mode == BRUSH_STROKE_INVERT) {
@@ -4230,6 +4616,10 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
paint_proj_begin_clone(ps, mouse);
+ /* special full screen draw mode for fill tool */
+ if (ps->tool == PAINT_TOOL_FILL)
+ ps->source = PROJ_SRC_VIEW_FILL;
+
return ps;
}
@@ -4278,14 +4668,22 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
int orig_brush_size;
IDProperty *idgroup;
IDProperty *view_data = NULL;
+ Object *ob = OBACT;
+ bool uvs, mat, tex;
- project_state_init(C, OBACT, &ps, BRUSH_STROKE_NORMAL);
-
- if (ps.ob == NULL || ps.ob->type != OB_MESH) {
+ if (ob == NULL || ob->type != OB_MESH) {
BKE_report(op->reports, RPT_ERROR, "No active mesh object");
return OPERATOR_CANCELLED;
}
+ if (!BKE_paint_proj_mesh_data_check(scene, ob, &uvs, &mat, &tex, NULL)) {
+ BKE_paint_data_warning(op->reports, uvs, mat, tex, true);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ return OPERATOR_CANCELLED;
+ }
+
+ project_state_init(C, ob, &ps, BRUSH_STROKE_NORMAL);
+
if (image == NULL) {
BKE_report(op->reports, RPT_ERROR, "Image could not be found");
return OPERATOR_CANCELLED;
@@ -4327,7 +4725,6 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
/* override */
ps.is_texbrush = false;
ps.is_maskbrush = false;
- ps.is_maskbrush_tiled = false;
ps.do_masking = false;
orig_brush_size = BKE_brush_size_get(scene, ps.brush);
BKE_brush_size_set(scene, ps.brush, 32); /* cover the whole image */
@@ -4337,7 +4734,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
scene->toolsettings->imapaint.flag |= IMAGEPAINT_DRAWING;
ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- ED_image_undo_restore, ED_image_undo_free);
+ ED_image_undo_restore, ED_image_undo_free, NULL);
/* allocate and initialize spatial data structures */
project_paint_begin(&ps);
@@ -4470,3 +4867,361 @@ void PAINT_OT_image_from_view(wmOperatorType *ot)
RNA_def_string_file_name(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Name of the file");
}
+
+/*********************************************
+ * Data generation for projective texturing *
+ * *******************************************/
+
+void BKE_paint_data_warning(struct ReportList *reports, bool uvs, bool mat, bool tex, bool stencil)
+{
+ BKE_reportf(reports, RPT_WARNING, "Missing%s%s%s%s detected!",
+ !uvs ? " UVs," : "",
+ !mat ? " Materials," : "",
+ !tex ? " Textures," : "",
+ !stencil ? " Stencil," : ""
+ );
+}
+
+/* Make sure that active object has a material, and assign UVs and image layers if they do not exist */
+bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil)
+{
+ Mesh *me;
+ int layernum;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+ Brush *br = BKE_paint_brush(&imapaint->paint);
+ bool hasmat = true;
+ bool hastex = true;
+ bool hasstencil = true;
+ bool hasuvs = true;
+
+ imapaint->missing_data = 0;
+
+ BLI_assert(ob->type == OB_MESH);
+
+ if (imapaint->mode == IMAGEPAINT_MODE_MATERIAL) {
+ /* no material, add one */
+ if (ob->totcol == 0) {
+ hasmat = false;
+ hastex = false;
+ }
+ else {
+ /* there may be material slots but they may be empty, check */
+ int i;
+ hasmat = false;
+ hastex = false;
+
+ for (i = 1; i < ob->totcol + 1; i++) {
+ Material *ma = give_current_material(ob, i);
+
+ if (ma) {
+ hasmat = true;
+ if (!ma->texpaintslot) {
+ /* refresh here just in case */
+ BKE_texpaint_slot_refresh_cache(scene, ma);
+
+ /* if still no slots, we have to add */
+ if (ma->texpaintslot) {
+ hastex = true;
+ break;
+ }
+ }
+ else {
+ hastex = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
+ if (imapaint->canvas == NULL) {
+ hastex = false;
+ }
+ }
+
+ me = BKE_mesh_from_object(ob);
+ layernum = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
+
+ if (layernum == 0) {
+ hasuvs = false;
+ }
+
+ /* Make sure we have a stencil to paint on! */
+ if (br && br->imagepaint_tool == PAINT_TOOL_MASK) {
+ imapaint->flag |= IMAGEPAINT_PROJECT_LAYER_STENCIL;
+
+ if (imapaint->stencil == NULL) {
+ hasstencil = false;
+ }
+ }
+
+ if (!hasuvs) imapaint->missing_data |= IMAGEPAINT_MISSING_UVS;
+ if (!hasmat) imapaint->missing_data |= IMAGEPAINT_MISSING_MATERIAL;
+ if (!hastex) imapaint->missing_data |= IMAGEPAINT_MISSING_TEX;
+ if (!hasstencil) imapaint->missing_data |= IMAGEPAINT_MISSING_STENCIL;
+
+ if (uvs) {
+ *uvs = hasuvs;
+ }
+ if (mat) {
+ *mat = hasmat;
+ }
+ if (tex) {
+ *tex = hastex;
+ }
+ if (stencil) {
+ *stencil = hasstencil;
+ }
+
+ return hasuvs && hasmat && hastex && hasstencil;
+}
+
+/* Add layer operator */
+
+static EnumPropertyItem layer_type_items[] = {
+ {MAP_COL, "DIFFUSE_COLOR", 0, "Diffuse Color", ""},
+ {MAP_REF, "DIFFUSE_INTENSITY", 0, "Diffuse Intensity", ""},
+ {MAP_ALPHA, "ALPHA", 0, "Alpha", ""},
+ {MAP_TRANSLU, "TRANSLUCENCY", 0, "Translucency", ""},
+ {MAP_COLSPEC, "SPECULAR_COLOR", 0, "Specular Color", ""},
+ {MAP_SPEC, "SPECULAR_INTENSITY", 0, "Specular Intensity", ""},
+ {MAP_HAR, "SPECULAR_HARDNESS", 0, "Specular Hardness", ""},
+ {MAP_AMB, "AMBIENT", 0, "Ambient", ""},
+ {MAP_EMIT, "EMIT", 0, "Emit", ""},
+ {MAP_COLMIR, "MIRROR_COLOR", 0, "Mirror Color", ""},
+ {MAP_RAYMIRR, "RAYMIRROR", 0, "Ray Mirror", ""},
+ {MAP_NORM, "NORMAL", 0, "Normal", ""},
+ {MAP_WARP, "WARP", 0, "Warp", ""},
+ {MAP_DISPLACE, "DISPLACE", 0, "Displace", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
+{
+ Image *ima;
+ float color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+ char imagename[MAX_ID_NAME - 2] = "Material Diffuse Color";
+ int width = 1024;
+ int height = 1024;
+ bool use_float = false;
+ short gen_type = IMA_GENTYPE_BLANK;
+ bool alpha = false;
+
+ if (op) {
+ width = RNA_int_get(op->ptr, "width");
+ height = RNA_int_get(op->ptr, "height");
+ use_float = RNA_boolean_get(op->ptr, "float");
+ gen_type = RNA_enum_get(op->ptr, "generated_type");
+ RNA_float_get_array(op->ptr, "color", color);
+ alpha = RNA_boolean_get(op->ptr, "alpha");
+ RNA_string_get(op->ptr, "name", imagename);
+ }
+ ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float,
+ gen_type, color);
+
+ return ima;
+}
+
+static bool proj_paint_add_slot(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ Material *ma;
+ bool is_bi = BKE_scene_uses_blender_internal(scene);
+ Image *ima = NULL;
+
+ if (!ob)
+ return false;
+
+ ma = give_current_material(ob, ob->actcol);
+
+ if (ma) {
+ Main *bmain = CTX_data_main(C);
+
+ if (!is_bi && BKE_scene_use_new_shading_nodes(scene)) {
+ bNode *imanode;
+ bNodeTree *ntree = ma->nodetree;
+
+ if (!ntree) {
+ ED_node_shader_default(C, &ma->id);
+ ntree = ma->nodetree;
+ }
+
+ ma->use_nodes = true;
+
+ /* try to add an image node */
+ imanode = nodeAddStaticNode(C, ntree, SH_NODE_TEX_IMAGE);
+
+ ima = proj_paint_image_create(op, bmain);
+ imanode->id = &ima->id;
+
+ nodeSetActive(ntree, imanode);
+
+ ntreeUpdateTree(CTX_data_main(C), ntree);
+ }
+ else {
+ MTex *mtex = add_mtex_id(&ma->id, -1);
+
+ /* successful creation of mtex layer, now create set */
+ if (mtex) {
+ int type = MAP_COL;
+ int type_id = 0;
+
+ if (op) {
+ int i;
+ type = RNA_enum_get(op->ptr, "type");
+
+ for (i = 0; i < ARRAY_SIZE(layer_type_items); i++) {
+ if (layer_type_items[i].value == type) {
+ type_id = i;
+ break;
+ }
+ }
+ }
+
+ mtex->tex = add_texture(bmain, DATA_(layer_type_items[type_id].name));
+ mtex->mapto = type;
+
+ if (mtex->tex) {
+ ima = mtex->tex->ima = proj_paint_image_create(op, bmain);
+ }
+
+ WM_event_add_notifier(C, NC_TEXTURE | NA_ADDED, mtex->tex);
+ }
+ }
+
+ if (ima) {
+ BKE_texpaint_slot_refresh_cache(scene, ma);
+ BKE_image_signal(ima, NULL, IMA_SIGNAL_USER_NEW_IMAGE);
+ WM_event_add_notifier(C, NC_IMAGE | NA_ADDED, ima);
+ DAG_id_tag_update(&ma->id, 0);
+ ED_area_tag_redraw(CTX_wm_area(C));
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int texture_paint_add_texture_paint_slot_exec(bContext *C, wmOperator *op)
+{
+ if (proj_paint_add_slot(C, op)) {
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+}
+
+
+static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ char imagename[MAX_ID_NAME - 2];
+ Object *ob = CTX_data_active_object(C);
+ Material *ma = give_current_material(ob, ob->actcol);
+ int type = RNA_enum_get(op->ptr, "type");
+
+ if (!ma) {
+ ma = BKE_material_add(CTX_data_main(C), "Material");
+ /* no material found, just assign to first slot */
+ assign_material(ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
+ }
+
+ type = RNA_enum_from_value(layer_type_items, type);
+
+ /* get the name of the texture layer type */
+ BLI_assert(type != -1);
+
+ /* take the second letter to avoid the ID identifier */
+ BLI_snprintf(imagename, FILE_MAX, "%s %s", &ma->id.name[2], layer_type_items[type].name);
+
+ RNA_string_set(op->ptr, "name", imagename);
+ return WM_operator_props_dialog_popup(C, op, 15 * UI_UNIT_X, 5 * UI_UNIT_Y);
+}
+
+#define IMA_DEF_NAME N_("Untitled")
+
+
+void PAINT_OT_add_texture_paint_slot(wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+ static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ /* identifiers */
+ ot->name = "Add Texture Paint Slot";
+ ot->description = "Add a texture paint slot";
+ ot->idname = "PAINT_OT_add_texture_paint_slot";
+
+ /* api callbacks */
+ ot->invoke = texture_paint_add_texture_paint_slot_invoke;
+ ot->exec = texture_paint_add_texture_paint_slot_exec;
+ ot->poll = ED_operator_region_view3d_active;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ prop = RNA_def_enum(ot->srna, "type", layer_type_items, 0, "Type", "Merge method to use");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "name", IMA_DEF_NAME, MAX_ID_NAME - 2, "Name", "Image datablock name");
+ prop = RNA_def_int(ot->srna, "width", 1024, 1, INT_MAX, "Width", "Image width", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ prop = RNA_def_int(ot->srna, "height", 1024, 1, INT_MAX, "Height", "Image height", 1, 16384);
+ RNA_def_property_subtype(prop, PROP_PIXEL);
+ prop = RNA_def_float_color(ot->srna, "color", 4, NULL, 0.0f, FLT_MAX, "Color", "Default fill color", 0.0f, 1.0f);
+ RNA_def_property_subtype(prop, PROP_COLOR_GAMMA);
+ RNA_def_property_float_array_default(prop, default_color);
+ RNA_def_boolean(ot->srna, "alpha", 1, "Alpha", "Create an image with an alpha channel");
+ RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK,
+ "Generated Type", "Fill the image with a grid for UV map testing");
+ RNA_def_boolean(ot->srna, "float", 0, "32 bit Float", "Create image with 32 bit floating point bit depth");
+}
+
+static int texture_paint_delete_texture_paint_slot_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = CTX_data_active_object(C);
+ Scene *scene = CTX_data_scene(C);
+ Material *ma;
+ bool is_bi = BKE_scene_uses_blender_internal(scene);
+ TexPaintSlot *slot;
+
+ /* not supported for node-based engines */
+ if (!ob || !is_bi)
+ return OPERATOR_CANCELLED;
+
+ ma = give_current_material(ob, ob->actcol);
+
+ if (!ma->texpaintslot || ma->use_nodes)
+ return OPERATOR_CANCELLED;
+
+ slot = ma->texpaintslot + ma->paint_active_slot;
+
+ if (ma->mtex[slot->index]->tex)
+ id_us_min(&ma->mtex[slot->index]->tex->id);
+ MEM_freeN(ma->mtex[slot->index]);
+ ma->mtex[slot->index] = NULL;
+
+ BKE_texpaint_slot_refresh_cache(scene, ma);
+ DAG_id_tag_update(&ma->id, 0);
+ WM_event_add_notifier(C, NC_MATERIAL, CTX_data_scene(C));
+ /* we need a notifier for data change since we change the displayed modifier uvs */
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
+ return OPERATOR_FINISHED;
+}
+
+
+void PAINT_OT_delete_texture_paint_slot(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Texture Paint Slot";
+ ot->description = "Delete selected texture paint slot";
+ ot->idname = "PAINT_OT_delete_texture_paint_slot";
+
+ /* api callbacks */
+ ot->exec = texture_paint_delete_texture_paint_slot_exec;
+ ot->poll = ED_operator_region_view3d_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h
index d8f7a3d8e05..c3b7ec60e71 100644
--- a/source/blender/editors/sculpt_paint/paint_intern.h
+++ b/source/blender/editors/sculpt_paint/paint_intern.h
@@ -38,7 +38,9 @@ struct bglMats;
struct Brush;
struct ImagePool;
struct ColorSpace;
+struct ColorManagedDisplay;
struct ListBase;
+struct Material;
struct Mesh;
struct MTex;
struct Object;
@@ -65,7 +67,7 @@ typedef void (*StrokeUpdateStep)(struct bContext *C, struct PaintStroke *stroke,
typedef void (*StrokeRedraw)(const struct bContext *C, struct PaintStroke *stroke, bool final);
typedef void (*StrokeDone)(const struct bContext *C, struct PaintStroke *stroke);
-struct PaintStroke *paint_stroke_new(struct bContext *C,
+struct PaintStroke *paint_stroke_new(struct bContext *C, struct wmOperator *op,
StrokeGetLocation get_location, StrokeTestStart test_start,
StrokeUpdateStep update_step, StrokeRedraw redraw,
StrokeDone done, int event_type);
@@ -82,8 +84,10 @@ struct wmKeyMap *paint_stroke_modal_keymap(struct wmKeyConfig *keyconf);
int paint_stroke_modal(struct bContext *C, struct wmOperator *op, const struct wmEvent *event);
int paint_stroke_exec(struct bContext *C, struct wmOperator *op);
void paint_stroke_cancel(struct bContext *C, struct wmOperator *op);
+bool paint_stroke_flipped(struct PaintStroke *stroke);
struct ViewContext *paint_stroke_view_context(struct PaintStroke *stroke);
void *paint_stroke_mode_data(struct PaintStroke *stroke);
+float paint_stroke_distance_get(struct PaintStroke *stroke);
void paint_stroke_set_mode_data(struct PaintStroke *stroke, void *mode_data);
int paint_poll(struct bContext *C);
void paint_cursor_start(struct bContext *C, int (*poll)(struct bContext *C));
@@ -117,7 +121,7 @@ void PAINT_OT_weight_gradient(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_vertex_paint(struct wmOperatorType *ot);
-unsigned int vpaint_get_current_col(struct VPaint *vp);
+unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp);
/* paint_vertex_proj.c */
@@ -144,32 +148,41 @@ typedef struct ImagePaintPartialRedraw {
#define IMAPAINT_TILE_NUMBER(size) (((size) + IMAPAINT_TILE_SIZE - 1) >> IMAPAINT_TILE_BITS)
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);
-void *image_undo_push_tile(struct Image *ima, struct ImBuf *ibuf, struct ImBuf **tmpibuf, int x_tile, int y_tile);
+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_remove_masks(void);
+void image_undo_init_locks(void);
+void image_undo_end_locks(void);
+
void imapaint_image_update(struct SpaceImage *sima, struct Image *image, struct ImBuf *ibuf, short texpaint);
struct ImagePaintPartialRedraw *get_imapaintpartial(void);
void set_imapaintpartial(struct ImagePaintPartialRedraw *ippr);
void imapaint_region_tiles(struct ImBuf *ibuf, int x, int y, int w, int h, int *tx, int *ty, int *tw, int *th);
int get_imapaint_zoom(struct bContext *C, float *zoomx, float *zoomy);
-void *paint_2d_new_stroke(struct bContext *, struct wmOperator *);
+void *paint_2d_new_stroke(struct bContext *, struct wmOperator *, int mode);
void paint_2d_redraw(const bContext *C, void *ps, bool final);
void paint_2d_stroke_done(void *ps);
-void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], int eraser);
+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_proj_new_stroke(struct bContext *C, struct Object *ob, const float mouse[2], int mode);
-void paint_proj_stroke(struct bContext *C, void *ps, const float prevmval_i[2], const float mval_i[2]);
-void paint_proj_redraw(const bContext *C, void *pps, bool final);
+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);
void paint_proj_stroke_done(void *ps);
+
+void paint_brush_color_get(struct Scene *scene, struct Brush *br, bool color_correction, bool invert, float distance, float pressure, float color[3], struct ColorManagedDisplay *display);
+bool paint_use_opacity_masking(struct Brush *brush);
void paint_brush_init_tex(struct Brush *brush);
void paint_brush_exit_tex(struct Brush *brush);
void PAINT_OT_grab_clone(struct wmOperatorType *ot);
void PAINT_OT_sample_color(struct wmOperatorType *ot);
+void PAINT_OT_brush_colors_flip(struct wmOperatorType *ot);
void PAINT_OT_texture_paint_toggle(struct wmOperatorType *ot);
void PAINT_OT_project_image(struct wmOperatorType *ot);
void PAINT_OT_image_from_view(struct wmOperatorType *ot);
-
-/* new texture painting */
+void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot);
+void PAINT_OT_delete_texture_paint_slot(struct wmOperatorType *ot);
void PAINT_OT_image_paint(struct wmOperatorType *ot);
/* uv sculpting */
@@ -202,7 +215,10 @@ float paint_calc_object_space_radius(struct ViewContext *vc, const float center[
float paint_get_tex_pixel(struct MTex *mtex, float u, float v, struct ImagePool *pool, int thread);
void paint_get_tex_pixel_col(struct MTex *mtex, float u, float v, float rgba[4], struct ImagePool *pool, int thread, bool convert, struct ColorSpace *colorspace);
-void paint_sample_color(const struct bContext *C, struct ARegion *ar, int x, int y);
+void paint_sample_color(bContext *C, struct ARegion *ar, int x, int y, bool texpaint_proj, bool palette);
+
+void paint_stroke_operator_properties(struct wmOperatorType *ot);
+
void BRUSH_OT_curve_preset(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked(struct wmOperatorType *ot);
@@ -213,8 +229,10 @@ void PAINT_OT_face_select_reveal(struct wmOperatorType *ot);
void PAINT_OT_vert_select_all(struct wmOperatorType *ot);
void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot);
+
int vert_paint_poll(struct bContext *C);
int mask_paint_poll(struct bContext *C);
+int paint_curve_poll(struct bContext *C);
int facemask_paint_poll(struct bContext *C);
void flip_v3_v3(float out[3], const float in[3], const char symm);
@@ -250,10 +268,36 @@ void PAINT_OT_hide_show(struct wmOperatorType *ot);
typedef enum {
PAINT_MASK_FLOOD_VALUE,
+ PAINT_MASK_FLOOD_VALUE_INVERSE,
PAINT_MASK_INVERT
} PaintMaskFloodMode;
void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot);
void PAINT_OT_mask_lasso_gesture(struct wmOperatorType *ot);
+/* paint_curve.c */
+void PAINTCURVE_OT_new(struct wmOperatorType *ot);
+void PAINTCURVE_OT_add_point(struct wmOperatorType *ot);
+void PAINTCURVE_OT_delete_point(struct wmOperatorType *ot);
+void PAINTCURVE_OT_select(struct wmOperatorType *ot);
+void PAINTCURVE_OT_slide(struct wmOperatorType *ot);
+void PAINTCURVE_OT_draw(struct wmOperatorType *ot);
+void PAINTCURVE_OT_cursor(struct wmOperatorType *ot);
+
+/* image painting blur kernel */
+typedef struct {
+ float *wdata; /* actual kernel */
+ int side; /* kernel side */
+ int side_squared; /* data side */
+ int pixel_len; /* pixels around center that kernel is wide */
+} BlurKernel;
+
+enum BlurKernelType;
+/* can be extended to other blur kernels later */
+BlurKernel *paint_new_blur_kernel(struct Brush *br, bool proj);
+void paint_delete_blur_kernel(BlurKernel *);
+
+/* paint curve defines */
+#define PAINT_CURVE_NUM_SEGMENTS 40
+
#endif /* __PAINT_INTERN_H__ */
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 49b62140fe6..25f22996050 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -67,6 +67,13 @@
#include <stdlib.h>
+static EnumPropertyItem mode_items[] = {
+ {PAINT_MASK_FLOOD_VALUE, "VALUE", 0, "Value", "Set mask to the level specified by the 'value' property"},
+ {PAINT_MASK_FLOOD_VALUE_INVERSE, "VALUE_INVERSE", 0, "Value Inverted", "Set mask to the level specified by the inverted 'value' property"},
+ {PAINT_MASK_INVERT, "INVERT", 0, "Invert", "Invert the mask"},
+ {0}};
+
+
static void mask_flood_fill_set_elem(float *elem,
PaintMaskFloodMode mode,
float value)
@@ -75,6 +82,9 @@ static void mask_flood_fill_set_elem(float *elem,
case PAINT_MASK_FLOOD_VALUE:
(*elem) = value;
break;
+ case PAINT_MASK_FLOOD_VALUE_INVERSE:
+ (*elem) = 1.0f - value;
+ break;
case PAINT_MASK_INVERT:
(*elem) = 1.0f - (*elem);
break;
@@ -86,32 +96,26 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
struct Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
- struct MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
PaintMaskFloodMode mode;
float value;
- DerivedMesh *dm;
PBVH *pbvh;
PBVHNode **nodes;
int totnode, i;
+ bool multires;
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
mode = RNA_enum_get(op->ptr, "mode");
value = RNA_float_get(op->ptr, "value");
- BKE_sculpt_mask_layers_ensure(ob, mmd);
-
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- pbvh = dm->getPBVH(ob, dm);
- ob->sculpt->pbvh = pbvh;
-
- ob->sculpt->show_diffuse_color = sd->flags & SCULPT_SHOW_DIFFUSE;
- pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ BKE_sculpt_update_mesh_elements(scene, sd, ob, false, true);
+ pbvh = ob->sculpt->pbvh;
+ multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
sculpt_undo_push_begin("Mask flood fill");
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (i = 0; i < totnode; i++) {
PBVHVertexIter vi;
@@ -122,10 +126,13 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
} BKE_pbvh_vertex_iter_end;
BKE_pbvh_node_mark_redraw(nodes[i]);
- if (BKE_pbvh_type(pbvh) == PBVH_GRIDS)
- multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+ if (multires)
+ BKE_pbvh_node_mark_normals_update(nodes[i]);
}
-
+
+ if (multires)
+ multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+
sculpt_undo_push_end();
if (nodes)
@@ -133,16 +140,13 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op)
ED_region_tag_redraw(ar);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
return OPERATOR_FINISHED;
}
void PAINT_OT_mask_flood_fill(struct wmOperatorType *ot)
{
- static EnumPropertyItem mode_items[] = {
- {PAINT_MASK_FLOOD_VALUE, "VALUE", 0, "Value", "Set mask to the level specified by the 'value' property"},
- {PAINT_MASK_INVERT, "INVERT", 0, "Invert", "Invert the mask"},
- {0}};
-
/* identifiers */
ot->name = "Mask Flood Fill";
ot->idname = "PAINT_OT_mask_flood_fill";
@@ -185,7 +189,7 @@ static void flip_plane(float out[4], const float in[4], const char symm)
out[3] = in[3];
}
-int do_sculpt_mask_box_select(ViewContext *vc, rcti *rect, bool select, bool UNUSED(extend))
+int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select, bool UNUSED(extend))
{
Sculpt *sd = vc->scene->toolsettings->sculpt;
BoundBox bb;
@@ -195,10 +199,9 @@ int do_sculpt_mask_box_select(ViewContext *vc, rcti *rect, bool select, bool UNU
ARegion *ar = vc->ar;
struct Scene *scene = vc->scene;
Object *ob = vc->obact;
- struct MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
PaintMaskFloodMode mode;
float value;
- DerivedMesh *dm;
+ bool multires;
PBVH *pbvh;
PBVHNode **nodes;
int totnode, i, symmpass;
@@ -210,16 +213,11 @@ int do_sculpt_mask_box_select(ViewContext *vc, rcti *rect, bool select, bool UNU
/* transform the clip planes in object space */
view3d_get_transformation(vc->ar, vc->rv3d, vc->obact, &mats);
ED_view3d_clipping_calc(&bb, clip_planes, &mats, rect);
- mul_m4_fl(clip_planes, -1.0f);
-
- BKE_sculpt_mask_layers_ensure(ob, mmd);
+ negate_m4(clip_planes);
- dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
- pbvh = dm->getPBVH(ob, dm);
- ob->sculpt->pbvh = pbvh;
-
- ob->sculpt->show_diffuse_color = sd->flags & SCULPT_SHOW_DIFFUSE;
- pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ BKE_sculpt_update_mesh_elements(scene, sd, ob, false, true);
+ pbvh = ob->sculpt->pbvh;
+ multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
sculpt_undo_push_begin("Mask box fill");
@@ -238,7 +236,7 @@ int do_sculpt_mask_box_select(ViewContext *vc, rcti *rect, bool select, bool UNU
BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (i = 0; i < totnode; i++) {
PBVHVertexIter vi;
bool any_masked = false;
@@ -251,8 +249,8 @@ int do_sculpt_mask_box_select(ViewContext *vc, rcti *rect, bool select, bool UNU
sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
BKE_pbvh_node_mark_redraw(nodes[i]);
- if (BKE_pbvh_type(pbvh) == PBVH_GRIDS)
- multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+ if (multires)
+ BKE_pbvh_node_mark_normals_update(nodes[i]);
}
mask_flood_fill_set_elem(vi.mask, mode, value);
}
@@ -264,17 +262,22 @@ int do_sculpt_mask_box_select(ViewContext *vc, rcti *rect, bool select, bool UNU
}
}
+ if (multires)
+ multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+
sculpt_undo_push_end();
ED_region_tag_redraw(ar);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
return OPERATOR_FINISHED;
}
typedef struct LassoMaskData {
struct ViewContext *vc;
float projviewobjmat[4][4];
- bool *px;
+ BLI_bitmap *px;
int width;
rcti rect; /* bounding box for scanfilling */
int symmpass;
@@ -304,19 +307,19 @@ static bool is_effected_lasso(LassoMaskData *data, float co[3])
scr_co_s[0] -= data->rect.xmin;
scr_co_s[1] -= data->rect.ymin;
- return data->px[scr_co_s[1] * data->width + scr_co_s[0]];
+ return BLI_BITMAP_TEST_BOOL(data->px, scr_co_s[1] * data->width + scr_co_s[0]);
}
static void mask_lasso_px_cb(int x, int y, void *user_data)
{
struct LassoMaskData *data = user_data;
- data->px[(y * data->width) + x] = true;
+ BLI_BITMAP_ENABLE(data->px, (y * data->width) + x);
}
static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
{
int mcords_tot;
- int (*mcords)[2] = (int (*)[2])WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
+ const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
float clip_planes[4][4], clip_planes_final[4][4];
@@ -325,16 +328,15 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
Object *ob;
ViewContext vc;
LassoMaskData data;
+ struct Scene *scene = CTX_data_scene(C);
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
int symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
- struct MultiresModifierData *mmd;
- DerivedMesh *dm;
PBVH *pbvh;
PBVHNode **nodes;
int totnode, i, symmpass;
- PaintMaskFloodMode mode = PAINT_MASK_FLOOD_VALUE;
- bool select = true; /* TODO: see how to implement deselection */
- float value = select ? 1.0 : 0.0;
+ bool multires;
+ PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode");
+ float value = RNA_float_get(op->ptr, "value");
/* Calculations of individual vertices are done in 2D screen space to diminish the amount of
* calculations done. Bounding box PBVH collision is not computed against enclosing rectangle
@@ -347,26 +349,21 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
ob = vc.obact;
ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat);
- BLI_lasso_boundbox(&data.rect, (const int (*)[2])mcords, mcords_tot);
+ BLI_lasso_boundbox(&data.rect, mcords, mcords_tot);
data.width = data.rect.xmax - data.rect.xmin;
- data.px = MEM_callocN(sizeof(*data.px) * data.width * (data.rect.ymax - data.rect.ymin), "lasso_mask_pixel_buffer");
+ data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__);
fill_poly_v2i_n(
data.rect.xmin, data.rect.ymin, data.rect.xmax, data.rect.ymax,
- (const int (*)[2])mcords, mcords_tot,
+ mcords, mcords_tot,
mask_lasso_px_cb, &data);
ED_view3d_clipping_calc(&bb, clip_planes, &mats, &data.rect);
- mul_m4_fl(clip_planes, -1.0f);
+ negate_m4(clip_planes);
- mmd = BKE_sculpt_multires_active(vc.scene, ob);
- BKE_sculpt_mask_layers_ensure(ob, mmd);
- dm = mesh_get_derived_final(vc.scene, ob, CD_MASK_BAREMESH);
- pbvh = dm->getPBVH(ob, dm);
- ob->sculpt->pbvh = pbvh;
-
- ob->sculpt->show_diffuse_color = sd->flags & SCULPT_SHOW_DIFFUSE;
- pbvh_show_diffuse_color_set(pbvh, ob->sculpt->show_diffuse_color);
+ BKE_sculpt_update_mesh_elements(scene, sd, ob, false, true);
+ pbvh = ob->sculpt->pbvh;
+ multires = (BKE_pbvh_type(pbvh) == PBVH_GRIDS);
sculpt_undo_push_begin("Mask lasso fill");
@@ -388,7 +385,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
/* gather nodes inside lasso's enclosing rectangle (should greatly help with bigger meshes) */
BKE_pbvh_search_gather(pbvh, BKE_pbvh_node_planes_contain_AABB, clip_planes_final, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (i = 0; i < totnode; i++) {
PBVHVertexIter vi;
bool any_masked = false;
@@ -401,8 +398,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
sculpt_undo_push_node(ob, nodes[i], SCULPT_UNDO_MASK);
BKE_pbvh_node_mark_redraw(nodes[i]);
- if (BKE_pbvh_type(pbvh) == PBVH_GRIDS)
- multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+ if (multires)
+ BKE_pbvh_node_mark_normals_update(nodes[i]);
}
mask_flood_fill_set_elem(vi.mask, mode, value);
@@ -415,12 +412,17 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op)
}
}
+ if (multires)
+ multires_mark_as_modified(ob, MULTIRES_COORDS_MODIFIED);
+
sculpt_undo_push_end();
ED_region_tag_redraw(vc.ar);
MEM_freeN((void *)mcords);
MEM_freeN(data.px);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
return OPERATOR_FINISHED;
}
return OPERATOR_PASS_THROUGH;
@@ -444,4 +446,8 @@ void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot)
prop = RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
+
+ RNA_def_enum(ot->srna, "mode", mode_items, PAINT_MASK_FLOOD_VALUE, "Mode", NULL);
+ RNA_def_float(ot->srna, "value", 1.0, 0, 1.0, "Value",
+ "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0, 1);
}
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index 543463cd5f3..dc6be9caa53 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -40,7 +40,7 @@
#include "BKE_paint.h"
#include "BKE_main.h"
-#include "ED_sculpt.h"
+#include "ED_paint.h"
#include "ED_screen.h"
#include "ED_image.h"
#include "UI_resources.h"
@@ -149,11 +149,113 @@ static void BRUSH_OT_scale_size(wmOperatorType *ot)
RNA_def_float(ot->srna, "scalar", 1, 0, 2, "Scalar", "Factor to scale brush size by", 0, 2);
}
+/* Palette operators */
+
+static int palette_new_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Main *bmain = CTX_data_main(C);
+ Palette *palette;
+
+ palette = BKE_palette_add(bmain, "Palette");
+
+ BKE_paint_palette_set(paint, palette);
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_new(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add New Palette";
+ ot->description = "Add new palette";
+ ot->idname = "PALETTE_OT_new";
+
+ /* api callbacks */
+ ot->exec = palette_new_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int palette_poll(bContext *C)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+
+ if (paint && paint->palette != NULL)
+ return true;
+
+ return false;
+}
+
+static int palette_color_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Brush *brush = paint->brush;
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ Palette *palette = paint->palette;
+ PaletteColor *color = BKE_palette_color_add(palette);
+
+ if (ELEM(mode, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D, PAINT_VERTEX)) {
+ copy_v3_v3(color->rgb, BKE_brush_color_get(scene, brush));
+ color->value = 0.0;
+ }
+ else if (mode == PAINT_WEIGHT) {
+ zero_v3(color->rgb);
+ color->value = brush->weight;
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_color_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "New Palette Color";
+ ot->description = "Add new color to active palette";
+ ot->idname = "PALETTE_OT_color_add";
+
+ /* api callbacks */
+ ot->exec = palette_color_add_exec;
+ ot->poll = palette_poll;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+static int palette_color_delete_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = paint->palette;
+ PaletteColor *color = BLI_findlink(&palette->colors, palette->active_color);
+
+ BKE_palette_color_remove(palette, color);
+
+ return OPERATOR_FINISHED;
+}
+
+static void PALETTE_OT_color_delete(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Delete Palette Color";
+ ot->description = "Remove active color from palette";
+ ot->idname = "PALETTE_OT_color_delete";
+
+ /* api callbacks */
+ ot->exec = palette_color_delete_exec;
+ ot->poll = palette_poll;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+
+
static int vertex_color_set_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Object *obact = CTX_data_active_object(C);
- unsigned int paintcol = vpaint_get_current_col(scene->toolsettings->vpaint);
+ unsigned int paintcol = vpaint_get_current_col(scene, scene->toolsettings->vpaint);
if (ED_vpaint_fill(obact, paintcol)) {
ED_region_tag_redraw(CTX_wm_region(C)); // XXX - should redraw all 3D views
@@ -332,6 +434,7 @@ static int brush_generic_tool_set(Main *bmain, Paint *paint, const int tool,
if (brush) {
BKE_paint_brush_set(paint, brush);
BKE_paint_invalidate_overlay_all();
+
WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
return OPERATOR_FINISHED;
}
@@ -564,7 +667,7 @@ static void stencil_set_target(StencilControlData *scd)
scd->lenorig = len_v2(mdiff);
- scd->init_angle = atan2(mdiff[1], mdiff[0]);
+ scd->init_angle = atan2f(mdiff[1], mdiff[0]);
}
static int stencil_control_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -660,7 +763,7 @@ static void stencil_control_calculate(StencilControlData *scd, const int mval[2]
{
float angle;
sub_v2_v2v2(mdiff, mvalf, scd->pos_target);
- angle = atan2(mdiff[1], mdiff[0]);
+ angle = atan2f(mdiff[1], mdiff[0]);
angle = scd->init_rot + angle - scd->init_angle;
if (angle < 0.0f)
angle += (float)(2 * M_PI);
@@ -813,7 +916,7 @@ static int stencil_fit_image_aspect_exec(bContext *C, wmOperator *op)
stencil_area = br->stencil_dimension[0] * br->stencil_dimension[1];
}
- factor = sqrt(stencil_area / orig_area);
+ factor = sqrtf(stencil_area / orig_area);
if (do_mask) {
br->mask_stencil_dimension[0] = factor * aspx;
@@ -928,8 +1031,37 @@ static void ed_keymap_stencil(wmKeyMap *keymap)
/**************************** registration **********************************/
+void ED_operatormacros_paint(void)
+{
+ wmOperatorType *ot;
+ wmOperatorTypeMacro *otmacro;
+
+ ot = WM_operatortype_append_macro("PAINTCURVE_OT_add_point_slide", "Add Curve Point and Slide",
+ "Add new curve point and slide it", OPTYPE_UNDO);
+ ot->description = "Add new curve point and slide it";
+ WM_operatortype_macro_define(ot, "PAINTCURVE_OT_add_point");
+ otmacro = WM_operatortype_macro_define(ot, "PAINTCURVE_OT_slide");
+ RNA_boolean_set(otmacro->ptr, "align", true);
+ RNA_boolean_set(otmacro->ptr, "select", false);
+}
+
+
void ED_operatortypes_paint(void)
{
+ /* palette */
+ WM_operatortype_append(PALETTE_OT_new);
+ WM_operatortype_append(PALETTE_OT_color_add);
+ WM_operatortype_append(PALETTE_OT_color_delete);
+
+ /* paint curve */
+ WM_operatortype_append(PAINTCURVE_OT_new);
+ WM_operatortype_append(PAINTCURVE_OT_add_point);
+ WM_operatortype_append(PAINTCURVE_OT_delete_point);
+ WM_operatortype_append(PAINTCURVE_OT_select);
+ WM_operatortype_append(PAINTCURVE_OT_slide);
+ WM_operatortype_append(PAINTCURVE_OT_draw);
+ WM_operatortype_append(PAINTCURVE_OT_cursor);
+
/* brush */
WM_operatortype_append(BRUSH_OT_add);
WM_operatortype_append(BRUSH_OT_scale_size);
@@ -950,6 +1082,9 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_grab_clone);
WM_operatortype_append(PAINT_OT_project_image);
WM_operatortype_append(PAINT_OT_image_from_view);
+ WM_operatortype_append(PAINT_OT_brush_colors_flip);
+ WM_operatortype_append(PAINT_OT_add_texture_paint_slot);
+ WM_operatortype_append(PAINT_OT_delete_texture_paint_slot);
/* weight */
WM_operatortype_append(PAINT_OT_weight_paint_toggle);
@@ -1119,12 +1254,44 @@ static void paint_partial_visibility_keys(wmKeyMap *keymap)
RNA_enum_set(kmi->ptr, "area", PARTIALVIS_ALL);
}
+
+static void paint_keymap_curve(wmKeyMap *keymap)
+{
+ wmKeyMapItem *kmi;
+
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_add_point_slide", ACTIONMOUSE, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "extend", true);
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_slide", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "align", true);
+ kmi = WM_keymap_add_item(keymap, "PAINTCURVE_OT_select", AKEY, KM_PRESS, 0, 0);
+ RNA_boolean_set(kmi->ptr, "toggle", true);
+
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_cursor", ACTIONMOUSE, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_delete_point", XKEY, KM_PRESS, 0, 0);
+
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", RETKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "PAINTCURVE_OT_draw", PADENTER, KM_PRESS, 0, 0);
+
+ WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", GKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "TRANSFORM_OT_translate", EVT_TWEAK_S, KM_ANY, 0, 0);
+ WM_keymap_add_item(keymap, "TRANSFORM_OT_rotate", RKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "TRANSFORM_OT_resize", SKEY, KM_PRESS, 0, 0);
+}
+
void ED_keymap_paint(wmKeyConfig *keyconf)
{
wmKeyMap *keymap;
wmKeyMapItem *kmi;
int i;
+ keymap = WM_keymap_find(keyconf, "Paint Curve", 0, 0);
+ keymap->poll = paint_curve_poll;
+
+ paint_keymap_curve(keymap);
+
/* Sculpt mode */
keymap = WM_keymap_find(keyconf, "Sculpt", 0, 0);
keymap->poll = sculpt_mode_poll;
@@ -1191,7 +1358,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "create_missing", 1);
/* */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.sculpt.brush.stroke_method");
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", SKEY, KM_PRESS, KM_SHIFT, 0);
@@ -1225,7 +1392,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.texture_angle_source_random");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method");
/* Weight Paint mode */
@@ -1250,7 +1417,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
ed_keymap_stencil(keymap);
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.vertex_paint.brush.stroke_method");
kmi = WM_keymap_add_item(keymap, "WM_OT_context_toggle", MKEY, KM_PRESS, 0, 0); /* face mask toggle */
@@ -1283,6 +1450,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "mode", BRUSH_STROKE_NORMAL);
RNA_enum_set(WM_keymap_add_item(keymap, "PAINT_OT_image_paint", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "mode", BRUSH_STROKE_INVERT);
+ WM_keymap_add_item(keymap, "PAINT_OT_brush_colors_flip", XKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_grab_clone", RIGHTMOUSE, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "PAINT_OT_sample_color", SKEY, KM_PRESS, 0, 0);
@@ -1301,7 +1469,7 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", RKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.texture_angle_source_random");
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", AKEY, KM_PRESS, 0, 0);
+ kmi = WM_keymap_add_item(keymap, "WM_OT_context_menu_enum", EKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "tool_settings.image_paint.brush.stroke_method");
/* face-mask mode */
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index 7b9121446f5..9c4701d0a01 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -36,16 +36,19 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
#include "BLI_rand.h"
+#include "BLI_listbase.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
+#include "DNA_curve_types.h"
#include "RNA_access.h"
#include "BKE_context.h"
#include "BKE_paint.h"
#include "BKE_brush.h"
+#include "BKE_curve.h"
#include "BKE_colortools.h"
#include "BKE_image.h"
@@ -65,6 +68,12 @@
#include <float.h>
#include <math.h>
+// #define DEBUG_TIME
+
+#ifdef DEBUG_TIME
+# include "PIL_time_utildefines.h"
+#endif
+
typedef struct PaintSample {
float mouse[2];
float pressure;
@@ -72,7 +81,7 @@ typedef struct PaintSample {
typedef struct PaintStroke {
void *mode_data;
- void *smooth_stroke_cursor;
+ void *stroke_cursor;
wmTimer *timer;
/* Cached values */
@@ -81,6 +90,9 @@ typedef struct PaintStroke {
Brush *brush;
UnifiedPaintSettings *ups;
+ /* used for lines and curves */
+ ListBase line;
+
/* Paint stroke can use up to PAINT_MAX_INPUT_SAMPLES prior inputs
* to smooth the stroke */
PaintSample samples[PAINT_MAX_INPUT_SAMPLES];
@@ -88,6 +100,8 @@ typedef struct PaintStroke {
int cur_sample;
float last_mouse_position[2];
+ /* space distance covered so far */
+ float stroke_distance;
/* Set whether any stroke step has yet occurred
* e.g. in sculpt mode, stroke doesn't start until cursor
@@ -104,7 +118,7 @@ typedef struct PaintStroke {
float cached_size_pressure;
/* last pressure will store last pressure value for use in interpolation for space strokes */
float last_pressure;
-
+ int stroke_mode;
float zoom_2d;
int pen_flip;
@@ -116,18 +130,17 @@ typedef struct PaintStroke {
StrokeDone done;
} PaintStroke;
-/*** Cursor ***/
-static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata)
+/*** Cursors ***/
+static void paint_draw_smooth_cursor(bContext *C, int x, int y, void *customdata)
{
Paint *paint = BKE_paint_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
PaintStroke *stroke = customdata;
- if (stroke && brush && (brush->flag & BRUSH_SMOOTH_STROKE)) {
- glColor4ubv(paint->paint_cursor_col);
+ if (stroke && brush) {
glEnable(GL_LINE_SMOOTH);
glEnable(GL_BLEND);
-
+ glColor4ubv(paint->paint_cursor_col);
sdrawline(x, y, (int)stroke->last_mouse_position[0],
(int)stroke->last_mouse_position[1]);
glDisable(GL_BLEND);
@@ -135,35 +148,65 @@ static void paint_draw_smooth_stroke(bContext *C, int x, int y, void *customdata
}
}
-/* if this is a tablet event, return tablet pressure and set *pen_flip
- * to 1 if the eraser tool is being used, 0 otherwise */
-static float event_tablet_data(const wmEvent *event, int *pen_flip)
+static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
{
- int erasor = 0;
- float pressure = 1;
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintStroke *stroke = customdata;
- if (event->tablet_data) {
- wmTabletData *wmtab = event->tablet_data;
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
- erasor = (wmtab->Active == EVT_TABLET_ERASER);
- pressure = (wmtab->Active != EVT_TABLET_NONE) ? wmtab->Pressure : 1;
- }
+ glEnable(GL_LINE_STIPPLE);
+ glLineStipple(3, 0xAAAA);
+
+ glColor4ub(0, 0, 0, paint->paint_cursor_col[3]);
+ glLineWidth(3.0);
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ x, y);
- if (pen_flip)
- (*pen_flip) = erasor;
+ glColor4ub(255, 255, 255, paint->paint_cursor_col[3]);
+ glLineWidth(1.0);
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ x, y);
- return pressure;
+ glDisable(GL_LINE_STIPPLE);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
}
+static bool paint_tool_require_location(Brush *brush, PaintMode mode)
+{
+ switch (mode) {
+ case PAINT_SCULPT:
+ if (ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB))
+ {
+ return false;
+ }
+ else {
+ return true;
+ }
+ default:
+ break;
+ }
+
+ return true;
+}
/* Initialize the stroke cache variants from operator properties */
-static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
- struct PaintStroke *stroke,
- const float mouse[2], float pressure)
+static bool paint_brush_update(bContext *C,
+ Brush *brush,
+ PaintMode mode,
+ struct PaintStroke *stroke,
+ const float mouse_init[2],
+ float mouse[2], float pressure,
+ float location[3])
{
Scene *scene = CTX_data_scene(C);
- UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
-
+ UnifiedPaintSettings *ups = stroke->ups;
+ bool location_sampled = false;
+ bool location_success = false;
/* XXX: Use pressure value from first brush step for brushes which don't
* support strokes (grab, thumb). They depends on initial state and
* brush coord/pressure/etc.
@@ -176,6 +219,9 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
copy_v2_v2(ups->mask_tex_mouse, mouse);
stroke->cached_size_pressure = pressure;
+ ups->do_linear_conversion = false;
+ ups->colorspace = NULL;
+
/* check here if color sampling the main brush should do color conversion. This is done here
* to avoid locking up to get the image buffer during sampling */
if (brush->mtex.tex && brush->mtex.tex->type == TEX_IMAGE && brush->mtex.tex->ima) {
@@ -224,14 +270,14 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
else {
copy_v2_v2(ups->tex_mouse, mouse);
}
- }
- /* take care of mask texture, if any */
- if (brush->mask_mtex.tex) {
- if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
- BKE_brush_randomize_texture_coordinates(ups, true);
- else {
- copy_v2_v2(ups->mask_tex_mouse, mouse);
+ /* take care of mask texture, if any */
+ if (brush->mask_mtex.tex) {
+ if (brush->mask_mtex.brush_map_mode == MTEX_MAP_MODE_RANDOM)
+ BKE_brush_randomize_texture_coordinates(ups, true);
+ else {
+ copy_v2_v2(ups->mask_tex_mouse, mouse);
+ }
}
}
@@ -243,18 +289,21 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
const float dx = mouse[0] - stroke->initial_mouse[0];
const float dy = mouse[1] - stroke->initial_mouse[1];
- ups->anchored_size = ups->pixel_radius = sqrt(dx * dx + dy * dy);
+ ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy);
- ups->brush_rotation = atan2(dx, dy) + M_PI;
+ ups->brush_rotation = atan2f(dx, dy) + M_PI;
if (brush->flag & BRUSH_EDGE_TO_EDGE) {
- float out[3];
-
halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
halfway[1] = dy * 0.5f + stroke->initial_mouse[1];
if (stroke->get_location) {
- if (stroke->get_location(C, out, halfway)) {
+ if (stroke->get_location(C, location, halfway)) {
+ hit = true;
+ location_sampled = true;
+ location_success = true;
+ }
+ else if (!paint_tool_require_location(brush, mode)) {
hit = true;
}
}
@@ -265,30 +314,69 @@ static void paint_brush_update(bContext *C, Brush *brush, PaintMode mode,
if (hit) {
copy_v2_v2(ups->anchored_initial_mouse, halfway);
copy_v2_v2(ups->tex_mouse, halfway);
+ copy_v2_v2(ups->mask_tex_mouse, halfway);
+ copy_v2_v2(mouse, halfway);
ups->anchored_size /= 2.0f;
ups->pixel_radius /= 2.0f;
+ stroke->stroke_distance = ups->pixel_radius;
}
- else
+ else {
copy_v2_v2(ups->anchored_initial_mouse, stroke->initial_mouse);
-
+ copy_v2_v2(mouse, stroke->initial_mouse);
+ stroke->stroke_distance = ups->pixel_radius;
+ }
+ ups->pixel_radius /= stroke->zoom_2d;
ups->draw_anchored = true;
}
else if (brush->flag & BRUSH_RAKE) {
- paint_calculate_rake_rotation(ups, mouse);
+ /* here we are using the initial mouse coordinate because we do not want the rake
+ * result to depend on jittering */
+ if (!stroke->brush_init)
+ copy_v2_v2(ups->last_rake, mouse_init);
+ else
+ paint_calculate_rake_rotation(ups, mouse_init);
+ }
+
+ if (!location_sampled) {
+ if (stroke->get_location) {
+ if (stroke->get_location(C, location, mouse))
+ location_success = true;
+ else if (!paint_tool_require_location(brush, mode))
+ location_success = true;
+ }
+ else {
+ zero_v3(location);
+ location_success = true;
+ }
}
+
+ return location_success;
}
+static bool paint_stroke_use_jitter(PaintMode mode, Brush *brush, bool invert)
+{
+ bool use_jitter = (brush->flag & BRUSH_ABSOLUTE_JITTER) ?
+ (brush->jitter_absolute != 0) : (brush->jitter != 0);
+
+ /* jitter-ed brush gives weird and unpredictable result for this
+ * kinds of stroke, so manually disable jitter usage (sergey) */
+ use_jitter &= (brush->flag & (BRUSH_DRAG_DOT | BRUSH_ANCHORED)) == 0;
+ use_jitter &= (!ELEM(mode, PAINT_TEXTURE_2D, PAINT_TEXTURE_PROJECTIVE) ||
+ !(invert && brush->imagepaint_tool == PAINT_TOOL_CLONE));
+
+
+ return use_jitter;
+}
/* Put the location of the next stroke dot into the stroke RNA and apply it to the mesh */
static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float mouse_in[2], float pressure)
{
Scene *scene = CTX_data_scene(C);
- wmWindow *window = CTX_wm_window(C);
- ARegion *ar = CTX_wm_region(C);
Paint *paint = BKE_paint_get_active_from_context(C);
PaintMode mode = BKE_paintmode_get_active_from_context(C);
Brush *brush = BKE_paint_brush(paint);
PaintStroke *stroke = op->customdata;
+ UnifiedPaintSettings *ups = stroke->ups;
float mouse_out[2];
PointerRNA itemptr;
float location[3];
@@ -314,9 +402,7 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
copy_v2_v2(stroke->last_mouse_position, mouse_in);
stroke->last_pressure = pressure;
- paint_brush_update(C, brush, mode, stroke, mouse_in, pressure);
-
- {
+ if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) {
float delta[2];
float factor = stroke->zoom_2d;
@@ -334,16 +420,17 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
add_v2_v2v2(mouse_out, mouse_in, delta);
}
}
+ else {
+ copy_v2_v2(mouse_out, mouse_in);
+ }
- /* TODO: can remove the if statement once all modes have this */
- if (stroke->get_location)
- stroke->get_location(C, location, mouse_out);
- else
- zero_v3(location);
+ if (!paint_brush_update(C, brush, mode, stroke, mouse_in, mouse_out, pressure, location)) {
+ return;
+ }
/* Add to stroke */
RNA_collection_add(op->ptr, "stroke", &itemptr);
-
+ RNA_float_set(&itemptr, "size", ups->pixel_radius);
RNA_float_set_array(&itemptr, "location", location);
RNA_float_set_array(&itemptr, "mouse", mouse_out);
RNA_boolean_set(&itemptr, "pen_flip", stroke->pen_flip);
@@ -354,20 +441,12 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float
/* don't record this for now, it takes up a lot of memory when doing long
* strokes with small brush size, and operators have register disabled */
RNA_collection_clear(op->ptr, "stroke");
-
- /* always redraw region if brush is shown */
- if (ar && (paint->flags & PAINT_SHOW_BRUSH))
- WM_paint_cursor_tag_redraw(window, ar);
}
/* Returns zero if no sculpt changes should be made, non-zero otherwise */
static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outpressure,
const PaintSample *sample, PaintMode mode)
{
- output[0] = sample->mouse[0];
- output[1] = sample->mouse[1];
- *outpressure = sample->pressure;
-
if (paint_supports_smooth_stroke(stroke->brush, mode)) {
float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d;
float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u;
@@ -383,6 +462,11 @@ static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outp
output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u;
*outpressure = sample->pressure * v + stroke->last_pressure * u;
}
+ else {
+ output[0] = sample->mouse[0];
+ output[1] = sample->mouse[1];
+ *outpressure = sample->pressure;
+ }
return 1;
}
@@ -405,6 +489,55 @@ static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke,
return max_ff(1.0, size_clamp * spacing / 50.0f);
}
+
+
+static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing)
+{
+ int i;
+ const int n = 100 / spacing;
+ const float h = spacing / 50.0f;
+ const float x0 = x - 1;
+
+ float sum;
+
+ sum = 0;
+ for (i = 0; i < n; i++) {
+ float xx;
+
+ xx = fabsf(x0 + i * h);
+
+ if (xx < 1.0f)
+ sum += BKE_brush_curve_strength(br, xx, 1);
+ }
+
+ return sum;
+}
+
+static float paint_stroke_integrate_overlap(Brush *br, float factor)
+{
+ int i;
+ int m;
+ float g;
+ float max;
+
+ float spacing = br->spacing * factor;
+
+ if (!(br->flag & BRUSH_SPACE_ATTEN && (br->spacing < 100)))
+ return 1.0;
+
+ m = 10;
+ g = 1.0f / m;
+ max = 0;
+ for (i = 0; i < m; i++) {
+ float overlap = paint_stroke_overlapped_curve(br, i * g, spacing);
+
+ if (overlap > max)
+ max = overlap;
+ }
+
+ return 1.0f / max;
+}
+
static float paint_space_stroke_spacing_variable(const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length)
{
if (BKE_brush_use_size_pressure(scene, stroke->brush)) {
@@ -436,40 +569,42 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou
{
const Scene *scene = CTX_data_scene(C);
PaintStroke *stroke = op->customdata;
- PaintMode mode = BKE_paintmode_get_active_from_context(C);
+ UnifiedPaintSettings *ups = stroke->ups;
int cnt = 0;
- if (paint_space_stroke_enabled(stroke->brush, mode)) {
- float pressure, dpressure;
- float mouse[2], dmouse[2];
- float length;
+ float pressure, dpressure;
+ float mouse[2], dmouse[2];
+ float length;
+ float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f);
- sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
+ sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position);
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ pressure = stroke->last_pressure;
+ dpressure = final_pressure - stroke->last_pressure;
- length = normalize_v2(dmouse);
+ length = normalize_v2(dmouse);
- while (length > 0.0f) {
- float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length);
-
- if (length >= spacing) {
- mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
- mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
- pressure = stroke->last_pressure + (spacing / length) * dpressure;
+ while (length > 0.0f) {
+ float spacing = paint_space_stroke_spacing_variable(scene, stroke, pressure, dpressure, length);
- paint_brush_stroke_add_step(C, op, mouse, pressure);
+ if (length >= spacing) {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing;
+ pressure = stroke->last_pressure + (spacing / length) * dpressure;
- length -= spacing;
- pressure = stroke->last_pressure;
- dpressure = final_pressure - stroke->last_pressure;
+ ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, spacing / no_pressure_spacing);
- cnt++;
- }
- else {
- break;
- }
+ stroke->stroke_distance += spacing / stroke->zoom_2d;
+ paint_brush_stroke_add_step(C, op, mouse, pressure);
+
+ length -= spacing;
+ pressure = stroke->last_pressure;
+ dpressure = final_pressure - stroke->last_pressure;
+
+ cnt++;
+ }
+ else {
+ break;
}
}
@@ -479,6 +614,7 @@ static int paint_space_stroke(bContext *C, wmOperator *op, const float final_mou
/**** Public API ****/
PaintStroke *paint_stroke_new(bContext *C,
+ wmOperator *op,
StrokeGetLocation get_location,
StrokeTestStart test_start,
StrokeUpdateStep update_step,
@@ -489,6 +625,7 @@ PaintStroke *paint_stroke_new(bContext *C,
ToolSettings *toolsettings = CTX_data_tool_settings(C);
UnifiedPaintSettings *ups = &toolsettings->unified_paint_settings;
Brush *br = stroke->brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
+ float zoomx, zoomy;
view3d_set_viewcontext(C, &stroke->vc);
if (stroke->vc.v3d)
@@ -501,6 +638,19 @@ PaintStroke *paint_stroke_new(bContext *C,
stroke->done = done;
stroke->event_type = event_type; /* for modal, return event */
stroke->ups = ups;
+ stroke->stroke_mode = RNA_enum_get(op->ptr, "mode");
+
+ get_imapaint_zoom(C, &zoomx, &zoomy);
+ stroke->zoom_2d = max_ff(zoomx, zoomy);
+
+ if ((br->flag & BRUSH_CURVE) &&
+ RNA_struct_property_is_set(op->ptr, "mode"))
+ {
+ RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
+ }
+ /* initialize here */
+ ups->overlap_factor = 1.0;
+ ups->stroke_active = true;
/* initialize here to avoid initialization conflict with threaded strokes */
curvemapping_initialize(br->curve);
@@ -513,8 +663,7 @@ PaintStroke *paint_stroke_new(bContext *C,
void paint_stroke_data_free(struct wmOperator *op)
{
BKE_paint_set_overlay_override(0);
- MEM_freeN(op->customdata);
- op->customdata = NULL;
+ MEM_SAFE_FREE(op->customdata);
}
static void stroke_done(struct bContext *C, struct wmOperator *op)
@@ -544,8 +693,10 @@ static void stroke_done(struct bContext *C, struct wmOperator *op)
stroke->timer);
}
- if (stroke->smooth_stroke_cursor)
- WM_paint_cursor_end(CTX_wm_manager(C), stroke->smooth_stroke_cursor);
+ if (stroke->stroke_cursor)
+ WM_paint_cursor_end(CTX_wm_manager(C), stroke->stroke_cursor);
+
+ BLI_freelistN(&stroke->line);
paint_stroke_data_free(op);
}
@@ -558,7 +709,7 @@ bool paint_space_stroke_enabled(Brush *br, PaintMode mode)
static bool sculpt_is_grab_tool(Brush *br)
{
- return ELEM4(br->sculpt_tool,
+ return ELEM(br->sculpt_tool,
SCULPT_TOOL_GRAB,
SCULPT_TOOL_THUMB,
SCULPT_TOOL_ROTATE,
@@ -576,6 +727,16 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode)
if (sculpt_is_grab_tool(br))
return false;
break;
+
+ case PAINT_TEXTURE_2D: /* fall through */
+ case PAINT_TEXTURE_PROJECTIVE:
+ if ((br->imagepaint_tool == PAINT_TOOL_FILL) &&
+ (br->flag & BRUSH_USE_GRADIENT))
+ {
+ return false;
+ }
+ break;
+
default:
break;
}
@@ -585,8 +746,7 @@ bool paint_supports_dynamic_size(Brush *br, PaintMode mode)
bool paint_supports_smooth_stroke(Brush *br, PaintMode mode)
{
if (!(br->flag & BRUSH_SMOOTH_STROKE) ||
- (br->flag & BRUSH_ANCHORED) ||
- (br->flag & BRUSH_DRAG_DOT))
+ (br->flag & (BRUSH_ANCHORED | BRUSH_DRAG_DOT | BRUSH_LINE)))
{
return false;
}
@@ -604,8 +764,8 @@ bool paint_supports_smooth_stroke(Brush *br, PaintMode mode)
bool paint_supports_texture(PaintMode mode)
{
- /* ommit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
- return ELEM4(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D);
+ /* omit: PAINT_WEIGHT, PAINT_SCULPT_UV, PAINT_INVALID */
+ return ELEM(mode, PAINT_SCULPT, PAINT_VERTEX, PAINT_TEXTURE_PROJECTIVE, PAINT_TEXTURE_2D);
}
/* return true if the brush size can change during paint (normally used for pressure) */
@@ -693,28 +853,151 @@ static void paint_stroke_sample_average(const PaintStroke *stroke,
/*printf("avg=(%f, %f), num=%d\n", average->mouse[0], average->mouse[1], stroke->num_samples);*/
}
+/**
+ * Slightly different version of spacing for line/curve strokes,
+ * makes sure the dabs stay on the line path.
+ */
+static void paint_line_strokes_spacing(
+ bContext *C, wmOperator *op, PaintStroke *stroke, float spacing, float *length_residue,
+ const float old_pos[2], const float new_pos[2])
+{
+ UnifiedPaintSettings *ups = stroke->ups;
+
+ float mouse[2], dmouse[2];
+ float length;
+
+ sub_v2_v2v2(dmouse, new_pos, old_pos);
+ copy_v2_v2(stroke->last_mouse_position, old_pos);
+
+ length = normalize_v2(dmouse);
+
+ BLI_assert(length >= 0.0f);
+
+ if (length == 0.0f)
+ return;
+
+ while (length > 0.0f) {
+ float spacing_final = spacing - *length_residue;
+ length += *length_residue;
+ *length_residue = 0.0;
+
+ if (length >= spacing) {
+ mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing_final;
+ mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing_final;
+
+ ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, 1.0);
+
+ stroke->stroke_distance += spacing / stroke->zoom_2d;
+ paint_brush_stroke_add_step(C, op, mouse, 1.0);
+
+ length -= spacing;
+ spacing_final = spacing;
+ }
+ else {
+ break;
+ }
+ }
+
+ *length_residue = length;
+}
+
+
+static void paint_stroke_line_end(bContext *C, wmOperator *op, PaintStroke *stroke, float mouse[2])
+{
+ Brush *br = stroke->brush;
+ if (stroke->stroke_started && (br->flag & BRUSH_LINE)) {
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+
+ paint_brush_stroke_add_step(C, op, stroke->last_mouse_position, 1.0);
+ paint_space_stroke(C, op, mouse, 1.0);
+ }
+}
+
+static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *stroke)
+{
+ Brush *br = stroke->brush;
+
+ if (br->flag & BRUSH_CURVE) {
+ 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;
+ PaintCurvePoint *pcp;
+ float length_residue = 0.0f;
+ int i;
+
+ if (!pc)
+ return true;
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(stroke);
+#endif
+
+ pcp = pc->points;
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+
+ for (i = 0; i < pc->tot_points - 1; i++, pcp++) {
+ int j;
+ float data[(PAINT_CURVE_NUM_SEGMENTS + 1) * 2];
+ PaintCurvePoint *pcp_next = pcp + 1;
+
+ 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]));
+
+
+ for (j = 0; j < PAINT_CURVE_NUM_SEGMENTS; j++) {
+ if (!stroke->stroke_started) {
+ stroke->last_pressure = 1.0;
+ copy_v2_v2(stroke->last_mouse_position, data + 2 * j);
+ stroke->stroke_started = stroke->test_start(C, op, stroke->last_mouse_position);
+
+ if (stroke->stroke_started) {
+ paint_brush_stroke_add_step(C, op, data + 2 * j, 1.0);
+ paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
+ }
+ }
+ else {
+ paint_line_strokes_spacing(C, op, stroke, spacing, &length_residue, data + 2 * j, data + 2 * (j + 1));
+ }
+ }
+ }
+
+ stroke_done(C, op);
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(stroke);
+#endif
+
+ return true;
+ }
+
+ return false;
+}
+
+
int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Paint *p = BKE_paint_get_active_from_context(C);
PaintMode mode = BKE_paintmode_get_active_from_context(C);
PaintStroke *stroke = op->customdata;
+ Brush *br = stroke->brush;
PaintSample sample_average;
float mouse[2];
bool first_dab = false;
bool first_modal = false;
- float zoomx, zoomy;
bool redraw = false;
float pressure;
- /* see if tablet affects event */
- pressure = event_tablet_data(event, &stroke->pen_flip);
+ /* see if tablet affects event. Line, anchored and drag dot strokes do not support pressure */
+ pressure = (br->flag & (BRUSH_LINE | BRUSH_ANCHORED | BRUSH_DRAG_DOT)) ? 1.0f : WM_event_tablet_data(event, &stroke->pen_flip, NULL);
paint_stroke_add_sample(p, stroke, event->mval[0], event->mval[1], pressure);
paint_stroke_sample_average(stroke, &sample_average);
- get_imapaint_zoom(C, &zoomx, &zoomy);
- stroke->zoom_2d = max_ff(zoomx, zoomy);
-
/* let NDOF motion pass through to the 3D view so we can paint and rotate simultaneously!
* this isn't perfect... even when an extra MOUSEMOVE is spoofed, the stroke discards it
* since the 2D deltas are zero -- code in this file needs to be updated to use the
@@ -724,8 +1007,12 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* one time initialization */
if (!stroke->stroke_init) {
- stroke->smooth_stroke_cursor =
- WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_stroke, stroke);
+ if (paint_stroke_curve_end(C, op, stroke))
+ return OPERATOR_FINISHED;
+
+ if (paint_supports_smooth_stroke(br, mode))
+ stroke->stroke_cursor =
+ WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_smooth_cursor, stroke);
stroke->stroke_init = true;
first_modal = true;
@@ -739,9 +1026,14 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */
if (stroke->stroke_started) {
- if (stroke->brush->flag & BRUSH_AIRBRUSH)
+ if (br->flag & BRUSH_AIRBRUSH)
stroke->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, stroke->brush->rate);
+ if (br->flag & BRUSH_LINE) {
+ stroke->stroke_cursor =
+ WM_paint_cursor_activate(CTX_wm_manager(C), paint_poll, paint_draw_line_cursor, stroke);
+ }
+
first_dab = true;
}
}
@@ -757,20 +1049,42 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- if (event->type == stroke->event_type && event->val == KM_RELEASE && !first_modal) {
+ if (event->type == stroke->event_type && !first_modal) {
+ if (event->val == KM_RELEASE) {
+ paint_stroke_line_end (C, op, stroke, sample_average.mouse);
+ stroke_done(C, op);
+ return OPERATOR_FINISHED;
+ }
+ }
+ else if (ELEM(event->type, RETKEY, SPACEKEY)) {
+ paint_stroke_line_end(C, op, stroke, sample_average.mouse);
stroke_done(C, op);
return OPERATOR_FINISHED;
}
- else if (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) ||
- (event->type == TIMER && (event->customdata == stroke->timer)) )
+ else if ((br->flag & BRUSH_LINE) && stroke->stroke_started &&
+ (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))))
+ {
+ if (br->flag & BRUSH_RAKE) {
+ copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
+ paint_calculate_rake_rotation(stroke->ups, sample_average.mouse);
+ }
+ }
+ else if (first_modal ||
+ /* regular dabs */
+ (!(br->flag & (BRUSH_AIRBRUSH)) && (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))) ||
+ /* airbrush */
+ ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer))
{
if (paint_smooth_stroke(stroke, mouse, &pressure, &sample_average, mode)) {
if (stroke->stroke_started) {
- if (paint_space_stroke_enabled(stroke->brush, mode)) {
+ if (paint_space_stroke_enabled(br, mode)) {
if (paint_space_stroke(C, op, mouse, pressure))
redraw = true;
}
else {
+ float dmouse[2];
+ sub_v2_v2v2(dmouse, mouse, stroke->last_mouse_position);
+ stroke->stroke_distance += len_v2(dmouse);
paint_brush_stroke_add_step(C, op, mouse, pressure);
redraw = true;
}
@@ -781,20 +1095,28 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* we want the stroke to have the first daub at the start location
* instead of waiting till we have moved the space distance */
if (first_dab &&
- paint_space_stroke_enabled(stroke->brush, mode) &&
- !(stroke->brush->flag & BRUSH_ANCHORED) &&
- !(stroke->brush->flag & BRUSH_SMOOTH_STROKE))
+ paint_space_stroke_enabled(br, mode) &&
+ !(br->flag & BRUSH_SMOOTH_STROKE))
{
- paint_brush_stroke_add_step(C, op, mouse, pressure);
+ stroke->ups->overlap_factor = paint_stroke_integrate_overlap(br, 1.0);
+ paint_brush_stroke_add_step(C, op, sample_average.mouse, sample_average.pressure);
redraw = true;
}
/* do updates for redraw. if event is inbetween mousemove there are more
* coming, so postpone potentially slow redraw updates until all are done */
- if (event->type != INBETWEEN_MOUSEMOVE)
+ if (event->type != INBETWEEN_MOUSEMOVE) {
+ wmWindow *window = CTX_wm_window(C);
+ ARegion *ar = CTX_wm_region(C);
+
+ /* At the very least, invalidate the cursor */
+ if (ar && (p->flags & PAINT_SHOW_BRUSH))
+ WM_paint_cursor_tag_redraw(window, ar);
+
if (redraw && stroke->redraw)
stroke->redraw(C, stroke, false);
-
+ }
+
return OPERATOR_RUNNING_MODAL;
}
@@ -835,6 +1157,16 @@ void *paint_stroke_mode_data(struct PaintStroke *stroke)
return stroke->mode_data;
}
+bool paint_stroke_flipped(struct PaintStroke *stroke)
+{
+ return stroke->pen_flip;
+}
+
+float paint_stroke_distance_get(struct PaintStroke *stroke)
+{
+ return stroke->stroke_distance;
+}
+
void paint_stroke_set_mode_data(PaintStroke *stroke, void *mode_data)
{
stroke->mode_data = mode_data;
@@ -848,6 +1180,6 @@ int paint_poll(bContext *C)
ARegion *ar = CTX_wm_region(C);
return p && ob && BKE_paint_brush(p) &&
- (sa && sa->spacetype == SPACE_VIEW3D) &&
+ (sa && ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE)) &&
(ar && ar->regiontype == RGN_TYPE_WINDOW);
}
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
index f3946e30b83..20e3155c01d 100644
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_undo.c
@@ -38,7 +38,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
-#include "ED_sculpt.h"
+#include "ED_paint.h"
#include "paint_intern.h"
@@ -51,6 +51,7 @@ typedef struct UndoElem {
UndoRestoreCb restore;
UndoFreeCb free;
+ UndoCleanupCb cleanup;
} UndoElem;
typedef struct UndoStack {
@@ -78,7 +79,7 @@ static void undo_elem_free(UndoStack *UNUSED(stack), UndoElem *uel)
}
}
-static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free)
+static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup)
{
UndoElem *uel;
int nr;
@@ -98,6 +99,7 @@ static void undo_stack_push_begin(UndoStack *stack, const char *name, UndoRestor
stack->current = uel = MEM_callocN(sizeof(UndoElem), "undo file");
uel->restore = restore;
uel->free = free;
+ uel->cleanup = cleanup;
BLI_addtail(&stack->elems, uel);
/* name can be a dynamic string */
@@ -171,10 +173,38 @@ static void undo_stack_push_end(UndoStack *stack)
}
}
+static void undo_stack_cleanup(UndoStack *stack, bContext *C)
+{
+ UndoElem *uel = stack->elems.first;
+ bool stack_reset = false;
+
+ while (uel) {
+ if (uel->cleanup && uel->cleanup(C, &uel->elems)) {
+ UndoElem *uel_tmp = uel->next;
+ if (stack->current == uel) {
+ stack->current = NULL;
+ stack_reset = true;
+ }
+ undo_elem_free(stack, uel);
+ BLI_freelinkN(&stack->elems, uel);
+ uel = uel_tmp;
+ }
+ else
+ uel = uel->next;
+ }
+ if (stack_reset) {
+ stack->current = stack->elems.last;
+ }
+
+}
+
static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *name)
{
UndoElem *undo;
+ /* first cleanup any old undo steps that may belong to invalid data */
+ undo_stack_cleanup(stack, C);
+
if (step == 1) {
if (stack->current == NULL) {
/* pass */
@@ -223,23 +253,25 @@ static void undo_stack_free(UndoStack *stack)
/* Exported Functions */
-void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free)
+void ED_undo_paint_push_begin(int type, const char *name, UndoRestoreCb restore, UndoFreeCb free, UndoCleanupCb cleanup)
{
if (type == UNDO_PAINT_IMAGE)
- undo_stack_push_begin(&ImageUndoStack, name, restore, free);
+ undo_stack_push_begin(&ImageUndoStack, name, restore, free, cleanup);
else if (type == UNDO_PAINT_MESH)
- undo_stack_push_begin(&MeshUndoStack, name, restore, free);
+ undo_stack_push_begin(&MeshUndoStack, name, restore, free, cleanup);
}
ListBase *undo_paint_push_get_list(int type)
{
if (type == UNDO_PAINT_IMAGE) {
- if (ImageUndoStack.current)
+ if (ImageUndoStack.current) {
return &ImageUndoStack.current->elems;
+ }
}
else if (type == UNDO_PAINT_MESH) {
- if (MeshUndoStack.current)
+ if (MeshUndoStack.current) {
return &MeshUndoStack.current->elems;
+ }
}
return NULL;
@@ -315,12 +347,17 @@ static char *undo_stack_get_name(UndoStack *stack, int nr, int *active)
return NULL;
}
-const char *ED_undo_paint_get_name(int type, int nr, int *active)
+const char *ED_undo_paint_get_name(bContext *C, int type, int nr, int *active)
{
- if (type == UNDO_PAINT_IMAGE)
+
+ if (type == UNDO_PAINT_IMAGE) {
+ undo_stack_cleanup(&ImageUndoStack, C);
return undo_stack_get_name(&ImageUndoStack, nr, active);
- else if (type == UNDO_PAINT_MESH)
+ }
+ else if (type == UNDO_PAINT_MESH) {
+ undo_stack_cleanup(&MeshUndoStack, C);
return undo_stack_get_name(&MeshUndoStack, nr, active);
+ }
return NULL;
}
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 642c1dd9529..e03c8a5f106 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -35,23 +35,28 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
+#include "DNA_material_types.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
#include "BLI_math.h"
+#include "BLI_math_color.h"
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
#include "BLF_translation.h"
+#include "BKE_scene.h"
#include "BKE_brush.h"
#include "BKE_context.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_material.h"
#include "BKE_image.h"
#include "BKE_paint.h"
#include "BKE_report.h"
+#include "BKE_image.h"
#include "RNA_access.h"
#include "RNA_define.h"
@@ -67,6 +72,10 @@
#include "ED_view3d.h"
#include "ED_screen.h"
+#include "ED_uvedit.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
#include "BLI_sys_types.h"
#include "ED_mesh.h" /* for face mask functions */
@@ -146,7 +155,7 @@ void paint_calc_redraw_planes(float planes[4][4],
rect.ymax += 2;
ED_view3d_clipping_calc(&bb, planes, &mats, &rect);
- mul_m4_fl(planes, -1.0f);
+ negate_m4(planes);
}
float paint_calc_object_space_radius(ViewContext *vc, const float center[3],
@@ -205,6 +214,192 @@ void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct
CLAMP(rgba[3], 0.0f, 1.0f);
}
+void paint_stroke_operator_properties(wmOperatorType *ot)
+{
+ static EnumPropertyItem stroke_mode_items[] = {
+ {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"},
+ {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
+ {BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke"},
+ {0}
+ };
+
+ RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+
+ RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL,
+ "Stroke Mode",
+ "Action taken when a paint stroke is made");
+
+}
+
+/* 3D Paint */
+
+static void imapaint_project(float matrix[4][4], const float co[3], float pco[4])
+{
+ copy_v3_v3(pco, co);
+ pco[3] = 1.0f;
+
+ mul_m4_v4(matrix, pco);
+}
+
+static void imapaint_tri_weights(float matrix[4][4], GLint view[4],
+ const float v1[3], const float v2[3], const float v3[3],
+ const float co[2], float w[3])
+{
+ float pv1[4], pv2[4], pv3[4], h[3], divw;
+ float wmat[3][3], invwmat[3][3];
+
+ /* compute barycentric coordinates */
+
+ /* project the verts */
+ imapaint_project(matrix, v1, pv1);
+ imapaint_project(matrix, v2, pv2);
+ imapaint_project(matrix, v3, pv3);
+
+ /* do inverse view mapping, see gluProject man page */
+ h[0] = (co[0] - view[0]) * 2.0f / view[2] - 1.0f;
+ h[1] = (co[1] - view[1]) * 2.0f / view[3] - 1.0f;
+ h[2] = 1.0f;
+
+ /* solve for (w1,w2,w3)/perspdiv in:
+ * h * perspdiv = Project * Model * (w1 * v1 + w2 * v2 + w3 * v3) */
+
+ wmat[0][0] = pv1[0]; wmat[1][0] = pv2[0]; wmat[2][0] = pv3[0];
+ wmat[0][1] = pv1[1]; wmat[1][1] = pv2[1]; wmat[2][1] = pv3[1];
+ wmat[0][2] = pv1[3]; wmat[1][2] = pv2[3]; wmat[2][2] = pv3[3];
+
+ invert_m3_m3(invwmat, wmat);
+ mul_m3_v3(invwmat, h);
+
+ copy_v3_v3(w, h);
+
+ /* w is still divided by perspdiv, make it sum to one */
+ divw = w[0] + w[1] + w[2];
+ if (divw != 0.0f) {
+ mul_v3_fl(w, 1.0f / divw);
+ }
+}
+
+/* compute uv coordinates of mouse in face */
+static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, const int xy[2], float uv[2])
+{
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+ MTFace *tf_base, *tf;
+ Material *ma;
+ TexPaintSlot *slot;
+ int numfaces = dm->getNumTessFaces(dm), a, findex;
+ float p[2], w[3], absw, minabsw;
+ MFace mf;
+ MVert mv[4];
+ float matrix[4][4], proj[4][4];
+ GLint view[4];
+
+ /* compute barycentric coordinates */
+
+ /* double lookup */
+ const int *index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ const int *index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ if (index_mf_to_mpoly == NULL) {
+ index_mp_to_orig = NULL;
+ }
+
+ /* get the needed opengl matrices */
+ glGetIntegerv(GL_VIEWPORT, view);
+ glGetFloatv(GL_MODELVIEW_MATRIX, (float *)matrix);
+ glGetFloatv(GL_PROJECTION_MATRIX, (float *)proj);
+ view[0] = view[1] = 0;
+ mul_m4_m4m4(matrix, matrix, ob->obmat);
+ mul_m4_m4m4(matrix, proj, matrix);
+
+ minabsw = 1e10;
+ uv[0] = uv[1] = 0.0;
+
+ /* test all faces in the derivedmesh with the original index of the picked face */
+ for (a = 0; a < numfaces; a++) {
+ findex = index_mf_to_mpoly ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
+
+ if (findex == faceindex) {
+ dm->getTessFace(dm, a, &mf);
+
+ ma = dm->mat[mf.mat_nr];
+ slot = &ma->texpaintslot[ma->paint_active_slot];
+
+ dm->getVert(dm, mf.v1, &mv[0]);
+ dm->getVert(dm, mf.v2, &mv[1]);
+ dm->getVert(dm, mf.v3, &mv[2]);
+ if (mf.v4)
+ dm->getVert(dm, mf.v4, &mv[3]);
+
+ if (!(slot && slot->uvname && (tf_base = CustomData_get_layer_named(&dm->faceData, CD_MTFACE, slot->uvname))))
+ tf_base = CustomData_get_layer(&dm->faceData, CD_MTFACE);
+
+ tf = &tf_base[a];
+
+ p[0] = xy[0];
+ p[1] = xy[1];
+
+ if (mf.v4) {
+ /* the triangle with the largest absolute values is the one
+ * with the most negative weights */
+ imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[3].co, p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[3][0] * w[2];
+ uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[3][1] * w[2];
+ minabsw = absw;
+ }
+
+ imapaint_tri_weights(matrix, view, mv[1].co, mv[2].co, mv[3].co, p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tf->uv[1][0] * w[0] + tf->uv[2][0] * w[1] + tf->uv[3][0] * w[2];
+ uv[1] = tf->uv[1][1] * w[0] + tf->uv[2][1] * w[1] + tf->uv[3][1] * w[2];
+ minabsw = absw;
+ }
+ }
+ else {
+ imapaint_tri_weights(matrix, view, mv[0].co, mv[1].co, mv[2].co, p, w);
+ absw = fabsf(w[0]) + fabsf(w[1]) + fabsf(w[2]);
+ if (absw < minabsw) {
+ uv[0] = tf->uv[0][0] * w[0] + tf->uv[1][0] * w[1] + tf->uv[2][0] * w[2];
+ uv[1] = tf->uv[0][1] * w[0] + tf->uv[1][1] * w[1] + tf->uv[2][1] * w[2];
+ minabsw = absw;
+ }
+ }
+ }
+ }
+
+ dm->release(dm);
+}
+
+/* returns 0 if not found, otherwise 1 */
+static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totface)
+{
+ if (totface == 0)
+ return 0;
+
+ /* sample only on the exact position */
+ *r_index = view3d_sample_backbuf(vc, mval[0], mval[1]);
+
+ if ((*r_index) == 0 || (*r_index) > (unsigned int)totface) {
+ return 0;
+ }
+
+ (*r_index)--;
+
+ return 1;
+}
+
+
+static Image *imapaint_face_image(DerivedMesh *dm, int face_index)
+{
+ Image *ima;
+ MFace *mf = dm->getTessFaceArray(dm) + face_index;
+ Material *ma = dm->mat[mf->mat_nr];
+ ima = ma ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
+
+ return ima;
+}
+
/* Uses symm to selectively flip any axis of a coordinate. */
void flip_v3_v3(float out[3], const float in[3], const char symm)
{
@@ -223,25 +418,132 @@ void flip_v3_v3(float out[3], const float in[3], const char symm)
}
/* used for both 3d view and image window */
-void paint_sample_color(const bContext *C, ARegion *ar, int x, int y) /* frontbuf */
+void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_proj, bool use_palette)
{
+ Scene *scene = CTX_data_scene(C);
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ Palette *palette = BKE_paint_palette(paint);
+ PaletteColor *color;
Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
unsigned int col;
- const char *cp;
+ const unsigned char *cp;
CLAMP(x, 0, ar->winx);
CLAMP(y, 0, ar->winy);
- glReadBuffer(GL_FRONT);
- glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
- glReadBuffer(GL_BACK);
+ if (use_palette) {
+ if (!palette) {
+ palette = BKE_palette_add(CTX_data_main(C), "Palette");
+ BKE_paint_palette_set(paint, palette);
+ }
- cp = (char *)&col;
+ color = BKE_palette_color_add(palette);
+ }
+
+
+ if (CTX_wm_view3d(C) && texpaint_proj) {
+ /* first try getting a colour directly from the mesh faces if possible */
+ Object *ob = OBACT;
+ bool sample_success = false;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
+ bool use_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
+
+ if (ob) {
+ DerivedMesh *dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
+
+ ViewContext vc;
+ const int mval[2] = {x, y};
+ unsigned int faceindex;
+ unsigned int totface = dm->getNumTessFaces(dm);
+ MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
+
+ DM_update_materials(dm, ob);
+
+ if (dm_mtface) {
+ view3d_set_viewcontext(C, &vc);
+
+ view3d_operator_needs_opengl(C);
+
+ if (imapaint_pick_face(&vc, mval, &faceindex, totface)) {
+ Image *image;
+
+ if (use_material)
+ image = imapaint_face_image(dm, faceindex);
+ else
+ image = imapaint->canvas;
+
+ if (image) {
+ ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
+ if (ibuf && ibuf->rect) {
+ float uv[2];
+ float u, v;
+ imapaint_pick_uv(scene, ob, faceindex, mval, uv);
+ sample_success = true;
+
+ u = fmodf(uv[0], 1.0f);
+ v = fmodf(uv[1], 1.0f);
+
+ 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;
+
+ if (ibuf->rect_float) {
+ float rgba_f[4];
+ 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);
+ }
+ else {
+ linearrgb_to_srgb_v3_v3(rgba_f, rgba_f);
+ BKE_brush_color_set(scene, br, rgba_f);
+ }
+ }
+ else {
+ unsigned char rgba[4];
+ bilinear_interpolation_color_wrap(ibuf, rgba, NULL, u, v);
+ if (use_palette) {
+ rgb_uchar_to_float(color->rgb, rgba);
+ }
+ else {
+ float rgba_f[3];
+ rgb_uchar_to_float(rgba_f, rgba);
+ BKE_brush_color_set(scene, br, rgba_f);
+ }
+ }
+ }
+
+ BKE_image_release_ibuf(image, ibuf, NULL);
+ }
+ }
+ }
+ dm->release(dm);
+ }
+
+ if (!sample_success) {
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+ }
+ else
+ return;
+ }
+ else {
+ glReadBuffer(GL_FRONT);
+ glReadPixels(x + ar->winrct.xmin, y + ar->winrct.ymin, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+ glReadBuffer(GL_BACK);
+ }
+ cp = (unsigned char *)&col;
- if (br) {
- br->rgb[0] = cp[0] / 255.0f;
- br->rgb[1] = cp[1] / 255.0f;
- br->rgb[2] = cp[2] / 255.0f;
+ if (use_palette) {
+ rgb_uchar_to_float(color->rgb, cp);
+ }
+ else {
+ float rgba_f[3];
+ rgb_uchar_to_float(rgba_f, cp);
+ BKE_brush_color_set(scene, br, rgba_f);
}
}
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 969c5a09a82..431dd54b3c0 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -33,6 +33,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
+#include "BLI_bitmap.h"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -75,7 +76,6 @@
#include "paint_intern.h" /* own include */
-
/* check if we can do partial updates and have them draw realtime
* (without rebuilding the 'derivedFinal') */
static bool vertex_paint_use_fast_update_check(Object *ob)
@@ -197,11 +197,11 @@ static int *get_indexarray(Mesh *me)
return MEM_mallocN(sizeof(int) * (me->totpoly + 1), "vertexpaint");
}
-unsigned int vpaint_get_current_col(VPaint *vp)
+unsigned int vpaint_get_current_col(Scene *scene, VPaint *vp)
{
Brush *brush = BKE_paint_brush(&vp->paint);
unsigned char col[4];
- rgb_float_to_uchar(col, brush->rgb);
+ rgb_float_to_uchar(col, BKE_brush_color_get(scene, brush));
col[3] = 255; /* alpha isn't used, could even be removed to speedup paint a little */
return *(unsigned int *)col;
}
@@ -919,7 +919,7 @@ static float calc_vp_strength_col_dl(VPaint *vp, ViewContext *vc, const float co
{
const float dist_sq = len_squared_v2v2(mval, co_ss);
- if (dist_sq <= brush_size_pressure * brush_size_pressure) {
+ if (dist_sq <= SQUARE(brush_size_pressure)) {
Brush *brush = BKE_paint_brush(&vp->paint);
const float dist = sqrtf(dist_sq);
float factor;
@@ -2547,14 +2547,17 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
- op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start,
wpaint_stroke_update_step, NULL,
wpaint_stroke_done, event->type);
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
/* add modal handler */
WM_event_add_modal_handler(C, op);
- retval = op->type->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
@@ -2563,7 +2566,7 @@ static int wpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int wpaint_exec(bContext *C, wmOperator *op)
{
- op->customdata = paint_stroke_new(C, NULL, wpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, wpaint_stroke_test_start,
wpaint_stroke_update_step, NULL,
wpaint_stroke_done, 0);
@@ -2595,8 +2598,8 @@ void PAINT_OT_weight_paint(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
-
- RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+
+ paint_stroke_operator_properties(ot);
}
static int weight_paint_set_exec(bContext *C, wmOperator *op)
@@ -2778,7 +2781,8 @@ static void vpaint_build_poly_facemap(struct VPaintData *vd, Mesh *me)
static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const float UNUSED(mouse[2]))
{
- ToolSettings *ts = CTX_data_tool_settings(C);
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
struct PaintStroke *stroke = op->customdata;
VPaint *vp = ts->vpaint;
Brush *brush = BKE_paint_brush(&vp->paint);
@@ -2810,7 +2814,7 @@ static bool vpaint_stroke_test_start(bContext *C, struct wmOperator *op, const f
vpd->vp_handle = ED_vpaint_proj_handle_create(vpd->vc.scene, ob, &vpd->vertexcosnos);
vpd->indexar = get_indexarray(me);
- vpd->paintcol = vpaint_get_current_col(vp);
+ vpd->paintcol = vpaint_get_current_col(scene, vp);
vpd->is_texbrush = !(brush->vertexpaint_tool == PAINT_BLEND_BLUR) &&
brush->mtex.tex;
@@ -3062,14 +3066,18 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
int retval;
- op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start,
vpaint_stroke_update_step, NULL,
vpaint_stroke_done, event->type);
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
+
/* add modal handler */
WM_event_add_modal_handler(C, op);
- retval = op->type->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
@@ -3078,7 +3086,7 @@ static int vpaint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int vpaint_exec(bContext *C, wmOperator *op)
{
- op->customdata = paint_stroke_new(C, NULL, vpaint_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, NULL, vpaint_stroke_test_start,
vpaint_stroke_update_step, NULL,
vpaint_stroke_done, 0);
@@ -3110,7 +3118,7 @@ void PAINT_OT_vertex_paint(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_UNDO | OPTYPE_BLOCKING;
- RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
+ paint_stroke_operator_properties(ot);
}
/* ********************** weight from bones operator ******************* */
@@ -3184,6 +3192,8 @@ typedef struct DMGradient_userData {
int def_nr;
short is_init;
DMGradient_vertStore *vert_cache;
+ /* only for init */
+ BLI_bitmap *vert_visit;
/* options */
short use_select;
@@ -3191,19 +3201,81 @@ typedef struct DMGradient_userData {
float weightpaint;
} DMGradient_userData;
-static void gradientVert__mapFunc(void *userData, int index, const float co[3],
- const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+static void gradientVert_update(DMGradient_userData *grad_data, int index)
{
- DMGradient_userData *grad_data = userData;
Mesh *me = grad_data->me;
+ DMGradient_vertStore *vs = &grad_data->vert_cache[index];
+ float alpha;
+
+ if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
+ alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
+ }
+ else {
+ BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL);
+ alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
+ }
+ /* no need to clamp 'alpha' yet */
- if (grad_data->use_select == false || (me->mvert[index].flag & SELECT)) {
+ /* adjust weight */
+ alpha = BKE_brush_curve_strength_clamp(grad_data->brush, alpha, 1.0f);
+
+ if (alpha != 0.0f) {
+ MDeformVert *dv = &me->dvert[index];
+ MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr);
+ // dw->weight = alpha; // testing
+ int tool = grad_data->brush->vertexpaint_tool;
+ float testw;
+
+ /* init if we just added */
+ testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
+ CLAMP(testw, 0.0f, 1.0f);
+ dw->weight = testw;
+ }
+ else {
+ MDeformVert *dv = &me->dvert[index];
+ if (vs->flag & VGRAD_STORE_DW_EXIST) {
+ /* normally we NULL check, but in this case we know it exists */
+ MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
+ dw->weight = vs->weight_orig;
+ }
+ else {
+ /* wasn't originally existing, remove */
+ MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
+ if (dw) {
+ defvert_remove_group(dv, dw);
+ }
+ }
+ }
+}
+
+static void gradientVertUpdate__mapFunc(
+ void *userData, int index, const float UNUSED(co[3]),
+ const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+ DMGradient_userData *grad_data = userData;
+ Mesh *me = grad_data->me;
+ if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) {
DMGradient_vertStore *vs = &grad_data->vert_cache[index];
+ if (vs->sco[0] != FLT_MAX) {
+ gradientVert_update(grad_data, index);
+ }
+ }
+}
- /* run first pass only, could be split into its own mapFunc
+static void gradientVertInit__mapFunc(
+ void *userData, int index, const float co[3],
+ const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
+{
+ DMGradient_userData *grad_data = userData;
+ Mesh *me = grad_data->me;
+
+ if ((grad_data->use_select == false) || (me->mvert[index].flag & SELECT)) {
+ /* run first pass only,
* the screen coords of the verts need to be cached because
* updating the mesh may move them about (entering feedback loop) */
- if (grad_data->is_init) {
+
+ if (BLI_BITMAP_TEST(grad_data->vert_visit, index) == 0) {
+ DMGradient_vertStore *vs = &grad_data->vert_cache[index];
if (ED_view3d_project_float_object(grad_data->ar,
co, vs->sco,
V3D_PROJ_TEST_CLIP_BB | V3D_PROJ_TEST_CLIP_NEAR) == V3D_PROJ_RET_OK)
@@ -3220,55 +3292,14 @@ static void gradientVert__mapFunc(void *userData, int index, const float co[3],
vs->weight_orig = 0.0f;
vs->flag = VGRAD_STORE_NOP;
}
- }
- else {
- /* no go */
- copy_v2_fl(vs->sco, FLT_MAX);
- }
- }
- /* end init */
- if (vs->sco[0] != FLT_MAX) {
- float alpha;
+ BLI_BITMAP_ENABLE(grad_data->vert_visit, index);
- if (grad_data->type == WPAINT_GRADIENT_TYPE_LINEAR) {
- alpha = line_point_factor_v2(vs->sco, grad_data->sco_start, grad_data->sco_end);
+ gradientVert_update(grad_data, index);
}
else {
- BLI_assert(grad_data->type == WPAINT_GRADIENT_TYPE_RADIAL);
- alpha = len_v2v2(grad_data->sco_start, vs->sco) * grad_data->sco_line_div;
- }
- /* no need to clamp 'alpha' yet */
-
- /* adjust weight */
- alpha = BKE_brush_curve_strength_clamp(grad_data->brush, alpha, 1.0f);
-
- if (alpha != 0.0f) {
- MDeformVert *dv = &me->dvert[index];
- MDeformWeight *dw = defvert_verify_index(dv, grad_data->def_nr);
- // dw->weight = alpha; // testing
- int tool = grad_data->brush->vertexpaint_tool;
- float testw;
-
- /* init if we just added */
- testw = wpaint_blend_tool(tool, vs->weight_orig, grad_data->weightpaint, alpha * grad_data->brush->alpha);
- CLAMP(testw, 0.0f, 1.0f);
- dw->weight = testw;
- }
- else {
- MDeformVert *dv = &me->dvert[index];
- if (vs->flag & VGRAD_STORE_DW_EXIST) {
- /* normally we NULL check, but in this case we know it exists */
- MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
- dw->weight = vs->weight_orig;
- }
- else {
- /* wasn't originally existing, remove */
- MDeformWeight *dw = defvert_find_index(dv, grad_data->def_nr);
- if (dw) {
- defvert_remove_group(dv, dw);
- }
- }
+ /* no go */
+ copy_v2_fl(vs->sco, FLT_MAX);
}
}
}
@@ -3364,6 +3395,7 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
data.def_nr = ob->actdef - 1;
data.use_select = (me->editflag & (ME_EDIT_PAINT_FACE_SEL | ME_EDIT_PAINT_VERT_SEL));
data.vert_cache = vert_cache;
+ data.vert_visit = NULL;
data.type = RNA_enum_get(op->ptr, "type");
{
@@ -3379,7 +3411,17 @@ static int paint_weight_gradient_exec(bContext *C, wmOperator *op)
ED_view3d_init_mats_rv3d(ob, ar->regiondata);
- dm->foreachMappedVert(dm, gradientVert__mapFunc, &data, DM_FOREACH_NOP);
+ if (data.is_init) {
+ data.vert_visit = BLI_BITMAP_NEW(me->totvert, __func__);
+
+ dm->foreachMappedVert(dm, gradientVertInit__mapFunc, &data, DM_FOREACH_NOP);
+
+ MEM_freeN(data.vert_visit);
+ data.vert_visit = NULL;
+ }
+ else {
+ dm->foreachMappedVert(dm, gradientVertUpdate__mapFunc, &data, DM_FOREACH_NOP);
+ }
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index c9101fff6e5..0e0012c198f 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -37,6 +37,7 @@
#include "BLI_math.h"
#include "BLI_blenlib.h"
+#include "BLI_dial.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
@@ -65,6 +66,7 @@
#include "BKE_modifier.h"
#include "BKE_multires.h"
#include "BKE_paint.h"
+#include "BKE_report.h"
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_subsurf.h"
@@ -87,6 +89,9 @@
#include "GPU_buffers.h"
+#include "UI_interface.h"
+#include "UI_resources.h"
+
#include "bmesh.h"
#include "bmesh_tools.h"
@@ -111,7 +116,7 @@ static int system_physical_thread_count(void)
}
#endif /* __APPLE__ */
-void ED_sculpt_get_average_stroke(Object *ob, float stroke[3])
+void ED_sculpt_stroke_get_average(Object *ob, float stroke[3])
{
if (ob->sculpt->last_stroke_valid && ob->sculpt->average_stroke_counter > 0) {
float fac = 1.0f / ob->sculpt->average_stroke_counter;
@@ -177,7 +182,7 @@ typedef struct StrokeCache {
float initial_mouse[2];
/* Pre-allocated temporary storage used during smoothing */
- int num_threads, max_threads;
+ int num_threads, init_num_threads;
float (**tmpgrid_co)[3], (**tmprow_co)[3];
float **tmpgrid_mask, **tmprow_mask;
@@ -187,8 +192,8 @@ typedef struct StrokeCache {
float true_location[3];
float location[3];
- float pen_flip;
- float invert;
+ bool pen_flip;
+ bool invert;
float pressure;
float mouse[2];
float bstrength;
@@ -222,7 +227,7 @@ typedef struct StrokeCache {
float sculpt_normal[3];
float sculpt_normal_symm[3];
- /* Used for wrap texture mode, local_mat gets calculated by
+ /* Used for area texture mode, local_mat gets calculated by
* calc_brush_local_mat() and used in tex_strength(). */
float brush_local_mat[4][4];
@@ -234,12 +239,8 @@ typedef struct StrokeCache {
float anchored_location[3];
float vertex_rotation; /* amount to rotate the vertices when using rotate brush */
- float previous_vertex_rotation; /* previous rotation, used to detect if we rotate more than
- * PI radians */
- short num_vertex_turns; /* records number of full 2*PI turns */
- float initial_mouse_dir[2]; /* used to calculate initial angle */
- bool init_dir_set; /* detect if we have initialized the initial mouse direction */
-
+ Dial *dial;
+
char saved_active_brush_name[MAX_ID_NAME];
char saved_mask_brush_tool;
int saved_smooth_size; /* smooth tool copies the size of the current tool */
@@ -267,8 +268,8 @@ typedef struct {
/* Original coordinate, normal, and mask */
const float *co;
- float mask;
const short *no;
+ float mask;
} SculptOrigVertData;
@@ -355,19 +356,19 @@ static int sculpt_stroke_dynamic_topology(const SculptSession *ss,
!(brush->flag & BRUSH_ANCHORED) &&
!(brush->flag & BRUSH_DRAG_DOT) &&
- (!ELEM6(brush->sculpt_tool,
- /* These brushes, as currently coded, cannot
- * support dynamic topology */
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER,
+ (!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)));
+ /* These brushes could handle dynamic topology,
+ * but user feedback indicates it's better not
+ * to */
+ SCULPT_TOOL_SMOOTH,
+ SCULPT_TOOL_MASK)));
}
/*** paint mesh ***/
@@ -392,7 +393,7 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob)
* entries might be inserted by sculpt_undo_push_node() into the
* GHash used internally by BM_log_original_vert_co() by a
* different thread. [#33787] */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP && !ss->bm)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && !ss->bm && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
SculptUndoNode *unode;
SculptUndoType type = (brush->sculpt_tool == SCULPT_TOOL_MASK ?
@@ -485,8 +486,8 @@ static bool sculpt_get_redraw_rect(ARegion *ar, RegionView3D *rv3d,
return 1;
}
-void sculpt_get_redraw_planes(float planes[4][4], ARegion *ar,
- RegionView3D *rv3d, Object *ob)
+void ED_sculpt_redraw_planes_get(float planes[4][4], ARegion *ar,
+ RegionView3D *rv3d, Object *ob)
{
PBVH *pbvh = ob->sculpt->pbvh;
/* copy here, original will be used below */
@@ -549,7 +550,7 @@ static bool sculpt_brush_test(SculptBrushTest *test, const float co[3])
if (sculpt_brush_test_clipping(test, co)) {
return 0;
}
- test->dist = sqrt(distsq);
+ test->dist = sqrtf(distsq);
return 1;
}
else {
@@ -659,47 +660,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, float co[3], float loca
/* ===== Sculpting =====
*
*/
-
-static float overlapped_curve(Brush *br, float x)
-{
- int i;
- const int n = 100 / br->spacing;
- const float h = br->spacing / 50.0f;
- const float x0 = x - 1;
-
- float sum;
-
- sum = 0;
- for (i = 0; i < n; i++) {
- float xx;
-
- xx = fabsf(x0 + i * h);
-
- if (xx < 1.0f)
- sum += BKE_brush_curve_strength(br, xx, 1);
- }
-
- return sum;
-}
-
-static float integrate_overlap(Brush *br)
-{
- int i;
- int m = 10;
- float g = 1.0f / m;
- float max;
-
- max = 0;
- for (i = 0; i < m; i++) {
- float overlap = overlapped_curve(br, i * g);
-
- if (overlap > max)
- max = overlap;
- }
-
- return max;
-}
-
static void flip_v3(float v[3], const char symm)
{
flip_v3_v3(v, v, symm);
@@ -772,7 +732,7 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache)
/* 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)
+static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather, UnifiedPaintSettings *ups)
{
const Scene *scene = cache->vc->scene;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -784,13 +744,10 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
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;
- float accum = integrate_overlap(brush);
+ float overlap = ups->overlap_factor;
/* spacing is integer percentage of radius, divide by 50 to get
* normalized diameter */
- float overlap = (brush->flag & BRUSH_SPACE_ATTEN &&
- brush->flag & BRUSH_SPACE &&
- !(brush->flag & BRUSH_ANCHORED) &&
- (brush->spacing < 100)) ? 1.0f / accum : 1;
+
float flip = dir * invert * pen_flip;
switch (brush->sculpt_tool) {
@@ -852,10 +809,10 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
return alpha * pressure * feather;
case SCULPT_TOOL_SNAKE_HOOK:
- return feather;
+ return root_alpha * feather;
case SCULPT_TOOL_GRAB:
- return feather;
+ return root_alpha * feather;
case SCULPT_TOOL_ROTATE:
return alpha * pressure * feather;
@@ -869,7 +826,6 @@ static float brush_strength(Sculpt *sd, StrokeCache *cache, float feather)
static float tex_strength(SculptSession *ss, Brush *br,
const float point[3],
const float len,
- const float sculpt_normal[3],
const short vno[3],
const float fno[3],
const float mask)
@@ -940,7 +896,7 @@ static float tex_strength(SculptSession *ss, Brush *br,
/* Falloff curve */
avg *= BKE_brush_curve_strength(br, len, cache->radius);
- avg *= frontface(br, sculpt_normal, vno, fno);
+ avg *= frontface(br, cache->view_normal, vno, fno);
/* Paint mask */
avg *= 1.0f - mask;
@@ -1037,7 +993,7 @@ static void calc_area_normal(Sculpt *sd, Object *ob, float an[3], PBVHNode **nod
zero_v3(an);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -1231,17 +1187,16 @@ 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) ||
- (brush->flag & BRUSH_FRONTFACE))) ||
-
- ELEM7(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->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));
}
@@ -1396,7 +1351,7 @@ static void do_mesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->view_normal, vd.no, vd.fno,
+ vd.no, vd.fno,
smooth_mask ? 0 : (vd.mask ? *vd.mask : 0.0f));
if (smooth_mask) {
float val = neighbor_average_mask(ss, vd.vert_indices[vd.i]) - *vd.mask;
@@ -1437,7 +1392,7 @@ static void do_bmesh_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *node,
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->view_normal, vd.no, vd.fno,
+ 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;
@@ -1565,7 +1520,7 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
int index;
if (gh) {
- if (BLI_BITMAP_GET(gh, y * gridsize + x))
+ if (BLI_BITMAP_TEST(gh, y * gridsize + x))
continue;
}
@@ -1589,7 +1544,6 @@ static void do_multires_smooth_brush(Sculpt *sd, SculptSession *ss, PBVHNode *no
if (sculpt_brush_test(&test, co)) {
const float strength_mask = (smooth_mask ? 0 : *mask);
const float fade = bstrength * tex_strength(ss, brush, co, test.dist,
- ss->cache->view_normal,
NULL, fno, strength_mask);
float n = 1.0f / 16.0f;
@@ -1645,7 +1599,7 @@ static void smooth(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode,
for (iteration = 0; iteration <= count; ++iteration) {
float strength = (iteration != count) ? 1.0f : last;
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
switch (type) {
case PBVH_GRIDS:
@@ -1681,7 +1635,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
int n;
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -1692,7 +1646,7 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot
{
if (sculpt_brush_test(&test, vd.co)) {
float fade = tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->view_normal, vd.no, vd.fno, 0);
+ vd.no, vd.fno, 0);
(*vd.mask) += fade * bstrength;
CLAMP(*vd.mask, 0, 1);
@@ -1734,7 +1688,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -1748,8 +1702,7 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
{
if (sculpt_brush_test(&test, vd.co)) {
/* offset vertex */
- float fade = tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->sculpt_normal_symm, vd.no,
+ float fade = tex_strength(ss, brush, vd.co, test.dist, vd.no,
vd.fno, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -1790,7 +1743,7 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
if (brush->sculpt_tool == SCULPT_TOOL_BLOB) flippedbstrength *= -1.0f;
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -1805,7 +1758,6 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
if (sculpt_brush_test(&test, vd.co)) {
/* offset vertex */
const float fade = tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->sculpt_normal_symm,
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
float val1[3];
float val2[3];
@@ -1834,7 +1786,7 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
float bstrength = ss->cache->bstrength;
int n;
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -1847,8 +1799,7 @@ static void do_pinch_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(&test, vd.co)) {
- float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->view_normal, vd.no,
+ float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist, vd.no,
vd.fno, vd.mask ? *vd.mask : 0.0f);
float val[3];
@@ -1882,7 +1833,7 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm);
}
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -1903,7 +1854,6 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
const float fade = bstrength * tex_strength(ss, brush,
orig_data.co,
test.dist,
- ss->cache->sculpt_normal_symm,
orig_data.no,
NULL, vd.mask ? *vd.mask : 0.0f);
@@ -1931,7 +1881,7 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -1945,7 +1895,6 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->sculpt_normal_symm,
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], cono, fade);
@@ -1980,7 +1929,7 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
add_v3_v3(grab_delta, ss->cache->sculpt_normal_symm);
}
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -1994,7 +1943,6 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->sculpt_normal_symm,
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], grab_delta, fade);
@@ -2021,7 +1969,7 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta);
cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2042,7 +1990,6 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
const float fade = bstrength * tex_strength(ss, brush,
orig_data.co,
test.dist,
- ss->cache->sculpt_normal_symm,
orig_data.no,
NULL, vd.mask ? *vd.mask : 0.0f);
@@ -2065,7 +2012,7 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
static const int flip[8] = { 1, -1, -1, 1, -1, 1, 1, -1 };
float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass];
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2087,7 +2034,6 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
const float fade = bstrength * tex_strength(ss, brush,
orig_data.co,
test.dist,
- ss->cache->sculpt_normal_symm,
orig_data.no,
NULL, vd.mask ? *vd.mask : 0.0f);
@@ -2119,7 +2065,7 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
mul_v3_v3v3(offset, ss->cache->scale, ss->cache->sculpt_normal_symm);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2143,7 +2089,6 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode
if (sculpt_brush_test(&test, orig_data.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->sculpt_normal_symm,
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
float *disp = &layer_disp[vd.i];
float val[3];
@@ -2183,7 +2128,7 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
float bstrength = ss->cache->bstrength;
int n;
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2197,7 +2142,6 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
{
if (sculpt_brush_test(&test, vd.co)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co, test.dist,
- ss->cache->view_normal,
vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
float val[3];
@@ -2229,7 +2173,7 @@ static void calc_flatten_center(Sculpt *sd, Object *ob, PBVHNode **nodes, int to
zero_v3(fc);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2336,7 +2280,7 @@ static void calc_area_normal_and_flatten_center(Sculpt *sd, Object *ob,
/* for flatten center */
zero_v3(fc);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2588,7 +2532,7 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2609,8 +2553,8 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrt(test.dist),
- an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2660,7 +2604,7 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
/* add_v3_v3v3(p, ss->cache->location, an); */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2682,9 +2626,8 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
sub_v3_v3v3(val, intr, vd.co);
if (plane_trim(ss->cache, brush, val)) {
- const float fade = bstrength * tex_strength(ss, brush, vd.co,
- sqrt(test.dist),
- an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ const float fade = bstrength * tex_strength(ss, brush, vd.co, sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2762,7 +2705,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
mul_m4_m4m4(tmat, mat, scale);
invert_m4_m4(mat, tmat);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2786,7 +2729,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co,
ss->cache->radius * test.dist,
- an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2826,7 +2769,7 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2849,8 +2792,8 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode)
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co,
- sqrt(test.dist),
- an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2890,7 +2833,7 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
mul_v3_fl(temp, displace);
add_v3_v3(fc, temp);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2913,8 +2856,8 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod
if (plane_trim(ss->cache, brush, val)) {
const float fade = bstrength * tex_strength(ss, brush, vd.co,
- sqrt(test.dist),
- an, vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
+ sqrtf(test.dist),
+ vd.no, vd.fno, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], val, fade);
@@ -2944,7 +2887,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
mul_v3_fl(offset, bstrength);
/* threaded loop over nodes */
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#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;
@@ -2956,8 +2899,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl
BKE_pbvh_vertex_iter_begin(ss->pbvh, nodes[n], vd, PBVH_ITER_UNIQUE) {
if (sculpt_brush_test_sq(&test, vd.co)) {
- const float fade = tex_strength(ss, brush, vd.co, sqrt(test.dist),
- ss->cache->sculpt_normal_symm, vd.no,
+ const float fade = tex_strength(ss, brush, vd.co, sqrtf(test.dist), vd.no,
vd.fno, vd.mask ? *vd.mask : 0.0f);
mul_v3_v3fl(proxy[vd.i], offset, fade);
@@ -3041,11 +2983,11 @@ static void sculpt_topology_update(Sculpt *sd, Object *ob, Brush *brush)
radius = ss->cache->radius * 1.25f;
data.radius_squared = radius * radius;
- data.original = ELEM4(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER) ? true : ss->cache->original;
BKE_pbvh_search_gather(ss->pbvh, sculpt_search_sphere_cb, &data, &nodes, &totnode);
@@ -3103,18 +3045,18 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush)
data.ss = ss;
data.sd = sd;
data.radius_squared = ss->cache->radius_squared;
- data.original = ELEM4(brush->sculpt_tool,
- SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_THUMB,
- SCULPT_TOOL_LAYER) ? true : ss->cache->original;
+ data.original = ELEM(brush->sculpt_tool,
+ SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_THUMB,
+ SCULPT_TOOL_LAYER) ? 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 */
if (totnode) {
float location[3];
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
sculpt_undo_push_node(ob, nodes[n],
brush->sculpt_tool == SCULPT_TOOL_MASK ?
@@ -3244,10 +3186,10 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob)
ss->cache->supports_gravity)
{
/* these brushes start from original coordinates */
- const bool use_orco = ELEM3(brush->sculpt_tool, SCULPT_TOOL_GRAB,
- SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
+ const bool use_orco = ELEM(brush->sculpt_tool, SCULPT_TOOL_GRAB,
+ SCULPT_TOOL_ROTATE, SCULPT_TOOL_THUMB);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
PBVHProxyNode *proxies;
@@ -3340,7 +3282,7 @@ static void sculpt_flush_stroke_deform(Sculpt *sd, Object *ob)
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (n = 0; n < totnode; n++) {
PBVHVertexIter vd;
@@ -3388,7 +3330,7 @@ static void calc_brushdata_symm(Sculpt *sd, StrokeCache *cache, const char symm,
/* XXX This reduces the length of the grab delta if it approaches the line of symmetry
* XXX However, a different approach appears to be needed */
#if 0
- if (sd->flags & SCULPT_SYMMETRY_FEATHER) {
+ if (sd->paint.symmetry_flags & SCULPT_SYMMETRY_FEATHER) {
float frac = 1.0f / max_overlap_count(sd);
float reduce = (feather - frac) / (1 - frac);
@@ -3448,7 +3390,7 @@ static void sculpt_fix_noise_tear(Sculpt *sd, Object *ob)
}
static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
- BrushActionFunc action)
+ BrushActionFunc action, UnifiedPaintSettings *ups)
{
Brush *brush = BKE_paint_brush(&sd->paint);
SculptSession *ss = ob->sculpt;
@@ -3458,7 +3400,7 @@ static void do_symmetrical_brush_actions(Sculpt *sd, Object *ob,
float feather = calc_symmetry_feather(sd, ss->cache);
- cache->bstrength = brush_strength(sd, cache, feather);
+ cache->bstrength = brush_strength(sd, cache, feather, ups);
cache->symmetry = symm;
/* symm is a bit combination of XYZ - 1 is mirror X; 2 is Y; 3 is XY; 4 is Z; 5 is XZ; 6 is YZ; 7 is XYZ */
@@ -3582,6 +3524,8 @@ 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);
}
@@ -3623,6 +3567,12 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
StrokeCache *cache = ss->cache;
#ifdef _OPENMP
+
+#if defined(__APPLE__)
+ cache->init_num_threads = BLI_system_thread_count();
+#else
+ cache->init_num_threads = omp_get_max_threads();
+#endif
/* If using OpenMP then create a number of threads two times the
* number of processor cores.
* Justification: Empirically I've found that two threads per
@@ -3631,13 +3581,12 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
#if defined(__APPLE__)
cache->num_threads = system_physical_thread_count();
#else
- cache->num_threads = omp_get_num_procs();
+ cache->num_threads = 2 * omp_get_num_procs();
#endif
}
else {
cache->num_threads = 1;
}
- cache->max_threads = omp_get_max_threads();
omp_set_num_threads(cache->num_threads);
#else
(void)sd;
@@ -3670,8 +3619,9 @@ static void sculpt_omp_start(Sculpt *sd, SculptSession *ss)
static void sculpt_omp_done(SculptSession *ss)
{
#ifdef _OPENMP
- omp_set_num_threads(ss->cache->max_threads);
+ omp_set_num_threads(ss->cache->init_num_threads);
#endif
+
if (ss->multires) {
int i;
@@ -3738,8 +3688,8 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
/* not very nice, but with current events system implementation
* we can't handle brush appearance inversion hotkey separately (sergey) */
- if (cache->invert) brush->flag |= BRUSH_INVERTED;
- else brush->flag &= ~BRUSH_INVERTED;
+ if (cache->invert) ups->draw_inverted = true;
+ else ups->draw_inverted = false;
/* Alt-Smooth */
if (cache->alt_smooth) {
@@ -3785,7 +3735,7 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
mul_m3_v3(mat, viewDir);
normalize_v3_v3(cache->true_view_normal, viewDir);
- cache->supports_gravity = (!ELEM3(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) &&
+ cache->supports_gravity = (!ELEM(brush->sculpt_tool, SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY) &&
(sd->gravity_factor > 0.0f));
/* get gravity vector in world space */
if (cache->supports_gravity) {
@@ -3843,10 +3793,10 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
cache->original = 1;
}
- if (ELEM9(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 (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 (!(brush->flag & BRUSH_ACCUMULATE)) {
cache->original = 1;
@@ -3855,11 +3805,12 @@ static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSessio
cache->first_time = 1;
- cache->vertex_rotation = 0;
- cache->num_vertex_turns = 0;
- cache->previous_vertex_rotation = 0;
- cache->init_dir_set = false;
-
+#define PIXEL_INPUT_THRESHHOLD 5
+ if (brush->sculpt_tool == SCULPT_TOOL_ROTATE)
+ cache->dial = BLI_dial_initialize(cache->initial_mouse, PIXEL_INPUT_THRESHHOLD);
+
+#undef PIXEL_INPUT_THRESHHOLD
+
sculpt_omp_start(sd, ss);
}
@@ -3873,10 +3824,10 @@ static void sculpt_update_brush_delta(UnifiedPaintSettings *ups, Object *ob, Bru
};
int tool = brush->sculpt_tool;
- if (ELEM5(tool,
- SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE,
- SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK,
- SCULPT_TOOL_THUMB))
+ if (ELEM(tool,
+ SCULPT_TOOL_GRAB, SCULPT_TOOL_NUDGE,
+ SCULPT_TOOL_CLAY_STRIPS, SCULPT_TOOL_SNAKE_HOOK,
+ SCULPT_TOOL_THUMB))
{
float grab_location[3], imat[4][4], delta[3], loc[3];
@@ -3997,16 +3948,9 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
cache->radius_squared = cache->radius * cache->radius;
if (brush->flag & BRUSH_ANCHORED) {
+ /* true location has been calculated as part of the stroke system already here */
if (brush->flag & BRUSH_EDGE_TO_EDGE) {
- float halfway[2];
- float out[3];
- halfway[0] = 0.5f * (cache->mouse[0] + cache->initial_mouse[0]);
- halfway[1] = 0.5f * (cache->mouse[1] + cache->initial_mouse[1]);
-
- if (sculpt_stroke_get_location(C, out, halfway)) {
- copy_v3_v3(cache->anchored_location, out);
- copy_v3_v3(cache->true_location, cache->anchored_location);
- }
+ RNA_float_get_array(ptr, "location", cache->true_location);
}
cache->radius = paint_calc_object_space_radius(cache->vc,
@@ -4020,48 +3964,7 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob,
sculpt_update_brush_delta(ups, ob, brush);
if (brush->sculpt_tool == SCULPT_TOOL_ROTATE) {
-#define PIXEL_INPUT_THRESHHOLD 5
-
- const float dx = cache->mouse[0] - cache->initial_mouse[0];
- const float dy = cache->mouse[1] - cache->initial_mouse[1];
-
- /* only update when we have enough precision, by having the mouse adequately away from center
- * may be better to convert to radial representation but square works for small values too*/
- if (fabsf(dx) > PIXEL_INPUT_THRESHHOLD && fabsf(dy) > PIXEL_INPUT_THRESHHOLD) {
- float mouse_angle;
- float dir[2] = {dx, dy};
- float cosval, sinval;
- normalize_v2(dir);
-
- if (!cache->init_dir_set) {
- copy_v2_v2(cache->initial_mouse_dir, dir);
- cache->init_dir_set = true;
- }
-
- /* calculate mouse angle between initial and final mouse position */
- cosval = dot_v2v2(dir, cache->initial_mouse_dir);
- sinval = cross_v2v2(dir, cache->initial_mouse_dir);
-
- /* clamp to avoid nans in acos */
- CLAMP(cosval, -1.0f, 1.0f);
- mouse_angle = (sinval > 0) ? acosf(cosval) : -acosf(cosval);
-
- /* change of sign, we passed the 180 degree threshold. This means we need to add a turn.
- * to distinguish between transition from 0 to -1 and -PI to +PI, use comparison with PI/2 */
- if ((mouse_angle * cache->previous_vertex_rotation < 0.0f) &&
- (fabsf(cache->previous_vertex_rotation) > (float)M_PI_2))
- {
- if (cache->previous_vertex_rotation < 0)
- cache->num_vertex_turns--;
- else
- cache->num_vertex_turns++;
- }
- cache->previous_vertex_rotation = mouse_angle;
-
- cache->vertex_rotation = -(mouse_angle + 2.0f * (float)M_PI * cache->num_vertex_turns) * cache->bstrength;
-
-#undef PIXEL_INPUT_THRESHHOLD
- }
+ cache->vertex_rotation = -BLI_dial_angle(cache->dial, cache->mouse) * cache->bstrength;
ups->draw_anchored = true;
copy_v2_v2(ups->anchored_initial_mouse, cache->initial_mouse);
@@ -4103,14 +4006,14 @@ static void sculpt_stroke_modifiers_check(const bContext *C, Object *ob)
typedef struct {
SculptSession *ss;
const float *ray_start, *ray_normal;
- int hit;
+ bool hit;
float dist;
- int original;
+ bool original;
} SculptRaycastData;
typedef struct {
const float *ray_start, *ray_normal;
- int hit;
+ bool hit;
float dist;
float detail;
} SculptDetailRaycastData;
@@ -4242,7 +4145,7 @@ static void sculpt_brush_init_tex(const Scene *scene, Sculpt *sd, SculptSession
sculpt_update_tex(scene, sd, ss);
}
-static int sculpt_brush_stroke_init(bContext *C, wmOperator *op)
+static bool sculpt_brush_stroke_init(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(C);
@@ -4398,10 +4301,10 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
}
if (sculpt_stroke_dynamic_topology(ss, brush)) {
- do_symmetrical_brush_actions(sd, ob, sculpt_topology_update);
+ do_symmetrical_brush_actions(sd, ob, sculpt_topology_update, ups);
}
- do_symmetrical_brush_actions(sd, ob, do_brush_action);
+ do_symmetrical_brush_actions(sd, ob, do_brush_action, ups);
sculpt_combine_proxies(sd, ob);
@@ -4451,8 +4354,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
/* Finished */
if (ss->cache) {
+ UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings;
Brush *brush = BKE_paint_brush(&sd->paint);
- brush->flag &= ~BRUSH_INVERTED;
+ ups->draw_inverted = false;
sculpt_stroke_modifiers_check(C, ob);
@@ -4473,7 +4377,7 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
/* update last stroke position */
ob->sculpt->last_stroke_valid = 1;
- ED_sculpt_get_average_stroke(ob, ob->sculpt->last_stroke);
+ ED_sculpt_stroke_get_average(ob, ob->sculpt->last_stroke);
sculpt_cache_free(ss->cache);
ss->cache = NULL;
@@ -4499,11 +4403,6 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
}
-#ifdef _OPENMP
- if (!(sd->flags & SCULPT_USE_OPENMP))
- omp_set_num_threads(BLI_system_thread_count()); /* set back to original logical corecount */
-#endif
-
sculpt_brush_exit_tex(sd);
}
@@ -4516,7 +4415,7 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
if (!sculpt_brush_stroke_init(C, op))
return OPERATOR_CANCELLED;
- stroke = paint_stroke_new(C, sculpt_stroke_get_location,
+ stroke = paint_stroke_new(C, op, sculpt_stroke_get_location,
sculpt_stroke_test_start,
sculpt_stroke_update_step, NULL,
sculpt_stroke_done, event->type);
@@ -4531,10 +4430,13 @@ static int sculpt_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_PASS_THROUGH;
}
+ if ((retval = op->type->modal(C, op, event)) == OPERATOR_FINISHED) {
+ paint_stroke_data_free(op);
+ return OPERATOR_FINISHED;
+ }
/* add modal handler */
WM_event_add_modal_handler(C, op);
- retval = op->type->modal(C, op, event);
OPERATOR_RETVAL_CHECK(retval);
BLI_assert(retval == OPERATOR_RUNNING_MODAL);
@@ -4546,7 +4448,7 @@ static int sculpt_brush_stroke_exec(bContext *C, wmOperator *op)
if (!sculpt_brush_stroke_init(C, op))
return OPERATOR_CANCELLED;
- op->customdata = paint_stroke_new(C, sculpt_stroke_get_location, sculpt_stroke_test_start,
+ op->customdata = paint_stroke_new(C, op, sculpt_stroke_get_location, sculpt_stroke_test_start,
sculpt_stroke_update_step, NULL, sculpt_stroke_done, 0);
/* frees op->customdata */
@@ -4577,13 +4479,6 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op)
static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
{
- static EnumPropertyItem stroke_mode_items[] = {
- {BRUSH_STROKE_NORMAL, "NORMAL", 0, "Normal", "Apply brush normally"},
- {BRUSH_STROKE_INVERT, "INVERT", 0, "Invert", "Invert action of brush for duration of stroke"},
- {BRUSH_STROKE_SMOOTH, "SMOOTH", 0, "Smooth", "Switch brush to smooth mode for duration of stroke"},
- {0}
- };
-
/* identifiers */
ot->name = "Sculpt";
ot->idname = "SCULPT_OT_brush_stroke";
@@ -4601,15 +4496,11 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot)
/* properties */
- RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
-
- RNA_def_enum(ot->srna, "mode", stroke_mode_items, BRUSH_STROKE_NORMAL,
- "Sculpt Stroke Mode",
- "Action taken when a sculpt stroke is made");
+ paint_stroke_operator_properties(ot);
RNA_def_boolean(ot->srna, "ignore_background_click", 0,
"Ignore Background Click",
- "Clicks on the background do not start the stroke");
+ "Clicks on the background do not start the stroke");
}
/**** Reset the copy of the mesh that is being sculpted on (currently just for the layer brush) ****/
@@ -4799,6 +4690,7 @@ void sculpt_dynamic_topology_disable(bContext *C,
sculpt_update_after_dynamic_topology_toggle(C);
}
+
static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *ob = CTX_data_active_object(C);
@@ -4819,26 +4711,79 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o
return OPERATOR_FINISHED;
}
+
+static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bool modifiers)
+{
+ uiPopupMenu *pup = uiPupMenuBegin(C, IFACE_("Warning!"), ICON_ERROR);
+ uiLayout *layout = uiPupMenuLayout(pup);
+
+ if (vdata) {
+ const char *msg_error = TIP_("Vertex Data Detected!");
+ const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata");
+ uiItemL(layout, msg_error, ICON_INFO);
+ uiItemL(layout, msg, ICON_NONE);
+ uiItemS(layout);
+ }
+
+ if (modifiers) {
+ const char *msg_error = TIP_("Generative Modifiers Detected!");
+ const char *msg = TIP_("Keeping the modifiers will increase polycount when returning to object mode");
+
+ uiItemL(layout, msg_error, ICON_INFO);
+ uiItemL(layout, msg, ICON_NONE);
+ uiItemS(layout);
+ }
+
+ uiItemFullO_ptr(layout, ot, IFACE_("OK"), ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0);
+
+ uiPupMenuEnd(C, pup);
+
+ return OPERATOR_CANCELLED;
+}
+
+
static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
Object *ob = CTX_data_active_object(C);
Mesh *me = ob->data;
SculptSession *ss = ob->sculpt;
- const char *msg = TIP_("Dynamic-topology sculpting will not preserve vertex colors, UVs, or other customdata");
if (!ss->bm) {
+ Scene *scene = CTX_data_scene(C);
+ ModifierData *md;
+ VirtualModifierData virtualModifierData;
int i;
+ bool vdata = false;
+ bool modifiers = false;
for (i = 0; i < CD_NUMTYPES; i++) {
- if (!ELEM7(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) &&
+ if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) &&
(CustomData_has_layer(&me->vdata, i) ||
CustomData_has_layer(&me->edata, i) ||
CustomData_has_layer(&me->fdata, i)))
{
- /* The mesh has customdata that will be lost, let the user confirm this is OK */
- return WM_operator_confirm_message(C, op, msg);
+ vdata = true;
+ break;
}
}
+
+ md = modifiers_getVirtualModifierList(ob, &virtualModifierData);
+
+ /* exception for shape keys because we can edit those */
+ for (; md; md = md->next) {
+ ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+ if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue;
+
+ if (mti->type == eModifierTypeType_Constructive) {
+ modifiers = true;
+ break;
+ }
+ }
+
+ if (vdata || modifiers) {
+ /* The mesh has customdata that will be lost, let the user confirm this is OK */
+ return dyntopo_warning_popup(C, op->type, vdata, modifiers);
+ }
}
return sculpt_dynamic_topology_toggle_exec(C, op);
@@ -5018,11 +4963,11 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
ts->sculpt->paint.flags |= PAINT_SHOW_BRUSH;
/* Make sure at least dyntopo subdivision is enabled */
- ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE;
+ ts->sculpt->flags |= SCULPT_DYNTOPO_SUBDIVIDE | SCULPT_DYNTOPO_COLLAPSE;
}
if (!ts->sculpt->detail_size) {
- ts->sculpt->detail_size = 30;
+ ts->sculpt->detail_size = 12;
}
if (ts->sculpt->constant_detail == 0.0f)
@@ -5041,6 +4986,15 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op)
BKE_sculpt_mask_layers_ensure(ob, mmd);
}
+ if (!(fabsf(ob->size[0] - ob->size[1]) < 1e-4f && fabsf(ob->size[1] - ob->size[2]) < 1e-4f)) {
+ BKE_report(op->reports, RPT_WARNING,
+ "Object has non-uniform scale, sculpting may be unpredictable");
+ }
+ else if (is_negative_m4(ob->obmat)) {
+ BKE_report(op->reports, RPT_WARNING,
+ "Object has negative scale, sculpting may be unpredictable");
+ }
+
BKE_paint_init(&ts->sculpt->paint, PAINT_CURSOR_SCULPT);
paint_cursor_start(C, sculpt_poll_view3d);
diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h
index cd79f525d82..a61f571fdf6 100644
--- a/source/blender/editors/sculpt_paint/sculpt_intern.h
+++ b/source/blender/editors/sculpt_paint/sculpt_intern.h
@@ -130,4 +130,11 @@ void sculpt_vertcos_to_key(Object *ob, KeyBlock *kb, float (*vertCos)[3]);
void sculpt_update_object_bounding_box(struct Object *ob);
+/* Setting zero so we can catch bugs in OpenMP/sculpt. */
+#ifdef DEBUG
+# define SCULPT_OMP_LIMIT 0
+#else
+# define SCULPT_OMP_LIMIT 4
+#endif
+
#endif
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 57e852db796..91f80a4fc40 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -62,7 +62,8 @@
#include "GPU_buffers.h"
-#include "ED_sculpt.h"
+#include "ED_paint.h"
+
#include "bmesh.h"
#include "paint_intern.h"
#include "sculpt_intern.h"
@@ -195,9 +196,9 @@ static int sculpt_undo_restore_hidden(bContext *C, DerivedMesh *dm,
for (i = 0; i < unode->totvert; i++) {
MVert *v = &mvert[unode->index[i]];
- int uval = BLI_BITMAP_GET(unode->vert_hidden, i);
+ int uval = BLI_BITMAP_TEST(unode->vert_hidden, i);
- BLI_BITMAP_MODIFY(unode->vert_hidden, i,
+ BLI_BITMAP_SET(unode->vert_hidden, i,
v->flag & ME_HIDE);
if (uval)
v->flag |= ME_HIDE;
@@ -290,7 +291,7 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C,
BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode);
-#pragma omp parallel for schedule(guided) if (sd->flags & SCULPT_USE_OPENMP)
+#pragma omp parallel for schedule(guided) if ((sd->flags & SCULPT_USE_OPENMP) && totnode > SCULPT_OMP_LIMIT)
for (i = 0; i < totnode; i++) {
BKE_pbvh_node_mark_redraw(nodes[i]);
}
@@ -526,9 +527,11 @@ static void sculpt_undo_free(ListBase *lb)
}
if (unode->mask)
MEM_freeN(unode->mask);
+
if (unode->bm_entry) {
BM_log_entry_drop(unode->bm_entry);
}
+
if (unode->bm_enter_totvert)
CustomData_free(&unode->bm_enter_vdata, unode->bm_enter_totvert);
if (unode->bm_enter_totedge)
@@ -540,6 +543,23 @@ static void sculpt_undo_free(ListBase *lb)
}
}
+static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptUndoNode *unode;
+
+ unode = lb->first;
+
+ if (unode && strcmp(unode->idname, ob->id.name) != 0) {
+ if (unode->bm_entry)
+ BM_log_cleanup_entry(unode->bm_entry);
+
+ return true;
+ }
+
+ return false;
+}
+
SculptUndoNode *sculpt_undo_get_node(PBVHNode *node)
{
ListBase *lb = undo_paint_push_get_list(UNDO_PAINT_MESH);
@@ -681,7 +701,7 @@ static void sculpt_undo_store_hidden(Object *ob, SculptUndoNode *unode)
BKE_pbvh_node_num_verts(pbvh, node, NULL, &allvert);
BKE_pbvh_node_get_verts(pbvh, node, &vert_indices, &mvert);
for (i = 0; i < allvert; i++) {
- BLI_BITMAP_MODIFY(unode->vert_hidden, i,
+ BLI_BITMAP_SET(unode->vert_hidden, i,
mvert[vert_indices[i]].flag & ME_HIDE);
}
}
@@ -859,7 +879,7 @@ SculptUndoNode *sculpt_undo_push_node(Object *ob, PBVHNode *node,
void sculpt_undo_push_begin(const char *name)
{
ED_undo_paint_push_begin(UNDO_PAINT_MESH, name,
- sculpt_undo_restore, sculpt_undo_free);
+ sculpt_undo_restore, sculpt_undo_free, sculpt_undo_cleanup);
}
void sculpt_undo_push_end(void)
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 797a881ce79..d90eaafa379 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -239,12 +239,14 @@ void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings
BKE_paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT);
- WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
- brush_drawcursor_uvsculpt, NULL);
+ settings->uvsculpt->paint.paint_cursor = WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
+ brush_drawcursor_uvsculpt, NULL);
}
else {
- if (settings->uvsculpt)
- settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH;
+ if (settings->uvsculpt) {
+ WM_paint_cursor_end(wm, settings->uvsculpt->paint.paint_cursor);
+ settings->uvsculpt->paint.paint_cursor = NULL;
+ }
}
}
@@ -271,7 +273,7 @@ static void HC_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata,
Temp_UVData *tmp_uvdata;
float diff[2];
int i;
- float radius_root = sqrt(radius);
+ float radius_root = sqrtf(radius);
Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
@@ -314,7 +316,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, sqrt(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength(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));
@@ -343,7 +345,7 @@ static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *scul
Temp_UVData *tmp_uvdata;
float diff[2];
int i;
- float radius_root = sqrt(radius);
+ float radius_root = sqrtf(radius);
Brush *brush = BKE_paint_brush(sculptdata->uvsculpt);
tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
@@ -378,7 +380,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, sqrt(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength(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];
@@ -432,7 +434,7 @@ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, const wmEvent *e
/* We will compare squares to save some computation */
radius = radius * radius;
- radius_root = sqrt(radius);
+ radius_root = sqrtf(radius);
/*
* Pinch Tool
@@ -453,7 +455,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, sqrt(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength(brush, sqrtf(dist), radius_root);
normalize_v2(diff);
sculptdata->uv[i].uv[0] -= strength * diff[0] * 0.001f;
@@ -561,7 +563,7 @@ static unsigned int uv_edge_hash(const void *key)
BLI_ghashutil_uinthash(edge->uv1));
}
-static int uv_edge_compare(const void *a, const void *b)
+static bool uv_edge_compare(const void *a, const void *b)
{
UvEdge *edge1 = (UvEdge *)a;
UvEdge *edge2 = (UvEdge *)b;
@@ -801,7 +803,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
aspectRatio = width / (float)height;
radius /= (width * zoomx);
radius = radius * radius;
- radius_root = sqrt(radius);
+ radius_root = sqrtf(radius);
/* Allocate selection stack */
data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke), "uv_sculpt_initial_stroke");
@@ -827,7 +829,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, sqrt(dist), radius_root);
+ strength = alpha * BKE_brush_curve_strength(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/space_action/CMakeLists.txt b/source/blender/editors/space_action/CMakeLists.txt
index e0dc2709cf3..96a1e74c882 100644
--- a/source/blender/editors/space_action/CMakeLists.txt
+++ b/source/blender/editors/space_action/CMakeLists.txt
@@ -22,10 +22,12 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -42,4 +44,6 @@ set(SRC
action_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_action "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_action/SConscript b/source/blender/editors/space_action/SConscript
index 2776bd2989a..2e2081b3c6e 100644
--- a/source/blender/editors/space_action/SConscript
+++ b/source/blender/editors/space_action/SConscript
@@ -29,16 +29,20 @@ Import ('env')
sources = env.Glob('*.c')
+defs = env['BF_GL_DEFINITIONS']
+
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
incs = ' '.join(incs)
-env.BlenderLib ( 'bf_editors_space_action', sources, Split(incs), [], libtype=['core'], priority=[40] )
+env.BlenderLib ( 'bf_editors_space_action', sources, Split(incs), defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c
index f15bbe0d2f1..335949e8495 100644
--- a/source/blender/editors/space_action/action_draw.c
+++ b/source/blender/editors/space_action/action_draw.c
@@ -139,7 +139,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* free tempolary channels */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ************************************************************************* */
@@ -219,7 +219,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
if (acf->has_setting(ac, ale, ACHANNEL_SETTING_SELECT))
sel = ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT);
- if (ELEM3(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
+ if (ELEM(ac->datatype, ANIMCONT_ACTION, ANIMCONT_DOPESHEET, ANIMCONT_SHAPEKEY)) {
switch (ale->type) {
case ANIMTYPE_SUMMARY:
{
@@ -346,7 +346,7 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar)
}
/* free tempolary channels used for drawing */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* black line marking 'current frame' for Time-Slide transform mode */
if (saction->flag & SACTION_MOVING) {
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 92e727fc2d7..091d3fe56b4 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -299,7 +299,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
}
/* free memory */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
else {
/* set default range */
@@ -362,10 +362,12 @@ void ACTION_OT_previewrange_set(wmOperatorType *ot)
/* ****************** View-All Operator ****************** */
-/* Find the extents of the active channel
- * > min: (float) bottom y-extent of channel
- * > max: (float) top y-extent of channel
- * > returns: success of finding a selected channel
+/**
+ * Find the extents of the active channel
+ *
+ * \param[out] min Bottom y-extent of channel
+ * \param[out] max Top y-extent of channel
+ * \return Success of finding a selected channel
*/
static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, float *max)
{
@@ -410,7 +412,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min,
}
/* free all temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return (found != 0);
}
@@ -536,7 +538,7 @@ static short copy_action_keys(bAnimContext *ac)
ok = copy_animedit_keys(ac, &anim_data);
/* clean up */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return ok;
}
@@ -561,9 +563,9 @@ static short paste_action_keys(bAnimContext *ac,
/* paste keyframes */
ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode);
-
+
/* clean up */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return ok;
}
@@ -640,10 +642,7 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
}
-
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
+
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -718,9 +717,12 @@ static void insert_action_keys(bAnimContext *ac, short mode)
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;
}
-
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -741,10 +743,7 @@ static int actkeys_insertkey_exec(bContext *C, wmOperator *op)
/* insert keyframes */
insert_action_keys(&ac, mode);
-
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
+
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
@@ -795,10 +794,12 @@ static void duplicate_action_keys(bAnimContext *ac)
ED_masklayer_frames_duplicate((MaskLayer *)ale->data);
else
BLI_assert(0);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
-
- /* free filtered list */
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -813,11 +814,7 @@ static int actkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
/* duplicate keyframes */
duplicate_action_keys(&ac);
-
- /* validate keyframes after editing */
- if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
- ANIM_editkeyframes_refresh(&ac);
-
+
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
@@ -854,40 +851,49 @@ static bool delete_action_keys(bAnimContext *ac)
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
- bool changed = false;
-
+ bool changed_final = false;
+
/* filter data */
if (ELEM(ac->datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
else
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_FOREDIT /*| ANIMFILTER_CURVESONLY*/ | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
-
+
/* loop through filtered data and delete selected keys */
for (ale = anim_data.first; ale; ale = ale->next) {
+ bool changed = false;
+
if (ale->type == ANIMTYPE_GPLAYER) {
- changed |= ED_gplayer_frames_delete((bGPDlayer *)ale->data);
+ changed = ED_gplayer_frames_delete((bGPDlayer *)ale->data);
}
else if (ale->type == ANIMTYPE_MASKLAYER) {
- changed |= ED_masklayer_frames_delete((MaskLayer *)ale->data);
+ changed = ED_masklayer_frames_delete((MaskLayer *)ale->data);
}
else {
FCurve *fcu = (FCurve *)ale->key_data;
AnimData *adt = ale->adt;
/* delete selected keyframes only */
- changed |= delete_fcurve_keys(fcu);
+ changed = delete_fcurve_keys(fcu);
/* Only delete curve too if it won't be doing anything anymore */
- if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0))
+ if ((fcu->totvert == 0) && (list_has_suitable_fmodifier(&fcu->modifiers, 0, FMI_TYPE_GENERATE_CURVE) == 0)) {
ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
+ ale->key_data = NULL;
+ }
+ }
+
+ if (changed) {
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ changed_final = true;
}
}
-
- /* free filtered list */
- BLI_freelistN(&anim_data);
- return changed;
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+
+ return changed_final;
}
/* ------------------- */
@@ -904,10 +910,6 @@ static int actkeys_delete_exec(bContext *C, wmOperator *UNUSED(op))
if (!delete_action_keys(&ac))
return OPERATOR_CANCELLED;
- /* validate keyframes after editing */
- if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
@@ -943,11 +945,14 @@ static void clean_action_keys(bAnimContext *ac, float thresh)
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and clean curves */
- for (ale = anim_data.first; ale; ale = ale->next)
+ for (ale = anim_data.first; ale; ale = ale->next) {
clean_fcurve((FCurve *)ale->key_data, thresh);
-
- /* free temp data */
- BLI_freelistN(&anim_data);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -969,9 +974,6 @@ static int actkeys_clean_exec(bContext *C, wmOperator *op)
/* clean keyframes */
clean_action_keys(&ac, thresh);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1011,11 +1013,14 @@ static void sample_action_keys(bAnimContext *ac)
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and add keys between selected keyframes on every frame */
- for (ale = anim_data.first; ale; ale = ale->next)
+ for (ale = anim_data.first; ale; ale = ale->next) {
sample_fcurve((FCurve *)ale->key_data);
-
- /* admin and redraws */
- BLI_freelistN(&anim_data);
+
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1033,9 +1038,6 @@ static int actkeys_sample_exec(bContext *C, wmOperator *UNUSED(op))
/* sample keyframes */
sample_action_keys(&ac);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1118,10 +1120,12 @@ static void setexpo_action_keys(bAnimContext *ac, short mode)
}
}
}
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
-
- /* cleanup */
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1143,9 +1147,6 @@ static int actkeys_expo_exec(bContext *C, wmOperator *op)
/* set handle type */
setexpo_action_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1188,11 +1189,14 @@ static void setipo_action_keys(bAnimContext *ac, short mode)
/* loop through setting BezTriple interpolation
* Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
*/
- for (ale = anim_data.first; ale; ale = ale->next)
+ for (ale = anim_data.first; ale; ale = ale->next) {
ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
-
- /* cleanup */
- BLI_freelistN(&anim_data);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1214,9 +1218,6 @@ static int actkeys_ipo_exec(bContext *C, wmOperator *op)
/* set handle type */
setipo_action_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1268,11 +1269,13 @@ static void sethandles_action_keys(bAnimContext *ac, short mode)
if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
/* change type of selected handles */
ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
}
-
- /* cleanup */
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1294,9 +1297,6 @@ static int actkeys_handletype_exec(bContext *C, wmOperator *op)
/* set handle type */
sethandles_action_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1339,11 +1339,14 @@ static void setkeytype_action_keys(bAnimContext *ac, short mode)
/* loop through setting BezTriple interpolation
* Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
*/
- for (ale = anim_data.first; ale; ale = ale->next)
+ for (ale = anim_data.first; ale; ale = ale->next) {
ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, NULL);
-
- /* cleanup */
- BLI_freelistN(&anim_data);
+
+ ale->update |= ANIM_UPDATE_DEPS | ANIM_UPDATE_HANDLES;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1365,9 +1368,6 @@ static int actkeys_keytype_exec(bContext *C, wmOperator *op)
/* set handle type */
setkeytype_action_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1436,7 +1436,7 @@ static int actkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_calc_average, NULL);
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set the new current frame value, based on the average time */
if (ked.i1) {
@@ -1525,9 +1525,12 @@ static void snap_action_keys(bAnimContext *ac, short mode)
else {
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
}
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
-
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1547,10 +1550,6 @@ static int actkeys_snap_exec(bContext *C, wmOperator *op)
/* snap keyframes */
snap_action_keys(&ac, mode);
- /* validate keyframes after editing */
- if (!ELEM(ac.datatype, ANIMCONT_GPENCIL, ANIMCONT_MASK))
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1635,9 +1634,12 @@ static void mirror_action_keys(bAnimContext *ac, short mode)
// snap_gplayer_frames(ale->data, mode);
else
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
-
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1661,9 +1663,6 @@ static int actkeys_mirror_exec(bContext *C, wmOperator *op)
/* mirror keyframes */
mirror_action_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c
index 93cd94ed892..b99419dec20 100644
--- a/source/blender/editors/space_action/action_ops.c
+++ b/source/blender/editors/space_action/action_ops.c
@@ -224,6 +224,9 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap)
*/
WM_keymap_add_item(keymap, "ANIM_OT_channels_editable_toggle", TABKEY, KM_PRESS, 0, 0);
+ /* 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);
+
/* transform system */
transform_keymap_for_space(keyconf, keymap, SPACE_ACTION);
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 1e89b304279..ddfca98a119 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -142,7 +142,7 @@ static void deselect_action_keys(bAnimContext *ac, short test, short sel)
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -294,7 +294,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -442,7 +442,7 @@ static void markers_selectkeys_between(bAnimContext *ac)
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
@@ -477,7 +477,7 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
for (ale = anim_data.first; ale; ale = ale->next)
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL);
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
break;
case ACTKEYS_COLUMNSEL_CFRA: /* current frame */
@@ -534,7 +534,7 @@ static void columnselect_action_keys(bAnimContext *ac, short mode)
/* free elements */
BLI_freelistN(&ked.list);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -612,7 +612,7 @@ static int actkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -675,7 +675,7 @@ static void select_moreless_action_keys(bAnimContext *ac, short mode)
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ----------------- */
@@ -838,7 +838,7 @@ static void actkeys_select_leftright(bAnimContext *ac, short leftright, short se
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ----------------- */
@@ -975,7 +975,7 @@ static void actkeys_mselect_single(bAnimContext *ac, bAnimListElem *ale, short s
}
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
else {
ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL);
@@ -1029,7 +1029,7 @@ static void actkeys_mselect_column(bAnimContext *ac, short select_mode, float se
/* free elements */
BLI_freelistN(&ked.list);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* option 4) select all keyframes in same channel */
@@ -1066,7 +1066,7 @@ static void actkeys_mselect_channel_only(bAnimContext *ac, bAnimListElem *ale, s
}
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
else {
ANIM_animchannel_keyframes_loop(NULL, ac->ads, ale, NULL, select_cb, NULL);
@@ -1086,8 +1086,9 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
View2D *v2d = &ac->ar->v2d;
bDopeSheet *ads = NULL;
int channel_index;
- short found = 0;
- float selx = 0.0f;
+ bool found = false;
+ float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */
+ float selx = 0.0f; /* frame of keyframe under mouse */
float x, y;
rctf rectf;
@@ -1112,7 +1113,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
if (ale == NULL) {
/* channel not found */
printf("Error: animation channel (index = %d) not found in mouse_action_keys()\n", channel_index);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return;
}
else {
@@ -1179,7 +1180,8 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
* requiring to map each frame once again...
*/
selx = BKE_nla_tweakedit_remap(adt, ak->cfra, NLATIME_CONVERT_UNMAP);
- found = 1;
+ frame = ak->cfra;
+ found = true;
break;
}
else if (ak->cfra < rectf.xmin)
@@ -1195,7 +1197,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
BLI_dlrbTree_free(&anim_keys);
/* free list of channels, since it's not used anymore */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* for replacing selection, firstly need to clear existing selection */
@@ -1258,8 +1260,11 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_
if (found) {
/* apply selection to keyframes */
if (column) {
- /* select all keyframes in the same frame as the one we hit on the active channel */
- actkeys_mselect_column(ac, select_mode, selx);
+ /* select all keyframes in the same frame as the one we hit on the active channel
+ * [T41077]: "frame" not "selx" here (i.e. no NLA corrections yet) as the code here
+ * does that itself again as it needs to work on multiple datablocks
+ */
+ actkeys_mselect_column(ac, select_mode, frame);
}
else if (same_channel) {
/* select all keyframes in the active channel */
diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c
index 69eeac69e85..7ca8968a705 100644
--- a/source/blender/editors/space_action/space_action.c
+++ b/source/blender/editors/space_action/space_action.c
@@ -476,7 +476,14 @@ static void action_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
break;
case NC_ANIMATION:
switch (wmn->data) {
- case ND_KEYFRAME:
+ case ND_ANIMCHAN: /* set of visible animchannels changed */
+ /* NOTE: for now, this should usually just mean that the filters changed
+ * It may be better if we had a dedicated flag for that though
+ */
+ ED_region_tag_redraw(ar);
+ break;
+
+ case ND_KEYFRAME: /* new keyframed added -> active action may have changed */
//saction->flag |= SACTION_TEMP_NEEDCHANSYNC;
ED_region_tag_redraw(ar);
break;
diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c
index 83040a26480..c8431d58bf5 100644
--- a/source/blender/editors/space_api/spacetypes.c
+++ b/source/blender/editors/space_api/spacetypes.c
@@ -53,6 +53,7 @@
#include "ED_mesh.h"
#include "ED_node.h"
#include "ED_object.h"
+#include "ED_paint.h"
#include "ED_physics.h"
#include "ED_render.h"
#include "ED_screen.h"
@@ -60,6 +61,7 @@
#include "ED_space_api.h"
#include "ED_sound.h"
#include "ED_uvedit.h"
+#include "ED_view3d.h"
#include "ED_mball.h"
#include "ED_logic.h"
#include "ED_clip.h"
@@ -129,8 +131,17 @@ void ED_spacetypes_init(void)
type->operatortypes();
}
- /* Macros's must go last since they reference other operators
- * maybe we'll need to have them go after python operators too? */
+ /* register internal render callbacks */
+ ED_render_internal_init();
+}
+
+void ED_spacemacros_init(void)
+{
+ const ListBase *spacetypes;
+ SpaceType *type;
+
+ /* Macros's must go last since they reference other operators.
+ * We need to have them go after python operators too */
ED_operatormacros_armature();
ED_operatormacros_mesh();
ED_operatormacros_metaball();
@@ -143,6 +154,7 @@ void ED_spacetypes_init(void)
ED_operatormacros_curve();
ED_operatormacros_mask();
ED_operatormacros_sequencer();
+ ED_operatormacros_paint();
/* register dropboxes (can use macros) */
spacetypes = BKE_spacetypes_list();
@@ -150,9 +162,6 @@ void ED_spacetypes_init(void)
if (type->dropboxes)
type->dropboxes();
}
-
- /* register internal render callbacks */
- ED_render_internal_init();
}
/* called in wm.c */
diff --git a/source/blender/editors/space_buttons/CMakeLists.txt b/source/blender/editors/space_buttons/CMakeLists.txt
index 9e045a39a0c..01a099e3701 100644
--- a/source/blender/editors/space_buttons/CMakeLists.txt
+++ b/source/blender/editors/space_buttons/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -46,6 +48,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
diff --git a/source/blender/editors/space_buttons/SConscript b/source/blender/editors/space_buttons/SConscript
index 61f9b6f496e..07fe17e302b 100644
--- a/source/blender/editors/space_buttons/SConscript
+++ b/source/blender/editors/space_buttons/SConscript
@@ -31,12 +31,14 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../bmesh',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -44,7 +46,8 @@ incs = [
'../../windowmanager',
]
incs = ' '.join(incs)
-defs = []
+
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c
index a00aac12fba..524a42ba388 100644
--- a/source/blender/editors/space_buttons/buttons_context.c
+++ b/source/blender/editors/space_buttons/buttons_context.c
@@ -55,6 +55,7 @@
#include "BKE_particle.h"
#include "BKE_screen.h"
#include "BKE_texture.h"
+#include "BKE_linestyle.h"
#include "RNA_access.h"
@@ -153,7 +154,7 @@ static int buttons_context_path_linestyle(ButsContextPath *path)
/* if we have a scene, use the lineset's linestyle */
else if (buttons_context_path_scene(path)) {
scene = path->ptr[path->len - 1].data;
- linestyle = CTX_data_linestyle_from_scene(scene);
+ linestyle = BKE_linestyle_active_from_scene(scene);
if (linestyle) {
RNA_id_pointer_create(&linestyle->id, &path->ptr[path->len]);
path->len++;
@@ -199,7 +200,7 @@ static int buttons_context_path_data(ButsContextPath *path, int type)
/* if we already have a data, we're done */
if (RNA_struct_is_a(ptr->type, &RNA_Mesh) && (type == -1 || type == OB_MESH)) return 1;
- else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM3(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
+ else if (RNA_struct_is_a(ptr->type, &RNA_Curve) && (type == -1 || ELEM(type, OB_CURVE, OB_SURF, OB_FONT))) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_Armature) && (type == -1 || type == OB_ARMATURE)) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_MetaBall) && (type == -1 || type == OB_MBALL)) return 1;
else if (RNA_struct_is_a(ptr->type, &RNA_Lattice) && (type == -1 || type == OB_LATTICE)) return 1;
@@ -229,14 +230,14 @@ static int buttons_context_path_modifier(ButsContextPath *path)
if (buttons_context_path_object(path)) {
ob = path->ptr[path->len - 1].data;
- if (ob && ELEM5(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
+ if (ob && ELEM(ob->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_LATTICE))
return 1;
}
return 0;
}
-static int buttons_context_path_material(ButsContextPath *path, int for_texture)
+static int buttons_context_path_material(ButsContextPath *path, bool for_texture, bool new_shading)
{
Object *ob;
PointerRNA *ptr = &path->ptr[path->len - 1];
@@ -257,11 +258,14 @@ static int buttons_context_path_material(ButsContextPath *path, int for_texture)
if (for_texture && give_current_material_texture_node(ma))
return 1;
-
- ma = give_node_material(ma);
- if (ma) {
- RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
- path->len++;
+
+ if (!new_shading) {
+ /* Only try to get mat from node in case of old shading system (see T40331). */
+ ma = give_node_material(ma);
+ if (ma) {
+ RNA_id_pointer_create(&ma->id, &path->ptr[path->len]);
+ path->len++;
+ }
}
return 1;
}
@@ -411,7 +415,7 @@ static int buttons_context_path_texture(ButsContextPath *path, ButsContextTextur
if (GS(id->name) == ID_BR)
buttons_context_path_brush(path);
else if (GS(id->name) == ID_MA)
- buttons_context_path_material(path, 0);
+ buttons_context_path_material(path, false, true);
else if (GS(id->name) == ID_WO)
buttons_context_path_world(path);
else if (GS(id->name) == ID_LA)
@@ -480,7 +484,7 @@ static int buttons_context_path_texture(ButsContextPath *path, ButsContextTextur
}
}
/* try material */
- else if ((path->tex_ctx == SB_TEXC_MATERIAL) && buttons_context_path_material(path, 1)) {
+ else if ((path->tex_ctx == SB_TEXC_MATERIAL) && buttons_context_path_material(path, true, false)) {
ma = path->ptr[path->len - 1].data;
if (ma) {
@@ -609,7 +613,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma
found = buttons_context_path_particle(path);
break;
case BCONTEXT_MATERIAL:
- found = buttons_context_path_material(path, 0);
+ found = buttons_context_path_material(path, false, (sbuts->texuser != NULL));
break;
case BCONTEXT_TEXTURE:
found = buttons_context_path_texture(path, sbuts->texuser);
@@ -634,7 +638,7 @@ static int buttons_shading_context(const bContext *C, int mainb)
{
Object *ob = CTX_data_active_object(C);
- if (ELEM3(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
+ if (ELEM(mainb, BCONTEXT_MATERIAL, BCONTEXT_WORLD, BCONTEXT_TEXTURE))
return 1;
if (mainb == BCONTEXT_DATA && ob && ELEM(ob->type, OB_LAMP, OB_CAMERA))
return 1;
@@ -1116,7 +1120,7 @@ void buttons_context_draw(const bContext *C, uiLayout *layout)
name = RNA_struct_name_get_alloc(ptr, namebuf, sizeof(namebuf), NULL);
if (name) {
- if (!ELEM3(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene)
+ if (!ELEM(sbuts->mainb, BCONTEXT_RENDER, BCONTEXT_SCENE, BCONTEXT_RENDER_LAYER) && ptr->type == &RNA_Scene)
uiItemLDrag(row, ptr, "", icon); /* save some space */
else
uiItemLDrag(row, ptr, name, icon);
diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c
index c0837b627b3..b651d684bf6 100644
--- a/source/blender/editors/space_buttons/buttons_ops.c
+++ b/source/blender/editors/space_buttons/buttons_ops.c
@@ -239,6 +239,8 @@ void BUTTONS_OT_file_browse(wmOperatorType *ot)
ot->exec = file_browse_exec;
ot->cancel = file_browse_cancel;
+ ot->flag |= OPTYPE_UNDO;
+
/* properties */
WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
@@ -257,6 +259,8 @@ void BUTTONS_OT_directory_browse(wmOperatorType *ot)
ot->exec = file_browse_exec;
ot->cancel = file_browse_cancel;
+ ot->flag |= OPTYPE_UNDO;
+
/* properties */
WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE,
WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY);
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index c558d811693..020d477fc39 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -53,8 +53,8 @@
#include "DNA_world_types.h"
#include "DNA_linestyle_types.h"
-
#include "BKE_context.h"
+#include "BKE_linestyle.h"
#include "BKE_material.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
@@ -352,7 +352,7 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
ob = (scene->basact) ? scene->basact->object : NULL;
wrld = scene->world;
brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
- linestyle = CTX_data_linestyle_from_scene(scene);
+ linestyle = BKE_linestyle_active_from_scene(scene);
}
if (ob && ob->type == OB_LAMP && !la)
@@ -370,7 +370,7 @@ static void buttons_texture_users_from_context(ListBase *users, const bContext *
if (wrld && !limited_mode)
buttons_texture_users_find_nodetree(users, &wrld->id, wrld->nodetree, "World");
if (linestyle && !limited_mode)
- buttons_texture_users_find_nodetree(users, &linestyle->id, linestyle->nodetree, "LineStyle");
+ buttons_texture_users_find_nodetree(users, &linestyle->id, linestyle->nodetree, "Line Style");
if (ob) {
ParticleSystem *psys = psys_get_current(ob);
@@ -442,7 +442,7 @@ void buttons_texture_context_compute(const bContext *C, SpaceButs *sbuts)
set_texture_context(C, sbuts);
- if (!(BKE_scene_use_new_shading_nodes(scene) || (sbuts->texture_context == SB_TEXC_OTHER))) {
+ if (!((sbuts->texture_context == SB_TEXC_OTHER) || BKE_scene_use_new_shading_nodes(scene))) {
if (ct) {
BLI_freelistN(&ct->users);
MEM_freeN(ct);
diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c
index 1257dcb5e4c..4d62f528915 100644
--- a/source/blender/editors/space_buttons/space_buttons.c
+++ b/source/blender/editors/space_buttons/space_buttons.c
@@ -233,6 +233,10 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
buttons_area_redraw(sa, BCONTEXT_RENDER);
buttons_area_redraw(sa, BCONTEXT_RENDER_LAYER);
break;
+ case ND_WORLD:
+ buttons_area_redraw(sa, BCONTEXT_WORLD);
+ sbuts->preview = 1;
+ break;
case ND_FRAME:
/* any buttons area can have animated properties so redraw all */
ED_area_tag_redraw(sa);
@@ -358,7 +362,7 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *
case NC_ANIMATION:
switch (wmn->data) {
case ND_KEYFRAME:
- if (wmn->action == NA_EDITED)
+ if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
ED_area_tag_redraw(sa);
break;
}
diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt
index 7689aa28169..4659e612b41 100644
--- a/source/blender/editors/space_clip/CMakeLists.txt
+++ b/source/blender/editors/space_clip/CMakeLists.txt
@@ -27,11 +27,12 @@ set(INC
../../blenfont
../../blenlib
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
- ../../gpu
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -56,6 +57,8 @@ set(SRC
clip_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/space_clip/SConscript b/source/blender/editors/space_clip/SConscript
index d4483eda6e3..8fec4ebf0fa 100644
--- a/source/blender/editors/space_clip/SConscript
+++ b/source/blender/editors/space_clip/SConscript
@@ -28,10 +28,13 @@
Import ('env')
sources = env.Glob('*.c')
-defs = []
+
+defs = env['BF_GL_DEFINITIONS']
+
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index cda46d2a9c2..889613b5d13 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -84,8 +84,8 @@ void ED_clip_buttons_register(ARegionType *art)
strcpy(pt->idname, "CLIP_PT_gpencil");
strcpy(pt->label, N_("Grease Pencil"));
strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = gpencil_panel_standard_header;
- pt->draw = gpencil_panel_standard;
+ pt->draw_header = ED_gpencil_panel_standard_header;
+ pt->draw = ED_gpencil_panel_standard;
pt->flag |= PNL_DEFAULT_CLOSED;
pt->poll = clip_grease_pencil_panel_poll;
BLI_addtail(&art->paneltypes, pt);
diff --git a/source/blender/editors/space_clip/clip_dopesheet_ops.c b/source/blender/editors/space_clip/clip_dopesheet_ops.c
index 573b6bc9276..7ae5eda7139 100644
--- a/source/blender/editors/space_clip/clip_dopesheet_ops.c
+++ b/source/blender/editors/space_clip/clip_dopesheet_ops.c
@@ -93,6 +93,7 @@ static int dopesheet_select_channel_exec(bContext *C, wmOperator *op)
float location[2];
const bool extend = RNA_boolean_get(op->ptr, "extend");
int current_channel_index = 0, channel_index;
+ const bool show_selected_only = (dopesheet->flag & TRACKING_DOPE_SELECTED_ONLY) != 0;
RNA_float_get_array(op->ptr, "location", location);
channel_index = -(location[1] - (CHANNEL_FIRST + CHANNEL_HEIGHT_HALF)) / CHANNEL_STEP;
@@ -110,6 +111,9 @@ static int dopesheet_select_channel_exec(bContext *C, wmOperator *op)
tracking->act_track = track;
BKE_tracking_track_select(tracksbase, track, TRACK_AREA_ALL, true);
}
+ else if (show_selected_only == false) {
+ BKE_tracking_track_deselect(track, TRACK_AREA_ALL);
+ }
}
else if (!extend)
track->flag &= ~TRACK_DOPE_SEL;
diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c
index 9d413e81ea8..a35251e71ef 100644
--- a/source/blender/editors/space_clip/clip_draw.c
+++ b/source/blender/editors/space_clip/clip_draw.c
@@ -1595,21 +1595,7 @@ static void draw_distortion(SpaceClip *sc, ARegion *ar, MovieClip *clip,
}
}
- if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking);
-
- if (track) {
- int framenr = ED_space_clip_get_clip_frame_number(sc);
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- offsx = marker->pos[0];
- offsy = marker->pos[1];
-
- gpd = track->gpd;
- }
-
- }
- else {
+ if (sc->gpencil_src != SC_GPENCIL_SRC_TRACK) {
gpd = clip->gpd;
}
@@ -1728,7 +1714,7 @@ void clip_draw_main(const bContext *C, SpaceClip *sc, ARegion *ar)
smat[1][1] = 1.0f / height;
invert_m4_m4(ismat, smat);
- mul_serie_m4(sc->unistabmat, smat, sc->stabmat, ismat, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(sc->unistabmat, smat, sc->stabmat, ismat);
}
}
else if ((sc->flag & SC_MUTE_FOOTAGE) == 0) {
@@ -1778,13 +1764,15 @@ void clip_draw_grease_pencil(bContext *C, int onlyv2d)
return;
if (onlyv2d) {
- /* if manual calibration is used then grease pencil data is already
- * drawn in draw_distortion */
- if ((sc->flag & SC_MANUAL_CALIBRATION) == 0) {
+ bool is_track_source = sc->gpencil_src == SC_GPENCIL_SRC_TRACK;
+ /* if manual calibration is used then grease pencil data
+ * associated with the clip is already drawn in draw_distortion
+ */
+ if ((sc->flag & SC_MANUAL_CALIBRATION) == 0 || is_track_source) {
glPushMatrix();
glMultMatrixf(sc->unistabmat);
- if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
+ if (is_track_source) {
MovieTrackingTrack *track = BKE_tracking_track_get_active(&sc->clip->tracking);
if (track) {
@@ -1795,12 +1783,12 @@ void clip_draw_grease_pencil(bContext *C, int onlyv2d)
}
}
- draw_gpencil_2dimage(C);
+ ED_gpencil_draw_2dimage(C);
glPopMatrix();
}
}
else {
- draw_gpencil_view2d(C, 0);
+ ED_gpencil_draw_view2d(C, 0);
}
}
diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c
index b7860643e1a..f25f035db32 100644
--- a/source/blender/editors/space_clip/clip_editor.c
+++ b/source/blender/editors/space_clip/clip_editor.c
@@ -48,7 +48,7 @@
#include "BLI_fileops.h"
#include "BLI_math.h"
#include "BLI_rect.h"
-#include "BLI_threads.h"
+#include "BLI_task.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -620,11 +620,6 @@ typedef struct PrefetchQueue {
float *progress;
} PrefetchQueue;
-typedef struct PrefetchThread {
- MovieClip *clip;
- PrefetchQueue *queue;
-} PrefetchThread;
-
/* check whether pre-fetching is allowed */
static bool check_prefetch_break(void)
{
@@ -757,15 +752,15 @@ static unsigned char *prefetch_thread_next_frame(PrefetchQueue *queue, MovieClip
return mem;
}
-static void *do_prefetch_thread(void *data_v)
+static void prefetch_task_func(TaskPool *pool, void *task_data, int UNUSED(threadid))
{
- PrefetchThread *data = (PrefetchThread *) data_v;
- MovieClip *clip = data->clip;
+ PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_userdata(pool);
+ MovieClip *clip = (MovieClip *)task_data;
unsigned char *mem;
size_t size;
int current_frame;
- while ((mem = prefetch_thread_next_frame(data->queue, data->clip, &size, &current_frame))) {
+ while ((mem = prefetch_thread_next_frame(queue, clip, &size, &current_frame))) {
ImBuf *ibuf;
MovieClipUser user = {0};
int flag = IB_rect | IB_alphamode_detect;
@@ -773,17 +768,17 @@ static void *do_prefetch_thread(void *data_v)
char *colorspace_name = NULL;
user.framenr = current_frame;
- user.render_size = data->queue->render_size;
- user.render_flag = data->queue->render_flag;
+ user.render_size = queue->render_size;
+ user.render_flag = queue->render_flag;
/* Proxies are stored in the display space. */
- if (data->queue->render_flag & MCLIP_USE_PROXY) {
+ if (queue->render_flag & MCLIP_USE_PROXY) {
colorspace_name = clip->colorspace_settings.name;
}
ibuf = IMB_ibImageFromMemory(mem, size, flag, colorspace_name, "prefetch frame");
- result = BKE_movieclip_put_frame_if_possible(data->clip, &user, ibuf);
+ result = BKE_movieclip_put_frame_if_possible(clip, &user, ibuf);
IMB_freeImBuf(ibuf);
@@ -791,27 +786,20 @@ static void *do_prefetch_thread(void *data_v)
if (!result) {
/* no more space in the cache, stop reading frames */
- *data->queue->stop = 1;
+ *queue->stop = 1;
break;
}
}
-
- return NULL;
}
static void start_prefetch_threads(MovieClip *clip, int start_frame, int current_frame, int end_frame,
short render_size, short render_flag, short *stop, short *do_update,
float *progress)
{
- ListBase threads;
PrefetchQueue queue;
- PrefetchThread *handles;
- int tot_thread = BLI_system_thread_count();
- int i;
-
- /* reserve one thread for the interface */
- if (tot_thread > 1)
- tot_thread--;
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
+ int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
/* initialize queue */
BLI_spin_init(&queue.spin);
@@ -828,29 +816,18 @@ static void start_prefetch_threads(MovieClip *clip, int start_frame, int current
queue.do_update = do_update;
queue.progress = progress;
- /* fill in thread handles */
- handles = MEM_callocN(sizeof(PrefetchThread) * tot_thread, "prefetch threaded handles");
-
- if (tot_thread > 1)
- BLI_init_threads(&threads, do_prefetch_thread, tot_thread);
-
+ task_pool = BLI_task_pool_create(task_scheduler, &queue);
for (i = 0; i < tot_thread; i++) {
- PrefetchThread *handle = &handles[i];
-
- handle->clip = clip;
- handle->queue = &queue;
-
- if (tot_thread > 1)
- BLI_insert_thread(&threads, handle);
+ BLI_task_pool_push(task_pool,
+ prefetch_task_func,
+ clip,
+ false,
+ TASK_PRIORITY_LOW);
}
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
- /* run the threads */
- if (tot_thread > 1)
- BLI_end_threads(&threads);
- else
- do_prefetch_thread(handles);
-
- MEM_freeN(handles);
+ BLI_spin_end(&queue.spin);
}
static bool prefetch_movie_frame(MovieClip *clip, int frame, short render_size,
diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c
index 95f59e79c08..d1e2c770ade 100644
--- a/source/blender/editors/space_clip/clip_graph_ops.c
+++ b/source/blender/editors/space_clip/clip_graph_ops.c
@@ -104,7 +104,7 @@ typedef struct {
int coord; /* coordinate index of found entuty (0 = X-axis, 1 = Y-axis) */
bool has_prev; /* if there's valid coordinate of previous point of curve segment */
- float min_dist, /* minimal distance between mouse and currently found entuty */
+ float min_dist_sq, /* minimal distance between mouse and currently found entity */
mouse_co[2], /* mouse coordinate */
prev_co[2], /* coordinate of previeous point of segment */
min_co[2]; /* coordinate of entity with minimal distance */
@@ -121,11 +121,11 @@ static void find_nearest_tracking_segment_cb(void *userdata, MovieTrackingTrack
float co[2] = {scene_framenr, val};
if (data->has_prev) {
- float d = dist_to_line_segment_v2(data->mouse_co, data->prev_co, co);
+ float dist_sq = dist_squared_to_line_segment_v2(data->mouse_co, data->prev_co, co);
- if (data->track == NULL || d < data->min_dist) {
+ if (data->track == NULL || dist_sq < data->min_dist_sq) {
data->track = track;
- data->min_dist = d;
+ data->min_dist_sq = dist_sq;
data->coord = coord;
copy_v2_v2(data->min_co, co);
}
@@ -146,15 +146,15 @@ static void find_nearest_tracking_knot_cb(void *userdata, MovieTrackingTrack *tr
MovieTrackingMarker *marker, int coord, int scene_framenr, float val)
{
MouseSelectUserData *data = userdata;
- float dx = scene_framenr - data->mouse_co[0], dy = val - data->mouse_co[1];
- float d = dx * dx + dy * dy;
+ float mdiff[2] = {scene_framenr - data->mouse_co[0], val - data->mouse_co[1]};
+ float dist_sq = len_squared_v2(mdiff);
- if (data->marker == NULL || d < data->min_dist) {
+ if (data->marker == NULL || dist_sq < data->min_dist_sq) {
float co[2] = {scene_framenr, val};
data->track = track;
data->marker = marker;
- data->min_dist = d;
+ data->min_dist_sq = dist_sq;
data->coord = coord;
copy_v2_v2(data->min_co, co);
}
@@ -164,7 +164,7 @@ static void find_nearest_tracking_knot_cb(void *userdata, MovieTrackingTrack *tr
static void mouse_select_init_data(MouseSelectUserData *userdata, const float co[2])
{
memset(userdata, 0, sizeof(MouseSelectUserData));
- userdata->min_dist = FLT_MAX;
+ userdata->min_dist_sq = FLT_MAX;
copy_v2_v2(userdata->mouse_co, co);
}
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 7ccee73626c..9f7bcae800a 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -49,7 +49,7 @@
#include "BLI_path_util.h"
#include "BLI_math.h"
#include "BLI_rect.h"
-#include "BLI_threads.h"
+#include "BLI_task.h"
#include "BLI_string.h"
#include "BLF_translation.h"
@@ -79,6 +79,8 @@
#include "UI_view2d.h"
+#include "PIL_time.h"
+
#include "clip_intern.h" // own include
/******************** view navigation utilities *********************/
@@ -486,18 +488,25 @@ typedef struct ViewZoomData {
float zoom;
int event_type;
float location[2];
+ wmTimer *timer;
+ double timer_lastdraw;
} ViewZoomData;
static void view_zoom_init(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceClip *sc = CTX_wm_space_clip(C);
ARegion *ar = CTX_wm_region(C);
-
ViewZoomData *vpd;
op->customdata = vpd = MEM_callocN(sizeof(ViewZoomData), "ClipViewZoomData");
WM_cursor_modal_set(CTX_wm_window(C), BC_NSEW_SCROLLCURSOR);
+ if (U.viewzoom == USER_ZOOM_CONT) {
+ /* needs a timer to continue redrawing */
+ vpd->timer = WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
+ vpd->timer_lastdraw = PIL_check_seconds_timer();
+ }
+
vpd->x = event->x;
vpd->y = event->y;
vpd->zoom = sc->zoom;
@@ -518,6 +527,10 @@ static void view_zoom_exit(bContext *C, wmOperator *op, bool cancel)
ED_region_tag_redraw(CTX_wm_region(C));
}
+ if (vpd->timer) {
+ WM_event_remove_timer(CTX_wm_manager(C), vpd->timer->win, vpd->timer);
+ }
+
WM_cursor_modal_restore(CTX_wm_window(C));
MEM_freeN(op->customdata);
}
@@ -555,22 +568,61 @@ static int view_zoom_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
}
+static void view_zoom_apply(bContext *C,
+ ViewZoomData *vpd,
+ wmOperator *op,
+ const wmEvent *event)
+{
+ float factor;
+
+ if (U.viewzoom == USER_ZOOM_CONT) {
+ SpaceClip *sclip = CTX_wm_space_clip(C);
+ double time = PIL_check_seconds_timer();
+ float time_step = (float)(time - vpd->timer_lastdraw);
+ float fac;
+ float zfac;
+
+ if (U.uiflag & USER_ZOOM_HORIZ) {
+ fac = (float)(event->x - vpd->x);
+ }
+ else {
+ fac = (float)(event->y - vpd->y);
+ }
+
+ if (U.uiflag & USER_ZOOM_INVERT) {
+ fac = -fac;
+ }
+
+ zfac = 1.0f + ((fac / 20.0f) * time_step);
+ vpd->timer_lastdraw = time;
+ factor = (sclip->zoom * zfac) / vpd->zoom;
+ }
+ else {
+ float delta = event->x - vpd->x + event->y - vpd->y;
+
+ if (U.uiflag & USER_ZOOM_INVERT) {
+ delta *= -1;
+ }
+
+ factor = 1.0f + delta / 300.0f;
+ }
+
+ RNA_float_set(op->ptr, "factor", factor);
+ sclip_zoom_set(C, vpd->zoom * factor, vpd->location);
+ ED_region_tag_redraw(CTX_wm_region(C));
+}
+
static int view_zoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewZoomData *vpd = op->customdata;
- float delta, factor;
-
switch (event->type) {
+ case TIMER:
+ if (event->customdata == vpd->timer) {
+ view_zoom_apply(C, vpd, op, event);
+ }
+ break;
case MOUSEMOVE:
- delta = event->x - vpd->x + event->y - vpd->y;
-
- if (U.uiflag & USER_ZOOM_INVERT)
- delta *= -1;
-
- factor = 1.0f + delta / 300.0f;
- RNA_float_set(op->ptr, "factor", factor);
- sclip_zoom_set(C, vpd->zoom * factor, vpd->location);
- ED_region_tag_redraw(CTX_wm_region(C));
+ view_zoom_apply(C, vpd, op, event);
break;
default:
if (event->type == vpd->event_type && event->val == KM_RELEASE) {
@@ -591,6 +643,8 @@ static void view_zoom_cancel(bContext *C, wmOperator *op)
void CLIP_OT_view_zoom(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Zoom";
ot->idname = "CLIP_OT_view_zoom";
@@ -607,8 +661,9 @@ void CLIP_OT_view_zoom(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
/* properties */
- RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX,
- "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
+ "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/********************** view zoom in/out operator *********************/
@@ -641,6 +696,8 @@ static int view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent *event
void CLIP_OT_view_zoom_in(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Zoom In";
ot->idname = "CLIP_OT_view_zoom_in";
@@ -652,8 +709,9 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* properties */
- RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location",
- "Cursor location in screen coordinates", -10.0f, 10.0f);
+ prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location",
+ "Cursor location in screen coordinates", -10.0f, 10.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
static int view_zoom_out_exec(bContext *C, wmOperator *op)
@@ -684,6 +742,8 @@ static int view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent *even
void CLIP_OT_view_zoom_out(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Zoom Out";
ot->idname = "CLIP_OT_view_zoom_out";
@@ -695,8 +755,9 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot)
ot->poll = ED_space_clip_view_clip_poll;
/* properties */
- RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location",
- "Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f);
+ prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location",
+ "Cursor location in normalized (0.0-1.0) coordinates", -10.0f, 10.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/********************** view zoom ratio operator *********************/
@@ -1062,10 +1123,7 @@ typedef struct ProxyQueue {
typedef struct ProxyThread {
MovieClip *clip;
- ProxyQueue *queue;
-
struct MovieDistortion *distortion;
-
int *build_sizes, build_count;
int *build_undistort_sizes, build_undistort_count;
} ProxyThread;
@@ -1085,7 +1143,7 @@ static unsigned char *proxy_thread_next_frame(ProxyQueue *queue, MovieClip *clip
BKE_movieclip_filename_for_frame(clip, &user, name);
- file = open(name, O_BINARY | O_RDONLY, 0);
+ file = BLI_open(name, O_BINARY | O_RDONLY, 0);
if (file < 0) {
BLI_spin_unlock(&queue->spin);
return NULL;
@@ -1121,14 +1179,15 @@ static unsigned char *proxy_thread_next_frame(ProxyQueue *queue, MovieClip *clip
return mem;
}
-static void *do_proxy_thread(void *data_v)
+static void proxy_task_func(TaskPool *pool, void *task_data, int UNUSED(threadid))
{
- ProxyThread *data = (ProxyThread *) data_v;
+ ProxyThread *data = (ProxyThread *)task_data;
+ ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_userdata(pool);
unsigned char *mem;
size_t size;
int cfra;
- while ((mem = proxy_thread_next_frame(data->queue, data->clip, &size, &cfra))) {
+ while ((mem = proxy_thread_next_frame(queue, data->clip, &size, &cfra))) {
ImBuf *ibuf;
ibuf = IMB_ibImageFromMemory(mem, size, IB_rect | IB_multilayer | IB_alphamode_detect,
@@ -1144,8 +1203,6 @@ static void *do_proxy_thread(void *data_v)
MEM_freeN(mem);
}
-
- return NULL;
}
static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
@@ -1155,12 +1212,18 @@ static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
ProxyJob *pj = pjv;
MovieClip *clip = pj->clip;
Scene *scene = pj->scene;
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool;
int sfra = SFRA, efra = EFRA;
ProxyThread *handles;
- ListBase threads;
- int i, tot_thread = BLI_system_thread_count();
+ int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler);
+ int width, height;
ProxyQueue queue;
+ if (build_undistort_count) {
+ BKE_movieclip_get_size(clip, NULL, &width, &height);
+ }
+
BLI_spin_init(&queue.spin);
queue.cfra = sfra;
@@ -1170,16 +1233,13 @@ static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
queue.do_update = do_update;
queue.progress = progress;
- handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles");
-
- if (tot_thread > 1)
- BLI_init_threads(&threads, do_proxy_thread, tot_thread);
-
+ task_pool = BLI_task_pool_create(task_scheduler, &queue);
+ handles = MEM_callocN(sizeof(ProxyThread) * tot_thread,
+ "proxy threaded handles");
for (i = 0; i < tot_thread; i++) {
ProxyThread *handle = &handles[i];
handle->clip = clip;
- handle->queue = &queue;
handle->build_count = build_count;
handle->build_sizes = build_sizes;
@@ -1188,29 +1248,29 @@ static void do_sequence_proxy(void *pjv, int *build_sizes, int build_count,
handle->build_undistort_sizes = build_undistort_sizes;
if (build_undistort_count) {
- int width, height;
- BKE_movieclip_get_size(clip, NULL, &width, &height);
- handle->distortion = BKE_tracking_distortion_new(&clip->tracking, width, height);
+ handle->distortion = BKE_tracking_distortion_new(&clip->tracking,
+ width, height);
}
- if (tot_thread > 1)
- BLI_insert_thread(&threads, handle);
+ BLI_task_pool_push(task_pool,
+ proxy_task_func,
+ handle,
+ false,
+ TASK_PRIORITY_LOW);
}
- if (tot_thread > 1)
- BLI_end_threads(&threads);
- else
- do_proxy_thread(handles);
-
- MEM_freeN(handles);
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
if (build_undistort_count) {
for (i = 0; i < tot_thread; i++) {
ProxyThread *handle = &handles[i];
-
BKE_tracking_distortion_free(handle->distortion);
}
}
+
+ BLI_spin_end(&queue.spin);
+ MEM_freeN(handles);
}
static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c
index d3be25050c8..a797a60f74c 100644
--- a/source/blender/editors/space_clip/space_clip.c
+++ b/source/blender/editors/space_clip/space_clip.c
@@ -754,6 +754,10 @@ static void clip_keymap(struct wmKeyConfig *keyconf)
RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
RNA_string_set(kmi->ptr, "value", "INDIVIDUAL_ORIGINS");
+ /* Copy-paste */
+ WM_keymap_add_item(keymap, "CLIP_OT_copy_tracks", CKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "CLIP_OT_paste_tracks", VKEY, KM_PRESS, KM_CTRL, 0);
+
/* ******** Hotkeys avalaible for preview region only ******** */
keymap = WM_keymap_find(keyconf, "Clip Graph Editor", SPACE_CLIP, 0);
@@ -846,7 +850,7 @@ static int clip_context(const bContext *C, const char *member, bContextDataResul
static int clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH)
- if (ELEM4(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
+ if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
return true;
return false;
diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c
index ce14471f608..fb6b1a0033c 100644
--- a/source/blender/editors/space_clip/tracking_ops.c
+++ b/source/blender/editors/space_clip/tracking_ops.c
@@ -2277,7 +2277,7 @@ static void set_axis(Scene *scene, Object *ob, MovieClip *clip, MovieTrackingOb
copy_v3_v3(lmat[3], obmat[3]);
invert_m4_m4(ilmat, lmat);
- mul_serie_m4(mat, lmat, mat, ilmat, obmat, NULL, NULL, NULL, NULL);
+ mul_m4_series(mat, lmat, mat, ilmat, obmat);
}
else {
mul_m4_m4m4(mat, obmat, mat);
@@ -2996,7 +2996,7 @@ void CLIP_OT_detect_features(wmOperatorType *ot)
/* properties */
RNA_def_enum(ot->srna, "placement", placement_items, 0, "Placement", "Placement for detected features");
RNA_def_int(ot->srna, "margin", 16, 0, INT_MAX, "Margin", "Only features further than margin pixels from the image edges are considered", 0, 300);
- RNA_def_float(ot->srna, "threshold", 1.0f, 0.0001f, FLT_MAX, "Threshold", "Threshold level to consider feature good enough for tracking", 0.0001f, FLT_MAX);
+ RNA_def_float(ot->srna, "threshold", 0.5f, 0.0001f, FLT_MAX, "Threshold", "Threshold level to consider feature good enough for tracking", 0.0001f, FLT_MAX);
RNA_def_int(ot->srna, "min_distance", 120, 0, INT_MAX, "Distance", "Minimal distance accepted between two features", 0, 300);
}
@@ -3811,7 +3811,9 @@ static int paste_tracks_exec(bContext *C, wmOperator *UNUSED(op))
MovieClip *clip = ED_space_clip_get_clip(sc);
MovieTracking *tracking = &clip->tracking;
MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
+ ListBase *tracks_base = BKE_tracking_object_get_tracks(tracking, object);
+ BKE_tracking_tracks_deselect_all(tracks_base);
BKE_tracking_clipboard_paste_tracks(tracking, object);
WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip);
diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c
index 4d9c262e1ff..860d9dc6b3c 100644
--- a/source/blender/editors/space_clip/tracking_select.c
+++ b/source/blender/editors/space_clip/tracking_select.c
@@ -792,7 +792,7 @@ void CLIP_OT_select_circle(wmOperatorType *ot)
/* properties */
RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
}
diff --git a/source/blender/editors/space_console/CMakeLists.txt b/source/blender/editors/space_console/CMakeLists.txt
index 241a48c1e2d..ecfb1f0e0df 100644
--- a/source/blender/editors/space_console/CMakeLists.txt
+++ b/source/blender/editors/space_console/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -45,4 +47,6 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_console "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_console/SConscript b/source/blender/editors/space_console/SConscript
index 0395a33cd97..87d12fe34bd 100644
--- a/source/blender/editors/space_console/SConscript
+++ b/source/blender/editors/space_console/SConscript
@@ -28,16 +28,19 @@
Import ('env')
sources = env.Glob('*.c')
-defs = []
+
+defs = env['BF_GL_DEFINITIONS']
incs = [
'../include',
- '#/extern/glew/include',
'#/intern/guardedalloc',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../../makesdna',
'../../makesrna',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../windowmanager',
'../../blenfont',
]
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index b8743d69762..b44e942527c 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -888,7 +888,7 @@ static int console_copy_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceConsole *sc = CTX_wm_space_console(C);
- DynStr *buf_dyn = BLI_dynstr_new();
+ DynStr *buf_dyn;
char *buf_str;
ConsoleLine *cl;
@@ -897,14 +897,6 @@ static int console_copy_exec(bContext *C, wmOperator *UNUSED(op))
ConsoleLine cl_dummy = {NULL};
-#if 0
- /* copy whole file */
- for (cl = sc->scrollback.first; cl; cl = cl->next) {
- BLI_dynstr_append(buf_dyn, cl->line);
- BLI_dynstr_append(buf_dyn, "\n");
- }
-#endif
-
if (sc->sel_start == sc->sel_end)
return OPERATOR_CANCELLED;
@@ -919,6 +911,7 @@ static int console_copy_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
+ buf_dyn = BLI_dynstr_new();
offset -= 1;
sel[0] = offset - sc->sel_end;
sel[1] = offset - sc->sel_start;
diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c
index 43313c7dd06..e4a61a8f06e 100644
--- a/source/blender/editors/space_console/space_console.c
+++ b/source/blender/editors/space_console/space_console.c
@@ -158,6 +158,18 @@ static void console_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_dropbox_handler(&ar->handlers, lb);
}
+/* same as 'text_cursor' */
+static void console_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
+{
+ SpaceText *st = sa->spacedata.first;
+ int wmcursor = BC_TEXTEDITCURSOR;
+
+ if (st->text && BLI_rcti_isect_pt(&st->txtbar, win->eventstate->x - ar->winrct.xmin, st->txtbar.ymin)) {
+ wmcursor = CURSOR_STD;
+ }
+
+ WM_cursor_set(win, wmcursor);
+}
/* ************* dropboxes ************* */
@@ -396,6 +408,7 @@ void ED_spacetype_console(void)
art->init = console_main_area_init;
art->draw = console_main_area_draw;
+ art->cursor = console_cursor;
art->listener = console_main_area_listener;
diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt
index 3b2db3ee7bc..fc007a659b4 100644
--- a/source/blender/editors/space_file/CMakeLists.txt
+++ b/source/blender/editors/space_file/CMakeLists.txt
@@ -25,11 +25,13 @@ set(INC
../../blenlib
../../blenloader
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -86,6 +88,8 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_FREESTYLE)
add_definitions(-DWITH_FREESTYLE)
endif()
diff --git a/source/blender/editors/space_file/SConscript b/source/blender/editors/space_file/SConscript
index d42394454eb..85c3e073922 100644
--- a/source/blender/editors/space_file/SConscript
+++ b/source/blender/editors/space_file/SConscript
@@ -30,12 +30,14 @@ Import ('env')
sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../blenloader',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -44,7 +46,7 @@ incs = [
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_OPENJPEG']:
defs.append('WITH_OPENJPEG')
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index f0a84ef482e..3e099b43a4b 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -416,11 +416,12 @@ static void draw_background(FileLayout *layout, View2D *v2d)
int i;
int sy;
+ UI_ThemeColorShade(TH_BACK, -7);
+
/* alternating flat shade background */
for (i = 0; (i <= layout->rows); i += 2) {
sy = (int)v2d->cur.ymax - i * (layout->tile_h + 2 * layout->tile_border_y) - layout->tile_border_y;
- UI_ThemeColorShade(TH_BACK, -7);
glRectf(v2d->cur.xmin, (float)sy, v2d->cur.xmax, (float)(sy + layout->tile_h + 2 * layout->tile_border_y));
}
@@ -428,18 +429,36 @@ static void draw_background(FileLayout *layout, View2D *v2d)
static void draw_dividers(FileLayout *layout, View2D *v2d)
{
+ const int step = (layout->tile_w + 2 * layout->tile_border_x);
+ int v1[2], v2[2];
int sx;
+ unsigned char col_hi[3], col_lo[3];
+
+ UI_GetThemeColorShade3ubv(TH_BACK, 30, col_hi);
+ UI_GetThemeColorShade3ubv(TH_BACK, -30, col_lo);
+
+ v1[1] = v2d->cur.ymax - layout->tile_border_y;
+ v2[1] = v2d->cur.ymin;
+
+ glBegin(GL_LINES);
/* vertical column dividers */
sx = (int)v2d->tot.xmin;
while (sx < v2d->cur.xmax) {
- sx += (layout->tile_w + 2 * layout->tile_border_x);
-
- UI_ThemeColorShade(TH_BACK, 30);
- sdrawline(sx + 1, (short)(v2d->cur.ymax - layout->tile_border_y), sx + 1, (short)v2d->cur.ymin);
- UI_ThemeColorShade(TH_BACK, -30);
- sdrawline(sx, (short)(v2d->cur.ymax - layout->tile_border_y), sx, (short)v2d->cur.ymin);
+ sx += step;
+
+ glColor3ubv(col_lo);
+ v1[0] = v2[0] = sx;
+ glVertex2iv(v1);
+ glVertex2iv(v2);
+
+ glColor3ubv(col_hi);
+ v1[0] = v2[0] = sx + 1;
+ glVertex2iv(v1);
+ glVertex2iv(v2);
}
+
+ glEnd();
}
void file_draw_list(const bContext *C, ARegion *ar)
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 1d3013bd8b4..27d6fabba4e 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -1277,8 +1277,9 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
/* if not, ask to create it and enter if confirmed */
+ wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
PointerRNA ptr;
- WM_operator_properties_create(&ptr, "FILE_OT_directory_new");
+ WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "directory", sfile->params->dir);
RNA_boolean_set(&ptr, "open", true);
@@ -1286,7 +1287,7 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
- WM_operator_name_call(C, "FILE_OT_directory_new", WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
WM_operator_properties_free(&ptr);
}
diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c
index 69789569912..8fad17e1210 100644
--- a/source/blender/editors/space_file/file_panels.c
+++ b/source/blender/editors/space_file/file_panels.c
@@ -57,12 +57,13 @@
static void file_panel_cb(bContext *C, void *arg_entry, void *UNUSED(arg_v))
{
+ wmOperatorType *ot = WM_operatortype_find("FILE_OT_select_bookmark", false);
PointerRNA ptr;
const char *entry = (char *)arg_entry;
- WM_operator_properties_create(&ptr, "FILE_OT_select_bookmark");
+ WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, "dir", entry);
- WM_operator_name_call(C, "FILE_OT_select_bookmark", WM_OP_INVOKE_REGION_WIN, &ptr);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_REGION_WIN, &ptr);
WM_operator_properties_free(&ptr);
}
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index e8371d7666b..afe3f29e9bc 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -281,14 +281,28 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar)
{
int numfiles;
+ /* Values in pixels.
+ *
+ * - *_item: size of each (row|col), (including padding)
+ * - *_view: (x|y) size of the view.
+ * - *_over: extra pixels, to take into account, when the fit isnt exact
+ * (needed since you may see the end of the previous column and the beginning of the next).
+ *
+ * Could be more clever and take scrolling into account,
+ * but for now don't bother.
+ */
if (layout->flag & FILE_LAYOUT_HOR) {
- int width = (int)(BLI_rctf_size_x(&ar->v2d.cur) - 2 * layout->tile_border_x);
- numfiles = (int)((float)width / (float)layout->tile_w + 0.5f);
+ const int x_item = layout->tile_w + (2 * layout->tile_border_x);
+ const int x_view = (int)(BLI_rctf_size_x(&ar->v2d.cur));
+ const int x_over = x_item - (x_view % x_item);
+ numfiles = (int)((float)(x_view + x_over) / (float)(x_item));
return numfiles * layout->rows;
}
else {
- int height = (int)(BLI_rctf_size_y(&ar->v2d.cur) - 2 * layout->tile_border_y);
- numfiles = (int)((float)height / (float)layout->tile_h + 0.5f);
+ const int y_item = layout->tile_h + (2 * layout->tile_border_y);
+ const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur));
+ const int y_over = y_item - (y_view % y_item);
+ numfiles = (int)((float)(y_view + y_over) / (float)(y_item));
return numfiles * layout->columns;
}
}
@@ -656,7 +670,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
}
else {
char path[FILE_MAX];
- struct stat status;
+ BLI_stat_t status;
BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 6284caf1456..c117b8c2d3e 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -441,9 +441,14 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
pathString = CFURLCopyFileSystemPath(cfURL, kCFURLPOSIXPathStyle);
- if (!CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII))
+ if (pathString == NULL || !CFStringGetCString(pathString, line, sizeof(line), kCFStringEncodingASCII))
continue;
- fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, FS_INSERT_SORTED);
+
+ /* Exclude "all my files" as it makes no sense in blender fileselector */
+ /* Exclude "airdrop" if wlan not active as it would show "" ) */
+ if (!strstr(line, "myDocuments.cannedSearch") && (*line != '\0')) {
+ fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM_BOOKMARKS, line, NULL);
+ }
CFRelease(pathString);
CFRelease(cfURL);
diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c
index 3a493c0338c..d5be04cff20 100644
--- a/source/blender/editors/space_file/space_file.c
+++ b/source/blender/editors/space_file/space_file.c
@@ -422,7 +422,7 @@ static void file_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, 0, 0);
kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", true);
- kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_ALT, 0);
+ kmi = WM_keymap_add_item(keymap, "FILE_OT_select", LEFTMOUSE, KM_CLICK, KM_CTRL | KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", true);
RNA_boolean_set(kmi->ptr, "fill", true);
diff --git a/source/blender/editors/space_graph/CMakeLists.txt b/source/blender/editors/space_graph/CMakeLists.txt
index d3fb87204fb..0a29810ff3d 100644
--- a/source/blender/editors/space_graph/CMakeLists.txt
+++ b/source/blender/editors/space_graph/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -56,4 +58,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_graph "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_graph/SConscript b/source/blender/editors/space_graph/SConscript
index 8ddeb0ccfe8..35e09749743 100644
--- a/source/blender/editors/space_graph/SConscript
+++ b/source/blender/editors/space_graph/SConscript
@@ -31,19 +31,21 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/audaspace/intern',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c
index 8193008098e..b59030d3c12 100644
--- a/source/blender/editors/space_graph/graph_buttons.c
+++ b/source/blender/editors/space_graph/graph_buttons.c
@@ -47,6 +47,7 @@
#include "BLF_translation.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_main.h"
@@ -226,15 +227,13 @@ static short get_active_fcurve_keyframe_edit(FCurve *fcu, BezTriple **bezt, BezT
}
/* update callback for active keyframe properties - base updates stuff */
-static void graphedit_activekey_update_cb(bContext *C, void *fcu_ptr, void *UNUSED(bezt_ptr))
+static void graphedit_activekey_update_cb(bContext *UNUSED(C), void *fcu_ptr, void *UNUSED(bezt_ptr))
{
- SpaceIpo *sipo = CTX_wm_space_graph(C);
- const short use_handle = !(sipo->flag & SIPO_NOHANDLES);
FCurve *fcu = (FCurve *)fcu_ptr;
/* make sure F-Curve and its handles are still valid after this editing */
sort_time_fcurve(fcu);
- testhandles_fcurve(fcu, use_handle);
+ calchandles_fcurve(fcu);
}
/* update callback for active keyframe properties - handle-editing wrapper */
@@ -250,6 +249,9 @@ static void graphedit_activekey_handles_cb(bContext *C, void *fcu_ptr, void *bez
bezt->h1 = HD_ALIGN;
bezt->h2 = HD_ALIGN;
}
+ else {
+ BKE_nurb_bezt_handle_test(bezt, true);
+ }
/* now call standard updates */
graphedit_activekey_update_cb(C, fcu_ptr, bezt_ptr);
@@ -259,6 +261,24 @@ static void graphedit_activekey_handles_cb(bContext *C, void *fcu_ptr, void *bez
* NOTE: we cannot just do graphedit_activekey_handles_cb() due to "order of computation"
* weirdness (see calchandleNurb_intern() and T39911)
*/
+static void graphedit_activekey_left_handle_coord_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
+{
+ BezTriple *bezt = (BezTriple *)bezt_ptr;
+
+ const char f1 = bezt->f1;
+ const char f3 = bezt->f3;
+
+ bezt->f1 |= SELECT;
+ bezt->f3 &= ~SELECT;
+
+ /* perform normal updates NOW */
+ graphedit_activekey_handles_cb(C, fcu_ptr, bezt_ptr);
+
+ /* restore selection state so that no-one notices this hack */
+ bezt->f1 = f1;
+ bezt->f3 = f3;
+}
+
static void graphedit_activekey_right_handle_coord_cb(bContext *C, void *fcu_ptr, void *bezt_ptr)
{
BezTriple *bezt = (BezTriple *)bezt_ptr;
@@ -270,8 +290,8 @@ static void graphedit_activekey_right_handle_coord_cb(bContext *C, void *fcu_ptr
/* temporarily make it so that only the right handle is selected, so that updates go correctly
* (i.e. it now acts as if we've just transforming the vert when it is selected by itself)
*/
- bezt->f1 = 0;
- bezt->f3 = 1;
+ bezt->f1 &= ~SELECT;
+ bezt->f3 |= SELECT;
/* perform normal updates NOW */
graphedit_activekey_handles_cb(C, fcu_ptr, bezt_ptr);
@@ -362,11 +382,11 @@ static void graph_panel_key_properties(const bContext *C, Panel *pa)
but = uiDefButR(block, NUM, B_REDR, "X:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "handle_left", 0, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
+ uiButSetFunc(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
but = uiDefButR(block, NUM, B_REDR, "Y:", 0, 0, UI_UNIT_X, UI_UNIT_Y,
&bezt_ptr, "handle_left", 1, 0, 0, -1, -1, NULL);
- uiButSetFunc(but, graphedit_activekey_handles_cb, fcu, bezt);
+ uiButSetFunc(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt);
uiButSetUnitType(but, unit);
/* XXX: with label? */
@@ -540,7 +560,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Bone 1:"));
- if (dtar->id && ob1->pose) {
+ if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
@@ -551,7 +571,7 @@ static void graph_panel_driverVar__rotDiff(uiLayout *layout, ID *id, DriverVar *
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Bone 2:"));
- if (dtar2->id && ob2->pose) {
+ if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
@@ -578,7 +598,7 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone 1:"));
- if (dtar->id && ob1->pose) {
+ if (dtar->id && GS(dtar->id->name) == ID_OB && ob1->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob1->pose, &tar_ptr);
@@ -592,7 +612,7 @@ static void graph_panel_driverVar__locDiff(uiLayout *layout, ID *id, DriverVar *
uiLayoutSetRedAlert(col, (dtar2->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar2_ptr, "id", "id_type", IFACE_("Ob/Bone 2:"));
- if (dtar2->id && ob2->pose) {
+ if (dtar2->id && GS(dtar2->id->name) == ID_OB && ob2->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar2->id, &RNA_Pose, ob2->pose, &tar_ptr);
@@ -619,7 +639,7 @@ static void graph_panel_driverVar__transChan(uiLayout *layout, ID *id, DriverVar
uiLayoutSetRedAlert(col, (dtar->flag & DTAR_FLAG_INVALID)); /* XXX: per field... */
uiTemplateAnyID(col, &dtar_ptr, "id", "id_type", IFACE_("Ob/Bone:"));
- if (dtar->id && ob->pose) {
+ if (dtar->id && GS(dtar->id->name) == ID_OB && ob->pose) {
PointerRNA tar_ptr;
RNA_pointer_create(dtar->id, &RNA_Pose, ob->pose, &tar_ptr);
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index 83f87ebc174..ed7cfe7da99 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -476,11 +476,12 @@ static void draw_fcurve_samples(SpaceIpo *sipo, ARegion *ar, FCurve *fcu)
static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, View2DGrid *grid)
{
ChannelDriver *driver;
- float samplefreq, ctime;
+ float samplefreq;
float stime, etime;
float unitFac;
float dx, dy;
short mapping_flag = ANIM_get_normalization_flags(ac);
+ int i, n;
/* when opening a blend file on a different sized screen or while dragging the toolbar this can happen
* best just bail out in this case */
@@ -524,10 +525,12 @@ static void draw_fcurve_curve(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d
* the displayed values appear correctly in the viewport
*/
glBegin(GL_LINE_STRIP);
-
- for (ctime = stime; ctime <= etime; ctime += samplefreq)
+
+ for (i = 0, n = (etime - stime) / samplefreq + 0.5f; i < n; ++i) {
+ float ctime = stime + i * samplefreq;
glVertex2f(ctime, evaluate_fcurve(fcu, ctime) * unitFac);
-
+ }
+
glEnd();
/* restore driver */
@@ -1054,7 +1057,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceIpo *sipo, ARegion *ar, View2DGrid
}
/* free list of curves */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ************************************************************************* */
@@ -1139,5 +1142,5 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* free tempolary channels */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index 364dd1d0344..c8298927f7d 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -151,7 +151,7 @@ void get_graph_keyframe_extents(bAnimContext *ac, float *xmin, float *xmax, floa
}
/* free memory */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
else {
/* set default range */
@@ -369,7 +369,7 @@ static void create_ghost_curves(bAnimContext *ac, int start, int end)
}
/* admin and redraws */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -505,9 +505,12 @@ static void insert_graph_keys(bAnimContext *ac, short mode)
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;
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -527,9 +530,6 @@ static int graphkeys_insertkey_exec(bContext *C, wmOperator *op)
/* insert keyframes */
insert_graph_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
@@ -581,6 +581,8 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
* keyframes if these will be visible after doing so...
*/
if (fcurve_is_keyframable(fcu)) {
+ ListBase anim_data;
+
short mapping_flag = ANIM_get_normalization_flags(&ac);
/* get frame and value from props */
@@ -596,6 +598,13 @@ static int graphkeys_click_insert_exec(bContext *C, wmOperator *op)
/* 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 {
/* warn about why this can't happen */
@@ -684,7 +693,7 @@ static short copy_graph_keys(bAnimContext *ac)
ok = copy_animedit_keys(ac, &anim_data);
/* clean up */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return ok;
}
@@ -708,9 +717,9 @@ static short paste_graph_keys(bAnimContext *ac,
/* paste keyframes */
ok = paste_animedit_keys(ac, &anim_data, offset_mode, merge_mode);
-
+
/* clean up */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return ok;
}
@@ -771,9 +780,6 @@ static int graphkeys_paste_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -815,10 +821,12 @@ static void duplicate_graph_keys(bAnimContext *ac)
/* loop through filtered data and delete selected keys */
for (ale = anim_data.first; ale; ale = ale->next) {
duplicate_fcurve_keys((FCurve *)ale->key_data);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
-
- /* free filtered list */
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -834,9 +842,6 @@ static int graphkeys_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
/* duplicate keyframes */
duplicate_graph_keys(&ac);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_ADDED, NULL);
@@ -876,7 +881,7 @@ static bool delete_graph_keys(bAnimContext *ac)
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
- bool changed = false;
+ bool changed_final = false;
/* filter data */
filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_NODUPLIS);
@@ -886,9 +891,15 @@ static bool delete_graph_keys(bAnimContext *ac)
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->key_data;
AnimData *adt = ale->adt;
+ bool changed;
/* delete selected keyframes only */
- changed |= delete_fcurve_keys(fcu);
+ changed = delete_fcurve_keys(fcu);
+
+ if (changed) {
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ changed_final = true;
+ }
/* Only delete curve too if it won't be doing anything anymore */
if ((fcu->totvert == 0) &&
@@ -896,13 +907,14 @@ static bool delete_graph_keys(bAnimContext *ac)
(fcu->driver == NULL))
{
ANIM_fcurve_delete_from_animdata(ac, adt, fcu);
+ ale->key_data = NULL;
}
}
-
- /* free filtered list */
- BLI_freelistN(&anim_data);
- return changed;
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+
+ return changed_final;
}
/* ------------------- */
@@ -919,9 +931,6 @@ static int graphkeys_delete_exec(bContext *C, wmOperator *UNUSED(op))
if (!delete_graph_keys(&ac))
return OPERATOR_CANCELLED;
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_REMOVED, NULL);
@@ -957,11 +966,14 @@ static void clean_graph_keys(bAnimContext *ac, float thresh)
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and clean curves */
- for (ale = anim_data.first; ale; ale = ale->next)
+ for (ale = anim_data.first; ale; ale = ale->next) {
clean_fcurve((FCurve *)ale->key_data, thresh);
-
- /* free temp data */
- BLI_freelistN(&anim_data);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -981,9 +993,6 @@ static int graphkeys_clean_exec(bContext *C, wmOperator *op)
/* clean keyframes */
clean_graph_keys(&ac, thresh);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1036,10 +1045,12 @@ static void bake_graph_curves(bAnimContext *ac, int start, int end)
/* restore driver */
fcu->driver = driver;
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
-
- /* admin and redraws */
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1063,9 +1074,6 @@ static int graphkeys_bake_exec(bContext *C, wmOperator *UNUSED(op))
/* bake keyframes */
bake_graph_curves(&ac, start, end);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
// NOTE: some distinction between order/number of keyframes and type should be made?
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1178,16 +1186,16 @@ static int graphkeys_sound_bake_exec(bContext *C, wmOperator *op)
/* sample the sound */
fcurve_store_samples(fcu, &sbi, start, end, fcurve_samplingcb_sound);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
/* free sample data */
free(sbi.samples);
- /* admin and redraws */
- BLI_freelistN(&anim_data);
-
/* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
+ ANIM_animdata_update(&ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that 'keyframes' have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1275,11 +1283,14 @@ static void sample_graph_keys(bAnimContext *ac)
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
/* loop through filtered data and add keys between selected keyframes on every frame */
- for (ale = anim_data.first; ale; ale = ale->next)
+ for (ale = anim_data.first; ale; ale = ale->next) {
sample_fcurve((FCurve *)ale->key_data);
-
- /* admin and redraws */
- BLI_freelistN(&anim_data);
+
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1295,9 +1306,6 @@ static int graphkeys_sample_exec(bContext *C, wmOperator *UNUSED(op))
/* sample keyframes */
sample_graph_keys(&ac);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1357,6 +1365,8 @@ static void setexpo_graph_keys(bAnimContext *ac, short mode)
if (mode >= 0) {
/* just set mode setting */
fcu->extend = mode;
+
+ ale->update |= ANIM_UPDATE_HANDLES;
}
else {
/* shortcuts for managing Cycles F-Modifiers to make it easier to toggle cyclic animation
@@ -1381,10 +1391,12 @@ static void setexpo_graph_keys(bAnimContext *ac, short mode)
}
}
}
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
-
- /* cleanup */
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1404,9 +1416,6 @@ static int graphkeys_expo_exec(bContext *C, wmOperator *op)
/* set handle type */
setexpo_graph_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1449,11 +1458,14 @@ static void setipo_graph_keys(bAnimContext *ac, short mode)
/* loop through setting BezTriple interpolation
* Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
*/
- for (ale = anim_data.first; ale; ale = ale->next)
+ for (ale = anim_data.first; ale; ale = ale->next) {
ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
-
- /* cleanup */
- BLI_freelistN(&anim_data);
+
+ ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1473,9 +1485,6 @@ static int graphkeys_ipo_exec(bContext *C, wmOperator *op)
/* set handle type */
setipo_graph_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1517,11 +1526,14 @@ static void seteasing_graph_keys(bAnimContext *ac, short mode)
/* loop through setting BezTriple easing
* Note: we do not supply KeyframeEditData to the looper yet. Currently that's not necessary here...
*/
- for (ale = anim_data.first; ale; ale = ale->next)
+ for (ale = anim_data.first; ale; ale = ale->next) {
ANIM_fcurve_keyframes_loop(NULL, ale->key_data, NULL, set_cb, calchandles_fcurve);
-
- /* cleanup */
- BLI_freelistN(&anim_data);
+
+ ale->update |= ANIM_UPDATE_DEFAULT_NOHANDLES;
+ }
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
static int graphkeys_easing_exec(bContext *C, wmOperator *op)
@@ -1539,9 +1551,6 @@ static int graphkeys_easing_exec(bContext *C, wmOperator *op)
/* set handle type */
seteasing_graph_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1593,11 +1602,13 @@ static void sethandles_graph_keys(bAnimContext *ac, short mode)
if (ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, sel_cb, NULL)) {
/* change type of selected handles */
ANIM_fcurve_keyframes_loop(NULL, fcu, NULL, edit_cb, calchandles_fcurve);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
}
-
- /* cleanup */
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -1616,9 +1627,6 @@ static int graphkeys_handletype_exec(bContext *C, wmOperator *op)
/* set handle type */
sethandles_graph_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframe properties have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME_PROP, NULL);
@@ -1699,7 +1707,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
*/
if (strstr(fcu->rna_path, "rotation_euler") == NULL)
continue;
- else if (ELEM3(fcu->array_index, 0, 1, 2) == 0) {
+ else if (ELEM(fcu->array_index, 0, 1, 2) == 0) {
BKE_reportf(op->reports, RPT_WARNING,
"Euler Rotation F-Curve has invalid index (ID='%s', Path='%s', Index=%d)",
(ale->id) ? ale->id->name : TIP_("<No ID>"), fcu->rna_path, fcu->array_index);
@@ -1724,10 +1732,12 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
euf->rna_path = fcu->rna_path; /* this should be safe, since we're only using it for a short time */
euf->fcurves[fcu->array_index] = fcu;
}
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
- BLI_freelistN(&anim_data);
-
+
if (groups == 0) {
+ ANIM_animdata_freelist(&anim_data);
BKE_report(op->reports, RPT_WARNING, "No Euler Rotation F-Curves to fix up");
return OPERATOR_CANCELLED;
}
@@ -1740,7 +1750,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
/* sanity check: ensure that there are enough F-Curves to work on in this group */
/* TODO: also enforce assumption that there be a full set of keyframes at each position by ensuring that totvert counts are same? */
- if (ELEM3(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
+ if (ELEM(NULL, euf->fcurves[0], euf->fcurves[1], euf->fcurves[2])) {
/* report which components are missing */
BKE_reportf(op->reports, RPT_WARNING,
"Missing %s%s%s component(s) of euler rotation for ID='%s' and RNA-Path='%s'",
@@ -1786,6 +1796,9 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
}
BLI_freelistN(&eulers);
+ ANIM_animdata_update(&ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
+
/* updates + finishing warnings */
if (failed == groups) {
BKE_report(op->reports, RPT_ERROR,
@@ -1801,9 +1814,6 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
"consecutive XYZ order and selected");
}
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -1882,7 +1892,7 @@ static int graphkeys_framejump_exec(bContext *C, wmOperator *UNUSED(op))
ked.i2 += current_ked.i2;
}
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set the new current frame and cursor values, based on the average time and value */
if (ked.i1) {
@@ -1984,9 +1994,12 @@ static void snap_graph_keys(bAnimContext *ac, short mode)
}
else
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
-
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -2006,9 +2019,6 @@ static int graphkeys_snap_exec(bContext *C, wmOperator *op)
/* snap keyframes */
snap_graph_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -2111,9 +2121,12 @@ static void mirror_graph_keys(bAnimContext *ac, short mode)
}
else
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, edit_cb, calchandles_fcurve);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
-
- BLI_freelistN(&anim_data);
+
+ ANIM_animdata_update(ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -2133,9 +2146,6 @@ static int graphkeys_mirror_exec(bContext *C, wmOperator *op)
/* mirror keyframes */
mirror_graph_keys(&ac, mode);
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -2185,11 +2195,12 @@ static int graphkeys_smooth_exec(bContext *C, wmOperator *UNUSED(op))
* Snap->Flatten Handles anyway.
*/
smooth_fcurve(ale->key_data);
+
+ ale->update |= ANIM_UPDATE_DEFAULT;
}
- BLI_freelistN(&anim_data);
-
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
+
+ ANIM_animdata_update(&ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
@@ -2217,39 +2228,33 @@ void GRAPH_OT_smooth(wmOperatorType *ot)
/* ******************** Add F-Modifier Operator *********************** */
-/* present a special customised popup menu for this, with some filtering */
-static int graph_fmodifier_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+static EnumPropertyItem *graph_fmodifier_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
- wmOperatorType *ot = WM_operatortype_find("GRAPH_OT_fmodifier_add", 1);
- uiPopupMenu *pup;
- uiLayout *layout;
- int i;
-
- pup = uiPupMenuBegin(C, IFACE_("Add F-Curve Modifier"), ICON_NONE);
- layout = uiPupMenuLayout(pup);
-
+ EnumPropertyItem *item = NULL;
+ int totitem = 0;
+ int i = 0;
+
+ if (C == NULL) {
+ return fmodifier_type_items;
+ }
+
/* start from 1 to skip the 'Invalid' modifier type */
for (i = 1; i < FMODIFIER_NUM_TYPES; i++) {
FModifierTypeInfo *fmi = get_fmodifier_typeinfo(i);
- PointerRNA props_ptr;
-
+ int index;
+
/* check if modifier is valid for this context */
if (fmi == NULL)
continue;
-
- /* create operator menu item with relevant properties filled in */
- props_ptr = uiItemFullO_ptr(layout, ot, IFACE_(fmi->name), ICON_NONE,
- NULL, WM_OP_EXEC_REGION_WIN, UI_ITEM_O_RETURN_PROPS);
- /* the only thing that gets set from the menu is the type of F-Modifier to add */
- RNA_enum_set(&props_ptr, "type", i);
- /* the following properties are just repeats of existing ones... */
- RNA_boolean_set(&props_ptr, "only_active", RNA_boolean_get(op->ptr, "only_active"));
+
+ index = RNA_enum_from_value(fmodifier_type_items, fmi->type);
+ RNA_enum_item_add(&item, &totitem, &fmodifier_type_items[index]);
}
- uiItemS(layout);
-
- uiPupMenuEnd(C, pup);
-
- return OPERATOR_CANCELLED;
+
+ RNA_enum_item_end(&item, &totitem);
+ *r_free = true;
+
+ return item;
}
static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
@@ -2289,11 +2294,12 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "Modifier could not be added (see console for details)");
break;
}
+
+ ale->update |= ANIM_UPDATE_DEPS;
}
- BLI_freelistN(&anim_data);
-
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
+
+ ANIM_animdata_update(&ac, &anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
// FIXME: this really isn't the best description for it...
@@ -2304,13 +2310,15 @@ static int graph_fmodifier_add_exec(bContext *C, wmOperator *op)
void GRAPH_OT_fmodifier_add(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Add F-Curve Modifier";
ot->idname = "GRAPH_OT_fmodifier_add";
ot->description = "Add F-Modifiers to the selected F-Curves";
/* api callbacks */
- ot->invoke = graph_fmodifier_add_invoke;
+ ot->invoke = WM_menu_invoke;
ot->exec = graph_fmodifier_add_exec;
ot->poll = graphop_selected_fcurve_poll;
@@ -2318,7 +2326,10 @@ void GRAPH_OT_fmodifier_add(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* id-props */
- ot->prop = RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
+ prop = RNA_def_enum(ot->srna, "type", fmodifier_type_items, 0, "Type", "");
+ RNA_def_enum_funcs(prop, graph_fmodifier_itemf);
+ ot->prop = prop;
+
RNA_def_boolean(ot->srna, "only_active", 1, "Only Active", "Only add F-Modifier to active F-Curve");
}
@@ -2398,19 +2409,26 @@ static int graph_fmodifier_paste_exec(bContext *C, wmOperator *op)
/* paste modifiers */
for (ale = anim_data.first; ale; ale = ale->next) {
FCurve *fcu = (FCurve *)ale->data;
+ int tot;
/* TODO: do we want to replace existing modifiers? add user pref for that! */
- ok += ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, 0);
+ tot = ANIM_fmodifiers_paste_from_buf(&fcu->modifiers, 0);
+
+ if (tot) {
+ ale->update |= ANIM_UPDATE_DEPS;
+ }
+
+ ok += tot;
}
-
- /* clean up */
- BLI_freelistN(&anim_data);
+
+ if (ok) {
+ ANIM_animdata_update(&ac, &anim_data);
+ }
+ ANIM_animdata_freelist(&anim_data);
/* successful or not? */
if (ok) {
- /* validate keyframes after editing */
- ANIM_editkeyframes_refresh(&ac);
-
+
/* set notifier that keyframes have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c
index cfd82b67289..62b6b59df29 100644
--- a/source/blender/editors/space_graph/graph_ops.c
+++ b/source/blender/editors/space_graph/graph_ops.c
@@ -167,6 +167,7 @@ static int graphview_cursor_modal(bContext *C, wmOperator *op, const wmEvent *ev
case LEFTMOUSE:
case RIGHTMOUSE:
+ case MIDDLEMOUSE:
/* we check for either mouse-button to end, as checking for ACTIONMOUSE (which is used to init
* the modal op) doesn't work for some reason
*/
@@ -441,8 +442,12 @@ void graphedit_keymap(wmKeyConfig *keyconf)
/* keymap for all regions */
keymap = WM_keymap_find(keyconf, "Graph Editor Generic", SPACE_IPO, 0);
WM_keymap_add_item(keymap, "GRAPH_OT_properties", NKEY, KM_PRESS, 0, 0);
+
/* extrapolation works on channels, not keys */
WM_keymap_add_item(keymap, "GRAPH_OT_extrapolation_type", EKEY, KM_PRESS, KM_SHIFT, 0);
+
+ /* 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);
/* channels */
/* Channels are not directly handled by the Graph Editor module, but are inherited from the Animation module.
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 82eddfbe4a9..378139accbc 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -141,7 +141,7 @@ static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short d
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -311,7 +311,7 @@ static void borderselect_graphkeys(
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -548,7 +548,7 @@ static void markers_selectkeys_between(bAnimContext *ac)
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
@@ -576,7 +576,7 @@ static void columnselect_graph_keys(bAnimContext *ac, short mode)
for (ale = anim_data.first; ale; ale = ale->next)
ANIM_fcurve_keyframes_loop(&ked, ale->key_data, NULL, bezt_to_cfraelem, NULL);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
break;
case GRAPHKEYS_COLUMNSEL_CFRA: /* current frame */
@@ -622,7 +622,7 @@ static void columnselect_graph_keys(bAnimContext *ac, short mode)
/* free elements */
BLI_freelistN(&ked.list);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -700,7 +700,7 @@ static int graphkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -764,7 +764,7 @@ static void select_moreless_graph_keys(bAnimContext *ac, short mode)
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ----------------- */
@@ -899,7 +899,7 @@ static void graphkeys_select_leftright(bAnimContext *ac, short leftright, short
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ----------------- */
@@ -1147,7 +1147,7 @@ static void get_nearest_fcurve_verts_list(bAnimContext *ac, const int mval[2], L
}
/* free channels */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* helper for find_nearest_fcurve_vert() - get the best match to use */
@@ -1400,7 +1400,7 @@ static void graphkeys_mselect_column(bAnimContext *ac, const int mval[2], short
/* free elements */
MEM_freeN(nvi);
BLI_freelistN(&ked.list);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c
index 07a582f7556..e9c8ae95acd 100644
--- a/source/blender/editors/space_graph/graph_utils.c
+++ b/source/blender/editors/space_graph/graph_utils.c
@@ -78,7 +78,7 @@ bAnimListElem *get_active_fcurve_channel(bAnimContext *ac)
/* remove first item from list, then free the rest of the list and return the stored one */
BLI_remlink(&anim_data, ale);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return ale;
}
@@ -135,7 +135,7 @@ int graphop_visible_keyframes_poll(bContext *C)
}
/* cleanup and return findings */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return found;
}
@@ -185,7 +185,7 @@ int graphop_editable_keyframes_poll(bContext *C)
}
/* cleanup and return findings */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return found;
}
@@ -251,7 +251,7 @@ int graphop_selected_fcurve_poll(bContext *C)
return 0;
/* cleanup and return findings */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return 1;
}
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index bfc1bcbcba0..6dba706b241 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -607,7 +607,7 @@ static void graph_refresh(const bContext *C, ScrArea *sa)
}
/* free temp list */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
}
diff --git a/source/blender/editors/space_image/CMakeLists.txt b/source/blender/editors/space_image/CMakeLists.txt
index 62ac3c2d985..30bfc2fbdfd 100644
--- a/source/blender/editors/space_image/CMakeLists.txt
+++ b/source/blender/editors/space_image/CMakeLists.txt
@@ -23,14 +23,15 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
- ../../imbuf
../../bmesh
+ ../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
- ../../gpu
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -71,4 +72,6 @@ if(WITH_IMAGE_CINEON)
add_definitions(-DWITH_CINEON)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_image "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_image/SConscript b/source/blender/editors/space_image/SConscript
index d878a726b55..e983db431b4 100644
--- a/source/blender/editors/space_image/SConscript
+++ b/source/blender/editors/space_image/SConscript
@@ -31,12 +31,14 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../bmesh',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -46,7 +48,7 @@ incs = [
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index c2b9d92d00a..154437ab53a 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -284,10 +284,10 @@ static void image_panel_preview(ScrArea *sa, short cntrl) // IMAGE_HANDLER_PRE
/* ********************* callbacks for standard image buttons *************** */
-static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *render_slot_p)
+static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *image_p)
{
uiBlock *block = uiLayoutGetBlock(layout);
- short *render_slot = render_slot_p;
+ Image *image = image_p;
int slot;
uiDefBut(block, LABEL, 0, IFACE_("Slot"),
@@ -296,10 +296,15 @@ static void ui_imageuser_slot_menu(bContext *UNUSED(C), uiLayout *layout, void *
slot = IMA_MAX_RENDER_SLOT;
while (slot--) {
- char str[32];
- BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), slot + 1);
+ char str[64];
+ if (image->render_slots[slot].name[0] != '\0') {
+ BLI_strncpy(str, image->render_slots[slot].name, sizeof(str));
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), slot + 1);
+ }
uiDefButS(block, BUTM, B_NOP, str, 0, 0,
- UI_UNIT_X * 5, UI_UNIT_X, render_slot, (float) slot, 0.0, 0, -1, "");
+ UI_UNIT_X * 5, UI_UNIT_X, &image->render_slot, (float) slot, 0.0, 0, -1, "");
}
}
@@ -320,13 +325,21 @@ static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void
{
void **rnd_data = rnd_pt;
uiBlock *block = uiLayoutGetBlock(layout);
- RenderResult *rr = rnd_data[0];
+ Image *image = rnd_data[0];
ImageUser *iuser = rnd_data[1];
+ Scene *scene = iuser->scene;
+ RenderResult *rr;
RenderLayer *rl;
RenderLayer rl_fake = {NULL};
const char *fake_name;
int nr;
+ /* may have been freed since drawing */
+ rr = BKE_image_acquire_renderresult(scene, image);
+ if (UNLIKELY(rr == NULL)) {
+ return;
+ }
+
uiBlockSetCurLayout(block, layout);
uiLayoutColumn(layout, false);
@@ -355,6 +368,8 @@ final:
}
BLI_assert(nr == -1);
+
+ BKE_image_release_renderresult(scene, image);
}
static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
@@ -369,17 +384,28 @@ static const char *ui_imageuser_pass_fake_name(RenderLayer *rl)
static void ui_imageuser_pass_menu(bContext *UNUSED(C), uiLayout *layout, void *ptrpair_p)
{
- void **ptrpair = ptrpair_p;
+ void **rnd_data = ptrpair_p;
uiBlock *block = uiLayoutGetBlock(layout);
- // RenderResult *rr = ptrpair[0];
- ImageUser *iuser = ptrpair[1];
- /* rl==NULL means composite result */
- RenderLayer *rl = ptrpair[2];
+ Image *image = rnd_data[0];
+ ImageUser *iuser = rnd_data[1];
+ /* (rpass_index == -1) means composite result */
+ const int rpass_index = GET_INT_FROM_POINTER(rnd_data[2]);
+ Scene *scene = iuser->scene;
+ RenderResult *rr;
+ RenderLayer *rl;
RenderPass rpass_fake = {NULL};
RenderPass *rpass;
const char *fake_name;
int nr;
+ /* may have been freed since drawing */
+ rr = BKE_image_acquire_renderresult(scene, image);
+ if (UNLIKELY(rr == NULL)) {
+ return;
+ }
+
+ rl = BLI_findlink(&rr->layers, rpass_index);
+
uiBlockSetCurLayout(block, layout);
uiLayoutColumn(layout, false);
@@ -410,6 +436,8 @@ final:
}
BLI_assert(nr == -1);
+
+ BKE_image_release_renderresult(scene, image);
}
/* 5 layer button callbacks... */
@@ -492,7 +520,7 @@ static void image_user_change(bContext *C, void *iuser_v, void *unused)
}
#endif
-static void uiblock_layer_pass_buttons(uiLayout *layout, RenderResult *rr, ImageUser *iuser, int w, short *render_slot)
+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 */
uiBlock *block = uiLayoutGetBlock(layout);
@@ -509,26 +537,33 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, RenderResult *rr, Image
wmenu2 = (3 * w) / 5;
wmenu3 = (3 * w) / 6;
- rnd_pt[0] = rr;
+ rnd_pt[0] = image;
rnd_pt[1] = iuser;
rnd_pt[2] = NULL;
/* menu buts */
if (render_slot) {
char str[64];
- BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1);
- but = uiDefMenuBut(block, ui_imageuser_slot_menu, render_slot, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot"));
+ if (image->render_slots[*render_slot].name[0] != '\0') {
+ BLI_strncpy(str, image->render_slots[*render_slot].name, sizeof(str));
+ }
+ else {
+ BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1);
+ }
+ but = uiDefMenuBut(block, ui_imageuser_slot_menu, image, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot"));
uiButSetFunc(but, image_multi_cb, rr, iuser);
uiButSetMenuFromPulldown(but);
}
if (rr) {
RenderPass *rpass;
+ int rpass_index;
/* layer */
fake_name = ui_imageuser_layer_fake_name(rr);
- rl = BLI_findlink(&rr->layers, iuser->layer - (fake_name ? 1 : 0));
- rnd_pt[2] = rl;
+ rpass_index = iuser->layer - (fake_name ? 1 : 0);
+ 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"));
@@ -547,7 +582,7 @@ static void uiblock_layer_pass_buttons(uiLayout *layout, RenderResult *rr, Image
}
}
-static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, RenderResult *rr, ImageUser *iuser, short *render_slot)
+static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, short *render_slot)
{
uiBlock *block = uiLayoutGetBlock(layout);
uiLayout *row;
@@ -569,7 +604,7 @@ static void uiblock_layer_pass_arrow_buttons(uiLayout *layout, RenderResult *rr,
but = uiDefIconBut(block, BUT, 0, ICON_TRIA_RIGHT, 0, 0, 0.90f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Next Layer"));
uiButSetFunc(but, image_multi_inclay_cb, rr, iuser);
- uiblock_layer_pass_buttons(row, rr, iuser, 230 * dpi_fac, render_slot);
+ uiblock_layer_pass_buttons(row, image, rr, iuser, 230 * dpi_fac, render_slot);
/* decrease, increase arrows */
but = uiDefIconBut(block, BUT, 0, ICON_TRIA_LEFT, 0, 0, 0.85f * UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Previous Pass"));
@@ -691,7 +726,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
/* 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, rr, iuser, &ima->render_slot);
+ uiblock_layer_pass_arrow_buttons(layout, ima, rr, iuser, &ima->render_slot);
BKE_image_release_renderresult(scene, ima);
}
}
@@ -724,7 +759,7 @@ 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->rr, iuser, NULL);
+ uiblock_layer_pass_arrow_buttons(layout, ima, ima->rr, iuser, NULL);
}
else if (ima->source != IMA_SRC_GENERATED) {
if (compact == 0) {
@@ -809,6 +844,10 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
uiItemR(col, &imaptr, "use_generated_float", 0, NULL, ICON_NONE);
uiItemR(split, &imaptr, "generated_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE);
+
+ if (ima->gen_type == IMA_GENTYPE_BLANK) {
+ uiItemR(layout, &imaptr, "generated_color", 0, NULL, ICON_NONE);
+ }
}
}
@@ -843,14 +882,14 @@ void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_man
uiItemR(sub, imfptr, "color_mode", UI_ITEM_R_EXPAND, IFACE_("Color"), ICON_NONE);
/* only display depth setting if multiple depths can be used */
- if ((ELEM7(depth_ok,
- R_IMF_CHAN_DEPTH_1,
- R_IMF_CHAN_DEPTH_8,
- R_IMF_CHAN_DEPTH_10,
- R_IMF_CHAN_DEPTH_12,
- R_IMF_CHAN_DEPTH_16,
- R_IMF_CHAN_DEPTH_24,
- R_IMF_CHAN_DEPTH_32)) == 0)
+ if ((ELEM(depth_ok,
+ R_IMF_CHAN_DEPTH_1,
+ R_IMF_CHAN_DEPTH_8,
+ R_IMF_CHAN_DEPTH_10,
+ R_IMF_CHAN_DEPTH_12,
+ R_IMF_CHAN_DEPTH_16,
+ R_IMF_CHAN_DEPTH_24,
+ R_IMF_CHAN_DEPTH_32)) == 0)
{
row = uiLayoutRow(col, false);
@@ -933,7 +972,7 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser
/* 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, rr, iuser, 160 * dpi_fac, (ima->type == IMA_TYPE_R_RESULT) ? &ima->render_slot : NULL);
+ uiblock_layer_pass_buttons(layout, ima, rr, iuser, 160 * dpi_fac, (ima->type == IMA_TYPE_R_RESULT) ? &ima->render_slot : NULL);
BKE_image_release_renderresult(scene, ima);
}
}
@@ -947,8 +986,8 @@ void image_buttons_register(ARegionType *art)
strcpy(pt->idname, "IMAGE_PT_gpencil");
strcpy(pt->label, N_("Grease Pencil"));
strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = gpencil_panel_standard_header;
- pt->draw = gpencil_panel_standard;
+ pt->draw_header = ED_gpencil_panel_standard_header;
+ pt->draw = ED_gpencil_panel_standard;
BLI_strncpy(pt->category, category, BLI_strlen_utf8(category));
BLI_addtail(&art->paneltypes, pt);
}
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 016143f640b..f41e237beb4 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -83,6 +83,7 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx,
{
RenderResult *rr;
Render *re = RE_GetRender(scene->id.name);
+ RenderData *rd = RE_engine_get_render_data(re);
rr = BKE_image_acquire_renderresult(scene, ima);
@@ -110,48 +111,16 @@ static void draw_render_info(Scene *scene, Image *ima, ARegion *ar, float zoomx,
glTranslatef(x, y, 0.0f);
glScalef(zoomx, zoomy, 1.0f);
- if (scene->r.mode & R_BORDER) {
- glTranslatef((int)(-scene->r.border.xmin * scene->r.xsch * scene->r.size / 100.0f),
- (int)(-scene->r.border.ymin * scene->r.ysch * scene->r.size / 100.0f),
+ if (rd->mode & R_BORDER) {
+ glTranslatef((int)(-rd->border.xmin * rd->xsch * rd->size / 100.0f),
+ (int)(-rd->border.ymin * rd->ysch * rd->size / 100.0f),
0.0f);
}
UI_ThemeColor(TH_FACE_SELECT);
for (i = 0, tile = tiles; i < total_tiles; i++, tile++) {
- float delta_x = 4.0f * UI_DPI_FAC / zoomx;
- float delta_y = 4.0f * UI_DPI_FAC / zoomy;
-
- delta_x = min_ff(delta_x, tile->xmax - tile->xmin);
- delta_y = min_ff(delta_y, tile->ymax - tile->ymin);
-
- /* left bottom corner */
- glBegin(GL_LINE_STRIP);
- glVertex2f(tile->xmin, tile->ymin + delta_y);
- glVertex2f(tile->xmin, tile->ymin);
- glVertex2f(tile->xmin + delta_x, tile->ymin);
- glEnd();
-
- /* left top corner */
- glBegin(GL_LINE_STRIP);
- glVertex2f(tile->xmin, tile->ymax - delta_y);
- glVertex2f(tile->xmin, tile->ymax);
- glVertex2f(tile->xmin + delta_x, tile->ymax);
- glEnd();
-
- /* right bottom corner */
- glBegin(GL_LINE_STRIP);
- glVertex2f(tile->xmax - delta_x, tile->ymin);
- glVertex2f(tile->xmax, tile->ymin);
- glVertex2f(tile->xmax, tile->ymin + delta_y);
- glEnd();
-
- /* right top corner */
- glBegin(GL_LINE_STRIP);
- glVertex2f(tile->xmax - delta_x, tile->ymax);
- glVertex2f(tile->xmax, tile->ymax);
- glVertex2f(tile->xmax, tile->ymax - delta_y);
- glEnd();
+ glaDrawBorderCorners(tile, zoomx, zoomy);
}
MEM_freeN(tiles);
@@ -644,14 +613,14 @@ void draw_image_grease_pencil(bContext *C, bool onlyv2d)
/* draw in View2D space? */
if (onlyv2d) {
/* draw grease-pencil ('image' strokes) */
- draw_gpencil_2dimage(C);
+ ED_gpencil_draw_2dimage(C);
}
else {
/* assume that UI_view2d_restore(C) has been called... */
//SpaceImage *sima = (SpaceImage *)CTX_wm_space_data(C);
/* draw grease-pencil ('screen' strokes) */
- draw_gpencil_view2d(C, 0);
+ ED_gpencil_draw_view2d(C, 0);
}
}
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index a2f7d9e7d6c..757059ebc29 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -28,6 +28,7 @@
* \ingroup spimage
*/
+#include "DNA_brush_types.h"
#include "DNA_mask_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -297,7 +298,7 @@ bool ED_space_image_show_render(SpaceImage *sima)
bool ED_space_image_show_paint(SpaceImage *sima)
{
if (ED_space_image_show_render(sima))
- return 0;
+ return false;
return (sima->mode == SI_MODE_PAINT);
}
@@ -305,36 +306,18 @@ bool ED_space_image_show_paint(SpaceImage *sima)
bool ED_space_image_show_uvedit(SpaceImage *sima, Object *obedit)
{
if (sima && (ED_space_image_show_render(sima) || ED_space_image_show_paint(sima)))
- return 0;
+ return false;
if (obedit && obedit->type == OB_MESH) {
struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
- int ret;
+ bool ret;
ret = EDBM_mtexpoly_check(em);
return ret;
}
- return 0;
-}
-
-bool ED_space_image_show_uvshadow(SpaceImage *sima, Object *obedit)
-{
- if (ED_space_image_show_render(sima))
- return 0;
-
- if (ED_space_image_show_paint(sima))
- if (obedit && obedit->type == OB_MESH) {
- struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
- int ret;
-
- ret = EDBM_mtexpoly_check(em);
-
- return ret;
- }
-
- return 0;
+ return false;
}
/* matches clip function */
@@ -361,6 +344,21 @@ int ED_space_image_maskedit_poll(bContext *C)
return false;
}
+bool ED_space_image_paint_curve(const bContext *C)
+{
+ SpaceImage *sima = CTX_wm_space_image(C);
+
+ if (sima && sima->mode == SI_MODE_PAINT) {
+ Brush *br = CTX_data_tool_settings(C)->imapaint.paint.brush;
+
+ if (br && (br->flag & BRUSH_CURVE))
+ return true;
+ }
+
+ return false;
+}
+
+
int ED_space_image_maskedit_mask_poll(bContext *C)
{
if (ED_space_image_maskedit_poll(C)) {
diff --git a/source/blender/editors/space_image/image_intern.h b/source/blender/editors/space_image/image_intern.h
index 4d391874f9b..aecc43f4fdf 100644
--- a/source/blender/editors/space_image/image_intern.h
+++ b/source/blender/editors/space_image/image_intern.h
@@ -71,6 +71,7 @@ void IMAGE_OT_view_ndof(struct wmOperatorType *ot);
void IMAGE_OT_new(struct wmOperatorType *ot);
void IMAGE_OT_open(struct wmOperatorType *ot);
+void IMAGE_OT_unlink(struct wmOperatorType *ot);
void IMAGE_OT_match_movie_length(struct wmOperatorType *ot);
void IMAGE_OT_replace(struct wmOperatorType *ot);
void IMAGE_OT_reload(struct wmOperatorType *ot);
@@ -90,6 +91,10 @@ void IMAGE_OT_curves_point_set(struct wmOperatorType *ot);
void IMAGE_OT_change_frame(struct wmOperatorType *ot);
+void IMAGE_OT_read_renderlayers(struct wmOperatorType *ot);
+void IMAGE_OT_render_border(struct wmOperatorType *ot);
+void IMAGE_OT_clear_render_border(struct wmOperatorType *ot);
+
/* image_panels.c */
struct ImageUser *ntree_get_active_iuser(struct bNodeTree *ntree);
void image_buttons_register(struct ARegionType *art);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index 57be15f23fb..df556f94f28 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -48,17 +48,21 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_icons.h"
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_packedFile.h"
+#include "BKE_paint.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BKE_sound.h"
#include "GPU_draw.h"
+#include "GPU_buffers.h"
#include "IMB_colormanagement.h"
#include "IMB_imbuf.h"
@@ -72,6 +76,7 @@
#include "RNA_enum_types.h"
#include "ED_image.h"
+#include "ED_paint.h"
#include "ED_render.h"
#include "ED_screen.h"
#include "ED_space_api.h"
@@ -88,7 +93,6 @@
#include "PIL_time.h"
#include "image_intern.h"
-#include "ED_sculpt.h"
/******************** view navigation utilities *********************/
@@ -564,6 +568,8 @@ static void image_view_zoom_cancel(bContext *C, wmOperator *op)
void IMAGE_OT_view_zoom(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Zoom";
ot->idname = "IMAGE_OT_view_zoom";
@@ -580,8 +586,9 @@ void IMAGE_OT_view_zoom(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_LOCK_BYPASS;
/* properties */
- RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX,
- "Factor", "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX);
+ prop = RNA_def_float(ot->srna, "factor", 0.0f, -FLT_MAX, FLT_MAX, "Factor",
+ "Zoom factor, values higher than 1.0 zoom in, lower values zoom out", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/********************** NDOF operator *********************/
@@ -799,6 +806,8 @@ static int image_view_zoom_in_invoke(bContext *C, wmOperator *op, const wmEvent
void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Zoom In";
ot->idname = "IMAGE_OT_view_zoom_in";
@@ -813,7 +822,9 @@ void IMAGE_OT_view_zoom_in(wmOperatorType *ot)
ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
- RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
+ prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
+ "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
static int image_view_zoom_out_exec(bContext *C, wmOperator *op)
@@ -844,6 +855,8 @@ static int image_view_zoom_out_invoke(bContext *C, wmOperator *op, const wmEvent
void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Zoom Out";
ot->idname = "IMAGE_OT_view_zoom_out";
@@ -858,7 +871,9 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot)
ot->flag = OPTYPE_LOCK_BYPASS;
/* properties */
- RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
+ prop = RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
+ "Location", "Cursor location in screen coordinates", -10.0f, 10.0f);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/********************** view zoom ratio operator *********************/
@@ -942,10 +957,10 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op)
}
/**
- * @brief Get a list of frames from the list of image files matching the first file name sequence pattern
- * @param ptr [in] the RNA pointer containing the "directory" entry and "files" collection
- * @param frames [out] the list of frame numbers found in the files matching the first one by name
- * @param path [out] the full path of the first file in the list of image files
+ * \brief Get a list of frames from the list of image files matching the first file name sequence pattern
+ * \param ptr [in] the RNA pointer containing the "directory" entry and "files" collection
+ * \param frames [out] the list of frame numbers found in the files matching the first one by name
+ * \param path [out] the full path of the first file in the list of image files
*/
static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen)
{
@@ -989,10 +1004,10 @@ static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *p
RNA_END
}
-static int image_cmp_frame(void *a, void *b)
+static int image_cmp_frame(const void *a, const void *b)
{
- ImageFrame *frame_a = (ImageFrame *)a;
- ImageFrame *frame_b = (ImageFrame *)b;
+ const ImageFrame *frame_a = a;
+ const ImageFrame *frame_b = b;
if (frame_a->framenr < frame_b->framenr) return -1;
if (frame_a->framenr > frame_b->framenr) return 1;
@@ -1000,10 +1015,10 @@ static int image_cmp_frame(void *a, void *b)
}
/**
- * @brief Return the start (offset) and the length of the sequence of continuous frames in the list of frames
- * @param frames [in] the list of frame numbers, as a side-effect the list is sorted
- * @param ofs [out] offest, the first frame number in the sequence
- * @return the number of continuos frames in the sequence
+ * \brief Return the start (offset) and the length of the sequence of continuous frames in the list of frames
+ * \param frames [in] the list of frame numbers, as a side-effect the list is sorted
+ * \param ofs [out] offest, the first frame number in the sequence
+ * \return the number of contiguous frames in the sequence
*/
static int image_sequence_get_len(ListBase *frames, int *ofs)
{
@@ -1040,7 +1055,11 @@ static int image_open_exec(bContext *C, wmOperator *op)
const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
- if (RNA_struct_property_is_set(op->ptr, "files") && RNA_struct_property_is_set(op->ptr, "directory")) {
+ 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"))
+ {
ListBase frames;
BLI_listbase_clear(&frames);
@@ -1048,9 +1067,6 @@ static int image_open_exec(bContext *C, wmOperator *op)
frame_seq_len = image_sequence_get_len(&frames, &frame_ofs);
BLI_freelistN(&frames);
}
- else {
- RNA_string_get(op->ptr, "filepath", path);
- }
errno = 0;
@@ -1381,7 +1397,7 @@ static int save_image_options_init(SaveImageOptions *simopts, SpaceImage *sima,
/* sanitize all settings */
/* unlikely but just in case */
- if (ELEM3(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
+ if (ELEM(simopts->im_format.planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB, R_IMF_PLANES_RGBA) == 0) {
simopts->im_format.planes = R_IMF_PLANES_RGBA;
}
@@ -1483,9 +1499,12 @@ static bool save_image_doit(bContext *C, SpaceImage *sima, wmOperator *op, SaveI
}
else {
/* TODO, better solution, if a 24bit image is painted onto it may contain alpha */
- if (ibuf->userflags & IB_BITMAPDIRTY) { /* it has been painted onto */
+ if ((simopts->im_format.planes == R_IMF_PLANES_RGBA) &&
+ /* it has been painted onto */
+ (ibuf->userflags & IB_BITMAPDIRTY))
+ {
/* checks each pixel, not ideal */
- ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? 32 : 24;
+ ibuf->planes = BKE_imbuf_alpha_test(ibuf) ? R_IMF_PLANES_RGBA : R_IMF_PLANES_RGB;
}
}
@@ -1865,6 +1884,7 @@ static int image_reload_exec(bContext *C, wmOperator *UNUSED(op))
// XXX other users?
BKE_image_signal(ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_RELOAD);
+ DAG_id_tag_update(&ima->id, 0);
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
@@ -1888,6 +1908,12 @@ void IMAGE_OT_reload(wmOperatorType *ot)
/********************** new image operator *********************/
#define IMA_DEF_NAME N_("Untitled")
+enum {
+ GEN_CONTEXT_NONE = 0,
+ GEN_CONTEXT_PAINT_CANVAS = 1,
+ GEN_CONTEXT_PAINT_STENCIL = 2
+};
+
static int image_new_exec(bContext *C, wmOperator *op)
{
SpaceImage *sima;
@@ -1901,6 +1927,7 @@ static int image_new_exec(bContext *C, wmOperator *op)
char *name = _name;
float color[4];
int width, height, floatbuf, gen_type, alpha;
+ int gen_context;
/* retrieve state */
sima = CTX_wm_space_image(C);
@@ -1920,7 +1947,8 @@ static int image_new_exec(bContext *C, wmOperator *op)
gen_type = RNA_enum_get(op->ptr, "generated_type");
RNA_float_get_array(op->ptr, "color", color);
alpha = RNA_boolean_get(op->ptr, "alpha");
-
+ gen_context = RNA_enum_get(op->ptr, "gen_context");
+
if (!alpha)
color[3] = 1.0f;
@@ -1944,6 +1972,40 @@ static int image_new_exec(bContext *C, wmOperator *op)
else if (sima) {
ED_space_image_set(sima, scene, obedit, ima);
}
+ else if (gen_context == GEN_CONTEXT_PAINT_CANVAS) {
+ bScreen *sc;
+ Object *ob = CTX_data_active_object(C);
+
+ GPU_drawobject_free(ob->derivedFinal);
+ if (scene->toolsettings->imapaint.canvas)
+ id_us_min(&scene->toolsettings->imapaint.canvas->id);
+ scene->toolsettings->imapaint.canvas = ima;
+
+ 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) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ if (!sima->pin)
+ ED_space_image_set(sima, scene, scene->obedit, ima);
+ }
+ }
+ }
+ }
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
+ else if (gen_context == GEN_CONTEXT_PAINT_STENCIL) {
+ Object *ob = CTX_data_active_object(C);
+ if (scene->toolsettings->imapaint.stencil)
+ id_us_min(&scene->toolsettings->imapaint.stencil->id);
+ scene->toolsettings->imapaint.stencil = ima;
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ }
else {
Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data;
if (tex && tex->type == TEX_IMAGE) {
@@ -1974,6 +2036,13 @@ void IMAGE_OT_new(wmOperatorType *ot)
{
PropertyRNA *prop;
static float default_color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
+
+ static EnumPropertyItem gen_context_items[] = {
+ {GEN_CONTEXT_NONE, "NONE", 0, "None", ""},
+ {GEN_CONTEXT_PAINT_CANVAS, "PAINT_CANVAS", 0, "Paint Canvas", ""},
+ {GEN_CONTEXT_PAINT_STENCIL, "PAINT_STENCIL", 0, "Paint Stencil", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
/* identifiers */
ot->name = "New Image";
@@ -2000,6 +2069,9 @@ void IMAGE_OT_new(wmOperatorType *ot)
RNA_def_enum(ot->srna, "generated_type", image_generated_type_items, IMA_GENTYPE_BLANK,
"Generated Type", "Fill the image with a grid for UV map testing");
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);
+
}
#undef IMA_DEF_NAME
@@ -2034,7 +2106,7 @@ static int image_invert_exec(bContext *C, wmOperator *op)
if (support_undo) {
ED_undo_paint_push_begin(UNDO_PAINT_IMAGE, op->type->name,
- ED_image_undo_restore, ED_image_undo_free);
+ ED_image_undo_restore, ED_image_undo_free, NULL);
/* 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();
@@ -2458,11 +2530,12 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event
int point = RNA_enum_get(op->ptr, "point");
if (point == 1) {
- curvemapping_set_black_white(curve_mapping, NULL, info->colfp);
+ curvemapping_set_black_white(curve_mapping, NULL, info->linearcol);
}
else if (point == 0) {
- curvemapping_set_black_white(curve_mapping, info->colfp, NULL);
+ curvemapping_set_black_white(curve_mapping, info->linearcol, NULL);
}
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
}
}
@@ -2996,3 +3069,120 @@ void IMAGE_OT_change_frame(wmOperatorType *ot)
/* rna */
RNA_def_int(ot->srna, "frame", 0, MINAFRAME, MAXFRAME, "Frame", "", MINAFRAME, MAXFRAME);
}
+
+/* Reload cached render results... */
+/* goes over all scenes, reads render layers */
+static int image_read_renderlayers_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ SpaceImage *sima = CTX_wm_space_image(C);
+ Image *ima;
+
+ ima = BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
+ if (sima->image == NULL) {
+ ED_space_image_set(sima, scene, NULL, ima);
+ }
+
+ RE_ReadRenderResult(scene, scene);
+
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima);
+ return OPERATOR_FINISHED;
+}
+
+void IMAGE_OT_read_renderlayers(wmOperatorType *ot)
+{
+ ot->name = "Read Render Layers";
+ ot->idname = "IMAGE_OT_read_renderlayers";
+ ot->description = "Read all the current scene's render layers from cache, as needed";
+
+ ot->poll = space_image_main_area_poll;
+ ot->exec = image_read_renderlayers_exec;
+
+ /* flags */
+ ot->flag = 0;
+}
+
+/* ********************* Render border operator ****************** */
+
+static int render_border_exec(bContext *C, wmOperator *op)
+{
+ ARegion *ar = CTX_wm_region(C);
+ Scene *scene = CTX_data_scene(C);
+ rctf border;
+
+ /* get rectangle from operator */
+ WM_operator_properties_border_to_rctf(op, &border);
+ UI_view2d_region_to_view_rctf(&ar->v2d, &border, &border);
+
+ /* actually set border */
+ CLAMP(border.xmin, 0.0f, 1.0f);
+ CLAMP(border.ymin, 0.0f, 1.0f);
+ CLAMP(border.xmax, 0.0f, 1.0f);
+ CLAMP(border.ymax, 0.0f, 1.0f);
+ scene->r.border = border;
+
+ /* drawing a border surrounding the entire camera view switches off border rendering
+ * or the border covers no pixels */
+ if ((border.xmin <= 0.0f && border.xmax >= 1.0f &&
+ border.ymin <= 0.0f && border.ymax >= 1.0f) ||
+ (border.xmin == border.xmax || border.ymin == border.ymax))
+ {
+ scene->r.mode &= ~R_BORDER;
+ }
+ else {
+ scene->r.mode |= R_BORDER;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ return OPERATOR_FINISHED;
+
+}
+
+void IMAGE_OT_render_border(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Render Border";
+ ot->description = "Set the boundaries of the border render and enable border render";
+ ot->idname = "IMAGE_OT_render_border";
+
+ /* api callbacks */
+ ot->invoke = WM_border_select_invoke;
+ ot->exec = render_border_exec;
+ ot->modal = WM_border_select_modal;
+ ot->cancel = WM_border_select_cancel;
+ ot->poll = image_cycle_render_slot_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* rna */
+ WM_operator_properties_border(ot);
+}
+
+/* ********************* Clear render border operator ****************** */
+
+static int clear_render_border_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ scene->r.mode &= ~R_BORDER;
+ WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ BLI_rctf_init(&scene->r.border, 0.0f, 1.0f, 0.0f, 1.0f);
+ return OPERATOR_FINISHED;
+
+}
+
+void IMAGE_OT_clear_render_border(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Render Border";
+ ot->description = "Clear the boundaries of the border render and disable border render";
+ ot->idname = "IMAGE_OT_clear_render_border";
+
+ /* api callbacks */
+ ot->exec = clear_render_border_exec;
+ ot->poll = image_cycle_render_slot_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index f60705ca52a..9cfd2e645f9 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -255,6 +255,10 @@ static void image_operatortypes(void)
WM_operatortype_append(IMAGE_OT_toolshelf);
WM_operatortype_append(IMAGE_OT_change_frame);
+
+ WM_operatortype_append(IMAGE_OT_read_renderlayers);
+ WM_operatortype_append(IMAGE_OT_render_border);
+ WM_operatortype_append(IMAGE_OT_clear_render_border);
}
static void image_keymap(struct wmKeyConfig *keyconf)
@@ -266,6 +270,7 @@ static void image_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "IMAGE_OT_new", NKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_open", OKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_reload", RKEY, KM_PRESS, KM_ALT, 0);
+ WM_keymap_add_item(keymap, "IMAGE_OT_read_renderlayers", RKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_save", SKEY, KM_PRESS, KM_ALT, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_save_as", F3KEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "IMAGE_OT_properties", NKEY, KM_PRESS, 0, 0);
@@ -322,9 +327,9 @@ static void image_keymap(struct wmKeyConfig *keyconf)
RNA_boolean_set(kmi->ptr, "toggle", true);
/* fast switch to render slots */
- for (i = 0; i < MAX2(IMA_MAX_RENDER_SLOT, 9); i++) {
+ for (i = 0; i < MIN2(IMA_MAX_RENDER_SLOT, 9); i++) {
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_int", ONEKEY + i, KM_PRESS, 0, 0);
- RNA_string_set(kmi->ptr, "data_path", "space_data.image.render_slot");
+ RNA_string_set(kmi->ptr, "data_path", "space_data.image.render_slots.active_index");
RNA_int_set(kmi->ptr, "value", i);
}
@@ -340,13 +345,17 @@ static void image_keymap(struct wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", PERIODKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "space_data.pivot_point");
RNA_string_set(kmi->ptr, "value", "CURSOR");
+
+ /* render border */
+ WM_keymap_add_item(keymap, "IMAGE_OT_render_border", BKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "IMAGE_OT_clear_render_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
}
/* dropboxes */
static int image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_PATH)
- if (ELEM3(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */
+ if (ELEM(drag->icon, 0, ICON_FILE_IMAGE, ICON_FILE_BLANK)) /* rule might not work? */
return 1;
return 0;
}
@@ -529,6 +538,19 @@ static void image_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
break;
}
+ case NC_ID:
+ {
+ if (wmn->action == NA_RENAME) {
+ ED_area_tag_redraw(sa);
+ }
+ break;
+ }
+ case NC_WM:
+ if (wmn->data == ND_UNDO) {
+ ED_area_tag_redraw(sa);
+ ED_area_tag_refresh(sa);
+ }
+ break;
}
}
@@ -623,6 +645,12 @@ static void image_main_area_init(wmWindowManager *wm, ARegion *ar)
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
/* image paint polls for mode */
+ keymap = WM_keymap_find(wm->defaultconf, "Curve", 0, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+ keymap = WM_keymap_find(wm->defaultconf, "Paint Curve", 0, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
+
keymap = WM_keymap_find(wm->defaultconf, "Image Paint", 0, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
@@ -647,6 +675,7 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
Object *obact = CTX_data_active_object(C);
Object *obedit = CTX_data_edit_object(C);
Mask *mask = NULL;
+ bool curve = false;
Scene *scene = CTX_data_scene(C);
View2D *v2d = &ar->v2d;
//View2DScrollers *scrollers;
@@ -692,6 +721,9 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
else if (sima->mode == SI_MODE_MASK) {
mask = ED_space_image_get_mask(sima);
}
+ else if (ED_space_image_paint_curve(C)) {
+ curve = true;
+ }
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
@@ -743,6 +775,11 @@ static void image_main_area_draw(const bContext *C, ARegion *ar)
draw_image_cursor(ar, sima->cursor);
UI_view2d_view_restore(C);
}
+ else if (curve) {
+ UI_view2d_view_ortho(v2d);
+ draw_image_cursor(ar, sima->cursor);
+ UI_view2d_view_restore(C);
+ }
draw_image_cache(C, ar);
diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt
index 94b40a9f40a..46ea251de03 100644
--- a/source/blender/editors/space_info/CMakeLists.txt
+++ b/source/blender/editors/space_info/CMakeLists.txt
@@ -26,10 +26,12 @@ set(INC
../../blenloader
../../imbuf
../../bmesh
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -52,4 +54,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_info "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_info/SConscript b/source/blender/editors/space_info/SConscript
index 2a1419984c6..378940805da 100644
--- a/source/blender/editors/space_info/SConscript
+++ b/source/blender/editors/space_info/SConscript
@@ -31,13 +31,15 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../blenloader',
'../../bmesh',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -45,7 +47,7 @@ incs = [
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c
index 8664ebf30b7..a0dfb285a1c 100644
--- a/source/blender/editors/space_info/info_stats.c
+++ b/source/blender/editors/space_info/info_stats.c
@@ -57,6 +57,7 @@
#include "ED_armature.h"
#define MAX_INFO_LEN 512
+#define MAX_INFO_NUM_LEN 16
typedef struct SceneStats {
int totvert, totvertsel;
@@ -65,11 +66,22 @@ typedef struct SceneStats {
int totbone, totbonesel;
int totobj, totobjsel;
int totlamp, totlampsel;
- int tottri, totmesh;
+ int tottri;
char infostr[MAX_INFO_LEN];
} SceneStats;
+typedef struct SceneStatsFmt {
+ /* Totals */
+ char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN];
+ char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN];
+ char totedge[MAX_INFO_NUM_LEN], totedgesel[MAX_INFO_NUM_LEN];
+ char totbone[MAX_INFO_NUM_LEN], totbonesel[MAX_INFO_NUM_LEN];
+ char totobj[MAX_INFO_NUM_LEN], totobjsel[MAX_INFO_NUM_LEN];
+ char totlamp[MAX_INFO_NUM_LEN], totlampsel[MAX_INFO_NUM_LEN];
+ char tottri[MAX_INFO_NUM_LEN];
+} SceneStatsFmt;
+
static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
{
switch (ob->type) {
@@ -79,8 +91,6 @@ static void stats_object(Object *ob, int sel, int totob, SceneStats *stats)
DerivedMesh *dm = ob->derivedFinal;
int totvert, totedge, totface, totloop;
- stats->totmesh += totob;
-
if (dm) {
totvert = dm->getNumVerts(dm);
totedge = dm->getNumEdges(dm);
@@ -367,6 +377,7 @@ static void stats_string(Scene *scene)
{
#define MAX_INFO_MEM_LEN 64
SceneStats *stats = scene->stats;
+ SceneStatsFmt stats_fmt;
Object *ob = (scene->basact) ? scene->basact->object : NULL;
uintptr_t mem_in_use, mmap_in_use;
char memstr[MAX_INFO_MEM_LEN];
@@ -376,6 +387,34 @@ static void stats_string(Scene *scene)
mem_in_use = MEM_get_memory_in_use();
mmap_in_use = MEM_get_mapped_memory_in_use();
+
+ /* Generate formatted numbers */
+#define SCENE_STATS_FMT_INT(_id) \
+ BLI_str_format_int_grouped(stats_fmt._id, stats->_id)
+
+ SCENE_STATS_FMT_INT(totvert);
+ SCENE_STATS_FMT_INT(totvertsel);
+
+ SCENE_STATS_FMT_INT(totedge);
+ SCENE_STATS_FMT_INT(totedgesel);
+
+ SCENE_STATS_FMT_INT(totface);
+ SCENE_STATS_FMT_INT(totfacesel);
+
+ SCENE_STATS_FMT_INT(totbone);
+ SCENE_STATS_FMT_INT(totbonesel);
+
+ SCENE_STATS_FMT_INT(totobj);
+ SCENE_STATS_FMT_INT(totobjsel);
+
+ SCENE_STATS_FMT_INT(totlamp);
+ SCENE_STATS_FMT_INT(totlampsel);
+
+ SCENE_STATS_FMT_INT(tottri);
+
+#undef SCENE_STATS_FMT_INT
+
+
/* get memory statistics */
s = memstr;
ofs += BLI_snprintf(s + ofs, MAX_INFO_MEM_LEN - ofs, IFACE_(" | Mem:%.2fM"),
@@ -394,32 +433,36 @@ static void stats_string(Scene *scene)
if (scene->obedit->type == OB_MESH) {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
- IFACE_("Verts:%d/%d | Edges:%d/%d | Faces:%d/%d | Tris:%d"),
- stats->totvertsel, stats->totvert, stats->totedgesel, stats->totedge,
- stats->totfacesel, stats->totface, stats->tottri);
+ IFACE_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"),
+ stats_fmt.totvertsel, stats_fmt.totvert, stats_fmt.totedgesel, stats_fmt.totedge,
+ stats_fmt.totfacesel, stats_fmt.totface, stats_fmt.tottri);
}
else if (scene->obedit->type == OB_ARMATURE) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d | Bones:%d/%d"), stats->totvertsel,
- stats->totvert, stats->totbonesel, stats->totbone);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s/%s | Bones:%s/%s"), stats_fmt.totvertsel,
+ stats_fmt.totvert, stats_fmt.totbonesel, stats_fmt.totbone);
}
else {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d/%d"), stats->totvertsel, stats->totvert);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s/%s"), stats_fmt.totvertsel,
+ stats_fmt.totvert);
}
ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs);
}
else if (ob && (ob->mode & OB_MODE_POSE)) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%d/%d %s"),
- stats->totbonesel, stats->totbone, memstr);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Bones:%s/%s %s"),
+ stats_fmt.totbonesel, stats_fmt.totbone, memstr);
}
else if (stats_is_object_dynamic_topology_sculpt(ob)) {
- ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%d | Tris:%d"), stats->totvert, stats->tottri);
+ ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, IFACE_("Verts:%s | Tris:%s"), stats_fmt.totvert,
+ stats_fmt.tottri);
}
else {
ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs,
- IFACE_("Verts:%d | Faces:%d | Tris:%d | Objects:%d/%d | Lamps:%d/%d%s"), stats->totvert,
- stats->totface, stats->tottri, stats->totobjsel, stats->totobj, stats->totlampsel,
- stats->totlamp, memstr);
+ IFACE_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s | Lamps:%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);
}
if (ob)
diff --git a/source/blender/editors/space_info/textview.c b/source/blender/editors/space_info/textview.c
index c09c684ac7a..33333e4c992 100644
--- a/source/blender/editors/space_info/textview.c
+++ b/source/blender/editors/space_info/textview.c
@@ -290,7 +290,7 @@ int textview_draw(TextViewContext *tvc, const int draw, int mval[2], void **mous
cdc.lheight = tvc->lheight;
cdc.lofs = -BLF_descender(mono);
/* note, scroll bar must be already subtracted () */
- cdc.console_width = (tvc->winx - (CONSOLE_DRAW_MARGIN * 2) ) / cdc.cwidth;
+ cdc.console_width = (tvc->winx - (CONSOLE_DRAW_MARGIN * 2)) / cdc.cwidth;
/* avoid divide by zero on small windows */
if (cdc.console_width < 1)
cdc.console_width = 1;
diff --git a/source/blender/editors/space_logic/CMakeLists.txt b/source/blender/editors/space_logic/CMakeLists.txt
index af2e8476511..19525c87923 100644
--- a/source/blender/editors/space_logic/CMakeLists.txt
+++ b/source/blender/editors/space_logic/CMakeLists.txt
@@ -24,10 +24,12 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -47,6 +49,8 @@ if(WITH_GAMEENGINE)
add_definitions(-DWITH_GAMEENGINE)
endif()
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/editors/space_logic/SConscript b/source/blender/editors/space_logic/SConscript
index ae8e929a684..067073fab22 100644
--- a/source/blender/editors/space_logic/SConscript
+++ b/source/blender/editors/space_logic/SConscript
@@ -31,12 +31,14 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../interface',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -44,7 +46,7 @@ incs = [
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_GAMEENGINE']:
defs.append('WITH_GAMEENGINE')
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 4b533292a95..dd152022762 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -519,6 +519,8 @@ static const char *actuator_name(int type)
return N_("Armature");
case ACT_STEERING:
return N_("Steering");
+ case ACT_MOUSE:
+ return N_("Mouse");
}
return N_("Unknown");
}
@@ -1142,15 +1144,30 @@ static void draw_sensor_message(uiLayout *layout, PointerRNA *ptr)
uiItemR(layout, ptr, "subject", 0, NULL, ICON_NONE);
}
-static void draw_sensor_mouse(uiLayout *layout, PointerRNA *ptr)
+static void draw_sensor_mouse(uiLayout *layout, PointerRNA *ptr, bContext *C)
{
- uiLayout *split;
+ uiLayout *split, *split2;
+ PointerRNA main_ptr;
split = uiLayoutSplit(layout, 0.8f, false);
uiItemR(split, ptr, "mouse_event", 0, NULL, ICON_NONE);
- if (RNA_enum_get(ptr, "mouse_event") == BL_SENS_MOUSE_MOUSEOVER_ANY)
+ if (RNA_enum_get(ptr, "mouse_event") == BL_SENS_MOUSE_MOUSEOVER_ANY) {
uiItemR(split, ptr, "use_pulse", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
+
+ split = uiLayoutSplit(layout, 0.3f, false);
+ uiItemR(split, ptr, "use_material", 0, "", ICON_NONE);
+
+ split2 = uiLayoutSplit(split, 0.7f, false);
+ if (RNA_enum_get(ptr, "use_material") == SENS_RAY_PROPERTY) {
+ uiItemR(split2, ptr, "property", 0, "", ICON_NONE);
+ }
+ else {
+ RNA_main_pointer_create(CTX_data_main(C), &main_ptr);
+ uiItemPointerR(split2, ptr, "material", &main_ptr, "materials", "", ICON_MATERIAL_DATA);
+ }
+ uiItemR(split2, ptr, "use_x_ray", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
+ }
}
static void draw_sensor_near(uiLayout *layout, PointerRNA *ptr)
@@ -1182,9 +1199,9 @@ static void draw_sensor_property(uiLayout *layout, PointerRNA *ptr)
uiItemR(row, ptr, "value_max", 0, NULL, ICON_NONE);
break;
case SENS_PROP_EQUAL:
- uiItemR(layout, ptr, "value", 0, NULL, ICON_NONE);
- break;
case SENS_PROP_NEQUAL:
+ case SENS_PROP_LESSTHAN:
+ case SENS_PROP_GREATERTHAN:
uiItemR(layout, ptr, "value", 0, NULL, ICON_NONE);
break;
case SENS_PROP_CHANGED:
@@ -1271,7 +1288,7 @@ static void draw_brick_sensor(uiLayout *layout, PointerRNA *ptr, bContext *C)
draw_sensor_message(box, ptr);
break;
case SENS_MOUSE:
- draw_sensor_mouse(box, ptr);
+ draw_sensor_mouse(box, ptr, C);
break;
case SENS_NEAR:
draw_sensor_near(box, ptr);
@@ -1718,6 +1735,12 @@ static void draw_actuator_edit_object(uiLayout *layout, PointerRNA *ptr)
sub = uiLayoutSplit(split, 0.7f, false);
uiItemR(sub, ptr, "time", 0, NULL, ICON_NONE);
uiItemR(sub, ptr, "use_3d_tracking", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "up_axis", 0, NULL, ICON_NONE);
+
+ row = uiLayoutRow(layout, false);
+ uiItemR(row, ptr, "track_axis", 0, NULL, ICON_NONE);
break;
case ACT_EDOB_DYNAMICS:
if (ob->type != OB_MESH) {
@@ -1809,7 +1832,7 @@ static void draw_actuator_motion(uiLayout *layout, PointerRNA *ptr)
uiItemR(row, ptr, "offset_rotation", 0, NULL, ICON_NONE);
uiItemR(split, ptr, "use_local_rotation", UI_ITEM_R_TOGGLE, NULL, ICON_NONE);
- if (ELEM3(physics_type, OB_BODY_TYPE_DYNAMIC, OB_BODY_TYPE_RIGID, OB_BODY_TYPE_SOFT)) {
+ if (ELEM(physics_type, OB_BODY_TYPE_DYNAMIC, OB_BODY_TYPE_RIGID, OB_BODY_TYPE_SOFT)) {
uiItemL(layout, IFACE_("Dynamic Object Settings:"), ICON_NONE);
split = uiLayoutSplit(layout, 0.9, false);
row = uiLayoutRow(split, false);
@@ -1931,6 +1954,7 @@ static void draw_actuator_property(uiLayout *layout, PointerRNA *ptr)
switch (RNA_enum_get(ptr, "mode")) {
case ACT_PROP_TOGGLE:
+ case ACT_PROP_LEVEL:
break;
case ACT_PROP_ADD:
uiItemR(layout, ptr, "value", 0, NULL, ICON_NONE);
@@ -2177,6 +2201,68 @@ static void draw_actuator_steering(uiLayout *layout, PointerRNA *ptr)
}
}
+static void draw_actuator_mouse(uiLayout *layout, PointerRNA *ptr)
+{
+ uiLayout *row, *col, *subcol, *split, *subsplit;
+
+ uiItemR(layout, ptr, "mode", 0, NULL, 0);
+
+ switch (RNA_enum_get(ptr, "mode")) {
+ case ACT_MOUSE_VISIBILITY:
+ row = uiLayoutRow(layout, 0);
+ uiItemR(row, ptr, "visible", UI_ITEM_R_TOGGLE, NULL, 0);
+ break;
+
+ case ACT_MOUSE_LOOK:
+ /* X axis */
+ row = uiLayoutRow(layout, 0);
+ col = uiLayoutColumn(row, 1);
+
+ uiItemR(col, ptr, "use_axis_x", UI_ITEM_R_TOGGLE, NULL, 0);
+
+ subcol = uiLayoutColumn(col, 1);
+ uiLayoutSetActive(subcol, RNA_boolean_get(ptr, "use_axis_x")==1);
+ uiItemR(subcol, ptr, "sensitivity_x", 0, NULL, 0);
+ uiItemR(subcol, ptr, "threshold_x", 0, NULL, 0);
+
+ uiItemR(subcol, ptr, "min_x", 0, NULL, 0);
+ uiItemR(subcol, ptr, "max_x", 0, NULL, 0);
+
+ uiItemR(subcol, ptr, "object_axis_x", 0, NULL, 0);
+
+ /* Y Axis */
+ col = uiLayoutColumn(row, 1);
+
+ uiItemR(col, ptr, "use_axis_y", UI_ITEM_R_TOGGLE, NULL, 0);
+
+ subcol = uiLayoutColumn(col, 1);
+ uiLayoutSetActive(subcol, RNA_boolean_get(ptr, "use_axis_y")==1);
+ uiItemR(subcol, ptr, "sensitivity_y", 0, NULL, 0);
+ uiItemR(subcol, ptr, "threshold_y", 0, NULL, 0);
+
+ uiItemR(subcol, ptr, "min_y", 0, NULL, 0);
+ uiItemR(subcol, ptr, "max_y", 0, NULL, 0);
+
+ uiItemR(subcol, ptr, "object_axis_y", 0, NULL, 0);
+
+ /* Lower options */
+ row = uiLayoutRow(layout, 0);
+ split = uiLayoutSplit(row, 0.5, 0);
+
+ subsplit = uiLayoutSplit(split, 0.5, 1);
+ uiLayoutSetActive(subsplit, RNA_boolean_get(ptr, "use_axis_x")==1);
+ uiItemR(subsplit, ptr, "local_x", UI_ITEM_R_TOGGLE, NULL, 0);
+ uiItemR(subsplit, ptr, "reset_x", UI_ITEM_R_TOGGLE, NULL, 0);
+
+ subsplit = uiLayoutSplit(split, 0.5, 1);
+ uiLayoutSetActive(subsplit, RNA_boolean_get(ptr, "use_axis_y")==1);
+ uiItemR(subsplit, ptr, "local_y", UI_ITEM_R_TOGGLE, NULL, 0);
+ uiItemR(subsplit, ptr, "reset_y", UI_ITEM_R_TOGGLE, NULL, 0);
+
+ break;
+ }
+}
+
static void draw_brick_actuator(uiLayout *layout, PointerRNA *ptr, bContext *C)
{
uiLayout *box;
@@ -2241,6 +2327,10 @@ static void draw_brick_actuator(uiLayout *layout, PointerRNA *ptr, bContext *C)
break;
case ACT_STEERING:
draw_actuator_steering(box, ptr);
+ break;
+ case ACT_MOUSE:
+ draw_actuator_mouse(box, ptr);
+ break;
}
}
diff --git a/source/blender/editors/space_nla/CMakeLists.txt b/source/blender/editors/space_nla/CMakeLists.txt
index a74fc3191b7..ab0dfa30121 100644
--- a/source/blender/editors/space_nla/CMakeLists.txt
+++ b/source/blender/editors/space_nla/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -49,4 +51,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_nla "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_nla/SConscript b/source/blender/editors/space_nla/SConscript
index a00337e0b58..9e743d918b9 100644
--- a/source/blender/editors/space_nla/SConscript
+++ b/source/blender/editors/space_nla/SConscript
@@ -31,18 +31,20 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c
index 808bd622c0d..1090106d79f 100644
--- a/source/blender/editors/space_nla/nla_buttons.c
+++ b/source/blender/editors/space_nla/nla_buttons.c
@@ -174,7 +174,7 @@ bool nla_panel_context(const bContext *C, PointerRNA *adt_ptr, PointerRNA *nlt_p
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return (found != 0);
}
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 16572f1790b..fbb4d273626 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -50,6 +50,7 @@
#include "ED_anim_api.h"
#include "ED_keyframes_edit.h"
+#include "ED_object.h"
#include "ED_screen.h"
#include "RNA_access.h"
@@ -73,7 +74,7 @@
* --> Most channels are now selection only...
*/
-static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, short selectmode)
+static int mouse_nla_channels(bContext *C, bAnimContext *ac, float x, int channel_index, short selectmode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -94,7 +95,7 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor
if (G.debug & G_DEBUG)
printf("Error: animation channel (index = %d) not found in mouse_anim_channels()\n", channel_index);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return 0;
}
@@ -154,6 +155,9 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor
if (adt) adt->flag |= ADT_UI_SELECTED;
}
+ /* change active object - regardless of whether it is now selected [T37883] */
+ ED_base_object_activate(C, base); /* adds notifier */
+
if ((adt) && (adt->flag & ADT_UI_SELECTED))
adt->flag |= ADT_UI_ACTIVE;
@@ -322,7 +326,7 @@ static int mouse_nla_channels(bAnimContext *ac, float x, int channel_index, shor
}
/* free channels */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* return the notifier-flags set */
return notifierFlags;
@@ -366,7 +370,7 @@ static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEv
UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
/* handle mouse-click in the relevant channel then */
- notifierFlags = mouse_nla_channels(&ac, x, channel_index, selectmode);
+ notifierFlags = mouse_nla_channels(C, &ac, x, channel_index, selectmode);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, NULL);
@@ -416,8 +420,8 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
/* active animdata block */
if (nla_panel_context(C, &adt_ptr, NULL, NULL) == 0 || (adt_ptr.data == NULL)) {
- BKE_report(op->reports, RPT_ERROR, "No active AnimData block to use. "
- "Select a datablock expander first or set the appropriate flags on an AnimData block");
+ BKE_report(op->reports, RPT_ERROR, "No active AnimData block to use "
+ "(select a datablock expander first or set the appropriate flags on an AnimData block)");
return OPERATOR_CANCELLED;
}
else {
@@ -437,13 +441,13 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
/* get channel from index */
ale = BLI_findlink(&anim_data, channel_index);
if (ale == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "No animation channel found at index = %d", channel_index);
- BLI_freelistN(&anim_data);
+ BKE_reportf(op->reports, RPT_ERROR, "No animation channel found at index %d", channel_index);
+ ANIM_animdata_freelist(&anim_data);
return OPERATOR_CANCELLED;
}
else if (ale->type != ANIMTYPE_NLAACTION) {
- BKE_reportf(op->reports, RPT_ERROR, "Animation channel at index = %d is not a NLA 'Active Action' channel", channel_index);
- BLI_freelistN(&anim_data);
+ BKE_reportf(op->reports, RPT_ERROR, "Animation channel at index %d is not a NLA 'Active Action' channel", channel_index);
+ ANIM_animdata_freelist(&anim_data);
return OPERATOR_CANCELLED;
}
@@ -451,7 +455,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
adt = ale->adt;
/* we don't need anything here anymore, so free it all */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* double-check that we are free to push down here... */
@@ -460,7 +464,8 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
else if (nlaedit_is_tweakmode_on(&ac)) {
- BKE_report(op->reports, RPT_WARNING, "Cannot push down actions while tweaking a strip's action. Exit tweakmode first");
+ BKE_report(op->reports, RPT_WARNING,
+ "Cannot push down actions while tweaking a strip's action, exit tweak mode first");
return OPERATOR_CANCELLED;
}
else if (adt->action == NULL) {
@@ -538,7 +543,7 @@ bool nlaedit_add_tracks_existing(bAnimContext *ac, bool above_sel)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return added;
}
@@ -571,7 +576,7 @@ bool nlaedit_add_tracks_empty(bAnimContext *ac)
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return added;
}
@@ -665,7 +670,7 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c
index 943112624cd..ac8dca6e83a 100644
--- a/source/blender/editors/space_nla/nla_draw.c
+++ b/source/blender/editors/space_nla/nla_draw.c
@@ -613,7 +613,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *ar)
}
/* free tempolary channels */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* *********************************************** */
@@ -704,7 +704,7 @@ void draw_nla_channel_list(bContext *C, bAnimContext *ac, ARegion *ar)
}
/* free temporary channels */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* *********************************************** */
diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c
index 93d0f7527ef..c787177a62a 100644
--- a/source/blender/editors/space_nla/nla_edit.c
+++ b/source/blender/editors/space_nla/nla_edit.c
@@ -93,7 +93,7 @@ void ED_nla_postop_refresh(bAnimContext *ac)
}
/* free temp memory */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* *********************************************** */
@@ -136,7 +136,7 @@ static int nlaedit_enable_tweakmode_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* if we managed to enter tweakmode on at least one AnimData block,
* set the flag for this in the active scene and send notifiers
@@ -200,7 +200,7 @@ bool nlaedit_disable_tweakmode(bAnimContext *ac)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* if we managed to enter tweakmode on at least one AnimData block,
* set the flag for this in the active scene and send notifiers
@@ -293,7 +293,7 @@ static void get_nlastrip_extents(bAnimContext *ac, float *min, float *max, const
}
/* free memory */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* set default range if nothing happened */
@@ -356,10 +356,12 @@ void NLA_OT_previewrange_set(wmOperatorType *ot)
/* ****************** View-All Operator ****************** */
-/* Find the extents of the active channel
- * > min: (float) bottom y-extent of channel
- * > max: (float) top y-extent of channel
- * > returns: success of finding a selected channel
+/**
+ * Find the extents of the active channel
+ *
+ * \param[out] min Bottom y-extent of channel
+ * \param[out] max Top y-extent of channel
+ * \return Success of finding a selected channel
*/
static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, float *max)
{
@@ -406,7 +408,7 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, floa
}
/* free all temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return (found != 0);
}
@@ -602,7 +604,7 @@ static int nlaedit_add_actionclip_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -723,7 +725,7 @@ static int nlaedit_add_transition_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* was anything added? */
if (done) {
@@ -815,7 +817,7 @@ static int nlaedit_add_sound_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -880,7 +882,7 @@ static int nlaedit_add_meta_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -932,7 +934,7 @@ static int nlaedit_remove_meta_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -1019,7 +1021,7 @@ static int nlaedit_duplicate_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
if (done) {
/* refresh auto strip properties */
@@ -1111,7 +1113,7 @@ static int nlaedit_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -1256,7 +1258,7 @@ static int nlaedit_split_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -1309,7 +1311,7 @@ static int nlaedit_bake_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -1375,7 +1377,7 @@ static int nlaedit_toggle_mute_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -1529,7 +1531,7 @@ static int nlaedit_swap_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -1603,7 +1605,7 @@ static int nlaedit_move_up_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -1677,7 +1679,7 @@ static int nlaedit_move_down_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -1756,7 +1758,7 @@ static int nlaedit_sync_actlen_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -1832,7 +1834,7 @@ static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -1928,7 +1930,7 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -1988,7 +1990,7 @@ static int nlaedit_clear_scale_exec(bContext *C, wmOperator *UNUSED(op))
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -2129,7 +2131,7 @@ static int nlaedit_snap_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* refresh auto strip properties */
ED_nla_postop_refresh(&ac);
@@ -2252,7 +2254,7 @@ static int nla_fmodifier_add_exec(bContext *C, wmOperator *op)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_NLA | NA_EDITED, NULL);
@@ -2375,7 +2377,7 @@ static int nla_fmodifier_paste_exec(bContext *C, wmOperator *op)
}
/* clean up */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* successful or not? */
if (ok) {
diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c
index 295a7ab2e04..5e1381db696 100644
--- a/source/blender/editors/space_nla/nla_ops.c
+++ b/source/blender/editors/space_nla/nla_ops.c
@@ -323,6 +323,9 @@ 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);
+ /* 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);
+
/* channels ---------------------------------------------------------- */
/* Channels are not directly handled by the NLA Editor module, but are inherited from the Animation module.
* Most of the relevant operations, keymaps, drawing, etc. can therefore all be found in that module instead, as there
diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c
index 3e7a6f4578c..8261397c940 100644
--- a/source/blender/editors/space_nla/nla_select.c
+++ b/source/blender/editors/space_nla/nla_select.c
@@ -153,7 +153,7 @@ static void deselect_nla_strips(bAnimContext *ac, short test, short sel)
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -268,7 +268,7 @@ static void borderselect_nla_strips(bAnimContext *ac, rcti rect, short mode, sho
}
/* cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -412,7 +412,7 @@ static void nlaedit_select_leftright(bContext *C, bAnimContext *ac, short leftri
}
/* Cleanup */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ------------------- */
@@ -465,9 +465,9 @@ static int nlaedit_select_leftright_invoke(bContext *C, wmOperator *op, const wm
/* determine which side of the current frame mouse is on */
x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
if (x < CFRA)
- RNA_int_set(op->ptr, "mode", NLAEDIT_LRSEL_LEFT);
+ RNA_enum_set(op->ptr, "mode", NLAEDIT_LRSEL_LEFT);
else
- RNA_int_set(op->ptr, "mode", NLAEDIT_LRSEL_RIGHT);
+ RNA_enum_set(op->ptr, "mode", NLAEDIT_LRSEL_RIGHT);
}
/* perform selection */
@@ -537,7 +537,7 @@ static void mouse_nla_strips(bContext *C, bAnimContext *ac, const int mval[2], s
if (ale == NULL) {
/* channel not found */
printf("Error: animation channel (index = %d) not found in mouse_nla_strips()\n", channel_index);
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return;
}
else {
@@ -556,7 +556,7 @@ static void mouse_nla_strips(bContext *C, bAnimContext *ac, const int mval[2], s
BLI_remlink(&anim_data, ale);
/* free list of channels, since it's not used anymore */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* if currently in tweakmode, exit tweakmode before changing selection states
diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt
index 6b0460ce5cd..34887f8388d 100644
--- a/source/blender/editors/space_node/CMakeLists.txt
+++ b/source/blender/editors/space_node/CMakeLists.txt
@@ -32,6 +32,7 @@ set(INC
../../windowmanager
../../compositor
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -64,4 +65,6 @@ if(WITH_COMPOSITOR)
add_definitions(-DWITH_COMPOSITOR)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_node/SConscript b/source/blender/editors/space_node/SConscript
index 94756b96035..435a78f1b7e 100644
--- a/source/blender/editors/space_node/SConscript
+++ b/source/blender/editors/space_node/SConscript
@@ -31,7 +31,8 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
@@ -47,7 +48,8 @@ incs = [
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
+
cf = []
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
#cf.append('/WX')
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 8ef1d0bef99..ffc82128181 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -181,7 +181,7 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt
}
#endif
- uiTemplateCurveMapping(layout, ptr, "curve", 's', 0, 0);
+ uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false);
row = uiLayoutRow(layout, true);
uiItemR(row, ptr, "frame_start", 0, IFACE_("Sta"), ICON_NONE);
@@ -195,7 +195,7 @@ static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRN
static void node_buts_curvevec(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
- uiTemplateCurveMapping(layout, ptr, "mapping", 'v', 0, 0);
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'v', false, false, false);
}
#define SAMPLE_FLT_ISNONE FLT_MAX
@@ -223,7 +223,7 @@ static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA
cumap->flag &= ~CUMA_DRAW_SAMPLE;
}
- uiTemplateCurveMapping(layout, ptr, "mapping", 'c', 0, 0);
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'c', false, false, false);
}
static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -605,7 +605,7 @@ static void node_draw_reroute(const bContext *C, ARegion *ar, SpaceNode *UNUSED(
static int node_tweak_area_reroute(bNode *node, int x, int y)
{
/* square of tweak radius */
- static const float tweak_radius_sq = 576; /* 24 * 24 */
+ const float tweak_radius_sq = SQUARE(24);
bNodeSocket *sock = node->inputs.first;
float dx = sock->locx - x;
@@ -885,6 +885,11 @@ static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *pt
}
}
+static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "use_tips", 0, NULL, 0);
+}
+
static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
uiItemR(layout, ptr, "space", 0, "", 0);
@@ -930,32 +935,30 @@ static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), Point
uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
}
+static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE);
+}
+
static void node_shader_buts_subsurface(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
- /* SSS does not work on GPU yet */
+ /* SSS only enabled in Experimental Kernel */
PointerRNA scene = CTX_data_pointer_get(C, "scene");
if (scene.data) {
PointerRNA cscene = RNA_pointer_get(&scene, "cycles");
- if (cscene.data && (RNA_enum_get(&cscene, "device") == 1 && U.compute_device_type != 0))
- uiItemL(layout, IFACE_("SSS not supported on GPU"), ICON_ERROR);
+ if (cscene.data &&
+ ((U.compute_device_type != USER_COMPUTE_DEVICE_NONE) &&
+ (RNA_enum_get(&cscene, "device") == 1) &&
+ (RNA_enum_get(&cscene, "feature_set") == 0)))
+ {
+ uiItemL(layout, IFACE_("Only enabled in experimental GPU kernel"), ICON_ERROR);
+ }
}
uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE);
}
-static void node_shader_buts_volume(uiLayout *layout, bContext *C, PointerRNA *UNUSED(ptr))
-{
- /* Volume does not work on GPU yet */
- PointerRNA scene = CTX_data_pointer_get(C, "scene");
- if (scene.data) {
- PointerRNA cscene = RNA_pointer_get(&scene, "cycles");
-
- if (cscene.data && (RNA_enum_get(&cscene, "device") == 1 && U.compute_device_type != 0))
- uiItemL(layout, IFACE_("Volumes not supported on GPU"), ICON_ERROR);
- }
-}
-
static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
uiItemR(layout, ptr, "component", 0, "", ICON_NONE);
@@ -995,6 +998,16 @@ static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA
#endif
}
+static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayout *row, *col;
+
+ col = uiLayoutColumn(layout, false);
+ row = uiLayoutRow(col, true);
+ uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE);
+ uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE);
+}
+
/* only once called */
static void node_shader_set_butfunc(bNodeType *ntype)
{
@@ -1096,15 +1109,12 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_BSDF_REFRACTION:
ntype->draw_buttons = node_shader_buts_glossy;
break;
+ case SH_NODE_BSDF_ANISOTROPIC:
+ ntype->draw_buttons = node_shader_buts_anisotropic;
+ break;
case SH_NODE_SUBSURFACE_SCATTERING:
ntype->draw_buttons = node_shader_buts_subsurface;
break;
- case SH_NODE_VOLUME_SCATTER:
- ntype->draw_buttons = node_shader_buts_volume;
- break;
- case SH_NODE_VOLUME_ABSORPTION:
- ntype->draw_buttons = node_shader_buts_volume;
- break;
case SH_NODE_BSDF_TOON:
ntype->draw_buttons = node_shader_buts_toon;
break;
@@ -1118,6 +1128,12 @@ static void node_shader_set_butfunc(bNodeType *ntype)
case SH_NODE_UVMAP:
ntype->draw_buttons = node_shader_buts_uvmap;
break;
+ case SH_NODE_UVALONGSTROKE:
+ ntype->draw_buttons = node_shader_buts_uvalongstroke;
+ break;
+ case SH_NODE_OUTPUT_LINESTYLE:
+ ntype->draw_buttons = node_buts_output_linestyle;
+ break;
}
}
@@ -1833,7 +1849,7 @@ static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C),
cumap->flag &= ~CUMA_DRAW_SAMPLE;
}
- uiTemplateCurveMapping(layout, ptr, "mapping", 'h', 0, 0);
+ uiTemplateCurveMapping(layout, ptr, "mapping", 'h', false, false, false);
}
static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -2299,6 +2315,12 @@ static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), bContext *UNU
{
}
+static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "source", UI_ITEM_R_EXPAND, "", ICON_NONE);
+ uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE);
+}
+
/* only once called */
static void node_composit_set_butfunc(bNodeType *ntype)
{
@@ -2523,6 +2545,9 @@ static void node_composit_set_butfunc(bNodeType *ntype)
case CMP_NODE_CORNERPIN:
ntype->draw_buttons = node_composit_buts_cornerpin;
break;
+ case CMP_NODE_SUNBEAMS:
+ ntype->draw_buttons = node_composit_buts_sunbeams;
+ break;
}
}
@@ -3031,7 +3056,8 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
glaDefine2DArea(&ar->winrct);
/* ortho at pixel level curarea */
- wmOrtho2(-GLA_PIXEL_OFS, ar->winx - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, ar->winy - GLA_PIXEL_OFS);
+ /* almost #wmOrtho2_region_pixelspace, but no +1 px */
+ wmOrtho2_pixelspace(ar->winx, ar->winy);
x = (ar->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
y = (ar->winy - snode->zoom * ibuf->y) / 2 + snode->yof;
@@ -3100,7 +3126,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
IMB_display_buffer_release(cache_handle);
}
- /** @note draw selected info on backdrop */
+ /** \note draw selected info on backdrop */
if (snode->edittree) {
bNode *node = snode->edittree->nodes.first;
rctf *viewer_border = &snode->nodetree->viewer_border;
@@ -3114,20 +3140,17 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
}
if ((snode->nodetree->flag & NTREE_VIEWER_BORDER) &&
- viewer_border->xmin < viewer_border->xmax &&
- viewer_border->ymin < viewer_border->ymax)
+ viewer_border->xmin < viewer_border->xmax &&
+ viewer_border->ymin < viewer_border->ymax)
{
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- setlinestyle(3);
- cpack(0x4040FF);
-
- glRectf(x + snode->zoom * viewer_border->xmin * ibuf->x,
- y + snode->zoom * viewer_border->ymin * ibuf->y,
- x + snode->zoom * viewer_border->xmax * ibuf->x,
- y + snode->zoom * viewer_border->ymax * ibuf->y);
-
- setlinestyle(0);
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ rcti pixel_border;
+ UI_ThemeColor(TH_ACTIVE);
+ BLI_rcti_init(&pixel_border,
+ x + snode->zoom * viewer_border->xmin * ibuf->x,
+ x + snode->zoom * viewer_border->xmax * ibuf->x,
+ y + snode->zoom * viewer_border->ymin * ibuf->y,
+ y + snode->zoom * viewer_border->ymax * ibuf->y);
+ glaDrawBorderCorners(&pixel_border, 1.0f, 1.0f);
}
}
@@ -3421,7 +3444,7 @@ void node_draw_link(View2D *v2d, SpaceNode *snode, bNodeLink *link)
{
bool do_shaded = false;
bool do_triple = false;
- int th_col1 = TH_HEADER, th_col2 = TH_HEADER, th_col3 = TH_WIRE;
+ int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE;
if (link->fromsock == NULL && link->tosock == NULL)
return;
diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c
index ebff840dc9f..58d94a28226 100644
--- a/source/blender/editors/space_node/node_buttons.c
+++ b/source/blender/editors/space_node/node_buttons.c
@@ -202,8 +202,8 @@ void node_buttons_register(ARegionType *art)
strcpy(pt->idname, "NODE_PT_gpencil");
strcpy(pt->label, N_("Grease Pencil"));
strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = gpencil_panel_standard_header;
- pt->draw = gpencil_panel_standard;
+ pt->draw_header = ED_gpencil_panel_standard_header;
+ pt->draw = ED_gpencil_panel_standard;
pt->poll = active_nodetree_poll;
BLI_addtail(&art->paneltypes, pt);
}
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index b3cf5ce0c81..7b5ec38f4c6 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -138,6 +138,10 @@ void ED_node_tag_update_id(ID *id)
DAG_id_tag_update(id, 0);
WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
}
+ else if (id == &ntree->id) {
+ /* node groups */
+ DAG_id_tag_update(id, 0);
+ }
}
void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree)
@@ -1341,7 +1345,7 @@ void drawnodespace(const bContext *C, ARegion *ar)
if (snode->flag & SNODE_SHOW_GPENCIL) {
/* draw grease-pencil ('canvas' strokes) */
- draw_gpencil_view2d(C, true);
+ ED_gpencil_draw_view2d(C, true);
}
}
else {
@@ -1360,7 +1364,7 @@ void drawnodespace(const bContext *C, ARegion *ar)
if (snode->treepath.last) {
if (snode->flag & SNODE_SHOW_GPENCIL) {
/* draw grease-pencil (screen strokes, and also paintbuffer) */
- draw_gpencil_view2d(C, false);
+ ED_gpencil_draw_view2d(C, false);
}
}
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index fc0c82faba8..ca13d87d632 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -640,11 +640,11 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
/* tree specific activate calls */
if (ntree->type == NTREE_SHADER) {
/* when we select a material, active texture is cleared, for buttons */
- if (node->id && ELEM3(GS(node->id->name), ID_MA, ID_LA, ID_WO))
+ if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO))
nodeClearActiveID(ntree, ID_TE);
- if (ELEM4(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL,
- SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP))
+ if (ELEM(node->type, SH_NODE_OUTPUT, SH_NODE_OUTPUT_MATERIAL,
+ SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LAMP, SH_NODE_OUTPUT_LINESTYLE))
{
bNode *tnode;
@@ -695,7 +695,12 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node)
for (scene = bmain->scene.first; scene; scene = scene->id.next) {
if (scene->nodetree && scene->use_nodes && ntreeHasTree(scene->nodetree, ntree)) {
if (node->id == NULL || node->id == (ID *)scene) {
+ int num_layers = BLI_countlist(&scene->r.layers);
scene->r.actlay = node->custom1;
+ /* Clamp the value, because it might have come from a different
+ * scene which could have more render layers than new one.
+ */
+ scene->r.actlay = min_ff(scene->r.actlay, num_layers - 1);
}
}
}
@@ -2477,14 +2482,6 @@ static int viewer_border_exec(bContext *C, wmOperator *op)
btree->flag &= ~NTREE_VIEWER_BORDER;
}
else {
- if (ibuf->rect)
- memset(ibuf->rect, 0, 4 * ibuf->x * ibuf->y);
-
- if (ibuf->rect_float)
- memset(ibuf->rect_float, 0, 4 * ibuf->x * ibuf->y * sizeof(float));
-
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
-
btree->flag |= NTREE_VIEWER_BORDER;
}
@@ -2521,3 +2518,30 @@ void NODE_OT_viewer_border(wmOperatorType *ot)
/* properties */
WM_operator_properties_gesture_border(ot, true);
}
+
+static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNodeTree *btree = snode->nodetree;
+
+ btree->flag &= ~NTREE_VIEWER_BORDER;
+ snode_notify(C, snode);
+ WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, NULL);
+
+ return OPERATOR_FINISHED;
+}
+
+void NODE_OT_clear_viewer_border(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Viewer Border";
+ ot->description = "Clear the boundaries for viewer operations";
+ ot->idname = "NODE_OT_clear_viewer_border";
+
+ /* api callbacks */
+ ot->exec = clear_viewer_border_exec;
+ ot->poll = composite_node_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index 39aba921f72..96cc7fb4407 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -200,7 +200,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode)
* - ngroup (i.e. the source NodeTree) is left unscathed
* - temp copy. don't change ID usercount
*/
- wgroup = ntreeCopyTree_ex(ngroup, false);
+ wgroup = ntreeCopyTree_ex(ngroup, G.main, false);
/* Add the nodes into the ntree */
for (node = wgroup->nodes.first; node; node = nextnode) {
diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h
index fa20aeb8624..9598ff190c0 100644
--- a/source/blender/editors/space_node/node_intern.h
+++ b/source/blender/editors/space_node/node_intern.h
@@ -107,8 +107,6 @@ void node_socket_select(struct bNode *node, struct bNodeSocket *sock);
void node_socket_deselect(struct bNode *node, struct bNodeSocket *sock, const bool deselect_node);
void node_deselect_all_input_sockets(struct SpaceNode *snode, const bool deselect_nodes);
void node_deselect_all_output_sockets(struct SpaceNode *snode, const bool deselect_nodes);
-int node_select_same_type(struct SpaceNode *snode);
-int node_select_same_type_np(struct SpaceNode *snode, int dir);
void node_select_single(struct bContext *C, struct bNode *node);
void NODE_OT_select(struct wmOperatorType *ot);
@@ -118,7 +116,7 @@ void NODE_OT_select_linked_from(struct wmOperatorType *ot);
void NODE_OT_select_border(struct wmOperatorType *ot);
void NODE_OT_select_circle(struct wmOperatorType *ot);
void NODE_OT_select_lasso(struct wmOperatorType *ot);
-void NODE_OT_select_same_type(struct wmOperatorType *ot);
+void NODE_OT_select_grouped(struct wmOperatorType *ot);
void NODE_OT_select_same_type_step(struct wmOperatorType *ot);
void NODE_OT_find_node(struct wmOperatorType *ot);
@@ -217,6 +215,7 @@ void NODE_OT_tree_socket_move(struct wmOperatorType *ot);
void NODE_OT_shader_script_update(struct wmOperatorType *ot);
void NODE_OT_viewer_border(struct wmOperatorType *ot);
+void NODE_OT_clear_viewer_border(struct wmOperatorType *ot);
extern const char *node_context_dir[];
diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c
index ac541ef6a28..7dcbeae4627 100644
--- a/source/blender/editors/space_node/node_ops.c
+++ b/source/blender/editors/space_node/node_ops.c
@@ -58,7 +58,7 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_select_border);
WM_operatortype_append(NODE_OT_select_circle);
WM_operatortype_append(NODE_OT_select_lasso);
- WM_operatortype_append(NODE_OT_select_same_type);
+ WM_operatortype_append(NODE_OT_select_grouped);
WM_operatortype_append(NODE_OT_select_same_type_step);
WM_operatortype_append(NODE_OT_find_node);
@@ -122,6 +122,7 @@ void node_operatortypes(void)
WM_operatortype_append(NODE_OT_shader_script_update);
WM_operatortype_append(NODE_OT_viewer_border);
+ WM_operatortype_append(NODE_OT_clear_viewer_border);
WM_operatortype_append(NODE_OT_tree_socket_add);
WM_operatortype_append(NODE_OT_tree_socket_remove);
@@ -292,7 +293,10 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_select_linked_to", LKEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "NODE_OT_select_linked_from", LKEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "NODE_OT_select_same_type", GKEY, KM_PRESS, KM_SHIFT, 0);
+ kmi = WM_keymap_add_item(keymap, "NODE_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT, 0);
+ RNA_boolean_set(kmi->ptr, "extend", false);
+ kmi = WM_keymap_add_item(keymap, "NODE_OT_select_grouped", GKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+ RNA_boolean_set(kmi->ptr, "extend", true);
kmi = WM_keymap_add_item(keymap, "NODE_OT_select_same_type_step", RIGHTBRACKETKEY, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "prev", false);
@@ -321,6 +325,7 @@ void node_keymap(struct wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "NODE_OT_clipboard_paste", VKEY, KM_PRESS, KM_OSKEY, 0);
#endif
WM_keymap_add_item(keymap, "NODE_OT_viewer_border", BKEY, KM_PRESS, KM_CTRL, 0);
+ WM_keymap_add_item(keymap, "NODE_OT_clear_viewer_border", BKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
transform_keymap_for_space(keyconf, keymap, SPACE_NODE);
}
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index 6a0e1f35d24..973ce56857c 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -67,12 +67,12 @@ typedef struct bNodeListItem {
struct bNode *node;
} bNodeListItem;
-static int sort_nodes_locx(void *a, void *b)
+static int sort_nodes_locx(const void *a, const void *b)
{
- bNodeListItem *nli1 = (bNodeListItem *)a;
- bNodeListItem *nli2 = (bNodeListItem *)b;
- bNode *node1 = nli1->node;
- bNode *node2 = nli2->node;
+ const bNodeListItem *nli1 = a;
+ const bNodeListItem *nli2 = b;
+ const bNode *node1 = nli1->node;
+ const bNode *node2 = nli2->node;
if (node1->locx > node2->locx)
return 1;
@@ -461,7 +461,7 @@ static bNodeSocket *node_find_linkable_socket(bNodeTree *ntree, bNode *node, bNo
sock = cur->next ? cur->next : first; /* wrap around the list end */
while (sock != cur) {
- if (node_link_socket_match(sock, cur)) {
+ if (!nodeSocketIsHidden(sock) && node_link_socket_match(sock, cur)) {
int link_count = node_count_links(ntree, sock);
/* take +1 into account since we would add a new link */
if (link_count + 1 <= sock->limit)
@@ -490,7 +490,6 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link, bool use_
if (new_from && new_from != from) {
/* redirect existing link */
tlink->fromsock = new_from;
- new_from->flag &= ~SOCK_HIDDEN;
}
else if (!new_from) {
/* no possible replacement, remove tlink */
@@ -504,7 +503,6 @@ static void node_remove_extra_links(SpaceNode *snode, bNodeLink *link, bool use_
if (new_to && new_to != to) {
/* redirect existing link */
tlink->tosock = new_to;
- new_to->flag &= ~SOCK_HIDDEN;
}
else if (!new_to) {
/* no possible replacement, remove tlink */
diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c
index 7371a3ef070..de580f612a0 100644
--- a/source/blender/editors/space_node/node_select.c
+++ b/source/blender/editors/space_node/node_select.c
@@ -32,10 +32,12 @@
#include "DNA_node_types.h"
+#include "BLI_utildefines.h"
#include "BLI_rect.h"
#include "BLI_lasso.h"
+#include "BLI_math.h"
#include "BLI_string.h"
-#include "BLI_utildefines.h"
+#include "BLI_string_utf8.h"
#include "BKE_context.h"
#include "BKE_main.h"
@@ -205,79 +207,156 @@ void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_node
}
}
-/* return 1 if we need redraw otherwise zero. */
-int node_select_same_type(SpaceNode *snode)
+/* Return true if we need redraw, otherwise false. */
+
+static bool node_select_grouped_type(SpaceNode *snode, bNode *node_act)
{
- bNode *nac, *p;
- int redraw;
+ bNode *node;
+ bool changed = false;
- /* search for the active node. */
- for (nac = snode->edittree->nodes.first; nac; nac = nac->next) {
- if (nac->flag & SELECT)
- break;
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ if ((node->flag & SELECT) == 0) {
+ if (node->type == node_act->type) {
+ nodeSetSelected(node, true);
+ changed = true;
+ }
+ }
}
- /* no active node, return. */
- if (!nac)
- return(0);
+ return changed;
+}
- redraw = 0;
- for (p = snode->edittree->nodes.first; p; p = p->next) {
- if (p->type != nac->type && p->flag & SELECT) {
- /* if it's selected but different type, unselect */
- redraw = 1;
- nodeSetSelected(p, false);
- }
- else if (p->type == nac->type && (!(p->flag & SELECT))) {
- /* if it's the same type and is not selected, select! */
- redraw = 1;
- nodeSetSelected(p, true);
+static bool node_select_grouped_color(SpaceNode *snode, bNode *node_act)
+{
+ bNode *node;
+ bool changed = false;
+
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ if ((node->flag & SELECT) == 0) {
+ if (compare_v3v3(node->color, node_act->color, 0.005f)) {
+ nodeSetSelected(node, true);
+ changed = true;
+ }
}
}
- return(redraw);
+
+ return changed;
}
-/* return 1 if we need redraw, otherwise zero.
- * dir can be 0 == next or 0 != prev.
- */
-int node_select_same_type_np(SpaceNode *snode, int dir)
+static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bool from_right)
{
- bNode *nac, *p, *tnode;
+ bNode *node;
+ bool changed = false;
+ const unsigned int delims[] = {'.', '-', '_', '\0'};
+ size_t pref_len_act, pref_len_curr;
+ char *sep, *suf_act, *suf_curr;
- /* search the active one. */
- for (nac = snode->edittree->nodes.first; nac; nac = nac->next) {
- if (nac->flag & SELECT)
- break;
+ pref_len_act = BLI_str_partition_ex_utf8(node_act->name, 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)) {
+ pref_len_act = 0;
+ suf_act = node_act->name;
}
- /* no active node, return. */
- if (!nac)
- return(0);
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ if (node->flag & SELECT) {
+ continue;
+ }
+ pref_len_curr = BLI_str_partition_ex_utf8(node->name, delims, &sep, &suf_curr, from_right);
- if (dir == 0)
- p = nac->next;
- else
- p = nac->prev;
+ /* Same as with active node name! */
+ if (from_right && !(sep && suf_curr)) {
+ pref_len_curr = 0;
+ suf_curr = node->name;
+ }
- while (p) {
- /* Now search the next with the same type. */
- if (p->type == nac->type)
- break;
+ if ((from_right && STREQ(suf_act, suf_curr)) ||
+ (!from_right && (pref_len_act == pref_len_curr) && STREQLEN(node_act->name, node->name, pref_len_act)))
+ {
+ nodeSetSelected(node, true);
+ changed = true;
+ }
+ }
- if (dir == 0)
- p = p->next;
- else
- p = p->prev;
+ return changed;
+}
+
+enum {
+ NODE_SELECT_GROUPED_TYPE = 0,
+ NODE_SELECT_GROUPED_COLOR = 1,
+ NODE_SELECT_GROUPED_PREFIX = 2,
+ NODE_SELECT_GROUPED_SUFIX = 3,
+};
+
+static int node_select_grouped_exec(bContext *C, wmOperator *op)
+{
+ SpaceNode *snode = CTX_wm_space_node(C);
+ bNode *node_act = nodeGetActive(snode->edittree);
+ bNode *node;
+ bool changed = false;
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
+ const int type = RNA_enum_get(op->ptr, "type");
+
+ if (!extend) {
+ for (node = snode->edittree->nodes.first; node; node = node->next) {
+ nodeSetSelected(node, false);
+ }
}
+ nodeSetSelected(node_act, true);
- if (p) {
- for (tnode = snode->edittree->nodes.first; tnode; tnode = tnode->next)
- if (tnode != p)
- nodeSetSelected(tnode, false);
- nodeSetSelected(p, true);
- return(1);
+ switch (type) {
+ case NODE_SELECT_GROUPED_TYPE:
+ changed = node_select_grouped_type(snode, node_act);
+ break;
+ case NODE_SELECT_GROUPED_COLOR:
+ changed = node_select_grouped_color(snode, node_act);
+ break;
+ case NODE_SELECT_GROUPED_PREFIX:
+ changed = node_select_grouped_name(snode, node_act, false);
+ break;
+ case NODE_SELECT_GROUPED_SUFIX:
+ changed = node_select_grouped_name(snode, node_act, true);
+ break;
+ default:
+ break;
}
- return(0);
+
+ if (changed) {
+ ED_node_sort(snode->edittree);
+ WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void NODE_OT_select_grouped(wmOperatorType *ot)
+{
+ static EnumPropertyItem prop_select_grouped_types[] = {
+ {NODE_SELECT_GROUPED_TYPE, "TYPE", 0, "Type", ""},
+ {NODE_SELECT_GROUPED_COLOR, "COLOR", 0, "Color", ""},
+ {NODE_SELECT_GROUPED_PREFIX, "PREFIX", 0, "Prefix", ""},
+ {NODE_SELECT_GROUPED_SUFIX, "SUFFIX", 0, "Suffix", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ /* identifiers */
+ ot->name = "Select Grouped";
+ ot->description = "Select nodes with similar properties";
+ ot->idname = "NODE_OT_select_grouped";
+
+ /* api callbacks */
+ ot->invoke = WM_menu_invoke;
+ ot->exec = node_select_grouped_exec;
+ ot->poll = ED_operator_node_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ /* properties */
+ RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_select_grouped_types, 0, "Type", "");
}
void node_select_single(bContext *C, bNode *node)
@@ -563,7 +642,7 @@ void NODE_OT_select_circle(wmOperatorType *ot)
/* rna */
RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
}
@@ -787,40 +866,6 @@ void NODE_OT_select_linked_from(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
-/* ****** Select Same Type ****** */
-
-static int node_select_same_type_exec(bContext *C, wmOperator *UNUSED(op))
-{
- SpaceNode *snode = CTX_wm_space_node(C);
-
- node_select_same_type(snode);
-
- ED_node_sort(snode->edittree);
-
- WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL);
- return OPERATOR_FINISHED;
-}
-
-void NODE_OT_select_same_type(wmOperatorType *ot)
-{
- /* identifiers */
- ot->name = "Select Same Type";
- ot->description = "Select all the nodes of the same type";
- ot->idname = "NODE_OT_select_same_type";
-
- /* api callbacks */
- ot->exec = node_select_same_type_exec;
- ot->poll = ED_operator_node_active;
-
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
-}
-
-/* ****** Select The Next/Prev Node Of The Same Type ****** */
-
-/* ************************** */
-
-
static int node_select_same_type_step_exec(bContext *C, wmOperator *op)
{
SpaceNode *snode = CTX_wm_space_node(C);
@@ -971,7 +1016,6 @@ static uiBlock *node_find_menu(bContext *C, ARegion *ar, void *arg_op)
uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxHeight(), uiSearchBoxWidth(), uiSearchBoxHeight(), NULL, 0, 0, 0, 0, NULL);
uiPopupBoundsBlock(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
- uiEndBlock(C, block);
// uiButActiveOnly(C, ar, block, but); XXX using this here makes Blender hang - investigate
wm_event_init_from_window(win, &event);
diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c
index 44639b1295c..99a481e5d82 100644
--- a/source/blender/editors/space_node/node_templates.c
+++ b/source/blender/editors/space_node/node_templates.c
@@ -511,6 +511,7 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_
bNodeSocket *sock = arg->sock;
bNodeTreeType *ntreetype = arg->ntree->typeinfo;
+ uiBlockSetFlag(block, UI_BLOCK_NO_FLIP);
uiBlockSetCurLayout(block, layout);
split = uiLayoutSplit(layout, 0.0f, false);
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index ddfbe3bebf2..ccaeae34927 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -420,6 +420,9 @@ static void node_area_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
}
}
break;
+ case ND_LAYER_CONTENT:
+ ED_area_tag_refresh(sa);
+ break;
}
break;
@@ -501,6 +504,17 @@ static void node_area_listener(bScreen *sc, ScrArea *sa, wmNotifier *wmn)
}
}
break;
+
+ case NC_LINESTYLE:
+ if (ED_node_is_shader(snode) && shader_type == SNODE_SHADER_LINESTYLE) {
+ ED_area_tag_refresh(sa);
+ }
+ break;
+ case NC_WM:
+ if (wmn->data == ND_UNDO) {
+ ED_area_tag_refresh(sa);
+ }
+ break;
}
}
@@ -740,6 +754,7 @@ static void node_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegi
case NC_TEXTURE:
case NC_WORLD:
case NC_NODE:
+ case NC_LINESTYLE:
ED_region_tag_redraw(ar);
break;
case NC_OBJECT:
diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt
index 4db47b75502..b716f0671bd 100644
--- a/source/blender/editors/space_outliner/CMakeLists.txt
+++ b/source/blender/editors/space_outliner/CMakeLists.txt
@@ -24,10 +24,12 @@ set(INC
../../blenlib
../../blenfont
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -50,4 +52,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_outliner "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_outliner/SConscript b/source/blender/editors/space_outliner/SConscript
index db8041f0235..cc02c9555a9 100644
--- a/source/blender/editors/space_outliner/SConscript
+++ b/source/blender/editors/space_outliner/SConscript
@@ -28,15 +28,18 @@
Import ('env')
sources = env.Glob('*.c')
-defs = []
+
+defs = env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 1f728b380d6..e033f781f62 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -29,6 +29,7 @@
* \ingroup spoutliner
*/
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
@@ -46,6 +47,7 @@
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -55,6 +57,7 @@
#include "BKE_object.h"
#include "ED_armature.h"
+#include "ED_keyframing.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -168,7 +171,7 @@ static void restrictbutton_recursive_bone(bContext *C, bArmature *arm, Bone *bon
}
static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob_parent, char flag,
- bool state, bool deselect)
+ bool state, bool deselect, const char *rnapropname)
{
Main *bmain = CTX_data_main(C);
Object *ob;
@@ -183,6 +186,33 @@ static void restrictbutton_recursive_child(bContext *C, Scene *scene, Object *ob
else {
ob->restrictflag &= ~flag;
}
+
+ if (rnapropname) {
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ ID *id;
+ bAction *action;
+ FCurve *fcu;
+ bool driven;
+
+ RNA_id_pointer_create(&ob->id, &ptr);
+ prop = RNA_struct_find_property(&ptr, rnapropname);
+ fcu = rna_get_fcurve_context_ui(C, &ptr, prop, 0, &action, &driven);
+
+ if (fcu && !driven) {
+ id = ptr.id.data;
+ if (autokeyframe_cfra_can_key(scene, id)) {
+ ReportList *reports = CTX_wm_reports(C);
+ short flag = ANIM_get_keyframing_flags(scene, 1);
+
+ fcu->flag &= ~FCURVE_SELECTED;
+ insert_keyframe(reports, id, action, ((fcu->grp) ? (fcu->grp->name) : (NULL)),
+ fcu->rna_path, fcu->array_index, CFRA, flag);
+ /* Assuming this is not necessary here, since 'ancestor' object button will do it anyway. */
+ /* WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); */
+ }
+ }
+ }
}
}
}
@@ -203,7 +233,7 @@ static void restrictbutton_view_cb(bContext *C, void *poin, void *poin2)
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_VIEW,
- (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true);
+ (ob->restrictflag & OB_RESTRICT_VIEW) != 0, true, "hide");
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -226,7 +256,7 @@ static void restrictbutton_sel_cb(bContext *C, void *poin, void *poin2)
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_child(C, scene, ob, OB_RESTRICT_SELECT,
- (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true);
+ (ob->restrictflag & OB_RESTRICT_SELECT) != 0, true, NULL);
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
@@ -239,7 +269,7 @@ static void restrictbutton_rend_cb(bContext *C, void *poin, void *poin2)
if (CTX_wm_window(C)->eventstate->ctrl) {
restrictbutton_recursive_child(C, (Scene *)poin, ob, OB_RESTRICT_RENDER,
- (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false);
+ (ob->restrictflag & OB_RESTRICT_RENDER) != 0, false, "hide_render");
}
WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, poin);
@@ -638,7 +668,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
uiButSetFlag(bt, UI_BUT_DRAG_LOCK);
layflag++; /* is lay_xor */
- if (ELEM8(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
+ if (ELEM(passflag, SCE_PASS_SPEC, SCE_PASS_SHADOW, SCE_PASS_AO, SCE_PASS_REFLECT, SCE_PASS_REFRACT,
SCE_PASS_INDIRECT, SCE_PASS_EMIT, SCE_PASS_ENVIRONMENT))
{
bt = uiDefIconButBitI(block, TOG, passflag, 0, (*layflag & passflag) ? ICON_DOT : ICON_BLANK1,
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index 17e1e032bbf..ef621407abd 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -215,15 +215,15 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot)
static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, ReportList *reports)
{
/* can't rename rna datablocks entries or listbases */
- if (ELEM4(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) {
+ if (ELEM(tselem->type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM, TSE_ID_BASE)) {
/* do nothing */;
}
- else if (ELEM10(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE,
- TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS))
+ else if (ELEM(tselem->type, TSE_ANIM_DATA, TSE_NLA, TSE_DEFGROUP_BASE, TSE_CONSTRAINT_BASE, TSE_MODIFIER_BASE,
+ TSE_DRIVER_BASE, TSE_POSE_BASE, TSE_POSEGRP_BASE, TSE_R_LAYER_BASE, TSE_R_PASS))
{
BKE_report(reports, RPT_WARNING, "Cannot edit builtin name");
}
- else if (ELEM3(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
+ else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
BKE_report(reports, RPT_WARNING, "Cannot edit sequence name");
}
else if (tselem->id->lib) {
@@ -1654,7 +1654,7 @@ static int outliner_parenting_poll(bContext *C)
SpaceOops *soops = CTX_wm_space_outliner(C);
if (soops) {
- return ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS);
+ return ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS);
}
return false;
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index d7521edd57a..6f5bf712d55 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -948,7 +948,7 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
}
- else if (ELEM5(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
+ else if (ELEM(te->idcode, ID_ME, ID_CU, ID_MB, ID_LT, ID_AR)) {
WM_operator_name_call(C, "OBJECT_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
}
else { // rest of types
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 8f5e2ad3693..d09ed1a100e 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -459,6 +459,13 @@ 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);
+}
+
+
static void unlinkact_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te),
TreeStoreElem *tselem, void *UNUSED(arg))
{
@@ -1076,6 +1083,8 @@ void OUTLINER_OT_action_set(wmOperatorType *ot)
typedef enum eOutliner_AnimDataOps {
OUTLINER_ANIMOP_INVALID = 0,
+ OUTLINER_ANIMOP_CLEAR_ADT,
+
OUTLINER_ANIMOP_SET_ACT,
OUTLINER_ANIMOP_CLEAR_ACT,
@@ -1087,6 +1096,7 @@ typedef enum eOutliner_AnimDataOps {
} eOutliner_AnimDataOps;
static EnumPropertyItem prop_animdata_op_types[] = {
+ {OUTLINER_ANIMOP_CLEAR_ADT, "CLEAR_ANIMDATA", 0, "Clear Animation Data", "Remove this animation data container"},
{OUTLINER_ANIMOP_SET_ACT, "SET_ACT", 0, "Set Action", ""},
{OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""},
{OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""},
@@ -1115,6 +1125,14 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op)
/* perform the core operation */
switch (event) {
+ case OUTLINER_ANIMOP_CLEAR_ADT:
+ /* Remove Animation Data - this may remove the active action, in some cases... */
+ outliner_do_data_operation(soops, datalevel, event, &soops->tree, clear_animdata_cb, NULL);
+
+ WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL);
+ ED_undo_push(C, "Clear Animation Data");
+ break;
+
case OUTLINER_ANIMOP_SET_ACT:
/* delegate once again... */
WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL);
@@ -1321,7 +1339,7 @@ static int do_outliner_operation_event(bContext *C, Scene *scene, ARegion *ar, S
else if (datalevel == TSE_DRIVER_BASE) {
/* do nothing... no special ops needed yet */
}
- else if (ELEM3(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) {
+ else if (ELEM(datalevel, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS)) {
/*WM_operator_name_call(C, "OUTLINER_OT_renderdata_operation", WM_OP_INVOKE_REGION_WIN, NULL)*/
}
else {
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 520cd9a544d..5801dd126e3 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -821,7 +821,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
TreeStoreElem *tselem;
ID *id = idv;
- if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
+ if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
id = ((PointerRNA *)idv)->id.data;
if (!id) id = ((PointerRNA *)idv)->data;
}
@@ -847,10 +847,10 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->parent = parent;
te->index = index; // for data arays
- if (ELEM3(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
+ if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) {
/* pass */
}
- else if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
+ else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
/* pass */
}
else if (type == TSE_ANIM_DATA) {
@@ -985,7 +985,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
te->directdata = seq;
te->name = seq->strip->stripdata->name;
}
- else if (ELEM3(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
+ else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) {
PointerRNA pptr, propptr, *ptr = (PointerRNA *)idv;
PropertyRNA *prop, *iterprop;
PropertyType proptype;
@@ -1062,7 +1062,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
else if (tot)
te->flag |= TE_LAZY_CLOSED;
}
- else if (ELEM3(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
tot = RNA_property_array_length(ptr, prop);
if (TSELEM_OPEN(tselem, soops)) {
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index e25e67a9f3e..504d9628d98 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -143,7 +143,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
- if (!ELEM4(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) {
+ if (!ELEM(soops->outlinevis, SO_ALL_SCENES, SO_CUR_SCENE, SO_VISIBLE, SO_GROUPS)) {
return false;
}
@@ -156,7 +156,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
switch (te->idcode) {
case ID_SCE:
- return (ELEM3(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS));
+ return (ELEM(tselem->type, TSE_R_LAYER_BASE, TSE_R_LAYER, TSE_R_PASS));
case ID_OB:
return (ELEM(tselem->type, TSE_MODIFIER_BASE, TSE_CONSTRAINT_BASE));
/* Other codes to ignore? */
@@ -345,6 +345,7 @@ static void outliner_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
case NC_GEOM:
switch (wmn->data) {
case ND_VERTEX_GROUP:
+ case ND_DATA:
ED_region_tag_redraw(ar);
break;
}
diff --git a/source/blender/editors/space_script/CMakeLists.txt b/source/blender/editors/space_script/CMakeLists.txt
index 26c4183f7df..2eb31576c57 100644
--- a/source/blender/editors/space_script/CMakeLists.txt
+++ b/source/blender/editors/space_script/CMakeLists.txt
@@ -22,10 +22,12 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -47,4 +49,6 @@ if(WITH_PYTHON)
add_definitions(-DWITH_PYTHON)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_script "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_script/SConscript b/source/blender/editors/space_script/SConscript
index acb0bf9f20b..e749780a4aa 100644
--- a/source/blender/editors/space_script/SConscript
+++ b/source/blender/editors/space_script/SConscript
@@ -31,10 +31,12 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
@@ -42,7 +44,7 @@ incs = [
'../../windowmanager',
]
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_PYTHON']:
defs.append('WITH_PYTHON')
diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt
index db5729a5762..4cf9c0c95c2 100644
--- a/source/blender/editors/space_sequencer/CMakeLists.txt
+++ b/source/blender/editors/space_sequencer/CMakeLists.txt
@@ -24,10 +24,12 @@ set(INC
../../blenkernel
../../blenlib
../../imbuf
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -60,4 +62,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_sequencer "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_sequencer/SConscript b/source/blender/editors/space_sequencer/SConscript
index 5aae30244a7..954f8abff69 100644
--- a/source/blender/editors/space_sequencer/SConscript
+++ b/source/blender/editors/space_sequencer/SConscript
@@ -31,19 +31,21 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/audaspace/intern',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs.append(env['BF_PTHREADS_INC'])
diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c
index 8fe9dbe3eb9..345988c1d5c 100644
--- a/source/blender/editors/space_sequencer/sequencer_add.c
+++ b/source/blender/editors/space_sequencer/sequencer_add.c
@@ -226,6 +226,32 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, wmOperator *op)
}
}
+/**
+ * Apply generic operator options.
+ */
+static void sequencer_add_apply_overlap(bContext *C, wmOperator *op, Sequence *seq)
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ if (RNA_boolean_get(op->ptr, "overlap") == false) {
+ if (BKE_sequence_test_overlap(ed->seqbasep, seq)) {
+ BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
+ }
+ }
+}
+
+static void sequencer_add_apply_replace_sel(bContext *C, wmOperator *op, Sequence *seq)
+{
+ Scene *scene = CTX_data_scene(C);
+
+ if (RNA_boolean_get(op->ptr, "replace_sel")) {
+ ED_sequencer_deselect_all(scene);
+ BKE_sequencer_active_set(scene, seq);
+ seq->flag |= SELECT;
+ }
+}
+
/* add scene operator */
static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
{
@@ -268,15 +294,8 @@ static int sequencer_add_scene_strip_exec(bContext *C, wmOperator *op)
BKE_sequence_calc_disp(scene, seq);
BKE_sequencer_sort(scene);
- if (RNA_boolean_get(op->ptr, "replace_sel")) {
- ED_sequencer_deselect_all(scene);
- BKE_sequencer_active_set(scene, seq);
- seq->flag |= SELECT;
- }
-
- if (RNA_boolean_get(op->ptr, "overlap") == false) {
- if (BKE_sequence_test_overlap(ed->seqbasep, seq)) BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
- }
+ sequencer_add_apply_replace_sel(C, op, seq);
+ sequencer_add_apply_overlap(C, op, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -363,15 +382,8 @@ static int sequencer_add_movieclip_strip_exec(bContext *C, wmOperator *op)
BKE_sequence_calc_disp(scene, seq);
BKE_sequencer_sort(scene);
- if (RNA_boolean_get(op->ptr, "replace_sel")) {
- ED_sequencer_deselect_all(scene);
- BKE_sequencer_active_set(scene, seq);
- seq->flag |= SELECT;
- }
-
- if (RNA_boolean_get(op->ptr, "overlap") == false) {
- if (BKE_sequence_test_overlap(ed->seqbasep, seq)) BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
- }
+ sequencer_add_apply_replace_sel(C, op, seq);
+ sequencer_add_apply_overlap(C, op, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -455,15 +467,8 @@ static int sequencer_add_mask_strip_exec(bContext *C, wmOperator *op)
BKE_sequence_calc_disp(scene, seq);
BKE_sequencer_sort(scene);
- if (RNA_boolean_get(op->ptr, "replace_sel")) {
- ED_sequencer_deselect_all(scene);
- BKE_sequencer_active_set(scene, seq);
- seq->flag |= SELECT;
- }
-
- if (RNA_boolean_get(op->ptr, "overlap") == false) {
- if (BKE_sequence_test_overlap(ed->seqbasep, seq)) BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
- }
+ sequencer_add_apply_replace_sel(C, op, seq);
+ sequencer_add_apply_overlap(C, op, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -513,9 +518,7 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
Scene *scene = CTX_data_scene(C); /* only for sound */
Editing *ed = BKE_sequencer_editing_get(scene, true);
SeqLoadInfo seq_load;
- Sequence *seq;
int tot_files;
- const bool overlap = RNA_boolean_get(op->ptr, "overlap");
seq_load_operator_info(&seq_load, op);
@@ -536,6 +539,8 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
RNA_BEGIN (op->ptr, itemptr, "files")
{
+ Sequence *seq;
+
RNA_string_get(&itemptr, "name", file_only);
BLI_join_dirfile(seq_load.path, sizeof(seq_load.path), dir_only, file_only);
@@ -544,21 +549,23 @@ static int sequencer_add_generic_strip_exec(bContext *C, wmOperator *op, SeqLoad
seq = seq_load_func(C, ed->seqbasep, &seq_load);
if (seq) {
- if (overlap == false) {
- if (BKE_sequence_test_overlap(ed->seqbasep, seq))
- BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
+ sequencer_add_apply_overlap(C, op, seq);
+ if (seq_load.seq_sound) {
+ sequencer_add_apply_overlap(C, op, seq_load.seq_sound);
}
}
}
RNA_END;
}
else {
+ Sequence *seq;
+
/* single file */
seq = seq_load_func(C, ed->seqbasep, &seq_load);
if (seq) {
- if (overlap == false) {
- if (BKE_sequence_test_overlap(ed->seqbasep, seq))
- BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
+ sequencer_add_apply_overlap(C, op, seq);
+ if (seq_load.seq_sound) {
+ sequencer_add_apply_overlap(C, op, seq_load.seq_sound);
}
}
}
@@ -728,10 +735,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
/* last active name */
BLI_strncpy(ed->act_imagedir, strip->dir, sizeof(ed->act_imagedir));
- if (RNA_boolean_get(op->ptr, "overlap") == false) {
- if (BKE_sequence_test_overlap(ed->seqbasep, seq))
- BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
- }
+ sequencer_add_apply_overlap(C, op, seq);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
@@ -859,9 +863,8 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
}
}
- if (RNA_boolean_get(op->ptr, "overlap") == false) {
- if (BKE_sequence_test_overlap(ed->seqbasep, seq)) BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
- }
+ sequencer_add_apply_replace_sel(C, op, seq);
+ sequencer_add_apply_overlap(C, op, seq);
BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1); /* runs BKE_sequence_calc */
@@ -870,12 +873,6 @@ static int sequencer_add_effect_strip_exec(bContext *C, wmOperator *op)
* it was NOT called in blender 2.4x, but wont hurt */
BKE_sequencer_sort(scene);
- if (RNA_boolean_get(op->ptr, "replace_sel")) {
- ED_sequencer_deselect_all(scene);
- BKE_sequencer_active_set(scene, seq);
- seq->flag |= SELECT;
- }
-
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_sequencer/sequencer_buttons.c b/source/blender/editors/space_sequencer/sequencer_buttons.c
index 36589984c78..d75eeca2c67 100644
--- a/source/blender/editors/space_sequencer/sequencer_buttons.c
+++ b/source/blender/editors/space_sequencer/sequencer_buttons.c
@@ -68,8 +68,8 @@ void sequencer_buttons_register(ARegionType *art)
strcpy(pt->idname, "SEQUENCER_PT_gpencil");
strcpy(pt->label, N_("Grease Pencil"));
strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = gpencil_panel_standard_header;
- pt->draw = gpencil_panel_standard;
+ pt->draw_header = ED_gpencil_panel_standard_header;
+ pt->draw = ED_gpencil_panel_standard;
pt->poll = sequencer_grease_pencil_panel_poll;
BLI_addtail(&art->paneltypes, pt);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index e2830fca4bb..f9ca713ad2d 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -142,19 +142,21 @@ static void get_seq_color3ubv(Scene *curscene, Sequence *seq, unsigned char col[
case SEQ_TYPE_GLOW:
case SEQ_TYPE_MULTICAM:
case SEQ_TYPE_ADJUSTMENT:
+ case SEQ_TYPE_GAUSSIAN_BLUR:
UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col);
/* slightly offset hue to distinguish different effects */
- if (seq->type == SEQ_TYPE_ADD) rgb_byte_set_hue_float_offset(col, 0.04);
- else if (seq->type == SEQ_TYPE_SUB) rgb_byte_set_hue_float_offset(col, 0.08);
- else if (seq->type == SEQ_TYPE_MUL) rgb_byte_set_hue_float_offset(col, 0.12);
- else if (seq->type == SEQ_TYPE_ALPHAOVER) rgb_byte_set_hue_float_offset(col, 0.16);
- else if (seq->type == SEQ_TYPE_ALPHAUNDER) rgb_byte_set_hue_float_offset(col, 0.20);
- else if (seq->type == SEQ_TYPE_OVERDROP) rgb_byte_set_hue_float_offset(col, 0.24);
- else if (seq->type == SEQ_TYPE_GLOW) rgb_byte_set_hue_float_offset(col, 0.28);
- else if (seq->type == SEQ_TYPE_TRANSFORM) rgb_byte_set_hue_float_offset(col, 0.36);
- else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32);
- else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40);
+ if (seq->type == SEQ_TYPE_ADD) rgb_byte_set_hue_float_offset(col, 0.04);
+ else if (seq->type == SEQ_TYPE_SUB) rgb_byte_set_hue_float_offset(col, 0.08);
+ else if (seq->type == SEQ_TYPE_MUL) rgb_byte_set_hue_float_offset(col, 0.12);
+ else if (seq->type == SEQ_TYPE_ALPHAOVER) rgb_byte_set_hue_float_offset(col, 0.16);
+ else if (seq->type == SEQ_TYPE_ALPHAUNDER) rgb_byte_set_hue_float_offset(col, 0.20);
+ else if (seq->type == SEQ_TYPE_OVERDROP) rgb_byte_set_hue_float_offset(col, 0.24);
+ else if (seq->type == SEQ_TYPE_GLOW) rgb_byte_set_hue_float_offset(col, 0.28);
+ else if (seq->type == SEQ_TYPE_TRANSFORM) rgb_byte_set_hue_float_offset(col, 0.36);
+ else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32);
+ else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40);
+ else if (seq->type == SEQ_TYPE_GAUSSIAN_BLUR) rgb_byte_set_hue_float_offset(col, 0.42);
break;
case SEQ_TYPE_COLOR:
@@ -833,6 +835,9 @@ ImBuf *sequencer_ibuf_get(struct Main *bmain, Scene *scene, SpaceSeq *sseq, int
short is_break = G.is_break;
render_size = sseq->render_size;
+ if (render_size == 99) {
+ render_size = 100;
+ }
if (render_size == 0) {
render_size = scene->r.size;
}
@@ -1233,7 +1238,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
if (sseq->flag & SEQ_SHOW_GPENCIL) {
if (is_imbuf) {
/* draw grease-pencil (image aligned) */
- draw_gpencil_2dimage(C);
+ ED_gpencil_draw_2dimage(C);
}
}
@@ -1246,7 +1251,7 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
if (sseq->flag & SEQ_SHOW_GPENCIL) {
if (is_imbuf) {
/* draw grease-pencil (screen aligned) */
- draw_gpencil_view2d(C, 0);
+ ED_gpencil_draw_view2d(C, 0);
}
}
@@ -1387,16 +1392,20 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar)
}
static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
-{
+{
+ const Editing *ed = BKE_sequencer_editing_get(scene, false);
+ const int frame_sta = PSFRA;
+ const int frame_end = PEFRA + 1;
+
glEnable(GL_BLEND);
/* draw darkened area outside of active timeline
* frame range used is preview range or scene range */
UI_ThemeColorShadeAlpha(TH_BACK, -25, -100);
- if (PSFRA < PEFRA + 1) {
- glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
- glRectf((float)(PEFRA + 1), v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
+ if (frame_sta < frame_end) {
+ glRectf(v2d->cur.xmin, v2d->cur.ymin, (float)frame_sta, v2d->cur.ymax);
+ glRectf((float)frame_end, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
}
else {
glRectf(v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax);
@@ -1404,9 +1413,21 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
UI_ThemeColorShade(TH_BACK, -60);
/* thin lines where the actual frames are */
- fdrawline((float)PSFRA, v2d->cur.ymin, (float)PSFRA, v2d->cur.ymax);
- fdrawline((float)(PEFRA + 1), v2d->cur.ymin, (float)(PEFRA + 1), v2d->cur.ymax);
-
+ fdrawline(frame_sta, v2d->cur.ymin, frame_sta, v2d->cur.ymax);
+ fdrawline(frame_end, v2d->cur.ymin, frame_end, v2d->cur.ymax);
+
+ if (ed && !BLI_listbase_is_empty(&ed->metastack)) {
+ MetaStack *ms = ed->metastack.last;
+
+ glColor4ub(255, 255, 255, 8);
+ glRectf(ms->disp_range[0], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax);
+
+ UI_ThemeColorShade(TH_BACK, -40);
+
+ fdrawline(ms->disp_range[0], v2d->cur.ymin, ms->disp_range[0], v2d->cur.ymax);
+ fdrawline(ms->disp_range[1], v2d->cur.ymin, ms->disp_range[1], v2d->cur.ymax);
+ }
+
glDisable(GL_BLEND);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 50efa881b39..01259bb688f 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -86,6 +86,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
{SEQ_TYPE_SPEED, "SPEED", 0, "Speed", "Color effect strip type"},
{SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
{SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
+ {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1230,6 +1231,358 @@ void SEQUENCER_OT_snap(struct wmOperatorType *ot)
RNA_def_int(ot->srna, "frame", 0, INT_MIN, INT_MAX, "Frame", "Frame where selected strips will be snapped", INT_MIN, INT_MAX);
}
+
+typedef struct TrimData {
+ int init_mouse[2];
+ float init_mouseloc[2];
+ TransSeq *ts;
+ Sequence **seq_array;
+ bool *trim;
+ int num_seq;
+ bool slow;
+ int slow_offset; /* offset at the point where offset was turned on */
+} TrimData;
+
+static void transseq_backup(TransSeq *ts, Sequence *seq)
+{
+ ts->start = seq->start;
+ ts->machine = seq->machine;
+ ts->startstill = seq->startstill;
+ ts->endstill = seq->endstill;
+ ts->startdisp = seq->startdisp;
+ ts->enddisp = seq->enddisp;
+ ts->startofs = seq->startofs;
+ ts->endofs = seq->endofs;
+ ts->anim_startofs = seq->anim_startofs;
+ ts->anim_endofs = seq->anim_endofs;
+ ts->len = seq->len;
+}
+
+
+static void transseq_restore(TransSeq *ts, Sequence *seq)
+{
+ seq->start = ts->start;
+ seq->machine = ts->machine;
+ seq->startstill = ts->startstill;
+ seq->endstill = ts->endstill;
+ seq->startdisp = ts->startdisp;
+ seq->enddisp = ts->enddisp;
+ seq->startofs = ts->startofs;
+ seq->endofs = ts->endofs;
+ seq->anim_startofs = ts->anim_startofs;
+ seq->anim_endofs = ts->anim_endofs;
+ seq->len = ts->len;
+}
+
+static int trim_add_sequences_rec(ListBase *seqbasep, Sequence **seq_array, bool *trim, int offset, bool first_level)
+{
+ Sequence *seq;
+ int num_items = 0;
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (!first_level || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) {
+ seq_array[offset + num_items] = seq;
+ trim[offset + num_items] = first_level;
+ num_items++;
+
+ if (seq->type == SEQ_TYPE_META) {
+ /* trim the sub-sequences */
+ num_items += trim_add_sequences_rec(&seq->seqbase, seq_array, trim, num_items + offset, false);
+ }
+ else if (seq->type & SEQ_TYPE_EFFECT) {
+ trim[offset + num_items] = false;
+ }
+ }
+ }
+
+ return num_items;
+}
+
+static int trim_count_sequences_rec(ListBase *seqbasep, bool first_level)
+{
+ Sequence *seq;
+ int trimmed_sequences = 0;
+
+ for (seq = seqbasep->first; seq; seq = seq->next) {
+ if (!first_level || (!(seq->type & SEQ_TYPE_EFFECT) && (seq->flag & SELECT))) {
+ trimmed_sequences++;
+
+ if (seq->type == SEQ_TYPE_META) {
+ /* trim the sub-sequences */
+ trimmed_sequences += trim_count_sequences_rec(&seq->seqbase, false);
+ }
+ }
+ }
+
+ return trimmed_sequences;
+}
+
+static int sequencer_trim_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ TrimData *data;
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ float mouseloc[2];
+ int num_seq, i;
+ View2D *v2d = UI_view2d_fromcontext(C);
+
+ /* first recursively cound the trimmed elements */
+ num_seq = trim_count_sequences_rec(ed->seqbasep, true);
+
+ if (num_seq == 0)
+ return OPERATOR_CANCELLED;
+
+ data = op->customdata = MEM_mallocN(sizeof(TrimData), "trimdata");
+ data->ts = MEM_mallocN(num_seq * sizeof(TransSeq), "trimdata_transform");
+ data->seq_array = MEM_mallocN(num_seq * sizeof(Sequence *), "trimdata_sequences");
+ data->trim = MEM_mallocN(num_seq * sizeof(bool), "trimdata_trim");
+ data->num_seq = num_seq;
+
+ trim_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true);
+
+ for (i = 0; i < num_seq; i++) {
+ transseq_backup(data->ts + i, data->seq_array[i]);
+ }
+
+ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
+
+ copy_v2_v2_int(data->init_mouse, event->mval);
+ copy_v2_v2(data->init_mouseloc, mouseloc);
+
+ data->slow = false;
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static bool sequencer_trim_recursively(Scene *scene, TrimData *data, int offset)
+{
+
+ /* only data types supported for now */
+ if (offset != 0) {
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ int i;
+
+ /* we iterate in reverse so metastrips are iterated after their children */
+ for (i = data->num_seq - 1; i >= 0; i--) {
+ Sequence *seq = data->seq_array[i];
+ int endframe;
+ /* we have the offset, do the terrible math */
+
+ /* first, do the offset */
+ seq->start = data->ts[i].start + offset;
+
+ if (data->trim[i]) {
+ /* find the endframe */
+ endframe = seq->start + seq->len;
+
+ /* now compute the terrible offsets */
+ if (endframe > seq->enddisp) {
+ seq->endstill = 0;
+ seq->endofs = endframe - seq->enddisp;
+ }
+ else if (endframe <= seq->enddisp) {
+ seq->endstill = seq->enddisp - endframe;
+ seq->endofs = 0;
+ }
+
+ if (seq->start > seq->startdisp) {
+ seq->startstill = seq->start - seq->startdisp;
+ seq->startofs = 0;
+ }
+ else if (seq->start <= seq->startdisp) {
+ seq->startstill = 0;
+ seq->startofs = seq->startdisp - seq->start;
+ }
+ }
+ else {
+ /* if no real trim, don't change the data, rather transform the strips themselves */
+ seq->startdisp = data->ts[i].startdisp + offset;
+ seq->enddisp = data->ts[i].enddisp + offset;
+ }
+
+ /* effects are only added if we they are in a metastrip. In this case, dependent strips will just be transformed and we can skip calculating for effects
+ * This way we can avoid an extra loop just for effects*/
+ if (!(seq->type & SEQ_TYPE_EFFECT))
+ BKE_sequence_calc(scene, seq);
+ }
+ BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
+
+ return true;
+ }
+
+ return false;
+}
+
+static int sequencer_trim_exec(bContext *C, wmOperator *op)
+{
+ TrimData *data;
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ int num_seq, i;
+ int offset = RNA_int_get(op->ptr, "offset");
+ bool success = false;
+
+ /* first recursively cound the trimmed elements */
+ num_seq = trim_count_sequences_rec(ed->seqbasep, true);
+
+ if (num_seq == 0)
+ return OPERATOR_CANCELLED;
+
+ data = op->customdata = MEM_mallocN(sizeof(TrimData), "trimdata");
+ data->ts = MEM_mallocN(num_seq * sizeof(TransSeq), "trimdata_transform");
+ data->seq_array = MEM_mallocN(num_seq * sizeof(Sequence *), "trimdata_sequences");
+ data->trim = MEM_mallocN(num_seq * sizeof(bool), "trimdata_trim");
+ data->num_seq = num_seq;
+
+ trim_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true);
+
+ for (i = 0; i < num_seq; i++) {
+ transseq_backup(data->ts + i, data->seq_array[i]);
+ }
+
+ success = sequencer_trim_recursively(scene, data, offset);
+
+ MEM_freeN(data->seq_array);
+ MEM_freeN(data->trim);
+ MEM_freeN(data->ts);
+ MEM_freeN(data);
+
+ if (success) return OPERATOR_FINISHED;
+ else return OPERATOR_CANCELLED;
+}
+
+static int sequencer_trim_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Scene *scene = CTX_data_scene(C);
+ TrimData *data = (TrimData *)op->customdata;
+ ScrArea *sa = CTX_wm_area(C);
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ {
+ float mouseloc[2];
+ int offset;
+ int mouse_x;
+ View2D *v2d = UI_view2d_fromcontext(C);
+
+ if (data->slow) {
+ mouse_x = event->mval[0] - data->slow_offset;
+ mouse_x *= 0.1f;
+ mouse_x += data->slow_offset;
+ }
+ else {
+ mouse_x = event->mval[0];
+ }
+
+
+ /* choose the side based on which side of the playhead the mouse is on */
+ UI_view2d_region_to_view(v2d, mouse_x, 0, &mouseloc[0], &mouseloc[1]);
+ offset = mouseloc[0] - data->init_mouseloc[0];
+
+ RNA_int_set(op->ptr, "offset", offset);
+
+ if (sa) {
+#define HEADER_LENGTH 40
+ char msg[HEADER_LENGTH];
+ BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %d", offset);
+#undef HEADER_LENGTH
+ ED_area_headerprint(sa, msg);
+ }
+
+ if (sequencer_trim_recursively(scene, data, offset)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ }
+ break;
+ }
+
+ case LEFTMOUSE:
+ {
+ MEM_freeN(data->seq_array);
+ MEM_freeN(data->trim);
+ MEM_freeN(data->ts);
+ MEM_freeN(data);
+ op->customdata = NULL;
+ if (sa) {
+ ED_area_headerprint(sa, NULL);
+ }
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ return OPERATOR_FINISHED;
+ }
+
+ case ESCKEY:
+ case RIGHTMOUSE:
+ {
+ int i;
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+
+ for (i = 0; i < data->num_seq; i++) {
+ transseq_restore(data->ts + i, data->seq_array[i]);
+ }
+
+ for (i = 0; i < data->num_seq; i++) {
+ Sequence *seq = data->seq_array[i];
+ BKE_sequence_reload_new_file(scene, seq, false);
+ BKE_sequence_calc(scene, seq);
+ }
+
+ MEM_freeN(data->seq_array);
+ MEM_freeN(data->ts);
+ MEM_freeN(data->trim);
+ MEM_freeN(data);
+ op->customdata = NULL;
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+ BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
+
+ if (sa) {
+ ED_area_headerprint(sa, NULL);
+ }
+
+ return OPERATOR_CANCELLED;
+ }
+
+ case RIGHTSHIFTKEY:
+ case LEFTSHIFTKEY:
+ if (event->val == KM_PRESS) {
+ data->slow = true;
+ data->slow_offset = event->mval[0];
+ }
+ else if (event->val == KM_RELEASE) {
+ data->slow = false;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+void SEQUENCER_OT_trim(struct wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Trim Strips";
+ ot->idname = "SEQUENCER_OT_trim";
+ ot->description = "Trim the contents of the active strip";
+
+ /* api callbacks */
+ ot->invoke = sequencer_trim_invoke;
+ ot->modal = sequencer_trim_modal;
+ ot->exec = sequencer_trim_exec;
+ ot->poll = sequencer_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_int(ot->srna, "offset", 0, INT32_MIN, INT32_MAX, "Offset", "Offset to the data of the strip",
+ INT32_MIN, INT32_MAX);
+}
+
+
/* mute operator */
static int sequencer_mute_exec(bContext *C, wmOperator *op)
{
@@ -1918,9 +2271,12 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
strip_new = seq_new->strip;
strip_new->us = 1;
- /* new stripdata */
- se_new = strip_new->stripdata;
+ /* new stripdata (only one element now!) */
+ /* Note this assume all elements (images) have the same dimension, since we only copy the name here. */
+ se_new = MEM_reallocN(strip_new->stripdata, sizeof(*se_new));
BLI_strncpy(se_new->name, se->name, sizeof(se_new->name));
+ strip_new->stripdata = se_new;
+
BKE_sequence_calc(scene, seq_new);
if (step > 1) {
@@ -1989,6 +2345,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
BLI_addtail(&ed->metastack, ms);
ms->parseq = last_seq;
ms->oldbasep = ed->seqbasep;
+ copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
ed->seqbasep = &last_seq->seqbase;
@@ -2008,12 +2365,25 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
ed->seqbasep = ms->oldbasep;
+ /* for old files, update from meta */
+ if (ms->disp_range[0] == ms->disp_range[1]) {
+ copy_v2_v2_int(ms->disp_range, &ms->parseq->startdisp);
+ }
+
/* recalc all: the meta can have effects connected to it */
for (seq = ed->seqbasep->first; seq; seq = seq->next)
BKE_sequence_calc(scene, seq);
+ /* 2.73+, keeping endpoings is important!
+ * moving them around means you can't usefully use metas in a complex edit */
+#if 1
+ BKE_sequence_tx_set_final_left(ms->parseq, ms->disp_range[0]);
+ BKE_sequence_tx_set_final_right(ms->parseq, ms->disp_range[1]);
+ BKE_sequence_calc(scene, ms->parseq);
+#else
if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq))
BKE_sequence_base_shuffle(ed->seqbasep, ms->parseq, scene);
+#endif
BKE_sequencer_active_set(scene, ms->parseq);
@@ -2055,8 +2425,8 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
Sequence *seq, *seqm, *next, *last_seq = BKE_sequencer_active_get(scene);
int channel_max = 1;
- if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) {
- BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
+ if (BKE_sequence_base_isolated_sel_check(ed->seqbasep, false) == false) {
+ BKE_report(op->reports, RPT_ERROR, "Please select more than one or all related strips");
return OPERATOR_CANCELLED;
}
@@ -2071,6 +2441,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
while (seq) {
next = seq->next;
if (seq != seqm && (seq->flag & SELECT)) {
+ BKE_sequence_invalidate_cache(scene, seq);
channel_max = max_ii(seq->machine, channel_max);
BLI_remlink(ed->seqbasep, seq);
BLI_addtail(&seqm->seqbase, seq);
@@ -2132,6 +2503,10 @@ static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
if (last_seq == NULL || last_seq->type != SEQ_TYPE_META)
return OPERATOR_CANCELLED;
+ for (seq = last_seq->seqbase.first; seq != NULL; seq = seq->next) {
+ BKE_sequence_invalidate_cache(scene, seq);
+ }
+
BLI_movelisttolist(ed->seqbasep, &last_seq->seqbase);
BLI_listbase_clear(&last_seq->seqbase);
@@ -2436,73 +2811,59 @@ static int find_next_prev_edit(Scene *scene, int cfra,
const bool do_skip_mute, const bool do_center)
{
Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq, *best_seq = NULL, *frame_seq = NULL;
+ Sequence *seq;
- int dist, best_dist;
+ int dist, best_dist, best_frame = cfra;
+ int seq_frames[2], seq_frames_tot;
+
best_dist = MAXFRAME * 2;
if (ed == NULL) return cfra;
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
- int seq_frame;
+ int i;
if (do_skip_mute && (seq->flag & SEQ_MUTE)) {
continue;
}
if (do_center) {
- seq_frame = (seq->startdisp + seq->enddisp) / 2;
+ seq_frames[0] = (seq->startdisp + seq->enddisp) / 2;
+ seq_frames_tot = 1;
}
else {
- seq_frame = seq->startdisp;
- }
+ seq_frames[0] = seq->startdisp;
+ seq_frames[1] = seq->enddisp;
- dist = MAXFRAME * 2;
-
- switch (side) {
- case SEQ_SIDE_LEFT:
- if (seq_frame < cfra) {
- dist = cfra - seq_frame;
- }
- break;
- case SEQ_SIDE_RIGHT:
- if (seq_frame > cfra) {
- dist = seq_frame - cfra;
- }
- else if (seq_frame == cfra) {
- frame_seq = seq;
- }
- break;
+ seq_frames_tot = 2;
}
- if (dist < best_dist) {
- best_dist = dist;
- best_seq = seq;
- }
- }
+ for (i = 0; i < seq_frames_tot; i++) {
+ const int seq_frame = seq_frames[i];
- /* if no sequence to the right is found and the
- * frame is on the start of the last sequence,
- * move to the end of the last sequence */
- if (frame_seq) {
- if (do_center) {
- cfra = (frame_seq->startdisp + frame_seq->enddisp) / 2;
- }
- else {
- cfra = frame_seq->enddisp;
- }
- }
+ dist = MAXFRAME * 2;
- if (best_seq) {
- if (do_center) {
- cfra = (best_seq->startdisp + best_seq->enddisp) / 2;
- }
- else {
- cfra = best_seq->startdisp;
+ switch (side) {
+ case SEQ_SIDE_LEFT:
+ if (seq_frame < cfra) {
+ dist = cfra - seq_frame;
+ }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if (seq_frame > cfra) {
+ dist = seq_frame - cfra;
+ }
+ break;
+ }
+
+ if (dist < best_dist) {
+ best_frame = seq_frame;
+ best_dist = dist;
+ }
}
}
- return cfra;
+ return best_frame;
}
static bool strip_jump_internal(Scene *scene,
@@ -2758,7 +3119,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
BKE_sequencer_free_clipboard();
- if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) {
+ if (BKE_sequence_base_isolated_sel_check(ed->seqbasep, true) == false) {
BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
return OPERATOR_CANCELLED;
}
@@ -2795,9 +3156,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
}
/* duplicate pointers */
- for (seq = seqbase_clipboard.first; seq; seq = seq->next) {
- BKE_sequence_clipboard_pointers_store(seq);
- }
+ BKE_sequencer_base_clipboard_pointers_store(&seqbase_clipboard);
}
return OPERATOR_FINISHED;
@@ -2841,9 +3200,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- for (iseq = nseqbase.first; iseq; iseq = iseq->next) {
- BKE_sequence_clipboard_pointers_restore(iseq, bmain);
- }
+ BKE_sequencer_base_clipboard_pointers_restore(&nseqbase, bmain);
for (iseq = nseqbase.first; iseq; iseq = iseq->next) {
BKE_sequence_sound_init(scene, iseq);
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 60fc300da1f..4fada72d0d9 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -84,6 +84,7 @@ struct wmOperatorType;
struct wmKeyConfig;
void SEQUENCER_OT_cut(struct wmOperatorType *ot);
+void SEQUENCER_OT_trim(struct wmOperatorType *ot);
void SEQUENCER_OT_mute(struct wmOperatorType *ot);
void SEQUENCER_OT_unmute(struct wmOperatorType *ot);
void SEQUENCER_OT_lock(struct wmOperatorType *ot);
@@ -165,6 +166,13 @@ enum {
SEQ_UNSELECTED
};
+enum {
+ SEQ_SELECT_LR_NONE = 0,
+ SEQ_SELECT_LR_MOUSE,
+ SEQ_SELECT_LR_LEFT,
+ SEQ_SELECT_LR_RIGHT
+};
+
/* defines used internally */
#define SCE_MARKERS 0 // XXX - dummy
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index e69a02aa3df..dff8f69509e 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -50,6 +50,7 @@ void sequencer_operatortypes(void)
{
/* sequencer_edit.c */
WM_operatortype_append(SEQUENCER_OT_cut);
+ WM_operatortype_append(SEQUENCER_OT_trim);
WM_operatortype_append(SEQUENCER_OT_mute);
WM_operatortype_append(SEQUENCER_OT_unmute);
WM_operatortype_append(SEQUENCER_OT_lock);
@@ -237,12 +238,12 @@ void sequencer_keymap(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "extend", false);
RNA_boolean_set(kmi->ptr, "linked_handle", false);
- RNA_boolean_set(kmi->ptr, "left_right", false);
+ RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
RNA_boolean_set(kmi->ptr, "linked_time", false);
kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
RNA_boolean_set(kmi->ptr, "extend", true);
RNA_boolean_set(kmi->ptr, "linked_handle", false);
- RNA_boolean_set(kmi->ptr, "left_right", false);
+ RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
RNA_boolean_set(kmi->ptr, "linked_time", false);
@@ -275,27 +276,27 @@ void sequencer_keymap(wmKeyConfig *keyconf)
kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "extend", false);
RNA_boolean_set(kmi->ptr, "linked_handle", true);
- RNA_boolean_set(kmi->ptr, "left_right", false);
+ RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
RNA_boolean_set(kmi->ptr, "linked_time", false);
kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0);
RNA_boolean_set(kmi->ptr, "extend", true);
RNA_boolean_set(kmi->ptr, "linked_handle", true);
- RNA_boolean_set(kmi->ptr, "left_right", false);
+ RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
RNA_boolean_set(kmi->ptr, "linked_time", false);
/* match action editor */
kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "extend", false);
RNA_boolean_set(kmi->ptr, "linked_handle", false);
- RNA_boolean_set(kmi->ptr, "left_right", true); /* grr, these conflict - only use left_right if not over an active seq */
+ RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_MOUSE); /* grr, these conflict - only use left_right if not over an active seq */
RNA_boolean_set(kmi->ptr, "linked_time", true);
/* adjusted since 2.4 */
kmi = WM_keymap_add_item(keymap, "SEQUENCER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "extend", true);
RNA_boolean_set(kmi->ptr, "linked_handle", false);
- RNA_boolean_set(kmi->ptr, "left_right", false);
+ RNA_enum_set(kmi->ptr, "left_right", SEQ_SELECT_LR_NONE);
RNA_boolean_set(kmi->ptr, "linked_time", true);
WM_keymap_add_item(keymap, "SEQUENCER_OT_select_more", PADPLUSKEY, KM_PRESS, KM_CTRL, 0);
@@ -316,6 +317,8 @@ void sequencer_keymap(wmKeyConfig *keyconf)
WM_keymap_add_menu(keymap, "SEQUENCER_MT_change", CKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "SEQUENCER_OT_trim", TKEY, KM_PRESS, 0, 0);
+
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_int", OKEY, KM_PRESS, 0, 0);
RNA_string_set(kmi->ptr, "data_path", "scene.sequence_editor.overlay_frame");
RNA_int_set(kmi->ptr, "value", 0);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 9826ef10902..933daf4adee 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -314,7 +314,7 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
const bool extend = RNA_boolean_get(op->ptr, "extend");
const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
- bool left_right = RNA_boolean_get(op->ptr, "left_right");
+ int left_right = RNA_enum_get(op->ptr, "left_right");
Sequence *seq, *neighbor, *act_orig;
int hand, sel_side;
@@ -328,8 +328,8 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
seq = find_nearest_seq(scene, v2d, &hand, event->mval);
// XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
- if (seq && linked_time && left_right)
- left_right = false;
+ if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE))
+ left_right = SEQ_SELECT_LR_NONE;
if (marker) {
@@ -348,12 +348,24 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
}
}
- else if (left_right) {
+ else if (left_right != SEQ_SELECT_LR_NONE) {
/* use different logic for this */
float x;
ED_sequencer_deselect_all(scene);
- x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
-
+
+ switch (left_right) {
+ case SEQ_SELECT_LR_MOUSE:
+ x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
+ break;
+
+ case SEQ_SELECT_LR_LEFT:
+ x = CFRA - 1;
+ break;
+ case SEQ_SELECT_LR_RIGHT:
+ x = CFRA + 1;
+ break;
+ }
+
SEQP_BEGIN (ed, seq)
{
if (x < CFRA) {
@@ -522,6 +534,14 @@ static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *e
void SEQUENCER_OT_select(wmOperatorType *ot)
{
+ static EnumPropertyItem sequencer_select_left_right_types[] = {
+ {SEQ_SELECT_LR_NONE, "NONE", 0, "None", "Don't do left-right selection"},
+ {SEQ_SELECT_LR_MOUSE, "MOUSE", 0, "Mouse", "Use mouse position for selection"},
+ {SEQ_SELECT_LR_LEFT, "LEFT", 0, "Left", "Select left"},
+ {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
/* identifiers */
ot->name = "Activate/Select";
ot->idname = "SEQUENCER_OT_select";
@@ -538,7 +558,7 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
RNA_def_boolean(ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip");
/* for animation this is an enum but atm having an enum isn't useful for us */
- RNA_def_boolean(ot->srna, "left_right", 0, "Left/Right", "Select based on the current frame side the cursor is on");
+ RNA_def_enum(ot->srna, "left_right", sequencer_select_left_right_types, 0, "Left/Right", "Select based on the current frame side the cursor is on");
RNA_def_boolean(ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time");
}
@@ -912,7 +932,7 @@ static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_IS_EFFECT(_seq) ((_seq->type & SEQ_TYPE_EFFECT) != 0)
-#define SEQ_USE_DATA(_seq) (ELEM3(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
+#define SEQ_USE_DATA(_seq) (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
static bool select_grouped_type(Editing *ed, Sequence *actseq)
{
@@ -1035,7 +1055,7 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq)
SEQP_BEGIN (ed, seq)
{
- if (ELEM3(actseq, seq->seq1, seq->seq2, seq->seq3)) {
+ if (ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
effects[seq->type] = true;
}
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index a94b73802b2..c0cfaed7867 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -279,24 +279,40 @@ static void sequencer_refresh(const bContext *C, ScrArea *sa)
}
break;
case SEQ_VIEW_SEQUENCE_PREVIEW:
- if (ar_main && (ar_main->flag & RGN_FLAG_HIDDEN)) {
- ar_main->flag &= ~RGN_FLAG_HIDDEN;
- ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
- view_changed = true;
- }
- if (ar_preview && (ar_preview->flag & RGN_FLAG_HIDDEN)) {
- ar_preview->flag &= ~RGN_FLAG_HIDDEN;
- ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
- ar_preview->v2d.cur = ar_preview->v2d.tot;
- view_changed = true;
- }
- if (ar_main && ar_main->alignment != RGN_ALIGN_NONE) {
- ar_main->alignment = RGN_ALIGN_NONE;
- view_changed = true;
- }
- if (ar_preview && ar_preview->alignment != RGN_ALIGN_TOP) {
- ar_preview->alignment = RGN_ALIGN_TOP;
- view_changed = true;
+ if (ar_main && ar_preview) {
+ /* Get available height (without DPI correction). */
+ const float height = (sa->winy - ED_area_headersize()) / UI_DPI_FAC;
+
+ /* We reuse hidden area's size, allows to find same layout as before if we just switch
+ * between one 'full window' view and the combined one. This gets lost if we switch to both
+ * 'full window' views before, though... Better than nothing. */
+ if (ar_main->flag & RGN_FLAG_HIDDEN) {
+ ar_main->flag &= ~RGN_FLAG_HIDDEN;
+ ar_main->v2d.flag &= ~V2D_IS_INITIALISED;
+ ar_preview->sizey = (int)(height - ar_main->sizey);
+ view_changed = true;
+ }
+ if (ar_preview->flag & RGN_FLAG_HIDDEN) {
+ ar_preview->flag &= ~RGN_FLAG_HIDDEN;
+ ar_preview->v2d.flag &= ~V2D_IS_INITIALISED;
+ ar_preview->v2d.cur = ar_preview->v2d.tot;
+ ar_main->sizey = (int)(height - ar_preview->sizey);
+ view_changed = true;
+ }
+ if (ar_main->alignment != RGN_ALIGN_NONE) {
+ ar_main->alignment = RGN_ALIGN_NONE;
+ view_changed = true;
+ }
+ if (ar_preview->alignment != RGN_ALIGN_TOP) {
+ ar_preview->alignment = RGN_ALIGN_TOP;
+ view_changed = true;
+ }
+ /* Final check that both preview and main height are reasonable! */
+ if (ar_preview->sizey < 10 || ar_main->sizey < 10 || ar_preview->sizey + ar_main->sizey > height) {
+ ar_preview->sizey = (int)(height * 0.4f + 0.5f);
+ ar_main->sizey = (int)(height - ar_preview->sizey);
+ view_changed = true;
+ }
}
break;
}
@@ -339,40 +355,6 @@ static void sequencer_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn
}
}
-/* *********************** sequencer (main) region ************************ */
-/* add handlers, stuff you only do once or on area/region changes */
-static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar)
-{
- wmKeyMap *keymap;
- ListBase *lb;
-
- UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
-
-// keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0);
-// WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
-
- keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
- WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
-
- /* own keymap */
- keymap = WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0);
- WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
-
- /* add drop boxes */
- lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
-
- WM_event_add_dropbox_handler(&ar->handlers, lb);
-
-}
-
-static void sequencer_main_area_draw(const bContext *C, ARegion *ar)
-{
-// ScrArea *sa = CTX_wm_area(C);
-
- /* NLE - strip editing timeline interface */
- draw_timeline_seq(C, ar);
-}
-
/* ************* dropboxes ************* */
static int image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
@@ -396,7 +378,7 @@ static int movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
int hand;
if (drag->type == WM_DRAG_PATH)
- if (ELEM3(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
+ if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) /* rule might not work? */
if (find_nearest_seq(scene, &ar->v2d, &hand, event->mval) == NULL)
return 1;
return 0;
@@ -439,7 +421,7 @@ static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop)
static void sequencer_dropboxes(void)
{
ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
-
+
WM_dropbox_add(lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy);
WM_dropbox_add(lb, "SEQUENCER_OT_movie_strip_add", movie_drop_poll, sequencer_drop_copy);
WM_dropbox_add(lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy);
@@ -469,16 +451,37 @@ static int sequencer_context(const bContext *C, const char *member, bContextData
return false;
}
-
+/* *********************** sequencer (main) region ************************ */
/* add handlers, stuff you only do once or on area/region changes */
-static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+static void sequencer_main_area_init(wmWindowManager *wm, ARegion *ar)
{
- ED_region_header_init(ar);
+ wmKeyMap *keymap;
+ ListBase *lb;
+
+ UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
+
+#if 0
+ keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+#endif
+
+ keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+ /* own keymap */
+ keymap = WM_keymap_find(wm->defaultconf, "Sequencer", SPACE_SEQ, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+ /* add drop boxes */
+ lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW);
+
+ WM_event_add_dropbox_handler(&ar->handlers, lb);
}
-static void sequencer_header_area_draw(const bContext *C, ARegion *ar)
+static void sequencer_main_area_draw(const bContext *C, ARegion *ar)
{
- ED_region_header(C, ar);
+ /* NLE - strip editing timeline interface */
+ draw_timeline_seq(C, ar);
}
static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa), ARegion *ar, wmNotifier *wmn)
@@ -512,15 +515,29 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
}
}
+/* *********************** header region ************************ */
+/* add handlers, stuff you only do once or on area/region changes */
+static void sequencer_header_area_init(wmWindowManager *UNUSED(wm), ARegion *ar)
+{
+ ED_region_header_init(ar);
+}
+
+static void sequencer_header_area_draw(const bContext *C, ARegion *ar)
+{
+ ED_region_header(C, ar);
+}
+
/* *********************** preview region ************************ */
static void sequencer_preview_area_init(wmWindowManager *wm, ARegion *ar)
{
wmKeyMap *keymap;
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_CUSTOM, ar->winx, ar->winy);
-
-// keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0);
-// WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+
+#if 0
+ keymap = WM_keymap_find(wm->defaultconf, "Mask Editing", 0, 0);
+ WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
+#endif
keymap = WM_keymap_find(wm->defaultconf, "SequencerCommon", SPACE_SEQ, 0);
WM_event_add_keymap_handler_bb(&ar->handlers, keymap, &ar->v2d.mask, &ar->winrct);
@@ -593,7 +610,6 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
break;
}
break;
-
case NC_MASK:
if (wmn->action == NA_EDITED) {
ED_region_tag_redraw(ar);
@@ -654,10 +670,10 @@ void ED_spacetype_sequencer(void)
{
SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype sequencer");
ARegionType *art;
-
+
st->spaceid = SPACE_SEQ;
strncpy(st->name, "Sequencer", BKE_ST_MAXNAME);
-
+
st->new = sequencer_new;
st->free = sequencer_free;
st->init = sequencer_init;
@@ -682,13 +698,12 @@ void ED_spacetype_sequencer(void)
/* preview */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_PREVIEW;
- art->prefsizey = 240; // XXX
art->init = sequencer_preview_area_init;
art->draw = sequencer_preview_area_draw;
art->listener = sequencer_preview_area_listener;
art->keymapflag = ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_GPENCIL;
BLI_addhead(&st->regiontypes, art);
-
+
/* regions: listview/buttons */
art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region");
art->regionid = RGN_TYPE_UI;
@@ -698,7 +713,7 @@ void ED_spacetype_sequencer(void)
art->init = sequencer_buttons_area_init;
art->draw = sequencer_buttons_area_draw;
BLI_addhead(&st->regiontypes, art);
-
+
sequencer_buttons_register(art);
/* regions: header */
@@ -706,13 +721,13 @@ void ED_spacetype_sequencer(void)
art->regionid = RGN_TYPE_HEADER;
art->prefsizey = HEADERY;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER;
-
+
art->init = sequencer_header_area_init;
art->draw = sequencer_header_area_draw;
art->listener = sequencer_main_area_listener;
-
+
BLI_addhead(&st->regiontypes, art);
-
+
BKE_spacetype_register(st);
/* set the sequencer callback when not in background mode */
diff --git a/source/blender/editors/space_text/CMakeLists.txt b/source/blender/editors/space_text/CMakeLists.txt
index bfeeb93372a..5367efbf84b 100644
--- a/source/blender/editors/space_text/CMakeLists.txt
+++ b/source/blender/editors/space_text/CMakeLists.txt
@@ -23,10 +23,12 @@ set(INC
../../blenfont
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -48,6 +50,8 @@ set(SRC
text_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
if(WITH_PYTHON)
list(APPEND INC
../../python
diff --git a/source/blender/editors/space_text/SConscript b/source/blender/editors/space_text/SConscript
index 3f617f95c58..8ee9bd745dd 100644
--- a/source/blender/editors/space_text/SConscript
+++ b/source/blender/editors/space_text/SConscript
@@ -28,14 +28,18 @@
Import ('env')
sources = env.Glob('*.c')
-defs = []
+
+defs = env['BF_GL_DEFINITIONS']
+
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../imbuf',
'../../makesdna',
'../../makesrna',
diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c
index 6e49569314f..1e710b88cad 100644
--- a/source/blender/editors/space_text/space_text.c
+++ b/source/blender/editors/space_text/space_text.c
@@ -462,10 +462,13 @@ static void text_cursor(wmWindow *win, ScrArea *sa, ARegion *ar)
static int text_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
- if (drag->type == WM_DRAG_PATH)
- if (ELEM(drag->icon, ICON_FILE_SCRIPT, ICON_FILE_BLANK)) /* rule might not work? */
- return 1;
- return 0;
+ if (drag->type == WM_DRAG_PATH) {
+ /* rule might not work? */
+ if (ELEM(drag->icon, ICON_FILE_SCRIPT, ICON_FILE_TEXT, ICON_FILE_BLANK)) {
+ return true;
+ }
+ }
+ return false;
}
static void text_drop_copy(wmDrag *drag, wmDropBox *drop)
@@ -484,7 +487,13 @@ static int text_drop_paste_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent
static void text_drop_paste(wmDrag *drag, wmDropBox *drop)
{
- RNA_string_set(drop->ptr, "text", ((ID *)drag->poin)->name + 2);
+ char *text;
+ ID *id = drag->poin;
+
+ /* copy drag path to properties */
+ text = RNA_path_full_ID_py(id);
+ RNA_string_set(drop->ptr, "text", text);
+ MEM_freeN(text);
}
/* this region dropbox definition */
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 6a98fd802f9..af827d6dc5a 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -373,9 +373,11 @@ static const char *txt_utf8_forward_columns(const char *str, int columns, int *p
static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w, const char *format, int skip)
{
+ const bool use_syntax = (st->showsyntax && format);
FlattenString fs;
int basex, lines;
int i, wrap, end, max, columns, padding; /* column */
+ /* warning, only valid when 'use_syntax' is set */
int a, fstart, fpos; /* utf8 chars */
int mi, ma, mstart, mend; /* mem */
char fmt_prev = 0xff;
@@ -397,6 +399,10 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
/* skip hidden part of line */
if (skip) {
skip--;
+ if (use_syntax) {
+ /* currently fpos only used when formatting */
+ fpos += BLI_strnlen_utf8(str + mstart, mend - mstart);
+ }
fstart = fpos; mstart = mend;
mend = txt_utf8_forward_columns(str + mend, max, &padding) - str;
end = (wrap += max - padding);
@@ -405,7 +411,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
/* Draw the visible portion of text on the overshot line */
for (a = fstart, ma = mstart; ma < mend; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
- if (st->showsyntax && format) {
+ if (use_syntax) {
if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
}
x += text_font_draw_character_utf8(st, x, y, str + ma);
@@ -427,7 +433,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
/* Draw the remaining text */
for (a = fstart, ma = mstart; str[ma] && y > 0; a++, ma += BLI_str_utf8_size_safe(str + ma)) {
- if (st->showsyntax && format) {
+ if (use_syntax) {
if (fmt_prev != format[a]) format_draw_color(fmt_prev = format[a]);
}
@@ -441,6 +447,7 @@ static int text_draw_wrapped(SpaceText *st, const char *str, int x, int y, int w
static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x, int y, const char *format)
{
+ const bool use_syntax = (st->showsyntax && format);
FlattenString fs;
int columns, size, n, w = 0, padding, amount = 0;
const char *in = NULL;
@@ -473,7 +480,7 @@ static void text_draw(SpaceText *st, char *str, int cshift, int maxwidth, int x,
x += st->cwidth * padding;
- if (st->showsyntax && format) {
+ if (use_syntax) {
int a, str_shift = 0;
char fmt_prev = 0xff;
@@ -1460,7 +1467,7 @@ void text_scroll_to_cursor(SpaceText *st, ScrArea *sa)
ARegion *ar = NULL;
int i, x, winx = 0;
- if (ELEM3(NULL, st, st->text, st->text->curl)) return;
+ if (ELEM(NULL, st, st->text, st->text->curl)) return;
text = st->text;
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 0263b6cd912..852edaac7dc 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -458,7 +458,7 @@ static void txt_write_file(Text *text, ReportList *reports)
{
FILE *fp;
TextLine *tmp;
- struct stat st;
+ BLI_stat_t st;
char filepath[FILE_MAX];
BLI_strncpy(filepath, text->name, FILE_MAX);
@@ -473,7 +473,9 @@ static void txt_write_file(Text *text, ReportList *reports)
for (tmp = text->lines.first; tmp; tmp = tmp->next) {
fputs(tmp->line, fp);
- fputc('\n', fp);
+ if (tmp->next) {
+ fputc('\n', fp);
+ }
}
fclose(fp);
@@ -1825,11 +1827,17 @@ static int text_move_cursor(bContext *C, int type, bool select)
switch (type) {
case LINE_BEGIN:
+ if (!select) {
+ txt_sel_clear(text);
+ }
if (st && st->wordwrap && ar) txt_wrap_move_bol(st, ar, select);
else txt_move_bol(text, select);
break;
case LINE_END:
+ if (!select) {
+ txt_sel_clear(text);
+ }
if (st && st->wordwrap && ar) txt_wrap_move_eol(st, ar, select);
else txt_move_eol(text, select);
break;
diff --git a/source/blender/editors/space_time/CMakeLists.txt b/source/blender/editors/space_time/CMakeLists.txt
index b42ae3ab725..90af405eaa8 100644
--- a/source/blender/editors/space_time/CMakeLists.txt
+++ b/source/blender/editors/space_time/CMakeLists.txt
@@ -22,10 +22,12 @@ set(INC
../include
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -39,4 +41,6 @@ set(SRC
time_intern.h
)
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_space_time "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/space_time/SConscript b/source/blender/editors/space_time/SConscript
index bf1b918f4f1..5a9e9a4cb42 100644
--- a/source/blender/editors/space_time/SConscript
+++ b/source/blender/editors/space_time/SConscript
@@ -31,15 +31,17 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenkernel',
'../../blenlib',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
-defs = []
+defs = env['BF_GL_DEFINITIONS']
env.BlenderLib('bf_editors_space_time', sources, incs, defs, libtype=['core'], priority=[65])
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 2fd4b0bc21d..88c57d45b79 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -405,6 +405,7 @@ static void time_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn)
case NC_OBJECT:
{
switch (wmn->data) {
+ case ND_BONE_SELECT:
case ND_BONE_ACTIVE:
case ND_POINTCACHE:
case ND_MODIFIER:
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index 97c328dbac2..320267a4a7c 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../../render/extern/include
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
../../../../intern/smoke/extern
)
@@ -76,7 +77,7 @@ if(WITH_GAMEENGINE)
add_definitions(-DWITH_GAMEENGINE)
endif()
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
index e6658ab3c49..a21da940906 100644
--- a/source/blender/editors/space_view3d/SConscript
+++ b/source/blender/editors/space_view3d/SConscript
@@ -28,11 +28,13 @@
Import ('env')
sources = env.Glob('*.c')
-defs = [ 'GLEW_STATIC' ]
+
+defs = env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/smoke/extern',
'#/source/gameengine/BlenderRoutines',
'../include',
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 245cdadc7a2..651c9389341 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -67,6 +67,7 @@
#include "view3d_intern.h"
+#include "GPU_select.h"
/* *************** Armature Drawing - Coloring API ***************************** */
@@ -93,7 +94,7 @@ static void set_pchan_colorset(Object *ob, bPoseChannel *pchan)
short color_index = 0;
/* sanity check */
- if (ELEM4(NULL, ob, arm, pose, pchan)) {
+ if (ELEM(NULL, ob, arm, pose, pchan)) {
bcolor = NULL;
return;
}
@@ -466,10 +467,10 @@ static const unsigned int bone_octahedral_solid_tris[8][3] = {
/* aligned with bone_octahedral_solid_tris */
static const float bone_octahedral_solid_normals[8][3] = {
- { 0.70710683f, -0.70710683f, 0.00000000f},
- {-0.00000000f, -0.70710683f, -0.70710683f},
- {-0.70710683f, -0.70710683f, 0.00000000f},
- { 0.00000000f, -0.70710683f, 0.70710683f},
+ { M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
+ {-0.00000000f, -M_SQRT1_2, -M_SQRT1_2},
+ {-M_SQRT1_2, -M_SQRT1_2, 0.00000000f},
+ { 0.00000000f, -M_SQRT1_2, M_SQRT1_2},
{ 0.99388373f, 0.11043154f, -0.00000000f},
{ 0.00000000f, 0.11043154f, -0.99388373f},
{-0.99388373f, 0.11043154f, 0.00000000f},
@@ -551,7 +552,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag,
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
if (id != -1)
- glLoadName(id | BONESEL_ROOT);
+ GPU_select_load_id(id | BONESEL_ROOT);
if (dt <= OB_WIRE) {
if (armflag & ARM_EDITMODE) {
@@ -574,7 +575,7 @@ static void draw_bone_points(const short dt, int armflag, unsigned int boneflag,
/* Draw tip point */
if (id != -1)
- glLoadName(id | BONESEL_TIP);
+ GPU_select_load_id(id | BONESEL_TIP);
if (dt <= OB_WIRE) {
if (armflag & ARM_EDITMODE) {
@@ -787,7 +788,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
if (id != -1)
- glLoadName(id | BONESEL_ROOT);
+ GPU_select_load_id(id | BONESEL_ROOT);
drawcircball(GL_LINE_LOOP, headvec, head, imat);
}
@@ -799,7 +800,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
}
if (id != -1)
- glLoadName(id | BONESEL_TIP);
+ GPU_select_load_id(id | BONESEL_TIP);
drawcircball(GL_LINE_LOOP, tailvec, tail, imat);
@@ -830,7 +831,7 @@ static void draw_sphere_bone_wire(float smat[4][4], float imat[4][4],
cross_v3_v3v3(norvect, vec, imat[2]);
if (id != -1)
- glLoadName(id | BONESEL_BONE);
+ GPU_select_load_id(id | BONESEL_BONE);
glBegin(GL_LINES);
@@ -907,7 +908,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
if (id != -1)
- glLoadName(id | BONESEL_ROOT);
+ GPU_select_load_id(id | BONESEL_ROOT);
gluSphere(qobj, head, 16, 10);
}
@@ -918,7 +919,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
}
if (id != -1)
- glLoadName(id | BONESEL_TIP);
+ GPU_select_load_id(id | BONESEL_TIP);
glTranslatef(0.0f, 0.0f, length);
gluSphere(qobj, tail, 16, 10);
@@ -939,7 +940,7 @@ static void draw_sphere_bone(const short dt, int armflag, int boneflag, short co
if (length > (head + tail)) {
if (id != -1)
- glLoadName(id | BONESEL_BONE);
+ GPU_select_load_id(id | BONESEL_BONE);
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(-1.0f, -1.0f);
@@ -1009,7 +1010,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
/* Draw root point if we are not connected */
if ((boneflag & BONE_CONNECTED) == 0) {
if (G.f & G_PICKSEL) { /* no bitmap in selection mode, crashes 3d cards... */
- glLoadName(id | BONESEL_ROOT);
+ GPU_select_load_id(id | BONESEL_ROOT);
glBegin(GL_POINTS);
glVertex3f(0.0f, 0.0f, 0.0f);
glEnd();
@@ -1021,7 +1022,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
}
if (id != -1)
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
glBegin(GL_LINES);
glVertex3f(0.0f, 0.0f, 0.0f);
@@ -1031,7 +1032,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
/* tip */
if (G.f & G_PICKSEL) {
/* no bitmap in selection mode, crashes 3d cards... */
- glLoadName(id | BONESEL_TIP);
+ GPU_select_load_id(id | BONESEL_TIP);
glBegin(GL_POINTS);
glVertex3f(0.0f, 1.0f, 0.0f);
glEnd();
@@ -1043,7 +1044,7 @@ static void draw_line_bone(int armflag, int boneflag, short constflag, unsigned
/* further we send no names */
if (id != -1)
- glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */
+ GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */
if (armflag & ARM_POSEMODE)
set_pchan_glColor(PCHAN_COLOR_LINEBONE, boneflag, constflag);
@@ -1161,7 +1162,7 @@ static void draw_b_bone(const short dt, int armflag, int boneflag, short constfl
}
if (id != -1) {
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
}
/* set up solid drawing */
@@ -1266,13 +1267,13 @@ static void draw_wire_bone(const short dt, int armflag, int boneflag, short cons
/* this chunk not in object mode */
if (armflag & (ARM_EDITMODE | ARM_POSEMODE)) {
if (id != -1)
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
draw_wire_bone_segments(pchan, bbones, length, segments);
/* further we send no names */
if (id != -1)
- glLoadName(id & 0xFFFF); /* object tag, for bordersel optim */
+ GPU_select_load_id(id & 0xFFFF); /* object tag, for bordersel optim */
}
/* colors for modes */
@@ -1315,7 +1316,7 @@ static void draw_bone(const short dt, int armflag, int boneflag, short constflag
/* now draw the bone itself */
if (id != -1) {
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
}
/* wire? */
@@ -1370,7 +1371,7 @@ static void draw_custom_bone(Scene *scene, View3D *v3d, RegionView3D *rv3d, Obje
}
if (id != -1) {
- glLoadName((GLuint) id | BONESEL_BONE);
+ GPU_select_load_id((GLuint) id | BONESEL_BONE);
}
draw_object_instance(scene, v3d, rv3d, ob, dt, armflag & ARM_POSEMODE);
@@ -1812,12 +1813,12 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
index += 0x10000; /* pose bones count in higher 2 bytes only */
}
- /* very very confusing... but in object mode, solid draw, we cannot do glLoadName yet,
+ /* very very confusing... but in object mode, solid draw, we cannot do GPU_select_load_id yet,
* stick bones and/or wire custom-shapes are drawn in next loop
*/
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false)) {
+ if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && (draw_wire == false) && index != -1) {
/* object tag, for bordersel optim */
- glLoadName(index & 0xFFFF);
+ GPU_select_load_id(index & 0xFFFF);
index = -1;
}
}
@@ -1881,9 +1882,9 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
index += 0x10000; /* pose bones count in higher 2 bytes only */
}
/* stick or wire bones have not been drawn yet so don't clear object selection in this case */
- if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire) {
+ if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE) == 0 && draw_wire && index != -1) {
/* object tag, for bordersel optim */
- glLoadName(index & 0xFFFF);
+ GPU_select_load_id(index & 0xFFFF);
index = -1;
}
}
@@ -1926,7 +1927,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
*/
if ((do_dashed & 2) && ((bone->flag & BONE_CONNECTED) == 0)) {
if (arm->flag & ARM_POSEMODE) {
- glLoadName(index & 0xFFFF); /* object tag, for bordersel optim */
+ GPU_select_load_id(index & 0xFFFF); /* object tag, for bordersel optim */
UI_ThemeColor(TH_WIRE);
}
setlinestyle(3);
@@ -1946,7 +1947,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (constflag & PCHAN_HAS_TARGET) glColor3ub(200, 120, 0);
else glColor3ub(200, 200, 50); /* add theme! */
- glLoadName(index & 0xFFFF);
+ GPU_select_load_id(index & 0xFFFF);
pchan_draw_IK_root_lines(pchan, !(do_dashed & 2));
}
}
@@ -1954,7 +1955,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (bone->flag & BONE_SELECTED) {
glColor3ub(150, 200, 50); /* add theme! */
- glLoadName(index & 0xFFFF);
+ GPU_select_load_id(index & 0xFFFF);
pchan_draw_IK_root_lines(pchan, !(do_dashed & 2));
}
}
@@ -2020,7 +2021,7 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
/* draw DoFs */
if (arm->flag & ARM_POSEMODE) {
- if (((base->flag & OB_FROMDUPLI) == 0)) {
+ if (((base->flag & OB_FROMDUPLI) == 0) && ((v3d->flag & V3D_HIDE_HELPLINES) == 0)) {
draw_pose_dofs(ob);
}
}
@@ -2087,6 +2088,10 @@ static void draw_pose_bones(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
}
+
+ if (index != -1) {
+ GPU_select_load_id(-1);
+ }
}
/* in editmode, we don't store the bone matrix... */
@@ -2174,7 +2179,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* if wire over solid, set offset */
index = -1;
- glLoadName(-1);
+ GPU_select_load_id(-1);
if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
if (G.f & G_PICKSEL)
index = 0;
@@ -2223,7 +2228,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* offset to parent */
if (eBone->parent) {
UI_ThemeColor(TH_WIRE_EDIT);
- glLoadName(-1); /* -1 here is OK! */
+ GPU_select_load_id(-1); /* -1 here is OK! */
setlinestyle(3);
glBegin(GL_LINES);
@@ -2240,7 +2245,7 @@ static void draw_ebones(View3D *v3d, ARegion *ar, Object *ob, const short dt)
/* restore */
if (index != -1) {
- glLoadName(-1);
+ GPU_select_load_id(-1);
}
if (ELEM(arm->drawtype, ARM_LINE, ARM_WIRE)) {
diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c
index 03f2fa86ecb..fa9ba23e454 100644
--- a/source/blender/editors/space_view3d/drawmesh.c
+++ b/source/blender/editors/space_view3d/drawmesh.c
@@ -113,8 +113,8 @@ static BLI_bitmap *get_tface_mesh_marked_edge_info(Mesh *me)
ml = me->mloop + mp->loopstart;
for (j = 0; j < mp->totloop; j++, ml++) {
- BLI_BITMAP_SET(bitmap_edge_flags, edge_vis_index(ml->e));
- if (select_set) BLI_BITMAP_SET(bitmap_edge_flags, edge_sel_index(ml->e));
+ BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_vis_index(ml->e));
+ if (select_set) BLI_BITMAP_ENABLE(bitmap_edge_flags, edge_sel_index(ml->e));
}
}
}
@@ -129,12 +129,12 @@ static DMDrawOption draw_mesh_face_select__setHiddenOpts(void *userData, int ind
Mesh *me = data->me;
if (me->drawflag & ME_DRAWEDGES) {
- if ((me->drawflag & ME_HIDDENEDGES) || (BLI_BITMAP_GET(data->edge_flags, edge_vis_index(index))))
+ if ((me->drawflag & ME_HIDDENEDGES) || (BLI_BITMAP_TEST(data->edge_flags, edge_vis_index(index))))
return DM_DRAW_OPTION_NORMAL;
else
return DM_DRAW_OPTION_SKIP;
}
- else if (BLI_BITMAP_GET(data->edge_flags, edge_sel_index(index)))
+ else if (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index)))
return DM_DRAW_OPTION_NORMAL;
else
return DM_DRAW_OPTION_SKIP;
@@ -143,7 +143,7 @@ static DMDrawOption draw_mesh_face_select__setHiddenOpts(void *userData, int ind
static DMDrawOption draw_mesh_face_select__setSelectOpts(void *userData, int index)
{
drawMeshFaceSelect_userData *data = userData;
- return (BLI_BITMAP_GET(data->edge_flags, edge_sel_index(index))) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP;
+ return (BLI_BITMAP_TEST(data->edge_flags, edge_sel_index(index))) ? DM_DRAW_OPTION_NORMAL : DM_DRAW_OPTION_SKIP;
}
/* draws unselected */
@@ -212,12 +212,16 @@ static Material *give_current_material_or_def(Object *ob, int matnr)
static struct TextureDrawState {
Object *ob;
+ Image *stencil; /* texture painting stencil */
+ Image *canvas; /* texture painting canvas, for image mode */
bool use_game_mat;
int is_lit, is_tex;
int color_profile;
bool use_backface_culling;
unsigned char obcol[4];
-} Gtexdraw = {NULL, false, 0, 0, 0, false, {0, 0, 0, 0}};
+ bool is_texpaint;
+ bool texpaint_material; /* use material slots for texture painting */
+} Gtexdraw = {NULL, NULL, NULL, false, 0, 0, 0, false, {0, 0, 0, 0}, false, false};
static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *ma, struct TextureDrawState gtexdraw)
{
@@ -229,23 +233,31 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
static int c_lit;
static int c_has_texface;
- Object *litob = NULL; /* to get mode to turn off mipmap in painting mode */
int backculled = 1;
int alphablend = GPU_BLEND_SOLID;
int textured = 0;
int lit = 0;
int has_texface = texface != NULL;
bool need_set_tpage = false;
+ bool texpaint = ((gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) != 0);
+
+ Image *ima = NULL;
+
+ if (ma != NULL) {
+ if (ma->mode & MA_TRANSP) {
+ alphablend = GPU_BLEND_ALPHA;
+ }
+ }
if (clearcache) {
c_textured = c_lit = c_backculled = -1;
memset(&c_texface, 0, sizeof(MTFace));
c_badtex = false;
c_has_texface = -1;
+ c_ma = NULL;
}
else {
textured = gtexdraw.is_tex;
- litob = gtexdraw.ob;
}
/* convert number of lights into boolean */
@@ -260,14 +272,19 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
}
}
- if (texface) {
+ if (texface && !texpaint) {
textured = textured && (texface->tpage);
/* no material, render alpha if texture has depth=32 */
if (!ma && BKE_image_has_alpha(texface->tpage))
alphablend = GPU_BLEND_ALPHA;
}
-
+ else if (texpaint) {
+ if (gtexdraw.texpaint_material)
+ ima = ma && ma->texpaintslot ? ma->texpaintslot[ma->paint_active_slot].ima : NULL;
+ else
+ ima = gtexdraw.canvas;
+ }
else
textured = 0;
@@ -281,11 +298,51 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
/* need to re-set tpage if textured flag changed or existsment of texface changed.. */
need_set_tpage = textured != c_textured || has_texface != c_has_texface;
/* ..or if settings inside texface were changed (if texface was used) */
- need_set_tpage |= texface && memcmp(&c_texface, texface, sizeof(c_texface));
+ need_set_tpage |= (texpaint && c_ma != ma) || (texface && memcmp(&c_texface, texface, sizeof(c_texface)));
if (need_set_tpage) {
if (textured) {
- c_badtex = !GPU_set_tpage(texface, !(litob->mode & OB_MODE_TEXTURE_PAINT), alphablend);
+ if (texpaint) {
+ c_badtex = false;
+ if (GPU_verify_image(ima, NULL, 0, 1, 0, false)) {
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_TEXTURE);
+
+ glActiveTexture(GL_TEXTURE1);
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+ glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glActiveTexture(GL_TEXTURE0);
+ }
+ else {
+ glActiveTexture(GL_TEXTURE1);
+ glDisable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glActiveTexture(GL_TEXTURE0);
+
+ c_badtex = true;
+ GPU_clear_tpage(true);
+ glDisable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ }
+ }
+ else {
+ c_badtex = !GPU_set_tpage(texface, !texpaint, alphablend);
+ }
}
else {
GPU_set_tpage(NULL, 0, 0);
@@ -319,6 +376,7 @@ static bool set_draw_settings_cached(int clearcache, MTFace *texface, Material *
glDisable(GL_COLOR_MATERIAL);
}
c_lit = lit;
+ c_ma = ma;
}
return c_badtex;
@@ -329,6 +387,7 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
unsigned char obcol[4];
bool is_tex, solidtex;
Mesh *me = ob->data;
+ ImagePaintSettings *imapaint = &scene->toolsettings->imapaint;
/* XXX scene->obedit warning */
@@ -358,8 +417,52 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
else is_tex = false;
Gtexdraw.ob = ob;
+ Gtexdraw.stencil = (imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL) ? imapaint->stencil : NULL;
+ Gtexdraw.is_texpaint = (ob->mode == OB_MODE_TEXTURE_PAINT);
+ Gtexdraw.texpaint_material = (imapaint->mode == IMAGEPAINT_MODE_MATERIAL);
+ Gtexdraw.canvas = (Gtexdraw.texpaint_material) ? NULL : imapaint->canvas;
Gtexdraw.is_tex = is_tex;
+ /* naughty multitexturing hacks to quickly support stencil + shading + alpha blending
+ * in new texpaint code. The better solution here would be to support GLSL */
+ if (Gtexdraw.is_texpaint) {
+ glActiveTexture(GL_TEXTURE1);
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_REPLACE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+
+ /* load the stencil texture here */
+ if (Gtexdraw.stencil != NULL) {
+ glActiveTexture(GL_TEXTURE2);
+ if (GPU_verify_image(Gtexdraw.stencil, NULL, false, false, false, false)) {
+ float col[4] = {imapaint->stencil_col[0], imapaint->stencil_col[1], imapaint->stencil_col[2], 1.0f};
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
+ glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE);
+ glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, col);
+ if ((imapaint->flag & IMAGEPAINT_PROJECT_LAYER_STENCIL_INV) == 0) {
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_ONE_MINUS_SRC_COLOR);
+ }
+ else {
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
+ }
+ }
+ }
+ glActiveTexture(GL_TEXTURE0);
+ }
+
Gtexdraw.color_profile = BKE_scene_check_color_management_enabled(scene);
Gtexdraw.use_game_mat = (RE_engines_find(scene->r.engine)->flag & RE_GAME) != 0;
Gtexdraw.use_backface_culling = (v3d->flag2 & V3D_BACKFACE_CULLING) != 0;
@@ -373,8 +476,31 @@ static void draw_textured_begin(Scene *scene, View3D *v3d, RegionView3D *rv3d, O
static void draw_textured_end(void)
{
- /* switch off textures */
- GPU_set_tpage(NULL, 0, 0);
+ if (Gtexdraw.ob->mode & OB_MODE_TEXTURE_PAINT) {
+ glActiveTexture(GL_TEXTURE1);
+ glDisable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ if (Gtexdraw.stencil != NULL) {
+ glActiveTexture(GL_TEXTURE2);
+ glDisable(GL_TEXTURE_2D);
+ glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ glActiveTexture(GL_TEXTURE0);
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ /* manual reset, since we don't use tpage */
+ glBindTexture(GL_TEXTURE_2D, 0);
+ /* force switch off textures */
+ GPU_clear_tpage(true);
+ }
+ else {
+ /* switch off textures */
+ GPU_set_tpage(NULL, 0, 0);
+ }
glShadeModel(GL_FLAT);
glDisable(GL_CULL_FACE);
@@ -450,7 +576,7 @@ static DMDrawOption draw_tface__set_draw(MTFace *tface, const bool UNUSED(has_mc
if (ma && (ma->game.flag & GEMAT_INVISIBLE)) return 0;
- if (tface)
+ if (tface || Gtexdraw.is_texpaint)
set_draw_settings_cached(0, tface, ma, Gtexdraw);
/* always use color from mcol, as set in update_tface_color_layer */
@@ -764,7 +890,8 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
Object *ob, DerivedMesh *dm, const int draw_flags)
{
Mesh *me = ob->data;
-
+ DMDrawFlag uvflag = DM_DRAW_USE_ACTIVE_UV;
+
/* correct for negative scale */
if (ob->transflag & OB_NEG_SCALE) glFrontFace(GL_CW);
else glFrontFace(GL_CCW);
@@ -774,6 +901,10 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
+ if (ob->mode & OB_MODE_TEXTURE_PAINT) {
+ uvflag = DM_DRAW_USE_TEXPAINT_UV;
+ }
+
if (ob->mode & OB_MODE_EDIT) {
drawEMTFMapped_userData data;
@@ -783,7 +914,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
data.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
data.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
- dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data);
+ dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data, 0);
}
else if (draw_flags & DRAW_FACE_SELECT) {
if (ob->mode & OB_MODE_WEIGHT_PAINT)
@@ -795,15 +926,15 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
userData.mf = DM_get_tessface_data_layer(dm, CD_MFACE);
userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
userData.me = me;
- dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData);
+ dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, compareDrawOptions, &userData, uvflag);
}
}
else {
if (GPU_buffer_legacy(dm)) {
if (draw_flags & DRAW_MODIFIERS_PREVIEW)
- dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL);
+ dm->drawFacesTex(dm, draw_mcol__set_draw_legacy, NULL, NULL, uvflag);
else
- dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL);
+ dm->drawFacesTex(dm, draw_tface__set_draw_legacy, NULL, NULL, uvflag);
}
else {
drawTFace_userData userData;
@@ -814,7 +945,7 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d
userData.tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
userData.me = NULL;
- dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData);
+ dm->drawFacesTex(dm, draw_tface__set_draw, compareDrawOptions, &userData, uvflag);
}
}
@@ -864,7 +995,7 @@ static void tex_mat_set_texture_cb(void *userData, int mat_nr, void *attribs)
int texture_set = 0;
/* draw image texture if we find one */
- if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node)) {
+ if (ED_object_get_active_image(data->ob, mat_nr, &ima, &iuser, &node, NULL)) {
/* get openl texture */
int mipmap = 1;
int bindcode = (ima) ? GPU_verify_image(ima, iuser, 0, 0, mipmap, false) : 0;
@@ -947,7 +1078,11 @@ void draw_mesh_textured(Scene *scene, View3D *v3d, RegionView3D *rv3d,
Object *ob, DerivedMesh *dm, const int draw_flags)
{
/* if not cycles, or preview-modifiers, or drawing matcaps */
- if ((!BKE_scene_use_new_shading_nodes(scene)) || (draw_flags & DRAW_MODIFIERS_PREVIEW) || (v3d->flag2 & V3D_SHOW_SOLID_MATCAP)) {
+ if ((draw_flags & DRAW_MODIFIERS_PREVIEW) ||
+ (v3d->flag2 & V3D_SHOW_SOLID_MATCAP) ||
+ (BKE_scene_use_new_shading_nodes(scene) == false) ||
+ ((ob->mode & OB_MODE_TEXTURE_PAINT) && ELEM(v3d->drawtype, OB_TEXTURE, OB_SOLID)))
+ {
draw_mesh_textured_old(scene, v3d, rv3d, ob, dm, draw_flags);
return;
}
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 7f56b4a9822..db04d3ccd66 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -86,6 +86,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_select.h"
#include "ED_mesh.h"
#include "ED_particle.h"
@@ -109,7 +110,7 @@
*
* Ideally we don't want to evaluate objects from drawing,
* but it'll require some major sequencer re-design. So
- * for now just fallback to legacy behaior with calling
+ * for now just fallback to legacy behavior with calling
* display ist creating from draw().
*/
#define SEQUENCER_DAG_WORKAROUND
@@ -145,6 +146,24 @@ typedef struct drawDMEdgesSel_userData {
BMEdge *eed_act;
} drawDMEdgesSel_userData;
+typedef struct drawDMEdgesSelInterp_userData {
+ BMesh *bm;
+
+ unsigned char *baseCol, *selCol;
+ unsigned char *lastCol;
+} drawDMEdgesSelInterp_userData;
+
+typedef struct drawDMEdgesWeightInterp_userData {
+ BMesh *bm;
+
+ int cd_dvert_offset;
+ int defgroup_tot;
+ int vgroup_index;
+ char weight_user;
+ float alert_color[3];
+
+} drawDMEdgesWeightInterp_userData;
+
typedef struct drawDMFacesSel_userData {
#ifdef WITH_FREESTYLE
unsigned char *cols[4];
@@ -168,16 +187,26 @@ typedef struct drawDMNormal_userData {
float imat[3][3];
} drawDMNormal_userData;
-typedef struct bbsObmodeMeshVerts_userData {
- void *offset;
+typedef struct drawMVertOffset_userData {
MVert *mvert;
-} bbsObmodeMeshVerts_userData;
+ int offset;
+} drawMVertOffset_userData;
typedef struct drawDMLayer_userData {
BMesh *bm;
int cd_layer_offset;
} drawDMLayer_userData;
+typedef struct drawBMOffset_userData {
+ BMesh *bm;
+ int offset;
+} drawBMOffset_userData;
+
+typedef struct drawBMSelect_userData {
+ BMesh *bm;
+ bool select;
+} drawBMSelect_userData;
+
static void draw_bounding_volume(Object *ob, char type);
static void drawcube_size(float size);
@@ -273,7 +302,8 @@ bool draw_glsl_material(Scene *scene, Object *ob, View3D *v3d, const char dt)
if (BKE_scene_use_new_shading_nodes(scene))
return false;
- return (scene->gm.matmode == GAME_MAT_GLSL) && (dt > OB_SOLID);
+ 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)
@@ -756,8 +786,10 @@ typedef struct ViewCachedString {
short sco[2];
short xoffs;
short flag;
- int str_len, pad;
+ int str_len;
+
/* str is allocated past the end */
+ char str[0];
} ViewCachedString;
/* one arena for all 3 string lists */
@@ -782,7 +814,6 @@ void view3d_cached_text_draw_add(const float co[3],
const unsigned char col[4])
{
int alloc_len = str_len + 1;
- /* TODO, replace with more efficient malloc, perhaps memarena per draw? */
ViewCachedString *vos;
BLI_assert(str_len == strlen(str));
@@ -802,7 +833,7 @@ void view3d_cached_text_draw_add(const float co[3],
vos->str_len = str_len;
/* allocate past the end */
- memcpy(vos + 1, str, alloc_len);
+ memcpy(vos->str, str, alloc_len);
}
void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, float mat[4][4])
@@ -850,7 +881,8 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
glPushMatrix();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
- ED_region_pixelspace(ar);
+ wmOrtho2_region_ui(ar);
+ glLoadIdentity();
if (depth_write) {
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
@@ -861,8 +893,6 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
for (vos = g_v3d_strings[g_v3d_string_level]; vos; vos = vos->next) {
if (vos->sco[0] != IS_CLIPPED) {
- const char *str = (char *)(vos + 1);
-
if (col_pack_prev != vos->col.pack) {
glColor3ubv(vos->col.ub);
col_pack_prev = vos->col.pack;
@@ -871,10 +901,10 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, bool depth_write, flo
((vos->flag & V3D_CACHE_TEXT_ASCII) ?
BLF_draw_default_ascii :
BLF_draw_default
- )( (float)vos->sco[0] + vos->xoffs,
- (float)vos->sco[1],
+ )((float)(vos->sco[0] + vos->xoffs),
+ (float)(vos->sco[1]),
(depth_write) ? 0.0f : 2.0f,
- str,
+ vos->str,
vos->str_len);
}
}
@@ -1408,8 +1438,10 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base,
drawshadbuflimits(la, ob->obmat);
}
- UI_GetThemeColor4ubv(TH_LAMP, col);
- glColor4ubv(col);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ UI_GetThemeColor4ubv(TH_LAMP, col);
+ glColor4ubv(col);
+ }
glEnable(GL_BLEND);
@@ -1448,7 +1480,9 @@ static void draw_limit_line(float sta, float end, const short dflag, unsigned in
if (!(dflag & DRAW_PICKING)) {
glPointSize(3.0);
glBegin(GL_POINTS);
- cpack(col);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ cpack(col);
+ }
glVertex3f(0.0, 0.0, -sta);
glVertex3f(0.0, 0.0, -end);
glEnd();
@@ -1555,7 +1589,7 @@ static void draw_viewport_object_reconstruction(Scene *scene, Base *base, View3D
continue;
if (dflag & DRAW_PICKING)
- glLoadName(base->selcol + (tracknr << 16));
+ GPU_select_load_id(base->selcol + (tracknr << 16));
glPushMatrix();
glTranslatef(track->bundle_pos[0], track->bundle_pos[1], track->bundle_pos[2]);
@@ -1706,7 +1740,7 @@ static void draw_viewport_reconstruction(Scene *scene, Base *base, View3D *v3d,
}
if (dflag & DRAW_PICKING)
- glLoadName(base->selcol);
+ GPU_select_load_id(base->selcol);
}
/* flag similar to draw_object() */
@@ -1942,7 +1976,29 @@ static void drawlattice__point(Lattice *lt, DispList *dl, int u, int v, int w, i
#ifdef SEQUENCER_DAG_WORKAROUND
static void ensure_curve_cache(Scene *scene, Object *object)
{
- if (object->curve_cache == NULL) {
+ bool need_recalc = object->curve_cache == NULL;
+ /* Render thread might have freed the curve cache if the
+ * object is not visible. If the object is also used for
+ * particles duplication, then render thread might have
+ * also created curve_cache with only bevel and path
+ * filled in.
+ *
+ * So check for curve_cache != NULL is not fully correct
+ * here, we also need to check whether display list is
+ * empty or not.
+ *
+ * The trick below tries to optimie calls to displist
+ * creation for cases curve is empty. Meaning, if the curve
+ * is empty (without splies) 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.
+ */
+ if (need_recalc == false) {
+ need_recalc = object->curve_cache->disp.first == NULL &&
+ object->curve_cache->bev.first != NULL;
+ }
+ if (need_recalc) {
switch (object->type) {
case OB_CURVE:
case OB_SURF:
@@ -2141,21 +2197,21 @@ static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, Object *ob, Deriv
static void draw_dm_face_centers__mapFunc(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
{
- BMFace *efa = BM_face_at_index(((void **)userData)[0], index);
- const char sel = *(((char **)userData)[1]);
+ drawBMSelect_userData *data = userData;
+ BMFace *efa = BM_face_at_index(data->bm, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN) &&
- (BM_elem_flag_test(efa, BM_ELEM_SELECT) == sel))
+ (BM_elem_flag_test(efa, BM_ELEM_SELECT) == data->select))
{
bglVertex3fv(cent);
}
}
-static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, char sel)
+static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, bool select)
{
- void *ptrs[2] = {em->bm, &sel};
+ drawBMSelect_userData data = {em->bm, select};
bglBegin(GL_POINTS);
- dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs, DM_FOREACH_NOP);
+ dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &data, DM_FOREACH_NOP);
bglEnd();
}
@@ -2338,29 +2394,155 @@ static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm)
/* Draw edges with color interpolated based on selection */
static DMDrawOption draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
{
- if (BM_elem_flag_test(BM_edge_at_index(((void **)userData)[0], index), BM_ELEM_HIDDEN))
+ drawDMEdgesSelInterp_userData *data = userData;
+ if (BM_elem_flag_test(BM_edge_at_index(data->bm, index), BM_ELEM_HIDDEN))
return DM_DRAW_OPTION_SKIP;
else
return DM_DRAW_OPTION_NORMAL;
}
static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
{
- BMEdge *eed = BM_edge_at_index(((void **)userData)[0], index);
+ drawDMEdgesSelInterp_userData *data = userData;
+ BMEdge *eed = BM_edge_at_index(data->bm, index);
unsigned char **cols = userData;
- unsigned char *col0 = cols[(BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1];
- unsigned char *col1 = cols[(BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1];
+ unsigned int col0_id = (BM_elem_flag_test(eed->v1, BM_ELEM_SELECT)) ? 2 : 1;
+ unsigned int col1_id = (BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) ? 2 : 1;
+ unsigned char *col0 = cols[col0_id];
+ unsigned char *col1 = cols[col1_id];
+ unsigned char *col_pt;
+
+ if (col0_id == col1_id) {
+ col_pt = col0;
+ }
+ else if (t == 0.0f) {
+ col_pt = col0;
+ }
+ else if (t == 1.0f) {
+ col_pt = col1;
+ }
+ else {
+ unsigned char col_blend[4];
+ interp_v4_v4v4_uchar(col_blend, col0, col1, t);
+ glColor4ubv(col_blend);
+ data->lastCol = NULL;
+ return;
+ }
- glColor4ub(col0[0] + (col1[0] - col0[0]) * t,
- col0[1] + (col1[1] - col0[1]) * t,
- col0[2] + (col1[2] - col0[2]) * t,
- col0[3] + (col1[3] - col0[3]) * t);
+ if (data->lastCol != col_pt) {
+ data->lastCol = col_pt;
+ glColor4ubv(col_pt);
+ }
}
static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
{
- void *cols[3] = {em->bm, baseCol, selCol};
+ drawDMEdgesSelInterp_userData data;
+ data.bm = em->bm;
+ data.baseCol = baseCol;
+ data.selCol = selCol;
+ data.lastCol = NULL;
+
+ dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, &data);
+}
+
+static void bm_color_from_weight(float col[3], BMVert *vert, drawDMEdgesWeightInterp_userData *data)
+{
+ MDeformVert *dvert = BM_ELEM_CD_GET_VOID_P(vert, data->cd_dvert_offset);
+ float weight = defvert_find_weight(dvert, data->vgroup_index);
+
+ if ((weight == 0.0f) &&
+ ((data->weight_user == OB_DRAW_GROUPUSER_ACTIVE) ||
+ ((data->weight_user == OB_DRAW_GROUPUSER_ALL) && defvert_is_weight_zero(dvert, data->defgroup_tot))))
+ {
+ copy_v3_v3(col, data->alert_color);
+ }
+ else {
+ weight_to_rgb(col, weight);
+ }
+}
+
+static void draw_dm_edges_nop_interp__setDrawInterpOptions(void *UNUSED(userData), int UNUSED(index), float UNUSED(t))
+{
+ /* pass */
+}
+
+static void draw_dm_edges_weight_interp__setDrawInterpOptions(void *userData, int index, float t)
+{
+ drawDMEdgesWeightInterp_userData *data = userData;
+ BMEdge *eed = BM_edge_at_index(data->bm, index);
+ float col[3];
+
+ if (t == 0.0f) {
+ bm_color_from_weight(col, eed->v1, data);
+ }
+ else if (t == 1.0f) {
+ bm_color_from_weight(col, eed->v2, data);
+ }
+ else {
+ float col_v1[3];
+ float col_v2[3];
+
+ bm_color_from_weight(col_v1, eed->v1, data);
+ bm_color_from_weight(col_v2, eed->v2, data);
+ interp_v3_v3v3(col, col_v1, col_v2, t);
+ }
+
+ glColor3fv(col);
+}
+
+static void draw_dm_edges_weight_interp(BMEditMesh *em, DerivedMesh *dm, const char weight_user)
+{
+ drawDMEdgesWeightInterp_userData data;
+ Object *ob = em->ob;
+
+ data.bm = em->bm;
+ data.cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT);
+ data.defgroup_tot = BLI_countlist(&ob->defbase);
+ data.vgroup_index = ob->actdef - 1;
+ data.weight_user = weight_user;
+ UI_GetThemeColor3fv(TH_VERTEX_UNREFERENCED, data.alert_color);
+
+ if ((data.vgroup_index != -1) && (data.cd_dvert_offset != -1)) {
+ glEnable(GL_BLEND);
+ dm->drawMappedEdgesInterp(
+ dm,
+ draw_dm_edges_sel_interp__setDrawOptions,
+ draw_dm_edges_weight_interp__setDrawInterpOptions,
+ &data);
+ glDisable(GL_BLEND);
+ }
+ else {
+ float col[3];
+
+ if (data.weight_user == OB_DRAW_GROUPUSER_NONE) {
+ weight_to_rgb(col, 0.0f);
+ }
+ else {
+ copy_v3_v3(col, data.alert_color);
+ }
+ glColor3fv(col);
+
+ dm->drawMappedEdgesInterp(
+ dm,
+ draw_dm_edges_sel_interp__setDrawOptions,
+ draw_dm_edges_nop_interp__setDrawInterpOptions,
+ &data);
+ }
+
+}
+
+static bool draw_dm_edges_weight_check(Mesh *me, View3D *v3d)
+{
+ if (me->drawflag & ME_DRAWEIGHT) {
+ if ((v3d->drawtype == OB_WIRE) ||
+ (v3d->flag2 & V3D_SOLID_MATCAP) ||
+ ((v3d->flag2 & V3D_OCCLUDE_WIRE) && (v3d->drawtype > OB_WIRE)))
+ {
+ return true;
+ }
+ }
- dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
+ return false;
}
/* Draw only seam edges */
@@ -2775,9 +2957,16 @@ static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d,
draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
}
else if ((me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE)) {
- if (cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
+ if (cageDM->drawMappedEdgesInterp &&
+ ((ts->selectmode & SCE_SELECT_VERTEX) || (me->drawflag & ME_DRAWEIGHT)))
+ {
glShadeModel(GL_SMOOTH);
- draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
+ if (draw_dm_edges_weight_check(me, v3d)) {
+ draw_dm_edges_weight_interp(em, cageDM, ts->weightuser);
+ }
+ else {
+ draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
+ }
glShadeModel(GL_FLAT);
}
else {
@@ -3424,7 +3613,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d,
draw_dm_vert_normals(em, scene, ob, cageDM);
}
if (me->drawflag & ME_DRAW_LNORMALS) {
- UI_ThemeColor(TH_VNORMAL);
+ UI_ThemeColor(TH_LNORMAL);
draw_dm_loop_normals(em, scene, ob, cageDM);
}
@@ -3564,7 +3753,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (ob->sculpt->partial_redraw) {
if (ar->do_draw & RGN_DRAW_PARTIAL) {
- sculpt_get_redraw_planes(planes, ar, rv3d, ob);
+ ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
fpl = planes;
ob->sculpt->partial_redraw = 0;
}
@@ -3662,7 +3851,7 @@ static void draw_mesh_fancy(Scene *scene, ARegion *ar, View3D *v3d, RegionView3D
if (ob->sculpt->partial_redraw) {
if (ar->do_draw & RGN_DRAW_PARTIAL) {
- sculpt_get_redraw_planes(planes, ar, rv3d, ob);
+ ED_sculpt_redraw_planes_get(planes, ar, rv3d, ob);
fpl = planes;
ob->sculpt->partial_redraw = 0;
}
@@ -3812,12 +4001,14 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
else {
/* ob->bb was set by derived mesh system, do NULL check just to be sure */
if (me->totpoly <= 4 || (!ob->bb || ED_view3d_boundbox_clip(rv3d, ob->bb))) {
- const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
- const bool check_alpha = check_alpha_pass(base);
+ if (dt > OB_WIRE) {
+ const bool glsl = draw_glsl_material(scene, ob, v3d, dt);
- if (dt == OB_SOLID || glsl) {
- GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl,
- (check_alpha) ? &do_alpha_after : NULL);
+ if (dt == OB_SOLID || glsl) {
+ const bool check_alpha = check_alpha_pass(base);
+ GPU_begin_object_materials(v3d, rv3d, scene, ob, glsl,
+ (check_alpha) ? &do_alpha_after : NULL);
+ }
}
draw_mesh_fancy(scene, ar, v3d, rv3d, base, dt, ob_wire_col, dflag);
@@ -3854,11 +4045,12 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3
/* ************** DRAW DISPLIST ****************** */
-static bool draw_index_wire = true;
-static bool index3_nors_incr = true;
-/* returns 1 when nothing was drawn */
-static bool drawDispListwire(ListBase *dlbase)
+/**
+ * \param dl_type_mask Only draw types matching this mask.
+ * \return true when nothing was drawn
+ */
+static bool drawDispListwire_ex(ListBase *dlbase, unsigned int dl_type_mask)
{
DispList *dl;
int parts, nr;
@@ -3870,8 +4062,13 @@ static bool drawDispListwire(ListBase *dlbase)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
for (dl = dlbase->first; dl; dl = dl->next) {
- if (dl->parts == 0 || dl->nr == 0)
+ if (dl->parts == 0 || dl->nr == 0) {
continue;
+ }
+
+ if ((dl_type_mask & (1 << dl->type)) == 0) {
+ continue;
+ }
data = dl->verts;
@@ -3930,17 +4127,13 @@ static bool drawDispListwire(ListBase *dlbase)
break;
case DL_INDEX3:
- if (draw_index_wire) {
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
- }
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ glDrawElements(GL_TRIANGLES, 3 * dl->parts, GL_UNSIGNED_INT, dl->index);
break;
case DL_INDEX4:
- if (draw_index_wire) {
- glVertexPointer(3, GL_FLOAT, 0, dl->verts);
- glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
- }
+ glVertexPointer(3, GL_FLOAT, 0, dl->verts);
+ glDrawElements(GL_QUADS, 4 * dl->parts, GL_UNSIGNED_INT, dl->index);
break;
}
}
@@ -3951,6 +4144,20 @@ static bool drawDispListwire(ListBase *dlbase)
return false;
}
+static bool drawDispListwire(ListBase *dlbase, const short ob_type)
+{
+ unsigned int dl_mask = 0xffffffff;
+
+ /* skip fill-faces for curves & fonts */
+ if (ELEM(ob_type, OB_FONT, OB_CURVE)) {
+ dl_mask &= ~((1 << DL_INDEX3) | (1 << DL_INDEX4));
+ }
+
+ return drawDispListwire_ex(dlbase, dl_mask);
+}
+
+static bool index3_nors_incr = true;
+
static void drawDispListsolid(ListBase *lb, Object *ob, const short dflag,
const unsigned char ob_wire_col[4], const bool use_glsl)
{
@@ -4143,6 +4350,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
lb = &ob->curve_cache->disp;
if (solid) {
+ const bool has_faces = BKE_displist_has_faces(lb);
dl = lb->first;
if (dl == NULL) {
return true;
@@ -4151,13 +4359,19 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
if (dl->nors == NULL) BKE_displist_normals_add(lb);
index3_nors_incr = false;
- if (BKE_displist_has_faces(lb) == false) {
- if (!render_only) {
- draw_index_wire = false;
- drawDispListwire(lb);
- draw_index_wire = true;
+ if (!render_only) {
+ /* when we have faces, only draw loose-wire */
+ if (has_faces) {
+ drawDispListwire_ex(lb, (1 << DL_SEGM));
+ }
+ else {
+ drawDispListwire(lb, ob->type);
}
}
+
+ if (has_faces == false) {
+ /* pass */
+ }
else {
if (draw_glsl_material(scene, ob, v3d, dt)) {
GPU_begin_object_materials(v3d, rv3d, scene, ob, 1, NULL);
@@ -4171,20 +4385,14 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
}
if (cu->editnurb && cu->bevobj == NULL && cu->taperobj == NULL && cu->ext1 == 0.0f && cu->ext2 == 0.0f) {
cpack(0);
- draw_index_wire = false;
- drawDispListwire(lb);
- draw_index_wire = true;
+ drawDispListwire(lb, ob->type);
}
}
index3_nors_incr = true;
}
else {
if (!render_only || (render_only && BKE_displist_has_faces(lb))) {
- int retval;
- draw_index_wire = false;
- retval = drawDispListwire(lb);
- draw_index_wire = true;
- return retval;
+ return drawDispListwire(lb, ob->type);
}
}
break;
@@ -4212,7 +4420,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
}
}
else {
- return drawDispListwire(lb);
+ return drawDispListwire(lb, ob->type);
}
break;
case OB_MBALL:
@@ -4237,8 +4445,7 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
}
}
else {
- /* MetaBalls use DL_INDEX4 type of DispList */
- return drawDispListwire(lb);
+ return drawDispListwire(lb, ob->type);
}
}
break;
@@ -4493,7 +4700,8 @@ static void draw_particle_data(ParticleSystem *psys, RegionView3D *rv3d,
/* 6. draw the arrays */
/* 7. clean up */
static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv3d,
- Base *base, ParticleSystem *psys, int ob_dt)
+ Base *base, ParticleSystem *psys,
+ const char ob_dt, const short dflag)
{
Object *ob = base->object;
ParticleEditSettings *pset = PE_settings(scene);
@@ -4571,7 +4779,9 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
copy_v3_v3(ma_col, &ma->r);
}
- glColor3ubv(tcol);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ glColor3ubv(tcol);
+ }
timestep = psys_get_timestep(&sim);
@@ -4661,7 +4871,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
normalize_v3(imat[1]);
}
- if (ELEM3(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) &&
+ if (ELEM(draw_as, PART_DRAW_DOT, PART_DRAW_CROSS, PART_DRAW_LINE) &&
(part->draw_col > PART_DRAW_COL_MAT))
{
create_cdata = 1;
@@ -4906,8 +5116,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (1) { //ob_dt > OB_WIRE) {
glEnableClientState(GL_NORMAL_ARRAY);
- if (part->draw_col == PART_DRAW_COL_MAT)
- glEnableClientState(GL_COLOR_ARRAY);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ if (part->draw_col == PART_DRAW_COL_MAT)
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
glEnable(GL_LIGHTING);
glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
@@ -4937,8 +5149,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (1) { //ob_dt > OB_WIRE) {
glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
- if (part->draw_col == PART_DRAW_COL_MAT)
- glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ if (part->draw_col == PART_DRAW_COL_MAT) {
+ glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
+ }
+ }
}
glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
@@ -4953,8 +5168,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
if (1) { //ob_dt > OB_WIRE) {
glNormalPointer(GL_FLOAT, sizeof(ParticleCacheKey), path->vel);
- if (part->draw_col == PART_DRAW_COL_MAT)
- glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ if (part->draw_col == PART_DRAW_COL_MAT) {
+ glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
+ }
+ }
}
glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
@@ -4964,7 +5182,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
/* restore & clean up */
if (1) { //ob_dt > OB_WIRE) {
if (part->draw_col == PART_DRAW_COL_MAT)
- glDisable(GL_COLOR_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
glDisable(GL_COLOR_MATERIAL);
}
@@ -4998,21 +5216,24 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
else
glDisableClientState(GL_VERTEX_ARRAY);
- if (select) {
- UI_ThemeColor(TH_ACTIVE);
-
- if (part->draw_size)
- glPointSize(part->draw_size + 2);
- else
- glPointSize(4.0);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ if (select) {
+ UI_ThemeColor(TH_ACTIVE);
- glLineWidth(3.0);
+ if (part->draw_size)
+ glPointSize(part->draw_size + 2);
+ else
+ glPointSize(4.0);
+
+ glLineWidth(3.0);
+
+ draw_particle_arrays(draw_as, totpoint, ob_dt, 1);
+ }
- draw_particle_arrays(draw_as, totpoint, ob_dt, 1);
+ /* restore from select */
+ glColor3fv(ma_col);
}
- /* restore from select */
- glColor3fv(ma_col);
glPointSize(part->draw_size ? part->draw_size : 2.0);
glLineWidth(1.0);
@@ -5029,9 +5250,11 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
glDisable(GL_LIGHTING);
}
- if (pdd->cdata) {
- glEnableClientState(GL_COLOR_ARRAY);
- glColorPointer(3, GL_FLOAT, 0, pdd->cdata);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ if (pdd->cdata) {
+ glEnableClientState(GL_COLOR_ARRAY);
+ glColorPointer(3, GL_FLOAT, 0, pdd->cdata);
+ }
}
draw_particle_arrays(draw_as, totpoint, ob_dt, 0);
@@ -5041,8 +5264,10 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
if (pdd && pdd->vedata) {
- glDisableClientState(GL_COLOR_ARRAY);
- cpack(0xC0C0C0);
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ glDisableClientState(GL_COLOR_ARRAY);
+ cpack(0xC0C0C0);
+ }
glVertexPointer(3, GL_FLOAT, 0, pdd->vedata);
@@ -5658,7 +5883,7 @@ static void editnurb_draw_active_nurbs(Nurb *nu)
glLineWidth(1);
}
-static void draw_editnurb(Object *ob, Nurb *nurb, int sel)
+static void draw_editnurb_splines(Object *ob, Nurb *nurb, const bool sel)
{
Nurb *nu;
BPoint *bp, *bp1;
@@ -5774,8 +5999,9 @@ static void draw_editnurb(Object *ob, Nurb *nurb, int sel)
}
}
-static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb,
- const char dt, const short dflag, const unsigned char ob_wire_col[4])
+static void draw_editnurb(
+ Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base, Nurb *nurb,
+ const char dt, const short dflag, const unsigned char ob_wire_col[4])
{
ToolSettings *ts = scene->toolsettings;
Object *ob = base->object;
@@ -5793,6 +6019,11 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ /* for shadows only show solid faces */
+ if (v3d->flag2 & V3D_RENDER_SHADOW) {
+ return;
+ }
+
if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
/* first non-selected and active handles */
@@ -5805,8 +6036,8 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
}
index++;
}
- draw_editnurb(ob, nurb, 0);
- draw_editnurb(ob, nurb, 1);
+ draw_editnurb_splines(ob, nurb, false);
+ draw_editnurb_splines(ob, nurb, true);
/* selected handles */
for (nu = nurb; nu; nu = nu->next) {
if (nu->type == CU_BEZIER && (cu->drawflag & CU_HIDE_HANDLES) == 0)
@@ -5816,13 +6047,13 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
+ glColor3ubv(wire_col);
+
/* direction vectors for 3d curve paths
* when at its lowest, don't render normals */
if ((cu->flag & CU_3D) && (ts->normalsize > 0.0015f) && (cu->drawflag & CU_HIDE_NORMALS) == 0) {
-
- UI_ThemeColor(TH_WIRE_EDIT);
for (bl = ob->curve_cache->bev.first, nu = nurb; nu && bl; bl = bl->next, nu = nu->next) {
- BevPoint *bevp = (BevPoint *)(bl + 1);
+ BevPoint *bevp = bl->bevpoints;
int nr = bl->nr;
int skip = nu->resolu / 16;
@@ -5868,6 +6099,149 @@ static void drawnurb(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
}
+static void draw_editfont_textcurs(RegionView3D *rv3d, float textcurs[4][2])
+{
+ cpack(0);
+ ED_view3d_polygon_offset(rv3d, -1.0);
+ set_inverted_drawing(1);
+ glBegin(GL_QUADS);
+ glVertex2fv(textcurs[0]);
+ glVertex2fv(textcurs[1]);
+ glVertex2fv(textcurs[2]);
+ glVertex2fv(textcurs[3]);
+ glEnd();
+ set_inverted_drawing(0);
+ ED_view3d_polygon_offset(rv3d, 0.0);
+}
+
+static void draw_editfont(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
+ const char dt, const short dflag, const unsigned char ob_wire_col[4])
+{
+ Object *ob = base->object;
+ Curve *cu = ob->data;
+ EditFont *ef = cu->editfont;
+ float vec1[3], vec2[3];
+ int i, selstart, selend;
+
+ draw_editfont_textcurs(rv3d, ef->textcurs);
+
+ if (cu->flag & CU_FAST) {
+ cpack(0xFFFFFF);
+ set_inverted_drawing(1);
+ drawDispList(scene, v3d, rv3d, base, OB_WIRE, dflag, ob_wire_col);
+ set_inverted_drawing(0);
+ }
+ else {
+ drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
+ }
+
+ if (cu->linewidth != 0.0f) {
+ UI_ThemeColor(TH_WIRE_EDIT);
+ copy_v3_v3(vec1, ob->orig);
+ copy_v3_v3(vec2, ob->orig);
+ vec1[0] += cu->linewidth;
+ vec2[0] += cu->linewidth;
+ vec1[1] += cu->linedist * cu->fsize;
+ vec2[1] -= cu->lines * cu->linedist * cu->fsize;
+ setlinestyle(3);
+ glBegin(GL_LINE_STRIP);
+ glVertex2fv(vec1);
+ glVertex2fv(vec2);
+ glEnd();
+ setlinestyle(0);
+ }
+
+ setlinestyle(3);
+ for (i = 0; i < cu->totbox; i++) {
+ if (cu->tb[i].w != 0.0f) {
+ UI_ThemeColor(i == (cu->actbox - 1) ? TH_ACTIVE : TH_WIRE);
+ vec1[0] = cu->xof + cu->tb[i].x;
+ vec1[1] = cu->yof + cu->tb[i].y + cu->fsize;
+ vec1[2] = 0.001;
+ glBegin(GL_LINE_STRIP);
+ glVertex3fv(vec1);
+ vec1[0] += cu->tb[i].w;
+ glVertex3fv(vec1);
+ vec1[1] -= cu->tb[i].h;
+ glVertex3fv(vec1);
+ vec1[0] -= cu->tb[i].w;
+ glVertex3fv(vec1);
+ vec1[1] += cu->tb[i].h;
+ glVertex3fv(vec1);
+ glEnd();
+ }
+ }
+ setlinestyle(0);
+
+
+ if (BKE_vfont_select_get(ob, &selstart, &selend) && ef->selboxes) {
+ const int seltot = selend - selstart;
+ float selboxw;
+
+ cpack(0xffffff);
+ set_inverted_drawing(1);
+ for (i = 0; i <= seltot; i++) {
+ EditFontSelBox *sb = &ef->selboxes[i];
+ float tvec[3];
+
+ if (i != seltot) {
+ if (ef->selboxes[i + 1].y == sb->y)
+ selboxw = ef->selboxes[i + 1].x - sb->x;
+ else
+ selboxw = sb->w;
+ }
+ else {
+ selboxw = sb->w;
+ }
+
+ /* fill in xy below */
+ tvec[2] = 0.001;
+
+ glBegin(GL_QUADS);
+
+ if (sb->rot == 0.0f) {
+ copy_v2_fl2(tvec, sb->x, sb->y);
+ glVertex3fv(tvec);
+
+ copy_v2_fl2(tvec, sb->x + selboxw, sb->y);
+ glVertex3fv(tvec);
+
+ copy_v2_fl2(tvec, sb->x + selboxw, sb->y + sb->h);
+ glVertex3fv(tvec);
+
+ copy_v2_fl2(tvec, sb->x, sb->y + sb->h);
+ glVertex3fv(tvec);
+ }
+ else {
+ float mat[2][2];
+
+ angle_to_mat2(mat, sb->rot);
+
+ copy_v2_fl2(tvec, sb->x, sb->y);
+ glVertex3fv(tvec);
+
+ copy_v2_fl2(tvec, selboxw, 0.0f);
+ mul_m2v2(mat, tvec);
+ add_v2_v2(tvec, &sb->x);
+ glVertex3fv(tvec);
+
+ copy_v2_fl2(tvec, selboxw, sb->h);
+ mul_m2v2(mat, tvec);
+ add_v2_v2(tvec, &sb->x);
+ glVertex3fv(tvec);
+
+ copy_v2_fl2(tvec, 0.0f, sb->h);
+ mul_m2v2(mat, tvec);
+ add_v2_v2(tvec, &sb->x);
+ glVertex3fv(tvec);
+ }
+
+ glEnd();
+ }
+ set_inverted_drawing(0);
+ }
+}
+
/* draw a sphere for use as an empty drawtype */
static void draw_empty_sphere(float size)
{
@@ -5924,21 +6298,6 @@ static void draw_empty_cone(float size)
gluDeleteQuadric(qobj);
}
-static void draw_textcurs(RegionView3D *rv3d, float textcurs[4][2])
-{
- cpack(0);
- ED_view3d_polygon_offset(rv3d, -1.0);
- set_inverted_drawing(1);
- glBegin(GL_QUADS);
- glVertex2fv(textcurs[0]);
- glVertex2fv(textcurs[1]);
- glVertex2fv(textcurs[2]);
- glVertex2fv(textcurs[3]);
- glEnd();
- set_inverted_drawing(0);
- ED_view3d_polygon_offset(rv3d, 0.0);
-}
-
static void drawspiral(const float cent[3], float rad, float tmat[4][4], int start)
{
float vec[3], vx[3], vy[3];
@@ -6129,7 +6488,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
if (G.f & G_PICKSEL) {
ml->selcol1 = code;
- glLoadName(code++);
+ GPU_select_load_id(code++);
}
}
drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad, imat);
@@ -6143,7 +6502,7 @@ static bool drawmball(Scene *scene, View3D *v3d, RegionView3D *rv3d, Base *base,
if (G.f & G_PICKSEL) {
ml->selcol2 = code;
- glLoadName(code++);
+ GPU_select_load_id(code++);
}
drawcircball(GL_LINE_LOOP, &(ml->x), ml->rad * atanf(ml->s) / (float)M_PI_2, imat);
}
@@ -6349,28 +6708,6 @@ static void draw_box(float vec[8][3])
glEnd();
}
-/* uses boundbox, function used by Ketsji */
-#if 0
-static void get_local_bounds(Object *ob, float center[3], float size[3])
-{
- BoundBox *bb = BKE_object_boundbox_get(ob);
-
- if (bb == NULL) {
- zero_v3(center);
- copy_v3_v3(size, ob->size);
- }
- else {
- size[0] = 0.5 * fabsf(bb->vec[0][0] - bb->vec[4][0]);
- size[1] = 0.5 * fabsf(bb->vec[0][1] - bb->vec[2][1]);
- size[2] = 0.5 * fabsf(bb->vec[0][2] - bb->vec[1][2]);
-
- center[0] = (bb->vec[0][0] + bb->vec[4][0]) / 2.0;
- center[1] = (bb->vec[0][1] + bb->vec[2][1]) / 2.0;
- center[2] = (bb->vec[0][2] + bb->vec[1][2]) / 2.0;
- }
-}
-#endif
-
static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
{
float size[3], cent[3];
@@ -6378,17 +6715,13 @@ static void draw_bb_quadric(BoundBox *bb, char type, bool around_origin)
gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
- size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]);
- size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]);
- size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]);
+ BKE_boundbox_calc_size_aabb(bb, size);
if (around_origin) {
zero_v3(cent);
}
else {
- cent[0] = 0.5f * (bb->vec[0][0] + bb->vec[4][0]);
- cent[1] = 0.5f * (bb->vec[0][1] + bb->vec[2][1]);
- cent[2] = 0.5f * (bb->vec[0][2] + bb->vec[1][2]);
+ BKE_boundbox_calc_center_aabb(bb, cent);
}
glPushMatrix();
@@ -6432,7 +6765,7 @@ static void draw_bounding_volume(Object *ob, char type)
if (ob->type == OB_MESH) {
bb = BKE_mesh_boundbox_get(ob);
}
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
bb = BKE_curve_boundbox_get(ob);
}
else if (ob->type == OB_MBALL) {
@@ -6457,9 +6790,7 @@ static void draw_bounding_volume(Object *ob, char type)
if (type == OB_BOUND_BOX) {
float vec[8][3], size[3];
- size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]);
- size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]);
- size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]);
+ BKE_boundbox_calc_size_aabb(bb, size);
vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = -size[0];
vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = +size[0];
@@ -6489,7 +6820,7 @@ static void drawtexspace(Object *ob)
if (ob->type == OB_MESH) {
BKE_mesh_texspace_get(ob->data, loc, NULL, size);
}
- else if (ELEM3(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF, OB_FONT)) {
BKE_curve_texspace_get(ob->data, loc, NULL, size);
}
else if (ob->type == OB_MBALL) {
@@ -6527,7 +6858,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f);
glDepthMask(0);
- if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
+ if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
DerivedMesh *dm = ob->derivedFinal;
bool has_faces = false;
@@ -6545,20 +6876,19 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
}
if (has_faces && ED_view3d_boundbox_clip(rv3d, ob->bb)) {
- draw_index_wire = false;
if (dm) {
draw_mesh_object_outline(v3d, ob, dm);
}
else {
- drawDispListwire(&ob->curve_cache->disp);
+ drawDispListwire(&ob->curve_cache->disp, ob->type);
}
- draw_index_wire = true;
}
}
else if (ob->type == OB_MBALL) {
if (BKE_mball_is_basis(ob)) {
- if ((base->flag & OB_FROMDUPLI) == 0)
- drawDispListwire(&ob->curve_cache->disp);
+ if ((base->flag & OB_FROMDUPLI) == 0) {
+ drawDispListwire(&ob->curve_cache->disp, ob->type);
+ }
}
}
else if (ob->type == OB_ARMATURE) {
@@ -6572,7 +6902,7 @@ static void drawObjectSelect(Scene *scene, View3D *v3d, ARegion *ar, Base *base,
static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const unsigned char ob_wire_col[4])
{
- if (ELEM4(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) {
+ if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL)) {
if (scene->obedit == ob) {
UI_ThemeColor(TH_WIRE_EDIT);
@@ -6584,25 +6914,20 @@ static void draw_wire_extra(Scene *scene, RegionView3D *rv3d, Object *ob, const
ED_view3d_polygon_offset(rv3d, 1.0);
glDepthMask(0); /* disable write in zbuffer, selected edge wires show better */
- if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
+ if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
if (ED_view3d_boundbox_clip(rv3d, ob->bb)) {
- if (ob->type == OB_CURVE)
- draw_index_wire = false;
if (ob->derivedFinal) {
drawCurveDMWired(ob);
}
else {
- drawDispListwire(&ob->curve_cache->disp);
+ drawDispListwire(&ob->curve_cache->disp, ob->type);
}
-
- if (ob->type == OB_CURVE)
- draw_index_wire = true;
}
}
else if (ob->type == OB_MBALL) {
if (BKE_mball_is_basis(ob)) {
- drawDispListwire(&ob->curve_cache->disp);
+ drawDispListwire(&ob->curve_cache->disp, ob->type);
}
}
@@ -6780,9 +7105,7 @@ static void draw_rigidbody_shape(Object *ob)
switch (ob->rigidbody_object->shape) {
case RB_SHAPE_BOX:
- size[0] = 0.5f * fabsf(bb->vec[0][0] - bb->vec[4][0]);
- size[1] = 0.5f * fabsf(bb->vec[0][1] - bb->vec[2][1]);
- size[2] = 0.5f * fabsf(bb->vec[0][2] - bb->vec[1][2]);
+ BKE_boundbox_calc_size_aabb(bb, size);
vec[0][0] = vec[1][0] = vec[2][0] = vec[3][0] = -size[0];
vec[4][0] = vec[5][0] = vec[6][0] = vec[7][0] = +size[0];
@@ -6818,32 +7141,32 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
Object *ob = base->object;
Curve *cu;
RegionView3D *rv3d = ar->regiondata;
- float vec1[3], vec2[3];
unsigned int col = 0;
unsigned char _ob_wire_col[4]; /* dont initialize this */
const unsigned char *ob_wire_col = NULL; /* dont initialize this, use NULL crashes as a way to find invalid use */
- int i, selstart, selend, empty_object = 0;
short dtx;
char dt;
- bool zbufoff = false, is_paint = false;
+ bool zbufoff = false, is_paint = false, empty_object = false;
const bool is_obact = (ob == OBACT);
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. */
- /* only once set now, will be removed too, should become a global standard */
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-
if (ob != scene->obedit) {
- if (ob->restrictflag & OB_RESTRICT_VIEW) {
- return;
- }
- else if ((ob->restrictflag & OB_RESTRICT_RENDER) && render_override) {
+ if (ob->restrictflag & OB_RESTRICT_VIEW)
return;
+
+ if (render_override) {
+ if (ob->restrictflag & OB_RESTRICT_RENDER)
+ return;
+
+ if (!has_particles && (ob->transflag & (OB_DUPLI & ~OB_DUPLIFRAMES)))
+ return;
}
}
- if (ob->particlesystem.first) {
+ if (has_particles) {
/* XXX particles are not safe for simultaneous threaded render */
if (G.is_rendering) {
return;
@@ -6883,7 +7206,13 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
+
+ /* -------------------------------------------------------------------- */
/* no return after this point, otherwise leaks */
+
+ /* only once set now, will be removed too, should become a global standard */
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
view3d_cached_text_draw_begin();
/* draw motion paths (in view space) */
@@ -6943,7 +7272,11 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
/* matcap check - only when not painting color */
- if ((v3d->flag2 & V3D_SOLID_MATCAP) && (dt == OB_SOLID) && (is_paint == false && is_picking == false)) {
+ if ((v3d->flag2 & V3D_SOLID_MATCAP) &&
+ (dt == OB_SOLID) &&
+ (is_paint == false && is_picking == false) &&
+ ((v3d->flag2 & V3D_RENDER_SHADOW) == 0))
+ {
draw_object_matcap_check(v3d, ob);
}
@@ -6979,125 +7312,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
case OB_FONT:
cu = ob->data;
if (cu->editfont) {
- EditFont *ef = cu->editfont;
-
- draw_textcurs(rv3d, ef->textcurs);
-
- if (cu->flag & CU_FAST) {
- cpack(0xFFFFFF);
- set_inverted_drawing(1);
- drawDispList(scene, v3d, rv3d, base, OB_WIRE, dflag, ob_wire_col);
- set_inverted_drawing(0);
- }
- else {
- drawDispList(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
- }
-
- if (cu->linewidth != 0.0f) {
- UI_ThemeColor(TH_WIRE_EDIT);
- copy_v3_v3(vec1, ob->orig);
- copy_v3_v3(vec2, ob->orig);
- vec1[0] += cu->linewidth;
- vec2[0] += cu->linewidth;
- vec1[1] += cu->linedist * cu->fsize;
- vec2[1] -= cu->lines * cu->linedist * cu->fsize;
- setlinestyle(3);
- glBegin(GL_LINE_STRIP);
- glVertex2fv(vec1);
- glVertex2fv(vec2);
- glEnd();
- setlinestyle(0);
- }
-
- setlinestyle(3);
- for (i = 0; i < cu->totbox; i++) {
- if (cu->tb[i].w != 0.0f) {
- UI_ThemeColor(i == (cu->actbox - 1) ? TH_ACTIVE : TH_WIRE);
- vec1[0] = (cu->xof * cu->fsize) + cu->tb[i].x;
- vec1[1] = (cu->yof * cu->fsize) + cu->tb[i].y + cu->fsize;
- vec1[2] = 0.001;
- glBegin(GL_LINE_STRIP);
- glVertex3fv(vec1);
- vec1[0] += cu->tb[i].w;
- glVertex3fv(vec1);
- vec1[1] -= cu->tb[i].h;
- glVertex3fv(vec1);
- vec1[0] -= cu->tb[i].w;
- glVertex3fv(vec1);
- vec1[1] += cu->tb[i].h;
- glVertex3fv(vec1);
- glEnd();
- }
- }
- setlinestyle(0);
-
-
- if (BKE_vfont_select_get(ob, &selstart, &selend) && ef->selboxes) {
- const int seltot = selend - selstart;
- float selboxw;
-
- cpack(0xffffff);
- set_inverted_drawing(1);
- for (i = 0; i <= seltot; i++) {
- EditFontSelBox *sb = &ef->selboxes[i];
- float tvec[3];
-
- if (i != seltot) {
- if (ef->selboxes[i + 1].y == sb->y)
- selboxw = ef->selboxes[i + 1].x - sb->x;
- else
- selboxw = sb->w;
- }
- else {
- selboxw = sb->w;
- }
-
- /* fill in xy below */
- tvec[2] = 0.001;
-
- glBegin(GL_QUADS);
-
- if (sb->rot == 0.0f) {
- copy_v2_fl2(tvec, sb->x, sb->y);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, sb->x + selboxw, sb->y);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, sb->x + selboxw, sb->y + sb->h);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, sb->x, sb->y + sb->h);
- glVertex3fv(tvec);
- }
- else {
- float mat[2][2];
-
- angle_to_mat2(mat, sb->rot);
-
- copy_v2_fl2(tvec, sb->x, sb->y);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, selboxw, 0.0f);
- mul_m2v2(mat, tvec);
- add_v2_v2(tvec, &sb->x);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, selboxw, sb->h);
- mul_m2v2(mat, tvec);
- add_v2_v2(tvec, &sb->x);
- glVertex3fv(tvec);
-
- copy_v2_fl2(tvec, 0.0f, sb->h);
- mul_m2v2(mat, tvec);
- add_v2_v2(tvec, &sb->x);
- glVertex3fv(tvec);
- }
-
- glEnd();
- }
- set_inverted_drawing(0);
- }
+ draw_editfont(scene, v3d, rv3d, base, dt, dflag, ob_wire_col);
}
else if (dt == OB_BOUNDBOX) {
if ((render_override && v3d->drawtype >= OB_WIRE) == 0) {
@@ -7118,7 +7333,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (cu->editnurb) {
ListBase *nurbs = BKE_curve_editNurbs_get(cu);
- drawnurb(scene, v3d, rv3d, base, nurbs->first, dt, dflag, ob_wire_col);
+ draw_editnurb(scene, v3d, rv3d, base, nurbs->first, dt, dflag, ob_wire_col);
}
else if (dt == OB_BOUNDBOX) {
if ((render_override && (v3d->drawtype >= OB_WIRE)) == 0) {
@@ -7249,7 +7464,12 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
{
ParticleSystem *psys;
- if (col || (ob->flag & SELECT)) cpack(0xFFFFFF); /* for visibility, also while wpaint */
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ /* for visibility, also while wpaint */
+ if (col || (ob->flag & SELECT)) {
+ cpack(0xFFFFFF);
+ }
+ }
//glDepthMask(GL_FALSE);
glLoadMatrixf(rv3d->viewmat);
@@ -7264,7 +7484,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
draw_update_ptcache_edit(scene, ob, edit);
}
- draw_new_particle_system(scene, v3d, rv3d, base, psys, dt);
+ draw_new_particle_system(scene, v3d, rv3d, base, psys, dt, dflag);
}
invert_m4_m4(ob->imat, ob->obmat);
view3d_cached_text_draw_end(v3d, ar, 0, NULL);
@@ -7292,7 +7512,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
/* draw code for smoke */
- if ((md = modifiers_findByType(ob, eModifierType_Smoke))) {
+ if ((md = modifiers_findByType(ob, eModifierType_Smoke)) && (modifier_isEnabled(scene, md, eModifierMode_Realtime))) {
SmokeModifierData *smd = (SmokeModifierData *)md;
// draw collision objects
@@ -7638,8 +7858,6 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
}
}
- free_old_images();
-
ED_view3d_clear_mats_rv3d(rv3d);
}
@@ -7648,23 +7866,22 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const float co[3],
const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
{
- bbsObmodeMeshVerts_userData *data = userData;
+ drawMVertOffset_userData *data = userData;
MVert *mv = &data->mvert[index];
- int offset = (intptr_t) data->offset;
if (!(mv->flag & ME_HIDE)) {
- WM_framebuffer_index_set(offset + index);
+ WM_framebuffer_index_set(data->offset + index);
bglVertex3fv(co);
}
}
static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset)
{
- bbsObmodeMeshVerts_userData data;
+ drawMVertOffset_userData data;
Mesh *me = ob->data;
MVert *mvert = me->mvert;
data.mvert = mvert;
- data.offset = (void *)(intptr_t) offset;
+ data.offset = offset;
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
bglBegin(GL_POINTS);
dm->foreachMappedVert(dm, bbs_obmode_mesh_verts__mapFunc, &data, DM_FOREACH_NOP);
@@ -7675,34 +7892,31 @@ static void bbs_obmode_mesh_verts(Object *ob, DerivedMesh *dm, int offset)
static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3],
const float UNUSED(no_f[3]), const short UNUSED(no_s[3]))
{
- void **ptrs = userData;
- int offset = (intptr_t) ptrs[0];
- BMVert *eve = BM_vert_at_index(ptrs[1], index);
+ drawBMOffset_userData *data = userData;
+ BMVert *eve = BM_vert_at_index(data->bm, index);
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(offset + index);
+ WM_framebuffer_index_set(data->offset + index);
bglVertex3fv(co);
}
}
static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset)
{
- void *ptrs[2] = {(void *)(intptr_t) offset, em->bm};
-
+ drawBMOffset_userData data = {em->bm, offset};
glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE));
bglBegin(GL_POINTS);
- dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, ptrs, DM_FOREACH_NOP);
+ dm->foreachMappedVert(dm, bbs_mesh_verts__mapFunc, &data, DM_FOREACH_NOP);
bglEnd();
glPointSize(1.0);
}
static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
{
- void **ptrs = userData;
- int offset = (intptr_t) ptrs[0];
- BMEdge *eed = BM_edge_at_index(ptrs[1], index);
+ drawBMOffset_userData *data = userData;
+ BMEdge *eed = BM_edge_at_index(data->bm, index);
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- WM_framebuffer_index_set(offset + index);
+ WM_framebuffer_index_set(data->offset + index);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -7711,18 +7925,31 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index)
}
static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset)
{
- void *ptrs[2] = {(void *)(intptr_t) offset, em->bm};
- dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, ptrs);
+ drawBMOffset_userData data = {em->bm, offset};
+ dm->drawMappedEdges(dm, bbs_mesh_wire__setDrawOptions, &data);
}
-static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int index)
+/**
+ * dont set #WM_framebuffer_index_set. just use to mask other
+ */
+static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index)
{
- BMFace *efa = BM_face_at_index(((void **)userData)[0], index);
+ BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
- if (((void **)userData)[1]) {
- WM_framebuffer_index_set(index + 1);
- }
+ return DM_DRAW_OPTION_NORMAL;
+ }
+ else {
+ return DM_DRAW_OPTION_SKIP;
+ }
+}
+
+static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int index)
+{
+ BMFace *efa = BM_face_at_index(userData, index);
+
+ if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
+ WM_framebuffer_index_set(index + 1);
return DM_DRAW_OPTION_NORMAL;
}
else {
@@ -7732,7 +7959,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde
static void bbs_mesh_solid__drawCenter(void *userData, int index, const float cent[3], const float UNUSED(no[3]))
{
- BMFace *efa = BM_face_at_index(((void **)userData)[0], index);
+ BMFace *efa = BM_face_at_index(userData, index);
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
WM_framebuffer_index_set(index + 1);
@@ -7743,26 +7970,24 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce
/* two options, facecolors or black */
static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d,
- Object *ob, DerivedMesh *dm, int facecol)
+ Object *ob, DerivedMesh *dm, bool use_faceselect)
{
- void *ptrs[2] = {em->bm, NULL}; //second one being null means to draw black
cpack(0);
- if (facecol) {
- ptrs[1] = (void *)(intptr_t) 1;
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, ptrs, 0);
+ if (use_faceselect) {
+ dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, em->bm, 0);
if (check_ob_drawface_dot(scene, v3d, ob->dt)) {
glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
bglBegin(GL_POINTS);
- dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, ptrs, DM_FOREACH_NOP);
+ dm->foreachMappedFaceCenter(dm, bbs_mesh_solid__drawCenter, em->bm, DM_FOREACH_NOP);
bglEnd();
}
}
else {
- dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, ptrs, 0);
+ dm->drawMappedFaces(dm, bbs_mesh_mask__setSolidDrawOptions, GPU_enable_material, NULL, em->bm, 0);
}
}
@@ -7851,7 +8076,7 @@ void draw_object_backbufsel(Scene *scene, View3D *v3d, RegionView3D *rv3d, Objec
DM_update_materials(dm, ob);
- bbs_mesh_solid_EM(em, scene, v3d, ob, dm, ts->selectmode & SCE_SELECT_FACE);
+ bbs_mesh_solid_EM(em, scene, v3d, ob, dm, (ts->selectmode & SCE_SELECT_FACE) != 0);
if (ts->selectmode & SCE_SELECT_FACE)
bm_solidoffs = 1 + em->bm->totface;
else
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 4d958a50857..b3accb431ee 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -43,7 +43,9 @@
#include "BLI_utildefines.h"
#include "BKE_context.h"
+#include "BKE_depsgraph.h"
#include "BKE_icons.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_object.h"
#include "BKE_scene.h"
@@ -285,7 +287,7 @@ static void view3d_stop_render_preview(wmWindowManager *wm, ARegion *ar)
}
}
-void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
+void ED_view3d_shade_update(Main *bmain, Scene *scene, View3D *v3d, ScrArea *sa)
{
wmWindowManager *wm = bmain->wm.first;
@@ -297,6 +299,10 @@ void ED_view3d_shade_update(Main *bmain, View3D *v3d, ScrArea *sa)
view3d_stop_render_preview(wm, ar);
}
}
+ else if (scene->obedit != NULL && scene->obedit->type == OB_MESH) {
+ /* Tag mesh to load edit data. */
+ DAG_id_tag_update(scene->obedit->data, 0);
+ }
}
/* ******************** default callbacks for view3d space ***************** */
@@ -389,7 +395,16 @@ static SpaceLink *view3d_new(const bContext *C)
static void view3d_free(SpaceLink *sl)
{
View3D *vd = (View3D *) sl;
+ BGpic *bgpic;
+ for (bgpic = vd->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->source == V3D_BGPIC_IMAGE) {
+ id_us_min((ID *)bgpic->ima);
+ }
+ else if (bgpic->source == V3D_BGPIC_MOVIE) {
+ id_us_min((ID *)bgpic->clip);
+ }
+ }
BLI_freelistN(&vd->bgpicbase);
if (vd->localvd) MEM_freeN(vd->localvd);
@@ -416,11 +431,10 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
{
View3D *v3do = (View3D *)sl;
View3D *v3dn = MEM_dupallocN(sl);
+ BGpic *bgpic;
/* clear or remove stuff from old */
-
-// XXX BIF_view3d_previewrender_free(v3do);
-
+
if (v3dn->localvd) {
v3dn->localvd = NULL;
v3dn->properties_storage = NULL;
@@ -433,8 +447,16 @@ static SpaceLink *view3d_duplicate(SpaceLink *sl)
/* copy or clear inside new stuff */
v3dn->defmaterial = NULL;
-
+
BLI_duplicatelist(&v3dn->bgpicbase, &v3do->bgpicbase);
+ for (bgpic = v3dn->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ if (bgpic->source == V3D_BGPIC_IMAGE) {
+ id_us_plus((ID *)bgpic->ima);
+ }
+ else if (bgpic->source == V3D_BGPIC_MOVIE) {
+ id_us_plus((ID *)bgpic->clip);
+ }
+ }
v3dn->properties_storage = NULL;
@@ -464,6 +486,12 @@ static void view3d_main_area_init(wmWindowManager *wm, ARegion *ar)
keymap = WM_keymap_find(wm->defaultconf, "Object Mode", 0, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
+ keymap = WM_keymap_find(wm->defaultconf, "Paint Curve", 0, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
+
+ keymap = WM_keymap_find(wm->defaultconf, "Curve", 0, 0);
+ WM_event_add_keymap_handler(&ar->handlers, keymap);
+
keymap = WM_keymap_find(wm->defaultconf, "Image Paint", 0, 0);
WM_event_add_keymap_handler(&ar->handlers, keymap);
@@ -593,8 +621,11 @@ static int view3d_ima_empty_drop_poll(bContext *C, wmDrag *drag, const wmEvent *
Base *base = ED_view3d_give_base_under_cursor(C, event->mval);
/* either holding and ctrl and no object, or dropping to empty */
- if ((event->ctrl && !base) || (base && base->object->type == OB_EMPTY))
+ if (((base == NULL) && event->ctrl) ||
+ ((base != NULL) && base->object->type == OB_EMPTY))
+ {
return view3d_ima_drop_poll(C, drag, event);
+ }
return 0;
}
@@ -651,7 +682,7 @@ static void view3d_dropboxes(void)
WM_dropbox_add(lb, "MESH_OT_drop_named_image", view3d_ima_mesh_drop_poll, view3d_id_path_drop_copy);
WM_dropbox_add(lb, "OBJECT_OT_drop_named_image", view3d_ima_empty_drop_poll, view3d_id_path_drop_copy);
WM_dropbox_add(lb, "VIEW3D_OT_background_image_add", view3d_ima_bg_drop_poll, view3d_id_path_drop_copy);
- WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy);
+ WM_dropbox_add(lb, "OBJECT_OT_group_instance_add", view3d_group_drop_poll, view3d_group_drop_copy);
}
@@ -665,10 +696,6 @@ static void view3d_main_area_free(ARegion *ar)
if (rv3d->localvd) MEM_freeN(rv3d->localvd);
if (rv3d->clipbb) MEM_freeN(rv3d->clipbb);
- if (rv3d->ri) {
- // XXX BIF_view3d_previewrender_free(rv3d);
- }
-
if (rv3d->render_engine)
RE_engine_free(rv3d->render_engine);
@@ -702,7 +729,6 @@ static void *view3d_main_area_duplicate(void *poin)
new->depths = NULL;
new->gpuoffscreen = NULL;
- new->ri = NULL;
new->render_engine = NULL;
new->sms = NULL;
new->smooth_timer = NULL;
@@ -757,7 +783,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
break;
case ND_NLA:
case ND_KEYFRAME:
- if (wmn->action == NA_EDITED)
+ if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
ED_region_tag_redraw(ar);
break;
case ND_ANIMCHAN:
@@ -838,14 +864,18 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
switch (wmn->data) {
case ND_SHADING:
case ND_NODES:
+ {
+ Object *ob = OBACT;
if ((v3d->drawtype == OB_MATERIAL) ||
+ (ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) ||
(v3d->drawtype == OB_TEXTURE &&
- (scene->gm.matmode == GAME_MAT_GLSL ||
- BKE_scene_use_new_shading_nodes(scene))))
+ (scene->gm.matmode == GAME_MAT_GLSL ||
+ BKE_scene_use_new_shading_nodes(scene))))
{
ED_region_tag_redraw(ar);
}
break;
+ }
case ND_SHADING_DRAW:
case ND_SHADING_LINKS:
ED_region_tag_redraw(ar);
@@ -883,7 +913,7 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
ED_region_tag_redraw(ar);
break;
case NC_MOVIECLIP:
- if (wmn->data == ND_DISPLAY)
+ if (wmn->data == ND_DISPLAY || wmn->action == NA_EDITED)
ED_region_tag_redraw(ar);
break;
case NC_SPACE:
@@ -968,6 +998,7 @@ static void view3d_header_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
case ND_LAYER:
case ND_TOOLSETTINGS:
case ND_LAYER_CONTENT:
+ case ND_RENDER_OPTIONS:
ED_region_tag_redraw(ar);
break;
}
@@ -1007,7 +1038,7 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
break;
case ND_NLA:
case ND_KEYFRAME:
- if (wmn->action == NA_EDITED)
+ if (ELEM(wmn->action, NA_EDITED, NA_ADDED, NA_REMOVED))
ED_region_tag_redraw(ar);
break;
}
@@ -1076,6 +1107,11 @@ static void view3d_buttons_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
if (wmn->data == ND_DATA || wmn->action == NA_EDITED)
ED_region_tag_redraw(ar);
break;
+ case NC_IMAGE:
+ /* Update for the image layers in texture paint. */
+ if (wmn->action == NA_EDITED)
+ 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 dfbae90655c..6a43357179e 100644
--- a/source/blender/editors/space_view3d/view3d_buttons.c
+++ b/source/blender/editors/space_view3d/view3d_buttons.c
@@ -82,7 +82,7 @@
#define B_REDR 2
#define B_OBJECTPANELMEDIAN 1008
-#define NBR_TRANSFORM_PROPERTIES 7
+#define NBR_TRANSFORM_PROPERTIES 8
/* temporary struct for storing transform properties */
typedef struct {
@@ -124,38 +124,84 @@ static float compute_scale_factor(const float ve_median, const float median)
}
}
+/* Apply helpers.
+ * Note: In case we only have one element, copy directly the value instead of applying the diff or scale factor.
+ * Avoids some glitches when going e.g. from 3 to 0.0001 (see T37327).
+ */
+static void apply_raw_diff(float *val, const int tot, const float ve_median, const float median)
+{
+ *val = (tot == 1) ? ve_median : (*val + median);
+}
+
+static void apply_raw_diff_v3(float val[3], const int tot, const float ve_median[3], const float median[3])
+{
+ if (tot == 1) {
+ copy_v3_v3(val, ve_median);
+ }
+ else {
+ add_v3_v3(val, median);
+ }
+}
+
+static void apply_scale_factor(float *val, const int tot, const float ve_median, const float median, const float sca)
+{
+ if (tot == 1 || ve_median == median) {
+ *val = ve_median;
+ }
+ else {
+ *val *= sca;
+ }
+}
+
+static void apply_scale_factor_clamp(float *val, const int tot, const float ve_median, const float sca)
+{
+ if (tot == 1) {
+ *val = ve_median;
+ CLAMP(*val, 0.0f, 1.0f);
+ }
+ else if (ELEM(sca, 0.0f, 1.0f)) {
+ *val = sca;
+ }
+ else {
+ *val = (sca > 0.0f) ? (*val * sca) : (1.0f + ((1.0f - *val) * sca));
+ CLAMP(*val, 0.0f, 1.0f);
+ }
+}
+
/* is used for both read and write... */
static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float lim)
{
/* Get rid of those ugly magic numbers, even in a single func they become confusing! */
/* Location, common to all. */
-/* XXX Those two *must* remain contiguous (used as array)! */
-#define LOC_X 0
-#define LOC_Y 1
-#define LOC_Z 2
+/* Next three *must* remain contiguous (used as array)! */
+#define LOC_X 0
+#define LOC_Y 1
+#define LOC_Z 2
/* Meshes... */
-#define M_CREASE 3
-#define M_WEIGHT 4
-/* XXX Those two *must* remain contiguous (used as array)! */
-#define M_SKIN_X 5
-#define M_SKIN_Y 6
+#define M_BV_WEIGHT 3
+/* Next two *must* remain contiguous (used as array)! */
+#define M_SKIN_X 4
+#define M_SKIN_Y 5
+#define M_BE_WEIGHT 6
+#define M_CREASE 7
/* Curves... */
-#define C_BWEIGHT 3
-#define C_WEIGHT 4
-#define C_RADIUS 5
-#define C_TILT 6
+#define C_BWEIGHT 3
+#define C_WEIGHT 4
+#define C_RADIUS 5
+#define C_TILT 6
/*Lattice... */
-#define L_WEIGHT 4
+#define L_WEIGHT 4
uiBlock *block = (layout) ? uiLayoutAbsoluteBlock(layout) : NULL;
TransformProperties *tfp;
float median[NBR_TRANSFORM_PROPERTIES], ve_median[NBR_TRANSFORM_PROPERTIES];
- int tot, totedgedata, totcurvedata, totlattdata, totskinradius, totcurvebweight;
+ int tot, totedgedata, totcurvedata, totlattdata, totcurvebweight;
bool has_meshdata = false;
+ bool has_skinradius = false;
PointerRNA data_ptr;
fill_vn_fl(median, NBR_TRANSFORM_PROPERTIES, 0.0f);
- tot = totedgedata = totcurvedata = totlattdata = totskinradius = totcurvebweight = 0;
+ tot = totedgedata = totcurvedata = totlattdata = totcurvebweight = 0;
/* make sure we got storage */
if (v3d->properties_storage == NULL)
@@ -170,37 +216,37 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
BMEdge *eed;
BMIter iter;
- const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ has_skinradius = (cd_vert_skin_offset != -1);
+
if (bm->totvertsel) {
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
tot++;
add_v3_v3(&median[LOC_X], eve->co);
- /* TODO cd_vert_bweight_offset */
- (void)cd_vert_bweight_offset;
+ if (cd_vert_bweight_offset != -1) {
+ median[M_BV_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset);
+ }
- if (cd_vert_skin_offset != -1) {
+ if (has_skinradius) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
add_v2_v2(&median[M_SKIN_X], vs->radius); /* Third val not used currently. */
- totskinradius++;
}
}
}
}
- if ((cd_edge_bweight_offset != -1) ||
- (cd_edge_crease_offset != -1))
- {
+ if ((cd_edge_bweight_offset != -1) || (cd_edge_crease_offset != -1)) {
if (bm->totedgesel) {
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
if (cd_edge_bweight_offset != -1) {
- median[M_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_bweight_offset);
+ median[M_BE_WEIGHT] += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_bweight_offset);
}
if (cd_edge_crease_offset != -1) {
@@ -216,7 +262,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
totedgedata = bm->totedgesel;
}
- has_meshdata = (totedgedata || totskinradius);
+ has_meshdata = (tot || totedgedata);
}
else if (ob->type == OB_CURVE || ob->type == OB_SURF) {
Curve *cu = ob->data;
@@ -326,22 +372,27 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (has_meshdata) {
if (totedgedata) {
median[M_CREASE] /= (float)totedgedata;
- median[M_WEIGHT] /= (float)totedgedata;
+ median[M_BE_WEIGHT] /= (float)totedgedata;
}
- if (totskinradius) {
- median[M_SKIN_X] /= (float)totskinradius;
- median[M_SKIN_Y] /= (float)totskinradius;
+ if (tot) {
+ median[M_BV_WEIGHT] /= (float)tot;
+ if (has_skinradius) {
+ median[M_SKIN_X] /= (float)tot;
+ median[M_SKIN_Y] /= (float)tot;
+ }
}
}
else if (totcurvedata) {
+ if (totcurvebweight) {
+ median[C_BWEIGHT] /= (float)totcurvebweight;
+ }
median[C_WEIGHT] /= (float)totcurvedata;
median[C_RADIUS] /= (float)totcurvedata;
median[C_TILT] /= (float)totcurvedata;
- if (totcurvebweight)
- median[C_BWEIGHT] /= (float)totcurvebweight;
}
- else if (totlattdata)
+ else if (totlattdata) {
median[L_WEIGHT] /= (float)totlattdata;
+ }
if (block) { /* buttons */
uiBut *but;
@@ -393,27 +444,40 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
/* Meshes... */
if (has_meshdata) {
- if (totedgedata) {
+ if (tot) {
+ uiDefBut(block, LABEL, 0, tot == 1 ? IFACE_("Vertex Data:") : IFACE_("Vertices Data:"),
+ 0, yi -= buth + but_margin, 200, buth, NULL, 0.0, 0.0, 0, 0, "");
/* customdata layer added on demand */
uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
- totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"),
+ tot == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by SubSurf modifier"));
- /* customdata layer added on demand */
- uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
- totedgedata == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
- 0, yi -= buth + but_margin, 200, buth,
- &(tfp->ve_median[M_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Weight used by Bevel modifier"));
+ &(tfp->ve_median[M_BV_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Vertex weight used by Bevel modifier"));
}
- if (totskinradius) {
+ if (has_skinradius) {
+ uiBlockBeginAlign(block);
uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
- totskinradius == 1 ? IFACE_("Radius X:") : IFACE_("Mean Radius X:"),
+ tot == 1 ? IFACE_("Radius X:") : IFACE_("Mean Radius X:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[M_SKIN_X]), 0.0, 100.0, 1, 3, TIP_("X radius used by Skin modifier"));
uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
- totskinradius == 1 ? IFACE_("Radius Y:") : IFACE_("Mean Radius Y:"),
+ tot == 1 ? IFACE_("Radius Y:") : IFACE_("Mean Radius Y:"),
0, yi -= buth + but_margin, 200, buth,
&(tfp->ve_median[M_SKIN_Y]), 0.0, 100.0, 1, 3, TIP_("Y radius used by Skin modifier"));
+ uiBlockEndAlign(block);
+ }
+ if (totedgedata) {
+ uiDefBut(block, LABEL, 0, totedgedata == 1 ? IFACE_("Edge Data:") : IFACE_("Edges Data:"),
+ 0, yi -= buth + but_margin, 200, buth, NULL, 0.0, 0.0, 0, 0, "");
+ /* customdata layer added on demand */
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
+ totedgedata == 1 ? IFACE_("Bevel Weight:") : IFACE_("Mean Bevel Weight:"),
+ 0, yi -= buth + but_margin, 200, buth,
+ &(tfp->ve_median[M_BE_WEIGHT]), 0.0, 1.0, 1, 2, TIP_("Edge weight used by Bevel modifier"));
+ /* customdata layer added on demand */
+ uiDefButF(block, NUM, B_OBJECTPANELMEDIAN,
+ totedgedata == 1 ? IFACE_("Crease:") : IFACE_("Mean Crease:"),
+ 0, yi -= buth + but_margin, 200, buth,
+ &(tfp->ve_median[M_CREASE]), 0.0, 1.0, 1, 2, TIP_("Weight used by SubSurf modifier"));
}
}
/* Curve... */
@@ -450,11 +514,10 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
}
uiBlockEndAlign(block);
- uiBlockEndAlign(block);
-
}
else { /* apply */
int i;
+ bool apply_vcos;
memcpy(ve_median, tfp->ve_median, sizeof(tfp->ve_median));
@@ -467,155 +530,130 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
while (i--)
median[i] = ve_median[i] - median[i];
- if (ob->type == OB_MESH) {
+ /* Note with a single element selected, we always do. */
+ apply_vcos = (tot == 1) || (len_squared_v3(&median[LOC_X]) != 0.0f);
+
+ if ((ob->type == OB_MESH) &&
+ (apply_vcos || median[M_BV_WEIGHT] || median[M_SKIN_X] || median[M_SKIN_Y] ||
+ median[M_BE_WEIGHT] || median[M_CREASE]))
+ {
Mesh *me = ob->data;
BMEditMesh *em = me->edit_btmesh;
BMesh *bm = em->bm;
BMIter iter;
+ BMVert *eve;
+ BMEdge *eed;
- if (tot == 1 || len_v3(&median[LOC_X]) != 0.0f) {
- BMVert *eve;
+ int cd_vert_bweight_offset = -1;
+ int cd_vert_skin_offset = -1;
+ int cd_edge_bweight_offset = -1;
+ int cd_edge_crease_offset = -1;
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- if (tot == 1) {
- /* In case we only have one element selected, copy directly the value instead of applying
- * the diff. Avoids some glitches when going e.g. from 3 to 0.0001 (see [#37327]).
- */
- copy_v3_v3(eve->co, &ve_median[LOC_X]);
- }
- else {
- add_v3_v3(eve->co, &median[LOC_X]);
- }
- }
- }
+ float scale_bv_weight = 1.0f;
+ float scale_skin_x = 1.0f;
+ float scale_skin_y = 1.0f;
+ float scale_be_weight = 1.0f;
+ float scale_crease = 1.0f;
- EDBM_mesh_normals_update(em);
- }
+ /* Vertices */
- if (median[M_CREASE] != 0.0f) {
- const int cd_edge_crease_offset = (BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE),
- CustomData_get_offset(&bm->edata, CD_CREASE));
- const float sca = compute_scale_factor(ve_median[M_CREASE], median[M_CREASE]);
- BMEdge *eed;
+ if (apply_vcos || median[M_BV_WEIGHT] || median[M_SKIN_X] || median[M_SKIN_Y]) {
+ if (median[M_BV_WEIGHT]) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT);
+ cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT);
+ BLI_assert(cd_vert_bweight_offset != -1);
- if (ELEM(sca, 0.0f, 1.0f)) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- BM_ELEM_CD_SET_FLOAT(eed, cd_edge_crease_offset, sca);
- }
- }
- }
- else if (sca > 0.0f) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
- *crease *= sca;
- CLAMP(*crease, 0.0f, 1.0f);
- }
- }
+ scale_bv_weight = compute_scale_factor(ve_median[M_BV_WEIGHT], median[M_BV_WEIGHT]);
}
- else {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
- *crease = 1.0f + ((1.0f - *crease) * sca);
- CLAMP(*crease, 0.0f, 1.0f);
- }
- }
- }
- }
- if (median[M_WEIGHT] != 0.0f) {
- const int cd_edge_bweight_offset = (BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT),
- CustomData_get_offset(&bm->edata, CD_BWEIGHT));
- const float sca = compute_scale_factor(ve_median[M_WEIGHT], median[M_WEIGHT]);
- BMEdge *eed;
+ if (median[M_SKIN_X]) {
+ cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
+ BLI_assert(cd_vert_skin_offset != -1);
- BLI_assert(cd_edge_bweight_offset != -1);
-
- if (ELEM(sca, 0.0f, 1.0f)) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
- *bweight = sca;
- }
+ if (ve_median[M_SKIN_X] != median[M_SKIN_X]) {
+ scale_skin_x = ve_median[M_SKIN_X] / (ve_median[M_SKIN_X] - median[M_SKIN_X]);
}
}
- else if (sca > 0.0f) {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
- *bweight *= sca;
- CLAMP(*bweight, 0.0f, 1.0f);
- }
+ if (median[M_SKIN_Y]) {
+ if (cd_vert_skin_offset == -1) {
+ cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
+ BLI_assert(cd_vert_skin_offset != -1);
}
- }
- else {
- BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT) && !BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
- float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
- *bweight = 1.0f + ((1.0f - *bweight) * sca);
- CLAMP(*bweight, 0.0f, 1.0f);
- }
+
+ if (ve_median[M_SKIN_Y] != median[M_SKIN_Y]) {
+ scale_skin_y = ve_median[M_SKIN_Y] / (ve_median[M_SKIN_Y] - median[M_SKIN_Y]);
}
}
- }
-
- if (median[M_SKIN_X] != 0.0f) {
- const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
- /* That one is not clamped to [0.0, 1.0]. */
- float sca = ve_median[M_SKIN_X];
- BMVert *eve;
- BLI_assert(cd_vert_skin_offset != -1);
+ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+ if (apply_vcos) {
+ apply_raw_diff_v3(eve->co, tot, &ve_median[LOC_X], &median[LOC_X]);
+ }
- if (ve_median[M_SKIN_X] - median[M_SKIN_X] == 0.0f) {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
- vs->radius[0] = sca;
+ if (cd_vert_bweight_offset != -1) {
+ float *bweight = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset);
+ apply_scale_factor_clamp(bweight, tot, ve_median[M_BV_WEIGHT], scale_bv_weight);
}
- }
- }
- else {
- sca /= (ve_median[M_SKIN_X] - median[M_SKIN_X]);
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
+
+ if (cd_vert_skin_offset != -1) {
MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
- vs->radius[0] *= sca;
+
+ /* That one is not clamped to [0.0, 1.0]. */
+ if (median[M_SKIN_X] != 0.0f) {
+ apply_scale_factor(&vs->radius[0], tot, ve_median[M_SKIN_X], median[M_SKIN_X],
+ scale_skin_x);
+ }
+ if (median[M_SKIN_Y] != 0.0f) {
+ apply_scale_factor(&vs->radius[1], tot, ve_median[M_SKIN_Y], median[M_SKIN_Y],
+ scale_skin_y);
+ }
}
}
}
}
- if (median[M_SKIN_Y] != 0.0f) {
- const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN);
- /* That one is not clamped to [0.0, 1.0]. */
- float sca = ve_median[M_SKIN_Y];
- BMVert *eve;
- BLI_assert(cd_vert_skin_offset != -1);
+ if (apply_vcos) {
+ EDBM_mesh_normals_update(em);
+ }
+
+ /* Edges */
- if (ve_median[M_SKIN_Y] - median[M_SKIN_Y] == 0.0f) {
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
- vs->radius[1] = sca;
- }
- }
+ if (median[M_BE_WEIGHT] || median[M_CREASE]) {
+ if (median[M_BE_WEIGHT]) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT);
+ cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT);
+ BLI_assert(cd_edge_bweight_offset != -1);
+
+ scale_be_weight = compute_scale_factor(ve_median[M_BE_WEIGHT], median[M_BE_WEIGHT]);
}
- else {
- sca /= (ve_median[M_SKIN_Y] - median[M_SKIN_Y]);
- BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset);
- vs->radius[1] *= sca;
+
+ if (median[M_CREASE]) {
+ BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE);
+ cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE);
+ BLI_assert(cd_edge_crease_offset != -1);
+
+ scale_crease = compute_scale_factor(ve_median[M_CREASE], median[M_CREASE]);
+ }
+
+ BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
+ if (median[M_BE_WEIGHT] != 0.0f) {
+ float *bweight = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_bweight_offset);
+ apply_scale_factor_clamp(bweight, tot, ve_median[M_BE_WEIGHT], scale_be_weight);
+ }
+
+ if (median[M_CREASE] != 0.0f) {
+ float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset);
+ apply_scale_factor_clamp(crease, tot, ve_median[M_CREASE], scale_crease);
}
}
}
}
}
- else if (ELEM(ob->type, OB_CURVE, OB_SURF)) {
+ else if (ELEM(ob->type, OB_CURVE, OB_SURF) &&
+ (apply_vcos || median[C_BWEIGHT] || median[C_WEIGHT] || median[C_RADIUS] || median[C_TILT]))
+ {
Curve *cu = ob->data;
Nurb *nu;
BPoint *bp;
@@ -629,44 +667,31 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
if (nu->type == CU_BEZIER) {
for (a = nu->pntsu, bezt = nu->bezt; a--; bezt++) {
if (bezt->f2 & SELECT) {
- /* Here we always have to use the diff... :/
- * Cannot avoid some glitches when going e.g. from 3 to 0.0001 (see [#37327]),
- * unless we use doubles.
- */
- add_v3_v3(bezt->vec[0], &median[LOC_X]);
- add_v3_v3(bezt->vec[1], &median[LOC_X]);
- add_v3_v3(bezt->vec[2], &median[LOC_X]);
-
- if (median[C_WEIGHT] != 0.0f) {
- if (ELEM(scale_w, 0.0f, 1.0f)) {
- bezt->weight = scale_w;
- }
- else {
- bezt->weight = scale_w > 0.0f ? bezt->weight * scale_w :
- 1.0f + ((1.0f - bezt->weight) * scale_w);
- CLAMP(bezt->weight, 0.0f, 1.0f);
- }
+ if (apply_vcos) {
+ /* Here we always have to use the diff... :/
+ * Cannot avoid some glitches when going e.g. from 3 to 0.0001 (see T37327),
+ * unless we use doubles.
+ */
+ add_v3_v3(bezt->vec[0], &median[LOC_X]);
+ add_v3_v3(bezt->vec[1], &median[LOC_X]);
+ add_v3_v3(bezt->vec[2], &median[LOC_X]);
+ }
+ if (median[C_WEIGHT]) {
+ apply_scale_factor_clamp(&bezt->weight, tot, ve_median[C_WEIGHT], scale_w);
+ }
+ if (median[C_RADIUS]) {
+ apply_raw_diff(&bezt->radius, tot, ve_median[C_RADIUS], median[C_RADIUS]);
+ }
+ if (median[C_TILT]) {
+ apply_raw_diff(&bezt->alfa, tot, ve_median[C_TILT], median[C_TILT]);
}
-
- bezt->radius += median[C_RADIUS];
- bezt->alfa += median[C_TILT];
}
- else {
+ else if (apply_vcos) { /* Handles can only have their coordinates changed here. */
if (bezt->f1 & SELECT) {
- if (tot == 1) {
- copy_v3_v3(bezt->vec[0], &ve_median[LOC_X]);
- }
- else {
- add_v3_v3(bezt->vec[0], &median[LOC_X]);
- }
+ apply_raw_diff_v3(bezt->vec[0], tot, &ve_median[LOC_X], &median[LOC_X]);
}
if (bezt->f3 & SELECT) {
- if (tot == 1) {
- copy_v3_v3(bezt->vec[2], &ve_median[LOC_X]);
- }
- else {
- add_v3_v3(bezt->vec[2], &median[LOC_X]);
- }
+ apply_raw_diff_v3(bezt->vec[2], tot, &ve_median[LOC_X], &median[LOC_X]);
}
}
}
@@ -674,28 +699,20 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
else {
for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a--; bp++) {
if (bp->f1 & SELECT) {
- if (tot == 1) {
- copy_v3_v3(bp->vec, &ve_median[LOC_X]);
- bp->vec[3] = ve_median[C_BWEIGHT];
- bp->radius = ve_median[C_RADIUS];
- bp->alfa = ve_median[C_TILT];
+ if (apply_vcos) {
+ apply_raw_diff_v3(bp->vec, tot, &ve_median[LOC_X], &median[LOC_X]);
}
- else {
- add_v3_v3(bp->vec, &median[LOC_X]);
- bp->vec[3] += median[C_BWEIGHT];
- bp->radius += median[C_RADIUS];
- bp->alfa += median[C_TILT];
+ if (median[C_BWEIGHT]) {
+ apply_raw_diff(&bp->vec[3], tot, ve_median[C_BWEIGHT], median[C_BWEIGHT]);
}
-
- if (median[C_WEIGHT] != 0.0f) {
- if (ELEM(scale_w, 0.0f, 1.0f)) {
- bp->weight = scale_w;
- }
- else {
- bp->weight = scale_w > 0.0f ? bp->weight * scale_w :
- 1.0f + ((1.0f - bp->weight) * scale_w);
- CLAMP(bp->weight, 0.0f, 1.0f);
- }
+ if (median[C_WEIGHT]) {
+ apply_scale_factor_clamp(&bp->weight, tot, ve_median[C_WEIGHT], scale_w);
+ }
+ if (median[C_RADIUS]) {
+ apply_raw_diff(&bp->radius, tot, ve_median[C_RADIUS], median[C_RADIUS]);
+ }
+ if (median[C_TILT]) {
+ apply_raw_diff(&bp->alfa, tot, ve_median[C_TILT], median[C_TILT]);
}
}
}
@@ -706,7 +723,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
nu = nu->next;
}
}
- else if (ob->type == OB_LATTICE) {
+ else if ((ob->type == OB_LATTICE) && (apply_vcos || median[L_WEIGHT])) {
Lattice *lt = ob->data;
BPoint *bp;
int a;
@@ -716,22 +733,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
bp = lt->editlatt->latt->def;
while (a--) {
if (bp->f1 & SELECT) {
- if (tot == 1) {
- copy_v3_v3(bp->vec, &ve_median[LOC_X]);
- }
- else {
- add_v3_v3(bp->vec, &median[LOC_X]);
+ if (apply_vcos) {
+ apply_raw_diff_v3(bp->vec, tot, &ve_median[LOC_X], &median[LOC_X]);
}
-
- if (median[L_WEIGHT] != 0.0f) {
- if (ELEM(scale_w, 0.0f, 1.0f)) {
- bp->weight = scale_w;
- }
- else {
- bp->weight = scale_w > 0.0f ? bp->weight * scale_w :
- 1.0f + ((1.0f - bp->weight) * scale_w);
- CLAMP(bp->weight, 0.0f, 1.0f);
- }
+ if (median[L_WEIGHT]) {
+ apply_scale_factor_clamp(&bp->weight, tot, ve_median[L_WEIGHT], scale_w);
}
}
bp++;
@@ -747,10 +753,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float
#undef LOC_Y
#undef LOC_Z
/* Meshes (and lattice)... */
-#undef M_CREASE
-#undef M_WEIGHT
+#undef M_BV_WEIGHT
#undef M_SKIN_X
#undef M_SKIN_Y
+#undef M_BE_WEIGHT
+#undef M_CREASE
/* Curves... */
#undef C_BWEIGHT
#undef C_WEIGHT
@@ -1182,8 +1189,8 @@ void view3d_buttons_register(ARegionType *art)
strcpy(pt->idname, "VIEW3D_PT_gpencil");
strcpy(pt->label, N_("Grease Pencil")); /* XXX C panels are not available through RNA (bpy.types)! */
strcpy(pt->translation_context, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
- pt->draw_header = gpencil_panel_standard_header;
- pt->draw = gpencil_panel_standard;
+ pt->draw_header = ED_gpencil_panel_standard_header;
+ pt->draw = ED_gpencil_panel_standard;
BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup");
diff --git a/source/blender/editors/space_view3d/view3d_camera_control.c b/source/blender/editors/space_view3d/view3d_camera_control.c
index 230df49f386..ee0f3da18b4 100644
--- a/source/blender/editors/space_view3d/view3d_camera_control.c
+++ b/source/blender/editors/space_view3d/view3d_camera_control.c
@@ -31,9 +31,9 @@
*
* Typical view-control usage:
*
- * - aquire a view-control (#ED_view3d_control_aquire).
+ * - acquire a view-control (#ED_view3d_control_acquire).
* - modify ``rv3d->ofs``, ``rv3d->viewquat``.
- * - update the view data (#ED_view3d_control_aquire) - within a loop which draws the viewport.
+ * - update the view data (#ED_view3d_control_acquire) - within a loop which draws the viewport.
* - finish and release the view-control (#ED_view3d_control_release),
* either keeping the current view or restoring the initial view.
*
@@ -138,7 +138,7 @@ Object *ED_view3d_cameracontrol_object_get(View3DCameraControl *vctrl)
* Creates a #View3DControl handle and sets up
* the view for first-person style navigation.
*/
-struct View3DCameraControl *ED_view3d_cameracontrol_aquire(
+struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
Scene *scene, View3D *v3d, RegionView3D *rv3d,
const bool use_parent_root)
{
@@ -272,28 +272,8 @@ void ED_view3d_cameracontrol_update(
}
/* record the motion */
- if (use_autokey && autokeyframe_cfra_can_key(scene, id_key)) {
- ListBase dsources = {NULL, NULL};
-
- /* add data-source override for the camera object */
- ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
-
- /* insert keyframes
- * 1) on the first frame
- * 2) on each subsequent frame
- * TODO: need to check in future that frame changed before doing this
- */
- if (do_rotate) {
- struct KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
- }
- if (do_translate) {
- struct KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
- ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
- }
-
- /* free temp data */
- BLI_freelistN(&dsources);
+ if (use_autokey) {
+ ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
}
}
@@ -302,7 +282,7 @@ void ED_view3d_cameracontrol_update(
* Release view control.
*
* \param restore Sets the view state to the values that were set
- * before #ED_view3d_control_aquire was called.
+ * before #ED_view3d_control_acquire was called.
*/
void ED_view3d_cameracontrol_release(
View3DCameraControl *vctrl,
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 9ce6bf58a0a..61bfb0176ef 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -37,6 +37,7 @@
#include "DNA_customdata_types.h"
#include "DNA_object_types.h"
#include "DNA_group_types.h"
+#include "DNA_mesh_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
#include "DNA_scene_types.h"
@@ -880,7 +881,7 @@ static void draw_selected_name(Scene *scene, Object *ob, rcti *rect)
}
}
}
- else if (ELEM3(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
+ else if (ELEM(ob->type, OB_MESH, OB_LATTICE, OB_CURVE)) {
Key *key = NULL;
KeyBlock *kb = NULL;
@@ -1090,6 +1091,9 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
/* passepartout, specified in camera edit buttons */
if (ca && (ca->flag & CAM_SHOWPASSEPARTOUT) && ca->passepartalpha > 0.000001f) {
+ const float winx = (ar->winx + 1);
+ const float winy = (ar->winy + 1);
+
if (ca->passepartalpha == 1.0f) {
glColor3f(0, 0, 0);
}
@@ -1099,11 +1103,11 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
glColor4f(0, 0, 0, ca->passepartalpha);
}
if (x1i > 0.0f)
- glRectf(0.0, (float)ar->winy, x1i, 0.0);
- if (x2i < (float)ar->winx)
- glRectf(x2i, (float)ar->winy, (float)ar->winx, 0.0);
- if (y2i < (float)ar->winy)
- glRectf(x1i, (float)ar->winy, x2i, y2i);
+ glRectf(0.0, winy, x1i, 0.0);
+ if (x2i < winx)
+ glRectf(x2i, winy, winx, 0.0);
+ if (y2i < winy)
+ glRectf(x1i, winy, x2i, y2i);
if (y2i > 0.0f)
glRectf(x1i, y1i, x2i, 0.0);
@@ -1286,6 +1290,12 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
{
/* do nothing */
}
+ /* texture paint mode sampling */
+ else if (base && (base->object->mode & OB_MODE_TEXTURE_PAINT) &&
+ (v3d->drawtype > OB_WIRE))
+ {
+ /* do nothing */
+ }
else if ((base && (base->object->mode & OB_MODE_PARTICLE_EDIT)) &&
v3d->drawtype > OB_WIRE && (v3d->flag & V3D_ZBUF_SELECT))
{
@@ -1578,6 +1588,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
int fg_flag = do_foreground ? V3D_BGPIC_FOREGROUND : 0;
for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) {
+ bgpic->iuser.scene = scene; /* Needed for render results. */
if ((bgpic->flag & V3D_BGPIC_FOREGROUND) != fg_flag)
continue;
@@ -1591,9 +1602,10 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
float x1, y1, x2, y2;
ImBuf *ibuf = NULL, *freeibuf, *releaseibuf;
+ void *lock;
- Image *ima;
- MovieClip *clip;
+ Image *ima = NULL;
+ MovieClip *clip = NULL;
/* disable individual images */
if ((bgpic->flag & V3D_BGPIC_DISABLED))
@@ -1610,16 +1622,14 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
ibuf = NULL; /* frame is out of range, dont show */
}
else {
- ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, NULL);
+ ibuf = BKE_image_acquire_ibuf(ima, &bgpic->iuser, &lock);
releaseibuf = ibuf;
}
image_aspect[0] = ima->aspx;
- image_aspect[1] = ima->aspx;
+ image_aspect[1] = ima->aspy;
}
else if (bgpic->source == V3D_BGPIC_MOVIE) {
- clip = NULL;
-
/* TODO: skip drawing when out of frame range (as image sequences do above) */
if (bgpic->flag & V3D_BGPIC_CAMERACLIP) {
@@ -1657,7 +1667,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if (freeibuf)
IMB_freeImBuf(freeibuf);
if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, NULL);
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
continue;
}
@@ -1756,7 +1766,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if (freeibuf)
IMB_freeImBuf(freeibuf);
if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, NULL);
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
continue;
}
@@ -1823,7 +1833,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if (freeibuf)
IMB_freeImBuf(freeibuf);
if (releaseibuf)
- BKE_image_release_ibuf(ima, releaseibuf, NULL);
+ BKE_image_release_ibuf(ima, releaseibuf, lock);
}
}
}
@@ -1961,7 +1971,9 @@ static DupliObject *dupli_step(DupliObject *dob)
return dob;
}
-static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Base *base, int color)
+static void draw_dupli_objects_color(
+ Scene *scene, ARegion *ar, View3D *v3d, Base *base,
+ const short dflag, const int color)
{
RegionView3D *rv3d = ar->regiondata;
ListBase *lb;
@@ -1970,18 +1982,30 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas
Base tbase = {NULL};
BoundBox bb, *bb_tmp; /* use a copy because draw_object, calls clear_mesh_caches */
GLuint displist = 0;
- short transflag, use_displist = -1; /* -1 is initialize */
+ unsigned char color_rgb[3];
+ const short dflag_dupli = dflag | DRAW_CONSTCOLOR;
+ short transflag;
+ bool use_displist = false; /* -1 is initialize */
char dt;
+ bool testbb = false;
short dtx;
DupliApplyData *apply_data;
if (base->object->restrictflag & OB_RESTRICT_VIEW) return;
-
+ if ((base->object->restrictflag & OB_RESTRICT_RENDER) && (v3d->flag2 & V3D_RENDER_OVERRIDE)) return;
+
+ if (dflag & DRAW_CONSTCOLOR) {
+ BLI_assert(color == TH_UNDEFINED);
+ }
+ else {
+ UI_GetThemeColorBlend3ubv(color, TH_BACK, 0.5f, color_rgb);
+ }
+
tbase.flag = OB_FROMDUPLI | base->flag;
lb = object_duplilist(G.main->eval_ctx, scene, base->object);
// BLI_sortlist(lb, dupli_ob_sort); /* might be nice to have if we have a dupli list with mixed objects. */
- apply_data = duplilist_apply_matrix(lb);
+ apply_data = duplilist_apply(base->object, lb);
dob = dupli_step(lb->first);
if (dob) dob_next = dupli_step(dob->next);
@@ -2018,68 +2042,77 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas
tbase.object->transflag |= OB_NEG_SCALE;
else
tbase.object->transflag &= ~OB_NEG_SCALE;
-
- UI_ThemeColorBlend(color, TH_BACK, 0.5);
-
+
+ /* should move outside the loop but possible color is set in draw_object still */
+ if ((dflag & DRAW_CONSTCOLOR) == 0) {
+ glColor3ubv(color_rgb);
+ }
+
/* generate displist, test for new object */
if (dob_prev && dob_prev->ob != dob->ob) {
if (use_displist == true)
glDeleteLists(displist, 1);
-
- use_displist = -1;
+
+ use_displist = false;
+ }
+
+ if ((bb_tmp = BKE_object_boundbox_get(dob->ob))) {
+ bb = *bb_tmp; /* must make a copy */
+ testbb = true;
}
- /* generate displist */
- if (use_displist == -1) {
-
- /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP)
- * however this is very slow, it was probably needed for the NLA
- * offset feature (used in group-duplicate.blend but no longer works in 2.5)
- * so for now it should be ok to - campbell */
-
- if ( /* if this is the last no need to make a displist */
- (dob_next == NULL || dob_next->ob != dob->ob) ||
- /* lamp drawing messes with matrices, could be handled smarter... but this works */
- (dob->ob->type == OB_LAMP) ||
- (dob->type == OB_DUPLIGROUP && dob->animated) ||
- !(bb_tmp = BKE_object_boundbox_get(dob->ob)) ||
- draw_glsl_material(scene, dob->ob, v3d, dt) ||
- check_object_draw_texture(scene, v3d, dt) ||
- (base->object == OBACT && v3d->flag2 & V3D_SOLID_MATCAP))
- {
- // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2);
- use_displist = false;
- }
- else {
- // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2);
- bb = *bb_tmp; /* must make a copy */
-
- /* disable boundbox check for list creation */
- BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1);
- /* need this for next part of code */
- unit_m4(dob->ob->obmat); /* obmat gets restored */
-
- displist = glGenLists(1);
- glNewList(displist, GL_COMPILE);
- draw_object(scene, ar, v3d, &tbase, DRAW_CONSTCOLOR);
- glEndList();
-
- use_displist = true;
- BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0);
+ if (!testbb || ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) {
+ /* generate displist */
+ if (use_displist == false) {
+
+ /* note, since this was added, its checked (dob->type == OB_DUPLIGROUP)
+ * however this is very slow, it was probably needed for the NLA
+ * offset feature (used in group-duplicate.blend but no longer works in 2.5)
+ * so for now it should be ok to - campbell */
+
+ if ( /* if this is the last no need to make a displist */
+ (dob_next == NULL || dob_next->ob != dob->ob) ||
+ /* lamp drawing messes with matrices, could be handled smarter... but this works */
+ (dob->ob->type == OB_LAMP) ||
+ (dob->type == OB_DUPLIGROUP && dob->animated) ||
+ !bb_tmp ||
+ draw_glsl_material(scene, dob->ob, v3d, dt) ||
+ check_object_draw_texture(scene, v3d, dt) ||
+ (v3d->flag2 & V3D_SOLID_MATCAP) != 0)
+ {
+ // printf("draw_dupli_objects_color: skipping displist for %s\n", dob->ob->id.name + 2);
+ use_displist = false;
+ }
+ else {
+ // printf("draw_dupli_objects_color: using displist for %s\n", dob->ob->id.name + 2);
+
+ /* disable boundbox check for list creation */
+ BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 1);
+ /* need this for next part of code */
+ unit_m4(dob->ob->obmat); /* obmat gets restored */
+
+ displist = glGenLists(1);
+ glNewList(displist, GL_COMPILE);
+ draw_object(scene, ar, v3d, &tbase, dflag_dupli);
+ glEndList();
+
+ use_displist = true;
+ BKE_object_boundbox_flag(dob->ob, BOUNDBOX_DISABLED, 0);
+ }
}
- }
- if (use_displist) {
- if (ED_view3d_boundbox_clip_ex(rv3d, &bb, dob->mat)) {
+
+ if (use_displist) {
+ glPushMatrix();
glMultMatrixf(dob->mat);
glCallList(displist);
- glLoadMatrixf(rv3d->viewmat);
+ glPopMatrix();
+ }
+ else {
+ copy_m4_m4(dob->ob->obmat, dob->mat);
+ draw_object(scene, ar, v3d, &tbase, dflag_dupli);
}
}
- else {
- copy_m4_m4(dob->ob->obmat, dob->mat);
- draw_object(scene, ar, v3d, &tbase, DRAW_CONSTCOLOR);
- }
-
+
tbase.object->dt = dt;
tbase.object->dtx = dtx;
tbase.object->transflag = transflag;
@@ -2087,7 +2120,7 @@ static void draw_dupli_objects_color(Scene *scene, ARegion *ar, View3D *v3d, Bas
}
if (apply_data) {
- duplilist_restore_matrix(lb, apply_data);
+ duplilist_restore(lb, apply_data);
duplilist_free_apply_data(apply_data);
}
@@ -2107,7 +2140,7 @@ static void draw_dupli_objects(Scene *scene, ARegion *ar, View3D *v3d, Base *bas
if (base->object->dup_group && base->object->dup_group->id.us < 1)
color = TH_REDALERT;
- draw_dupli_objects_color(scene, ar, v3d, base, color);
+ draw_dupli_objects_color(scene, ar, v3d, base, 0, color);
}
/* XXX warning, not using gpu offscreen here */
@@ -2221,7 +2254,7 @@ float view3d_depth_near(ViewDepths *d)
return far == far_real ? FLT_MAX : far;
}
-void draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
+void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
{
short zbuf = v3d->zbuf;
RegionView3D *rv3d = ar->regiondata;
@@ -2241,14 +2274,14 @@ void draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d)
glEnable(GL_DEPTH_TEST);
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
- draw_gpencil_view3d(scene, v3d, ar, true);
+ ED_gpencil_draw_view3d(scene, v3d, ar, true);
}
v3d->zbuf = zbuf;
}
-void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (*func)(void *), bool alphaoverride)
+void ED_view3d_draw_depth(Scene *scene, ARegion *ar, View3D *v3d, bool alphaoverride)
{
RegionView3D *rv3d = ar->regiondata;
Base *base;
@@ -2256,6 +2289,8 @@ void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (*func)(void *), boo
short flag = v3d->flag;
float glalphaclip = U.glalphaclip;
int obcenter_dia = U.obcenter_dia;
+ /* no need for color when drawing depth buffer */
+ const short dflag_depth = DRAW_CONSTCOLOR;
/* temp set drawtype to solid */
/* Setting these temporarily is not nice */
@@ -2287,11 +2322,9 @@ void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (*func)(void *), boo
Scene *sce_iter;
for (SETLOOPER(scene->set, sce_iter, base)) {
if (v3d->lay & base->lay) {
- if (func == NULL || func(base)) {
- draw_object(scene, ar, v3d, base, 0);
- if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects_color(scene, ar, v3d, base, TH_WIRE);
- }
+ draw_object(scene, ar, v3d, base, 0);
+ if (base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED);
}
}
}
@@ -2299,13 +2332,11 @@ void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (*func)(void *), boo
for (base = scene->base.first; base; base = base->next) {
if (v3d->lay & base->lay) {
- if (func == NULL || func(base)) {
- /* dupli drawing */
- if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects(scene, ar, v3d, base);
- }
- draw_object(scene, ar, v3d, base, 0);
+ /* dupli drawing */
+ if (base->object->transflag & OB_DUPLI) {
+ draw_dupli_objects_color(scene, ar, v3d, base, dflag_depth, TH_UNDEFINED);
}
+ draw_object(scene, ar, v3d, base, dflag_depth);
}
}
@@ -2327,7 +2358,7 @@ void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (*func)(void *), boo
glDepthFunc(GL_ALWAYS); /* always write into the depth bufer, overwriting front z values */
for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) {
next = v3da->next;
- draw_object(scene, ar, v3d, v3da->base, 0);
+ draw_object(scene, ar, v3d, v3da->base, dflag_depth);
}
glDepthFunc(GL_LEQUAL); /* Now write the depth buffer normally */
}
@@ -2337,7 +2368,7 @@ void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (*func)(void *), boo
v3d->transp = true;
for (v3da = v3d->afterdraw_transp.first; v3da; v3da = next) {
next = v3da->next;
- draw_object(scene, ar, v3d, v3da->base, 0);
+ draw_object(scene, ar, v3d, v3da->base, dflag_depth);
BLI_remlink(&v3d->afterdraw_transp, v3da);
MEM_freeN(v3da);
}
@@ -2346,7 +2377,7 @@ void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (*func)(void *), boo
v3d->transp = false;
for (v3da = v3d->afterdraw_xray.first; v3da; v3da = next) {
next = v3da->next;
- draw_object(scene, ar, v3d, v3da->base, 0);
+ draw_object(scene, ar, v3d, v3da->base, dflag_depth);
BLI_remlink(&v3d->afterdraw_xray, v3da);
MEM_freeN(v3da);
}
@@ -2355,7 +2386,7 @@ void draw_depth(Scene *scene, ARegion *ar, View3D *v3d, int (*func)(void *), boo
v3d->transp = true;
for (v3da = v3d->afterdraw_xraytransp.first; v3da; v3da = next) {
next = v3da->next;
- draw_object(scene, ar, v3d, v3da->base, 0);
+ draw_object(scene, ar, v3d, v3da->base, dflag_depth);
BLI_remlink(&v3d->afterdraw_xraytransp, v3da);
MEM_freeN(v3da);
}
@@ -2416,7 +2447,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
Scene *sce_iter;
Base *base;
Object *ob;
- SceneRenderLayer *srl = BLI_findlink(&scene->r.layers, scene->r.actlay);
+ SceneRenderLayer *srl = v3d->scenelock ? BLI_findlink(&scene->r.layers, scene->r.actlay) : NULL;
BLI_listbase_clear(&shadows);
@@ -2453,7 +2484,7 @@ static void gpu_update_lamps_shadows(Scene *scene, View3D *v3d)
v3d->drawtype = OB_SOLID;
v3d->lay &= GPU_lamp_shadow_layer(shadow->lamp);
- v3d->flag2 &= ~V3D_SOLID_TEX;
+ v3d->flag2 &= ~(V3D_SOLID_TEX | V3D_SHOW_SOLID_MATCAP);
v3d->flag2 |= V3D_RENDER_OVERRIDE | V3D_RENDER_SHADOW;
GPU_lamp_shadow_buffer_bind(shadow->lamp, viewmat, &winsize, winmat);
@@ -2495,8 +2526,11 @@ CustomDataMask ED_view3d_datamask(Scene *scene, View3D *v3d)
mask |= CD_MASK_ORCO;
}
else {
- if (scene->gm.matmode == GAME_MAT_GLSL)
+ if ((scene->gm.matmode == GAME_MAT_GLSL && v3d->drawtype == OB_TEXTURE) ||
+ (v3d->drawtype == OB_MATERIAL))
+ {
mask |= CD_MASK_ORCO;
+ }
}
}
@@ -2591,12 +2625,25 @@ static void view3d_draw_objects(
/* set zbuffer after we draw clipping region */
if (v3d->drawtype > OB_WIRE) {
v3d->zbuf = true;
- glEnable(GL_DEPTH_TEST);
}
else {
v3d->zbuf = false;
}
+ /* special case (depth for wire color) */
+ if (v3d->drawtype <= OB_WIRE) {
+ if (scene->obedit && scene->obedit->type == OB_MESH) {
+ Mesh *me = scene->obedit->data;
+ if (me->drawflag & ME_DRAWEIGHT) {
+ v3d->zbuf = true;
+ }
+ }
+ }
+
+ if (v3d->zbuf) {
+ glEnable(GL_DEPTH_TEST);
+ }
+
if (!draw_offscreen) {
/* needs to be done always, gridview is adjusted in drawgrid() now, but only for ortho views. */
rv3d->gridview = v3d->grid;
@@ -2633,14 +2680,15 @@ static void view3d_draw_objects(
/* draw set first */
if (scene->set) {
+ const short dflag = DRAW_CONSTCOLOR | DRAW_SCENESET;
Scene *sce_iter;
for (SETLOOPER(scene->set, sce_iter, base)) {
if (v3d->lay & base->lay) {
UI_ThemeColorBlend(TH_WIRE, TH_BACK, 0.6f);
- draw_object(scene, ar, v3d, base, DRAW_CONSTCOLOR | DRAW_SCENESET);
+ draw_object(scene, ar, v3d, base, dflag);
if (base->object->transflag & OB_DUPLI) {
- draw_dupli_objects_color(scene, ar, v3d, base, TH_WIRE);
+ draw_dupli_objects_color(scene, ar, v3d, base, dflag, TH_UNDEFINED);
}
}
}
@@ -2697,7 +2745,7 @@ static void view3d_draw_objects(
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
/* must be before xray draw which clears the depth buffer */
if (v3d->zbuf) glDisable(GL_DEPTH_TEST);
- draw_gpencil_view3d(scene, v3d, ar, true);
+ ED_gpencil_draw_view3d(scene, v3d, ar, true);
if (v3d->zbuf) glEnable(GL_DEPTH_TEST);
}
@@ -2727,6 +2775,10 @@ static void view3d_draw_objects(
v3d->zbuf = false;
glDisable(GL_DEPTH_TEST);
}
+
+ if ((v3d->flag2 & V3D_RENDER_SHADOW) == 0) {
+ GPU_free_images_old();
+ }
}
static void view3d_main_area_setup_view(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
@@ -2813,7 +2865,7 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx,
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
/* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
- draw_gpencil_view3d(scene, v3d, ar, false);
+ ED_gpencil_draw_view3d(scene, v3d, ar, false);
}
/* freeing the images again here could be done after the operator runs, leaving for now */
@@ -2954,10 +3006,11 @@ ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, Object *camera, int w
}
-/* NOTE: the info that this uses is updated in ED_refresh_viewport_fps(),
- * which currently gets called during SCREEN_OT_animation_step.
+/**
+ * \note The info that this uses is updated in #ED_refresh_viewport_fps,
+ * which currently gets called during #SCREEN_OT_animation_step.
*/
-void ED_scene_draw_fps(Scene *scene, rcti *rect)
+void ED_scene_draw_fps(Scene *scene, const rcti *rect)
{
ScreenFrameRateInfo *fpsi = scene->fps_info;
float fps;
@@ -3106,7 +3159,7 @@ static bool view3d_main_area_draw_engine(const bContext *C, Scene *scene,
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (v3d->flag & V3D_DISPBGPICS)
- view3d_draw_bgpic(scene, ar, v3d, false, true);
+ view3d_draw_bgpic_test(scene, ar, v3d, false, true);
else
fdrawcheckerboard(0, 0, ar->winx, ar->winy);
@@ -3115,7 +3168,7 @@ static bool view3d_main_area_draw_engine(const bContext *C, Scene *scene,
type->view_draw(rv3d->render_engine, C);
if (v3d->flag & V3D_DISPBGPICS)
- view3d_draw_bgpic(scene, ar, v3d, true, true);
+ view3d_draw_bgpic_test(scene, ar, v3d, true, true);
if (clip_border) {
/* restore scissor as it was before */
@@ -3428,7 +3481,7 @@ static void view3d_main_area_draw_info(const bContext *C, Scene *scene,
if (v3d->flag2 & V3D_SHOW_GPENCIL) {
/* draw grease-pencil stuff - needed to get paint-buffer shown too (since it's 2D) */
- draw_gpencil_view3d(scene, v3d, ar, false);
+ ED_gpencil_draw_view3d(scene, v3d, ar, false);
}
if ((v3d->flag2 & V3D_RENDER_OVERRIDE) == 0) {
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 6099ef49149..d3bd59cacc8 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -71,12 +71,14 @@
#include "ED_armature.h"
#include "ED_particle.h"
+#include "ED_keyframing.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_mesh.h"
#include "ED_view3d.h"
#include "ED_sculpt.h"
+#include "UI_resources.h"
#include "PIL_time.h" /* smoothview */
@@ -183,6 +185,72 @@ bool ED_view3d_camera_lock_sync(View3D *v3d, RegionView3D *rv3d)
}
}
+bool ED_view3d_camera_autokey(
+ Scene *scene, ID *id_key,
+ struct bContext *C, const bool do_rotate, const bool do_translate)
+{
+ if (autokeyframe_cfra_can_key(scene, id_key)) {
+ ListBase dsources = {NULL, NULL};
+
+ /* add data-source override for the camera object */
+ ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL);
+
+ /* insert keyframes
+ * 1) on the first frame
+ * 2) on each subsequent frame
+ * TODO: need to check in future that frame changed before doing this
+ */
+ if (do_rotate) {
+ struct KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_ROTATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ }
+ if (do_translate) {
+ struct KeyingSet *ks = ANIM_builtin_keyingset_get_named(NULL, ANIM_KS_LOCATION_ID);
+ ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
+ }
+
+ /* free temp data */
+ BLI_freelistN(&dsources);
+
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/**
+ * Call after modifying a locked view.
+ *
+ * \note Not every view edit currently auto-keys (numpad for eg),
+ * this is complicated because of smoothview.
+ */
+bool ED_view3d_camera_lock_autokey(
+ View3D *v3d, RegionView3D *rv3d,
+ struct bContext *C, const bool do_rotate, const bool do_translate)
+{
+ /* similar to ED_view3d_cameracontrol_update */
+ if (ED_view3d_camera_lock_check(v3d, rv3d)) {
+ Scene *scene = CTX_data_scene(C);
+ ID *id_key;
+ Object *root_parent;
+ if ((U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0 && (root_parent = v3d->camera->parent)) {
+ while (root_parent->parent) {
+ root_parent = root_parent->parent;
+ }
+ id_key = &root_parent->id;
+ }
+ else {
+ id_key = &v3d->camera->id;
+ }
+
+ return ED_view3d_camera_autokey(scene, id_key, C, do_rotate, do_translate);
+ }
+ else {
+ return false;
+ }
+}
+
/**
* For viewport operators that exit camera persp.
*
@@ -240,12 +308,12 @@ static void view3d_boxview_clip(ScrArea *sa)
}
for (val = 0; val < 8; val++) {
- if (ELEM4(val, 0, 3, 4, 7))
+ if (ELEM(val, 0, 3, 4, 7))
bb->vec[val][0] = -x1 - ofs[0];
else
bb->vec[val][0] = x1 - ofs[0];
- if (ELEM4(val, 0, 1, 4, 5))
+ if (ELEM(val, 0, 1, 4, 5))
bb->vec[val][1] = -y1 - ofs[1];
else
bb->vec[val][1] = y1 - ofs[1];
@@ -398,11 +466,13 @@ void ED_view3d_quadview_update(ScrArea *sa, ARegion *ar, bool do_clip)
* properties are always being edited, weak */
viewlock = rv3d->viewlock;
- if ((viewlock & RV3D_LOCKED) == 0)
+ if ((viewlock & RV3D_LOCKED) == 0) {
+ do_clip = (viewlock & RV3D_BOXCLIP) != 0;
viewlock = 0;
- else if ((viewlock & RV3D_BOXVIEW) == 0) {
- viewlock &= ~RV3D_BOXCLIP;
+ }
+ else if ((viewlock & RV3D_BOXVIEW) == 0 && (viewlock & RV3D_BOXCLIP) != 0) {
do_clip = true;
+ viewlock &= ~RV3D_BOXCLIP;
}
for (; ar; ar = ar->prev) {
@@ -558,7 +628,7 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
*/
if (ob->mode & OB_MODE_SCULPT) {
float stroke[3];
- ED_sculpt_get_average_stroke(ob, stroke);
+ ED_sculpt_stroke_get_average(ob, stroke);
copy_v3_v3(lastofs, stroke);
}
else {
@@ -581,6 +651,39 @@ static bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
is_set = true;
}
+ else if (ob == NULL || ob->mode == OB_MODE_OBJECT) {
+ /* object mode use boundbox centers */
+ View3D *v3d = CTX_wm_view3d(C);
+ Base *base;
+ unsigned int tot = 0;
+ float select_center[3];
+
+ zero_v3(select_center);
+ for (base = FIRSTBASE; base; base = base->next) {
+ if (TESTBASE(v3d, base)) {
+ /* use the boundbox if we can */
+ Object *ob = base->object;
+
+ if (ob->bb && !(ob->bb->flag & BOUNDBOX_DIRTY)) {
+ float cent[3];
+
+ BKE_boundbox_calc_center_aabb(ob->bb, cent);
+
+ mul_m4_v3(ob->obmat, cent);
+ add_v3_v3(select_center, cent);
+ }
+ else {
+ add_v3_v3(select_center, ob->obmat[3]);
+ }
+ tot++;
+ }
+ }
+ if (tot) {
+ mul_v3_fl(select_center, 1.0f / (float)tot);
+ copy_v3_v3(lastofs, select_center);
+ is_set = true;
+ }
+ }
else {
/* If there's no selection, lastofs is unmodified and last value since static */
is_set = calculateTransformCenter(C, V3D_CENTROID, lastofs, NULL);
@@ -934,8 +1037,8 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
* - dragged. */
phi = si * (float)(M_PI / 2.0);
- q1[0] = cos(phi);
- mul_v3_fl(q1 + 1, sin(phi));
+ q1[0] = cosf(phi);
+ mul_v3_fl(q1 + 1, sinf(phi));
mul_qt_qtqt(vod->viewquat, q1, vod->oldquat);
viewrotate_apply_dyn_ofs(vod, vod->viewquat);
@@ -1052,7 +1155,9 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
viewrotate_apply(vod, event->x, event->y);
}
else if (event_code == VIEW_CONFIRM) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, true);
ED_view3d_depth_tag_update(vod->rv3d);
+
viewops_data_free(C, op);
return OPERATOR_FINISHED;
@@ -1067,7 +1172,7 @@ static int viewrotate_modal(bContext *C, wmOperator *op, const wmEvent *event)
*
* shared with NDOF.
*/
-static void view3d_ensure_persp(struct View3D *v3d, ARegion *ar)
+static bool view3d_ensure_persp(struct View3D *v3d, ARegion *ar)
{
RegionView3D *rv3d = ar->regiondata;
const bool autopersp = (U.uiflag & USER_AUTOPERSP) != 0;
@@ -1075,7 +1180,7 @@ static void view3d_ensure_persp(struct View3D *v3d, ARegion *ar)
BLI_assert((rv3d->viewlock & RV3D_LOCKED) == 0);
if (ED_view3d_camera_lock_check(v3d, rv3d))
- return;
+ return false;
if (rv3d->persp != RV3D_PERSP) {
if (rv3d->persp == RV3D_CAMOB) {
@@ -1086,7 +1191,10 @@ static void view3d_ensure_persp(struct View3D *v3d, ARegion *ar)
else if (autopersp && RV3D_VIEW_IS_AXIS(rv3d->view)) {
rv3d->persp = RV3D_PERSP;
}
+ return true;
}
+
+ return false;
}
static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1105,8 +1213,14 @@ static int viewrotate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
}
/* switch from camera view when: */
- view3d_ensure_persp(vod->v3d, vod->ar);
-
+ if (view3d_ensure_persp(vod->v3d, vod->ar)) {
+ /* If we're switching from camera view to the perspective one,
+ * need to tag viewport update, so camera vuew and borders
+ * are properly updated.
+ */
+ ED_region_tag_redraw(vod->ar);
+ }
+
if (event->type == MOUSEPAN) {
/* Rotate direction we keep always same */
if (U.uiflag2 & USER_TRACKPAD_NATURAL)
@@ -1334,7 +1448,7 @@ static void view3d_ndof_orbit(const struct wmNDOFMotionData *ndof, ScrArea *sa,
/* Perform the up/down rotation */
angle = ndof->dt * rot[0];
quat[0] = cosf(angle);
- mul_v3_v3fl(quat + 1, xvec, sin(angle));
+ mul_v3_v3fl(quat + 1, xvec, sinf(angle));
mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, quat);
/* Perform the orbital rotation */
@@ -1860,6 +1974,7 @@ static int viewmove_modal(bContext *C, wmOperator *op, const wmEvent *event)
viewmove_apply(vod, event->x, event->y);
}
else if (event_code == VIEW_CONFIRM) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
@@ -2000,9 +2115,12 @@ static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzo
{
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;
@@ -2069,16 +2187,19 @@ static void viewzoom_apply(ViewOpsData *vod, const int xy[2], const short viewzo
}
if (!use_cam_zoom) {
- if (zfac != 1.0f && zfac * vod->rv3d->dist > 0.001f * vod->grid &&
- zfac * vod->rv3d->dist < 10.0f * vod->far)
- {
- view_zoom_mouseloc(vod->ar, zfac, vod->oldx, vod->oldy);
+ 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);
+ }
}
}
/* these limits were in old code too */
- if (vod->rv3d->dist < 0.001f * vod->grid) vod->rv3d->dist = 0.001f * vod->grid;
- if (vod->rv3d->dist > 10.0f * vod->far) vod->rv3d->dist = 10.0f * vod->far;
+ CLAMP(vod->rv3d->dist, dist_range[0], dist_range[1]);
if (vod->rv3d->viewlock & RV3D_BOXVIEW)
view3d_boxview_sync(vod->sa, vod->ar);
@@ -2125,6 +2246,7 @@ static int viewzoom_modal(bContext *C, wmOperator *op, const wmEvent *event)
viewzoom_apply(vod, &event->x, U.viewzoom, (U.uiflag & USER_ZOOM_INVERT) != 0);
}
else if (event_code == VIEW_CONFIRM) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
@@ -2141,6 +2263,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
ScrArea *sa;
ARegion *ar;
bool use_cam_zoom;
+ float dist_range[2];
const int delta = RNA_int_get(op->ptr, "delta");
int mx, my;
@@ -2164,13 +2287,15 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
use_cam_zoom = (rv3d->persp == RV3D_CAMOB) && !(rv3d->is_persp && ED_view3d_camera_lock_check(v3d, rv3d));
+ ED_view3d_dist_range_get(v3d, dist_range);
+
if (delta < 0) {
/* 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;
}
- else if (rv3d->dist < 10.0f * v3d->far) {
+ else if (rv3d->dist < dist_range[1]) {
view_zoom_mouseloc(ar, 1.2f, mx, my);
}
}
@@ -2179,7 +2304,7 @@ static int viewzoom_exec(bContext *C, wmOperator *op)
rv3d->camzoom += 10.0f;
if (rv3d->camzoom > RV3D_CAMZOOM_MAX) rv3d->camzoom = RV3D_CAMZOOM_MAX;
}
- else if (rv3d->dist > 0.001f * v3d->grid) {
+ else if (rv3d->dist > dist_range[0]) {
view_zoom_mouseloc(ar, 0.83333f, mx, my);
}
}
@@ -2292,6 +2417,8 @@ static void viewzoom_cancel(bContext *C, wmOperator *op)
void VIEW3D_OT_zoom(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Zoom View";
ot->description = "Zoom in/out in the view";
@@ -2308,8 +2435,10 @@ void VIEW3D_OT_zoom(wmOperatorType *ot)
ot->flag = OPTYPE_BLOCKING | OPTYPE_GRAB_POINTER;
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);
- RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
+ prop = RNA_def_int(ot->srna, "mx", 0, 0, INT_MAX, "Zoom Position X", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
+ prop = RNA_def_int(ot->srna, "my", 0, 0, INT_MAX, "Zoom Position Y", "", 0, INT_MAX);
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
@@ -2385,6 +2514,7 @@ static int viewdolly_modal(bContext *C, wmOperator *op, const wmEvent *event)
viewdolly_apply(vod, event->x, event->y, (U.uiflag & USER_ZOOM_INVERT) != 0);
}
else if (event_code == VIEW_CONFIRM) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, false, true);
ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
@@ -3171,6 +3301,8 @@ static int render_border_exec(bContext *C, wmOperator *op)
void VIEW3D_OT_render_border(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "Set Render Border";
ot->description = "Set the boundaries of the border render and enable border render";
@@ -3190,7 +3322,8 @@ void VIEW3D_OT_render_border(wmOperatorType *ot)
/* rna */
WM_operator_properties_border(ot);
- RNA_def_boolean(ot->srna, "camera_only", 0, "Camera Only", "Set render border for camera view and final render only");
+ prop = RNA_def_boolean(ot->srna, "camera_only", 0, "Camera Only", "Set render border for camera view and final render only");
+ RNA_def_property_flag(prop, PROP_HIDDEN);
}
/* ********************* Clear render border operator ****************** */
@@ -3254,7 +3387,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
/* Zooms in on a border drawn by the user */
rcti rect;
float dvec[3], vb[2], xscale, yscale;
- float dist_range_min;
+ float dist_range[2];
/* SMOOTHVIEW */
float new_dist;
@@ -3274,9 +3407,11 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
/* check if zooming in/out view */
gesture_mode = RNA_int_get(op->ptr, "gesture_mode");
+ ED_view3d_dist_range_get(v3d, dist_range);
+
/* Get Z Depths, needed for perspective, nice for ortho */
bgl_get_mats(&mats);
- draw_depth(scene, ar, v3d, NULL, true);
+ ED_view3d_draw_depth(scene, ar, v3d, true);
{
/* avoid allocating the whole depth buffer */
@@ -3288,7 +3423,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
/* find the closest Z pixel */
depth_close = view3d_depth_near(&depth_temp);
- MEM_freeN(depth_temp.depths);
+ MEM_SAFE_FREE(depth_temp.depths);
}
cent[0] = (((double)rect.xmin) + ((double)rect.xmax)) / 2;
@@ -3322,8 +3457,9 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
new_ofs[2] = -p[2];
new_dist = len_v3(dvec);
- dist_range_min = v3d->near * 1.5f;
+ /* ignore dist_range min */
+ dist_range[0] = v3d->near * 1.5f;
}
else { /* othographic */
/* find the current window width and height */
@@ -3365,9 +3501,6 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
xscale = (BLI_rcti_size_x(&rect) / vb[0]);
yscale = (BLI_rcti_size_y(&rect) / vb[1]);
new_dist *= max_ff(xscale, yscale);
-
- /* zoom in as required, or as far as we can go */
- dist_range_min = 0.001f * v3d->grid;
}
if (gesture_mode == GESTURE_MODAL_OUT) {
@@ -3377,9 +3510,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op)
}
/* clamp after because we may have been zooming out */
- if (new_dist < dist_range_min) {
- new_dist = dist_range_min;
- }
+ CLAMP(new_dist, dist_range[0], dist_range[1]);
ED_view3d_smooth_view(C, v3d, ar, NULL, NULL,
new_ofs, NULL, &new_dist, NULL,
@@ -3473,13 +3604,13 @@ void VIEW3D_OT_zoom_camera_1_to_1(wmOperatorType *ot)
/* ********************* Changing view operator ****************** */
static EnumPropertyItem prop_view_items[] = {
+ {RV3D_VIEW_LEFT, "LEFT", ICON_TRIA_LEFT, "Left", "View From the Left"},
+ {RV3D_VIEW_RIGHT, "RIGHT", ICON_TRIA_RIGHT, "Right", "View From the Right"},
+ {RV3D_VIEW_BOTTOM, "BOTTOM", ICON_TRIA_DOWN, "Bottom", "View From the Bottom"},
+ {RV3D_VIEW_TOP, "TOP", ICON_TRIA_UP, "Top", "View From the Top"},
{RV3D_VIEW_FRONT, "FRONT", 0, "Front", "View From the Front"},
{RV3D_VIEW_BACK, "BACK", 0, "Back", "View From the Back"},
- {RV3D_VIEW_LEFT, "LEFT", 0, "Left", "View From the Left"},
- {RV3D_VIEW_RIGHT, "RIGHT", 0, "Right", "View From the Right"},
- {RV3D_VIEW_TOP, "TOP", 0, "Top", "View From the Top"},
- {RV3D_VIEW_BOTTOM, "BOTTOM", 0, "Bottom", "View From the Bottom"},
- {RV3D_VIEW_CAMERA, "CAMERA", 0, "Camera", "View From the Active Camera"},
+ {RV3D_VIEW_CAMERA, "CAMERA", ICON_CAMERA_DATA, "Camera", "View From the Active Camera"},
{0, NULL, 0, NULL, NULL}
};
@@ -3867,6 +3998,7 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
viewroll_apply(vod, event->x, event->y);
}
else if (event_code == VIEW_CONFIRM) {
+ ED_view3d_camera_lock_autokey(vod->v3d, vod->rv3d, C, true, false);
ED_view3d_depth_tag_update(vod->rv3d);
viewops_data_free(C, op);
@@ -3876,6 +4008,14 @@ static int viewroll_modal(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_RUNNING_MODAL;
}
+static EnumPropertyItem prop_view_roll_items[] = {
+ {0, "ROLLANGLE", 0, "Roll Angle", "Roll the view using an angle value"},
+ {V3D_VIEW_STEPLEFT, "ROLLLEFT", 0, "Roll Left", "Roll the view around to the Left"},
+ {V3D_VIEW_STEPRIGHT, "ROLLTRIGHT", 0, "Roll Right", "Roll the view around to the Right"},
+ {0, NULL, 0, NULL, NULL}
+};
+
+
static int viewroll_exec(bContext *C, wmOperator *op)
{
View3D *v3d;
@@ -3893,12 +4033,17 @@ static int viewroll_exec(bContext *C, wmOperator *op)
rv3d = ar->regiondata;
if ((rv3d->persp != RV3D_CAMOB) || ED_view3d_camera_lock_check(v3d, rv3d)) {
- const float angle = RNA_float_get(op->ptr, "angle");
+ 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 mousevec[3];
float quat_new[4];
const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+ if (type == V3D_VIEW_STEPLEFT) {
+ angle = -angle;
+ }
+
normalize_v3_v3(mousevec, rv3d->viewinv[2]);
negate_v3(mousevec);
view_roll_angle(ar, quat_new, rv3d->viewquat, mousevec, angle);
@@ -3920,7 +4065,9 @@ static int viewroll_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
ViewOpsData *vod;
- if (RNA_struct_property_is_set(op->ptr, "angle")) {
+ bool use_angle = RNA_enum_get(op->ptr, "type") != 0;
+
+ if (use_angle || RNA_struct_property_is_set(op->ptr, "angle")) {
viewroll_exec(C, op);
}
else {
@@ -3958,6 +4105,8 @@ static void viewroll_cancel(bContext *C, wmOperator *op)
void VIEW3D_OT_view_roll(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
/* identifiers */
ot->name = "View Roll";
ot->description = "Roll the view";
@@ -3974,7 +4123,10 @@ void VIEW3D_OT_view_roll(wmOperatorType *ot)
ot->flag = 0;
/* properties */
- ot->prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX);
+ ot->prop = prop = RNA_def_float(ot->srna, "angle", 0, -FLT_MAX, FLT_MAX, "Roll", "", -FLT_MAX, FLT_MAX);
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "type", prop_view_roll_items, 0, "Roll Angle Source", "How roll angle is calculated");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
static EnumPropertyItem prop_view_pan_items[] = {
@@ -4148,8 +4300,7 @@ static int background_image_add_invoke(bContext *C, wmOperator *op, const wmEven
if (ima) {
bgpic->ima = ima;
- if (ima->id.us == 0) id_us_plus(&ima->id);
- else id_lib_extern(&ima->id);
+ id_us_plus(&ima->id);
if (!(v3d->flag & V3D_DISPBGPICS))
v3d->flag |= V3D_DISPBGPICS;
@@ -4191,7 +4342,15 @@ static int background_image_remove_exec(bContext *C, wmOperator *op)
BGpic *bgpic_rem = BLI_findlink(&v3d->bgpicbase, index);
if (bgpic_rem) {
+ if (bgpic_rem->source == V3D_BGPIC_IMAGE) {
+ id_us_min((ID *)bgpic_rem->ima);
+ }
+ else if (bgpic_rem->source == V3D_BGPIC_MOVIE) {
+ id_us_min((ID *)bgpic_rem->clip);
+ }
+
ED_view3D_background_image_remove(v3d, bgpic_rem);
+
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
return OPERATOR_FINISHED;
}
@@ -4221,12 +4380,16 @@ void VIEW3D_OT_background_image_remove(wmOperatorType *ot)
/* ********************* set clipping operator ****************** */
-static void calc_clipping_plane(float clip[6][4], const BoundBox *clipbb)
+static void calc_clipping_plane(float clip[6][4], const BoundBox *clipbb, const bool is_flip)
{
int val;
for (val = 0; val < 4; val++) {
normal_tri_v3(clip[val], clipbb->vec[val], clipbb->vec[val == 3 ? 0 : val + 1], clipbb->vec[val + 4]);
+ if (UNLIKELY(is_flip)) {
+ negate_v3(clip[val]);
+ }
+
clip[val][3] = -dot_v3v3(clip[val], clipbb->vec[val]);
}
}
@@ -4243,7 +4406,7 @@ static void calc_local_clipping(float clip_local[6][4], BoundBox *clipbb, float
mul_v3_m4v3(clipbb_local.vec[i], imat, clipbb->vec[i]);
}
- calc_clipping_plane(clip_local, &clipbb_local);
+ calc_clipping_plane(clip_local, &clipbb_local, is_negative_m4(mat));
}
void ED_view3d_clipping_local(RegionView3D *rv3d, float mat[4][4])
@@ -4355,20 +4518,25 @@ void ED_view3d_cursor3d_position(bContext *C, float fp[3], const int mval[2])
}
}
-static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+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, event->mval);
-
+ ED_view3d_cursor3d_position(C, fp, mval);
+
if (v3d && v3d->localvd)
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
else
WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
-
- return OPERATOR_FINISHED;
+}
+
+static int view3d_cursor3d_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
+{
+ ED_view3d_cursor3d_update(C, event->mval);
+
+ return OPERATOR_FINISHED;
}
void VIEW3D_OT_cursor3d(wmOperatorType *ot)
@@ -4496,7 +4664,7 @@ static float view_autodist_depth_margin(ARegion *ar, const int mval[2], int marg
view3d_update_depths_rect(ar, &depth_temp, &rect);
depth_close = view3d_depth_near(&depth_temp);
- if (depth_temp.depths) MEM_freeN(depth_temp.depths);
+ MEM_SAFE_FREE(depth_temp.depths);
return depth_close;
}
@@ -4511,7 +4679,7 @@ bool ED_view3d_autodist(Scene *scene, ARegion *ar, View3D *v3d,
/* Get Z Depths, needed for perspective, nice for ortho */
bgl_get_mats(&mats);
- draw_depth(scene, ar, v3d, NULL, alphaoverride);
+ ED_view3d_draw_depth(scene, ar, v3d, alphaoverride);
depth_close = view_autodist_depth_margin(ar, mval, 4);
@@ -4543,10 +4711,10 @@ void ED_view3d_autodist_init(Scene *scene, ARegion *ar, View3D *v3d, int mode)
/* Get Z Depths, needed for perspective, nice for ortho */
switch (mode) {
case 0:
- draw_depth(scene, ar, v3d, NULL, true);
+ ED_view3d_draw_depth(scene, ar, v3d, true);
break;
case 1:
- draw_depth_gpencil(scene, ar, v3d);
+ ED_view3d_draw_depth_gpencil(scene, ar, v3d);
break;
}
}
diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c
index 6afe0ef896f..da77c4f75f7 100644
--- a/source/blender/editors/space_view3d/view3d_fly.c
+++ b/source/blender/editors/space_view3d/view3d_fly.c
@@ -385,7 +385,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent
fly->zlock = FLY_AXISLOCK_STATE_IDLE;
}
- fly->v3d_camera_control = ED_view3d_cameracontrol_aquire(
+ fly->v3d_camera_control = ED_view3d_cameracontrol_acquire(
fly->scene, fly->v3d, fly->rv3d,
(U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0);
diff --git a/source/blender/editors/space_view3d/view3d_header.c b/source/blender/editors/space_view3d/view3d_header.c
index e3d0e87066b..a88724a1cdd 100644
--- a/source/blender/editors/space_view3d/view3d_header.c
+++ b/source/blender/editors/space_view3d/view3d_header.c
@@ -32,6 +32,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include "DNA_brush_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -45,6 +46,7 @@
#include "BKE_depsgraph.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
+#include "BKE_paint.h"
#include "BKE_screen.h"
#include "BKE_editmesh.h"
@@ -308,7 +310,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
/* mode */
if (ob) {
modeselect = ob->mode;
- is_paint = ELEM4(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT);
+ is_paint = ELEM(ob->mode, OB_MODE_SCULPT, OB_MODE_VERTEX_PAINT, OB_MODE_WEIGHT_PAINT, OB_MODE_TEXTURE_PAINT);
}
else {
modeselect = OB_MODE_OBJECT;
@@ -336,8 +338,7 @@ void uiTemplateHeader3D(uiLayout *layout, struct bContext *C)
uiItemR(layout, &v3dptr, "viewport_shade", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
if (obedit == NULL && is_paint) {
-
- if (ob->mode & OB_MODE_WEIGHT_PAINT) {
+ if (ob->mode & OB_MODE_ALL_PAINT) {
/* Only for Weight Paint. makes no sense in other paint modes. */
row = uiLayoutRow(layout, true);
uiItemR(row, &v3dptr, "pivot_point", UI_ITEM_R_ICON_ONLY, "", ICON_NONE);
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index 2c6fc1cfe02..84ac4f7d02d 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -177,8 +177,8 @@ void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
/* view3d_draw.c */
void view3d_main_area_draw(const struct bContext *C, struct ARegion *ar);
-void draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, int (*func)(void *), bool alphaoverride);
-void draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d);
+void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride);
+void ED_view3d_draw_depth_gpencil(Scene *scene, ARegion *ar, View3D *v3d);
void ED_view3d_after_add(ListBase *lb, Base *base, const short dflag);
void circf(float x, float y, float rad);
@@ -218,7 +218,7 @@ 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, rctf *rect);
+void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rctf *rect);
void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d);
void fly_modal_keymap(struct wmKeyConfig *keyconf);
@@ -233,7 +233,7 @@ void VIEW3D_OT_properties(struct wmOperatorType *ot);
void view3d_buttons_register(struct ARegionType *art);
/* view3d_camera_control.c */
-struct View3DCameraControl *ED_view3d_cameracontrol_aquire(
+struct View3DCameraControl *ED_view3d_cameracontrol_acquire(
Scene *scene, View3D *v3d, RegionView3D *rv3d,
const bool use_parent_root);
void ED_view3d_cameracontrol_update(
@@ -285,7 +285,7 @@ void draw_smoke_heat(struct SmokeDomainSettings *domain, struct Object *ob);
/* workaround for trivial but noticeable camera bug caused by imprecision
* between view border calculation in 2D/3D space, workaround for bug [#28037].
- * without this deifne we get the old behavior which is to try and align them
+ * without this define we get the old behavior which is to try and align them
* both which _mostly_ works fine, but when the camera moves beyond ~1000 in
* any direction it starts to fail */
#define VIEW3D_CAMERA_BORDER_HACK
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index a8128ba7ae8..6a505959820 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -77,7 +77,7 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op)
}
CTX_DATA_END;
- BLI_make_file_string("/", str, BLI_temporary_dir(), "copybuffer.blend");
+ BLI_make_file_string("/", str, BLI_temp_dir_base(), "copybuffer.blend");
BKE_copybuffer_save(str, op->reports);
BKE_report(op->reports, RPT_INFO, "Copied selected objects to buffer");
@@ -102,7 +102,7 @@ static int view3d_pastebuffer_exec(bContext *C, wmOperator *op)
{
char str[FILE_MAX];
- BLI_make_file_string("/", str, BLI_temporary_dir(), "copybuffer.blend");
+ BLI_make_file_string("/", str, BLI_temp_dir_base(), "copybuffer.blend");
if (BKE_copybuffer_paste(C, str, op->reports)) {
WM_event_add_notifier(C, NC_WINDOW, NULL);
@@ -296,8 +296,8 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD4, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD6, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", PAD8, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANUP);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "angle", M_PI / -12);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD6, KM_PRESS, KM_SHIFT, 0)->ptr, "angle", M_PI / 12);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD4, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", PAD6, KM_PRESS, KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELUPMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANRIGHT);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_pan", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "type", V3D_VIEW_PANLEFT);
@@ -309,8 +309,8 @@ void view3d_keymap(wmKeyConfig *keyconf)
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELUPMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPUP);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_orbit", WHEELDOWNMOUSE, KM_PRESS, KM_SHIFT | KM_ALT, 0)->ptr, "type", V3D_VIEW_STEPDOWN);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "angle", M_PI / -12);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "angle", M_PI / 12);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELUPMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPLEFT);
+ RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", WHEELDOWNMOUSE, KM_PRESS, KM_CTRL | KM_SHIFT, 0)->ptr, "type", V3D_VIEW_STEPRIGHT);
/* active aligned, replaces '*' key in 2.4x */
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", PAD1, KM_PRESS, KM_SHIFT, 0);
diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c
index 6ee1750b85d..75c1d9dcd22 100644
--- a/source/blender/editors/space_view3d/view3d_project.c
+++ b/source/blender/editors/space_view3d/view3d_project.c
@@ -277,7 +277,7 @@ eV3DProjStatus ED_view3d_project_float_object(const ARegion *ar, const float co[
* *************************************************** */
/**
- * Caculate a depth value from \a co, use with #ED_view3d_win_to_delta
+ * Calculate a depth value from \a co, use with #ED_view3d_win_to_delta
*/
float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_flip)
{
@@ -315,22 +315,27 @@ static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const floa
if (rv3d->is_persp) {
copy_v3_v3(r_ray_co, rv3d->viewinv[3]);
-
- start_offset = v3d->near;
- end_offset = v3d->far;
}
else {
- float vec[4];
- vec[0] = 2.0f * mval[0] / ar->winx - 1;
- vec[1] = 2.0f * mval[1] / ar->winy - 1;
- vec[2] = 0.0f;
- vec[3] = 1.0f;
+ r_ray_co[0] = 2.0f * mval[0] / ar->winx - 1.0f;
+ r_ray_co[1] = 2.0f * mval[1] / ar->winy - 1.0f;
+
+ if (rv3d->persp == RV3D_CAMOB) {
+ r_ray_co[2] = -1.0f;
+ }
+ else {
+ r_ray_co[2] = 0.0f;
+ }
- mul_m4_v4(rv3d->persinv, vec);
- copy_v3_v3(r_ray_co, vec);
+ mul_project_m4_v3(rv3d->persinv, r_ray_co);
+ }
- start_offset = -1000.0f;
- end_offset = 1000.0f;
+ if ((rv3d->is_persp == false) && (rv3d->persp != RV3D_CAMOB)) {
+ end_offset = v3d->far / 2.0f;
+ start_offset = -end_offset;
+ }
+ else {
+ ED_view3d_clip_range_get(v3d, rv3d, &start_offset, &end_offset, false);
}
if (r_ray_start) {
@@ -388,7 +393,7 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2]
* \param ar The region (used for the window width and height).
* \param v3d The 3d viewport (used for near clipping value).
* \param mval The area relative 2d location (such as event->mval, converted into float[2]).
- * \param r_ray_co The world-space point where the ray intersects the window plane.
+ * \param r_ray_start The world-space point where the ray intersects the window plane.
* \param r_ray_normal The normalized world-space direction of towards mval.
* \param do_clip Optionally clip the start of the ray by the view clipping planes.
* \return success, false if the ray is totally clipped.
diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c
index 9d0a70ea9d0..652f44ea95a 100644
--- a/source/blender/editors/space_view3d/view3d_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_ruler.c
@@ -122,12 +122,10 @@ static bool ED_view3d_snap_ray(bContext *C, float r_co[3],
bool ret;
Scene *scene = CTX_data_scene(C);
- View3D *v3d = CTX_wm_view3d(C);
- ARegion *ar = CTX_wm_region(C);
struct Object *obedit = CTX_data_edit_object(C);
/* try snap edge, then face if it fails */
- ret = snapObjectsRayEx(scene, NULL, v3d, ar, obedit, SCE_SNAP_MODE_FACE,
+ ret = snapObjectsRayEx(scene, NULL, NULL, NULL, obedit, SCE_SNAP_MODE_FACE,
NULL, NULL,
ray_start, ray_normal, &ray_dist,
NULL, &dist_px, r_co, r_no_dummy, SNAP_ALL);
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index d18eab6da48..9d5240feb43 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1147,11 +1147,12 @@ static Base *object_mouse_select_menu(bContext *C, ViewContext *vc, unsigned int
}
{
+ wmOperatorType *ot = WM_operatortype_find("VIEW3D_OT_select_menu", false);
PointerRNA ptr;
- WM_operator_properties_create(&ptr, "VIEW3D_OT_select_menu");
+ WM_operator_properties_create_ptr(&ptr, ot);
RNA_boolean_set(&ptr, "toggle", toggle);
- WM_operator_name_call(C, "VIEW3D_OT_select_menu", WM_OP_INVOKE_DEFAULT, &ptr);
+ WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
WM_operator_properties_free(&ptr);
}
@@ -1180,28 +1181,45 @@ static short selectbuffer_ret_hits_15(unsigned int *UNUSED(buffer), const short
static short selectbuffer_ret_hits_9(unsigned int *buffer, const short hits15, const short hits9)
{
const int offs = 4 * hits15;
- memcpy(buffer, buffer + offs, 4 * offs);
+ memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(unsigned int));
return hits9;
}
static short selectbuffer_ret_hits_5(unsigned int *buffer, const short hits15, const short hits9, const short hits5)
{
const int offs = 4 * hits15 + 4 * hits9;
- memcpy(buffer, buffer + offs, 4 * offs);
+ memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
return hits5;
}
/* we want a select buffer with bones, if there are... */
/* so check three selection levels and compare */
-static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2])
+static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buffer, const int mval[2], bool *p_do_nearest, bool enumerate)
{
rcti rect;
int offs;
short hits15, hits9 = 0, hits5 = 0;
bool has_bones15 = false, has_bones9 = false, has_bones5 = false;
-
+ static int last_mval[2] = {-100, -100};
+ bool do_nearest = false;
+ View3D *v3d = vc->v3d;
+
+ /* define if we use solid nearest select or not */
+ if (v3d->drawtype > OB_WIRE) {
+ do_nearest = true;
+ if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
+ do_nearest = false;
+ }
+ }
+ copy_v2_v2_int(last_mval, mval);
+
+ if (p_do_nearest)
+ *p_do_nearest = do_nearest;
+
+ do_nearest = do_nearest && !enumerate;
+
BLI_rcti_init(&rect, mval[0] - 14, mval[0] + 14, mval[1] - 14, mval[1] + 14);
- hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect);
+ hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, do_nearest);
if (hits15 == 1) {
return selectbuffer_ret_hits_15(buffer, hits15);
}
@@ -1210,7 +1228,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff
offs = 4 * hits15;
BLI_rcti_init(&rect, mval[0] - 9, mval[0] + 9, mval[1] - 9, mval[1] + 9);
- hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect);
+ hits9 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
if (hits9 == 1) {
return selectbuffer_ret_hits_9(buffer, hits15, hits9);
}
@@ -1219,7 +1237,7 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff
offs += 4 * hits9;
BLI_rcti_init(&rect, mval[0] - 5, mval[0] + 5, mval[1] - 5, mval[1] + 5);
- hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect);
+ hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, do_nearest);
if (hits5 == 1) {
return selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5);
}
@@ -1241,25 +1259,13 @@ static short mixed_bones_object_selectbuffer(ViewContext *vc, unsigned int *buff
}
/* returns basact */
-static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits, const int mval[2],
- Base *startbase, bool has_bones)
+static Base *mouse_select_eval_buffer(ViewContext *vc, unsigned int *buffer, int hits,
+ Base *startbase, bool has_bones, bool do_nearest)
{
Scene *scene = vc->scene;
View3D *v3d = vc->v3d;
Base *base, *basact = NULL;
- static int lastmval[2] = {-100, -100};
int a;
- bool do_nearest = false;
-
- /* define if we use solid nearest select or not */
- if (v3d->drawtype > OB_WIRE) {
- do_nearest = true;
- if (ABS(mval[0] - lastmval[0]) < 3 && ABS(mval[1] - lastmval[1]) < 3) {
- if (!has_bones) /* hrms, if theres bones we always do nearest */
- do_nearest = false;
- }
- }
- lastmval[0] = mval[0]; lastmval[1] = mval[1];
if (do_nearest) {
unsigned int min = 0xFFFFFFFF;
@@ -1342,16 +1348,17 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
Base *basact = NULL;
unsigned int buffer[4 * MAXPICKBUF];
int hits;
+ bool do_nearest;
/* setup view context for argument to callbacks */
view3d_operator_needs_opengl(C);
view3d_set_viewcontext(C, &vc);
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval);
+ hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, false);
if (hits > 0) {
const bool has_bones = selectbuffer_has_bones(buffer, hits);
- basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, vc.scene->base.first, has_bones);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, vc.scene->base.first, has_bones, do_nearest);
}
return basact;
@@ -1438,10 +1445,11 @@ static bool mouse_select(bContext *C, const int mval[2],
}
else {
unsigned int buffer[4 * MAXPICKBUF];
+ bool do_nearest;
/* if objects have posemode set, the bones are in the same selection buffer */
- hits = mixed_bones_object_selectbuffer(&vc, buffer, mval);
+ hits = mixed_bones_object_selectbuffer(&vc, buffer, mval, &do_nearest, enumerate);
if (hits > 0) {
/* note: bundles are handling in the same way as bones */
@@ -1452,7 +1460,7 @@ static bool mouse_select(bContext *C, const int mval[2],
basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, toggle);
}
else {
- basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, has_bones);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest);
}
if (has_bones && basact) {
@@ -1510,11 +1518,11 @@ static bool mouse_select(bContext *C, const int mval[2],
if (!changed) {
/* fallback to regular object selection if no new bundles were selected,
* allows to select object parented to reconstruction object */
- basact = mouse_select_eval_buffer(&vc, buffer, hits, mval, startbase, 0);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest);
}
}
}
- else if (ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend, deselect, toggle) ) {
+ else if (ED_do_pose_selectbuffer(scene, basact, buffer, hits, extend, deselect, toggle, do_nearest)) {
/* then bone is found */
/* we make the armature selected:
@@ -1872,7 +1880,7 @@ static int do_meta_box_select(ViewContext *vc, rcti *rect, bool select, bool ext
unsigned int buffer[4 * MAXPICKBUF];
short hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
if (extend == false && select)
BKE_mball_deselect_all(mb);
@@ -1906,7 +1914,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
unsigned int buffer[4 * MAXPICKBUF];
short hits;
- hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect);
+ hits = view3d_opengl_select(vc, buffer, MAXPICKBUF, rect, false);
/* clear flag we use to detect point was affected */
for (ebone = arm->edbo->first; ebone; ebone = ebone->next)
@@ -1964,7 +1972,7 @@ static int do_armature_box_select(ViewContext *vc, rcti *rect, bool select, bool
ED_armature_sync_selection(arm->edbo);
- return OPERATOR_CANCELLED;
+ return hits > 0 ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend)
@@ -2000,7 +2008,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
/* selection buffer now has bones potentially too, so we add MAXPICKBUF */
vbuffer = MEM_mallocN(4 * (totobj + MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
- hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect);
+ hits = view3d_opengl_select(vc, vbuffer, 4 * (totobj + MAXPICKBUF), rect, false);
/*
* LOGIC NOTES (theeth):
* The buffer and ListBase have the same relative order, which makes the selection
@@ -2128,7 +2136,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
}
else { /* no editmode, unified for bones and objects */
if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) {
- ret = do_sculpt_mask_box_select(&vc, &rect, select, extend);
+ ret = ED_sculpt_mask_box_select(C, &vc, &rect, select, extend);
}
else if (vc.obact && BKE_paint_select_face_test(vc.obact)) {
ret = do_paintface_box_select(&vc, &rect, select, extend);
@@ -2841,6 +2849,6 @@ void VIEW3D_OT_select_circle(wmOperatorType *ot)
RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
}
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index ebdcc757acc..858d001a381 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -56,6 +56,7 @@
#include "BIF_glutil.h"
#include "GPU_draw.h"
+#include "GPU_select.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -273,7 +274,7 @@ void ED_view3d_smooth_view_ex(
rv3d->rflag |= RV3D_NAVIGATING;
/* not essential but in some cases the caller will tag the area for redraw,
- * and in that case we can get a ficker of the 'org' user view but we want to see 'src' */
+ * and in that case we can get a flicker of the 'org' user view but we want to see 'src' */
view3d_smooth_view_state_restore(&sms.src, v3d, rv3d);
/* keep track of running timer! */
@@ -723,6 +724,13 @@ 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])
+{
+ 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)
@@ -782,13 +790,13 @@ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist)
}
/**
- * \param rect, optional for picking (can be NULL).
+ * \param rect optional for picking (can be NULL).
*/
-void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect)
+void view3d_winmatrix_set(ARegion *ar, View3D *v3d, const rctf *rect)
{
RegionView3D *rv3d = ar->regiondata;
rctf viewplane;
- float clipsta, clipend, x1, y1, x2, y2;
+ float clipsta, clipend;
bool is_ortho;
is_ortho = ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
@@ -800,28 +808,20 @@ void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect)
clipsta, clipend);
#endif
- x1 = viewplane.xmin;
- y1 = viewplane.ymin;
- x2 = viewplane.xmax;
- y2 = viewplane.ymax;
-
if (rect) { /* picking */
- rect->xmin /= (float)ar->winx;
- rect->xmin = x1 + rect->xmin * (x2 - x1);
- rect->ymin /= (float)ar->winy;
- rect->ymin = y1 + rect->ymin * (y2 - y1);
- rect->xmax /= (float)ar->winx;
- rect->xmax = x1 + rect->xmax * (x2 - x1);
- rect->ymax /= (float)ar->winy;
- rect->ymax = y1 + rect->ymax * (y2 - y1);
-
- if (is_ortho) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
- else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
+ rctf r;
+ r.xmin = viewplane.xmin + (BLI_rctf_size_x(&viewplane) * (rect->xmin / (float)ar->winx));
+ r.ymin = viewplane.ymin + (BLI_rctf_size_y(&viewplane) * (rect->ymin / (float)ar->winy));
+ r.xmax = viewplane.xmin + (BLI_rctf_size_x(&viewplane) * (rect->xmax / (float)ar->winx));
+ r.ymax = viewplane.ymin + (BLI_rctf_size_y(&viewplane) * (rect->ymax / (float)ar->winy));
+ viewplane = r;
+ }
+ if (is_ortho) {
+ wmOrtho(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
}
else {
- if (is_ortho) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
- else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
+ wmFrustum(viewplane.xmin, viewplane.xmax, viewplane.ymin, viewplane.ymax, clipsta, clipend);
}
/* update matrix in 3d view region */
@@ -963,6 +963,78 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
}
}
+static void view3d_select_loop(ViewContext *vc, Scene *scene, View3D *v3d, ARegion *ar, bool use_obedit_skip)
+{
+ short code = 1;
+ char dt;
+ short dtx;
+
+ if (vc->obedit && vc->obedit->type == OB_MBALL) {
+ draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
+ }
+ else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
+ /* if not drawing sketch, draw bones */
+ if (!BDR_drawSketchNames(vc)) {
+ draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
+ }
+ }
+ else {
+ Base *base;
+
+ v3d->xray = true; /* otherwise it postpones drawing */
+ for (base = scene->base.first; base; base = base->next) {
+ if (base->lay & v3d->lay) {
+
+ if ((base->object->restrictflag & OB_RESTRICT_SELECT) ||
+ (use_obedit_skip && (scene->obedit->data == base->object->data)))
+ {
+ base->selcol = 0;
+ }
+ else {
+ base->selcol = code;
+
+ if (GPU_select_load_id(code)) {
+ draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR);
+
+ /* we draw duplicators for selection too */
+ if ((base->object->transflag & OB_DUPLI)) {
+ ListBase *lb;
+ DupliObject *dob;
+ Base tbase;
+
+ tbase.flag = OB_FROMDUPLI;
+ lb = object_duplilist(G.main->eval_ctx, scene, base->object);
+
+ for (dob = lb->first; dob; dob = dob->next) {
+ float omat[4][4];
+
+ tbase.object = dob->ob;
+ copy_m4_m4(omat, dob->ob->obmat);
+ copy_m4_m4(dob->ob->obmat, dob->mat);
+
+ /* extra service: draw the duplicator in drawtype of parent */
+ /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
+ dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
+ dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
+
+ draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
+
+ tbase.object->dt = dt;
+ tbase.object->dtx = dtx;
+
+ copy_m4_m4(dob->ob->obmat, omat);
+ }
+ free_object_duplilist(lb);
+ }
+ }
+ code++;
+ }
+ }
+ }
+ v3d->xray = false; /* restore */
+ }
+}
+
/**
* \warning be sure to account for a negative return value
* This is an error, "Too many objects in select buffer"
@@ -970,17 +1042,16 @@ void view3d_viewmatrix_set(Scene *scene, View3D *v3d, RegionView3D *rv3d)
*
* \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
*/
-short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
+short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, const rcti *input, bool do_nearest)
{
Scene *scene = vc->scene;
View3D *v3d = vc->v3d;
ARegion *ar = vc->ar;
rctf rect;
- short code, hits;
- char dt;
- short dtx;
+ short hits;
const bool use_obedit_skip = (scene->obedit != NULL) && (vc->obedit == NULL);
-
+ const bool do_passes = do_nearest && GPU_select_query_check_active();
+
G.f |= G_PICKSEL;
/* case not a border select */
@@ -1005,78 +1076,24 @@ short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int b
if (vc->rv3d->rflag & RV3D_CLIPPING)
ED_view3d_clipping_set(vc->rv3d);
- glSelectBuffer(bufsize, (GLuint *)buffer);
- glRenderMode(GL_SELECT);
- glInitNames(); /* these two calls whatfor? It doesnt work otherwise */
- glPushName(-1);
- code = 1;
+ if (do_passes)
+ GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
+ else
+ GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_ALL, 0);
+
+ view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
+
+ hits = GPU_select_end();
- if (vc->obedit && vc->obedit->type == OB_MBALL) {
- draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
- }
- else if ((vc->obedit && vc->obedit->type == OB_ARMATURE)) {
- /* if not drawing sketch, draw bones */
- if (!BDR_drawSketchNames(vc)) {
- draw_object(scene, ar, v3d, BASACT, DRAW_PICKING | DRAW_CONSTCOLOR);
- }
- }
- else {
- Base *base;
-
- v3d->xray = true; /* otherwise it postpones drawing */
- for (base = scene->base.first; base; base = base->next) {
- if (base->lay & v3d->lay) {
-
- if ((base->object->restrictflag & OB_RESTRICT_SELECT) ||
- (use_obedit_skip && (scene->obedit->data == base->object->data)))
- {
- base->selcol = 0;
- }
- else {
- base->selcol = code;
- glLoadName(code);
- draw_object(scene, ar, v3d, base, DRAW_PICKING | DRAW_CONSTCOLOR);
-
- /* we draw duplicators for selection too */
- if ((base->object->transflag & OB_DUPLI)) {
- ListBase *lb;
- DupliObject *dob;
- Base tbase;
-
- tbase.flag = OB_FROMDUPLI;
- lb = object_duplilist(G.main->eval_ctx, scene, base->object);
-
- for (dob = lb->first; dob; dob = dob->next) {
- float omat[4][4];
-
- tbase.object = dob->ob;
- copy_m4_m4(omat, dob->ob->obmat);
- copy_m4_m4(dob->ob->obmat, dob->mat);
-
- /* extra service: draw the duplicator in drawtype of parent */
- /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
- dt = tbase.object->dt; tbase.object->dt = MIN2(tbase.object->dt, base->object->dt);
- dtx = tbase.object->dtx; tbase.object->dtx = base->object->dtx;
-
- draw_object(scene, ar, v3d, &tbase, DRAW_PICKING | DRAW_CONSTCOLOR);
-
- tbase.object->dt = dt;
- tbase.object->dtx = dtx;
-
- copy_m4_m4(dob->ob->obmat, omat);
- }
- free_object_duplilist(lb);
- }
- code++;
- }
- }
- }
- v3d->xray = false; /* restore */
+ /* second pass, to get the closest object to camera */
+ if (do_passes) {
+ GPU_select_begin(buffer, bufsize, &rect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+
+ view3d_select_loop(vc, scene, v3d, ar, use_obedit_skip);
+
+ GPU_select_end();
}
-
- glPopName(); /* see above (pushname) */
- hits = glRenderMode(GL_RENDER);
-
+
G.f &= ~G_PICKSEL;
view3d_winmatrix_set(ar, v3d, NULL);
mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->winmat, vc->rv3d->viewmat);
@@ -1293,7 +1310,7 @@ static bool view3d_localview_init(
return ok;
}
-static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, ScrArea *sa, const int smooth_viewtx)
+static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmain, Scene *scene, ScrArea *sa, const int smooth_viewtx)
{
const bool free = true;
ARegion *ar;
@@ -1343,7 +1360,7 @@ static void restore_localviewdata(wmWindowManager *wm, wmWindow *win, Main *bmai
}
}
- ED_view3d_shade_update(bmain, v3d, sa);
+ ED_view3d_shade_update(bmain, scene, v3d, sa);
}
}
}
@@ -1360,7 +1377,7 @@ static bool view3d_localview_exit(
locallay = v3d->lay & 0xFF000000;
- restore_localviewdata(wm, win, bmain, sa, smooth_viewtx);
+ restore_localviewdata(wm, win, bmain, scene, sa, smooth_viewtx);
/* for when in other window the layers have changed */
if (v3d->scenelock) v3d->lay = scene->lay;
diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c
index 1c3e223f3ed..c54948b23c6 100644
--- a/source/blender/editors/space_view3d/view3d_walk.c
+++ b/source/blender/editors/space_view3d/view3d_walk.c
@@ -60,10 +60,8 @@
#include "view3d_intern.h" /* own include */
-#define EARTH_GRAVITY 9.80668f /* m/s2 */
-
/* prototypes */
-static float getVelocityZeroTime(float velocity);
+static float getVelocityZeroTime(const float gravity, const float velocity);
/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
enum {
@@ -280,7 +278,8 @@ typedef struct WalkInfo {
bool is_reversed;
/* gravity system */
- eWalkGravityState gravity;
+ eWalkGravityState gravity_state;
+ float gravity;
/* height to use in walk mode */
float view_height;
@@ -360,11 +359,11 @@ static void walk_navigation_mode_set(bContext *C, WalkInfo *walk, eWalkMethod mo
{
if (mode == WALK_MODE_FREE) {
walk->navigation_mode = WALK_MODE_FREE;
- walk->gravity = WALK_GRAVITY_STATE_OFF;
+ walk->gravity_state = WALK_GRAVITY_STATE_OFF;
}
else { /* WALK_MODE_GRAVITY */
walk->navigation_mode = WALK_MODE_GRAVITY;
- walk->gravity = WALK_GRAVITY_STATE_START;
+ walk->gravity_state = WALK_GRAVITY_STATE_START;
}
walk_update_header(C, walk);
@@ -510,7 +509,14 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->speed = U.walk_navigation.walk_speed;
walk->speed_factor = U.walk_navigation.walk_speed_factor;
- walk->gravity = WALK_GRAVITY_STATE_OFF;
+ walk->gravity_state = WALK_GRAVITY_STATE_OFF;
+
+ if ((walk->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY)) {
+ walk->gravity = fabsf(walk->scene->physics_settings.gravity[2]);
+ }
+ else {
+ walk->gravity = 9.80668f; /* m/s2 */
+ }
walk->is_reversed = ((U.walk_navigation.flag & USER_WALK_MOUSE_REVERSE) != 0);
@@ -532,7 +538,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op)
walk->rv3d->rflag |= RV3D_NAVIGATING;
- walk->v3d_camera_control = ED_view3d_cameracontrol_aquire(
+ walk->v3d_camera_control = ED_view3d_cameracontrol_acquire(
walk->scene, walk->v3d, walk->rv3d,
(U.uiflag & USER_CAM_LOCK_NO_PARENT) == 0);
@@ -755,10 +761,10 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
#define JUMP_SPEED_MIN 1.0f
#define JUMP_TIME_MAX 0.2f /* s */
-#define JUMP_SPEED_MAX sqrtf(2.0f * EARTH_GRAVITY * walk->jump_height)
+#define JUMP_SPEED_MAX sqrtf(2.0f * walk->gravity * walk->jump_height)
case WALK_MODAL_JUMP_STOP:
- if (walk->gravity == WALK_GRAVITY_STATE_JUMP) {
+ if (walk->gravity_state == WALK_GRAVITY_STATE_JUMP) {
float t;
/* delta time */
@@ -769,21 +775,21 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
walk->speed_jump = JUMP_SPEED_MIN + t * (JUMP_SPEED_MAX - JUMP_SPEED_MIN) / JUMP_TIME_MAX;
/* when jumping, duration is how long it takes before we start going down */
- walk->teleport.duration = getVelocityZeroTime(walk->speed_jump);
+ walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump);
/* no more increase of jump speed */
- walk->gravity = WALK_GRAVITY_STATE_ON;
+ walk->gravity_state = WALK_GRAVITY_STATE_ON;
}
break;
case WALK_MODAL_JUMP:
if ((walk->navigation_mode == WALK_MODE_GRAVITY) &&
- (walk->gravity == WALK_GRAVITY_STATE_OFF) &&
+ (walk->gravity_state == WALK_GRAVITY_STATE_OFF) &&
(walk->teleport.state == WALK_TELEPORT_STATE_OFF))
{
/* no need to check for ground,
* walk->gravity wouldn't be off
* if we were over a hole */
- walk->gravity = WALK_GRAVITY_STATE_JUMP;
+ walk->gravity_state = WALK_GRAVITY_STATE_JUMP;
walk->speed_jump = JUMP_SPEED_MAX;
walk->teleport.initial_time = PIL_check_seconds_timer();
@@ -793,7 +799,7 @@ static void walkEvent(bContext *C, wmOperator *UNUSED(op), WalkInfo *walk, const
copy_v2_v2(walk->teleport.direction, walk->dvec_prev);
/* when jumping, duration is how long it takes before we start going down */
- walk->teleport.duration = getVelocityZeroTime(walk->speed_jump);
+ walk->teleport.duration = getVelocityZeroTime(walk->gravity, walk->speed_jump);
}
break;
@@ -853,14 +859,14 @@ static void walkMoveCamera(bContext *C, WalkInfo *walk,
ED_view3d_cameracontrol_update(walk->v3d_camera_control, true, C, do_rotate, do_translate);
}
-static float getFreeFallDistance(const float time)
+static float getFreeFallDistance(const float gravity, const float time)
{
- return EARTH_GRAVITY * (time * time) * 0.5f;
+ return gravity * (time * time) * 0.5f;
}
-static float getVelocityZeroTime(float velocity)
+static float getVelocityZeroTime(const float gravity, const float velocity)
{
- return velocity / EARTH_GRAVITY;
+ return velocity / gravity;
}
static int walkApply(bContext *C, WalkInfo *walk)
@@ -910,7 +916,7 @@ static int walkApply(bContext *C, WalkInfo *walk)
if ((walk->active_directions) ||
moffset[0] || moffset[1] ||
walk->teleport.state == WALK_TELEPORT_STATE_ON ||
- walk->gravity != WALK_GRAVITY_STATE_OFF)
+ walk->gravity_state != WALK_GRAVITY_STATE_OFF)
{
float dvec_tmp[3];
@@ -955,7 +961,7 @@ static int walkApply(bContext *C, WalkInfo *walk)
/* clamp the angle limits */
/* it ranges from 90.0f to -90.0f */
- angle = -asin(rv3d->viewmat[2][2]);
+ angle = -asinf(rv3d->viewmat[2][2]);
if (angle > WALK_TOP_LIMIT && y > 0.0f)
y = 0.0f;
@@ -1000,7 +1006,7 @@ static int walkApply(bContext *C, WalkInfo *walk)
/* WASD - 'move' translation code */
if ((walk->active_directions) &&
- (walk->gravity == WALK_GRAVITY_STATE_OFF))
+ (walk->gravity_state == WALK_GRAVITY_STATE_OFF))
{
short direction;
@@ -1076,7 +1082,7 @@ static int walkApply(bContext *C, WalkInfo *walk)
/* stick to the floor */
if (walk->navigation_mode == WALK_MODE_GRAVITY &&
- ELEM(walk->gravity,
+ ELEM(walk->gravity_state,
WALK_GRAVITY_STATE_OFF,
WALK_GRAVITY_STATE_START))
{
@@ -1101,13 +1107,13 @@ static int walkApply(bContext *C, WalkInfo *walk)
dvec[2] -= difference;
/* in case we switched from FREE to GRAVITY too close to the ground */
- if (walk->gravity == WALK_GRAVITY_STATE_START)
- walk->gravity = WALK_GRAVITY_STATE_OFF;
+ if (walk->gravity_state == WALK_GRAVITY_STATE_START)
+ walk->gravity_state = WALK_GRAVITY_STATE_OFF;
}
else {
/* hijack the teleport variables */
walk->teleport.initial_time = PIL_check_seconds_timer();
- walk->gravity = WALK_GRAVITY_STATE_ON;
+ walk->gravity_state = WALK_GRAVITY_STATE_ON;
walk->teleport.duration = 0.0f;
copy_v3_v3(walk->teleport.origin, walk->rv3d->viewinv[3]);
@@ -1117,7 +1123,7 @@ static int walkApply(bContext *C, WalkInfo *walk)
}
/* Falling or jumping) */
- if (ELEM(walk->gravity, WALK_GRAVITY_STATE_ON, WALK_GRAVITY_STATE_JUMP)) {
+ if (ELEM(walk->gravity_state, WALK_GRAVITY_STATE_ON, WALK_GRAVITY_STATE_JUMP)) {
float t;
float z_cur, z_new;
bool ret;
@@ -1130,7 +1136,7 @@ static int walkApply(bContext *C, WalkInfo *walk)
copy_v2_v2(dvec, walk->teleport.direction);
z_cur = walk->rv3d->viewinv[3][2];
- z_new = walk->teleport.origin[2] - getFreeFallDistance(t) * walk->grid;
+ z_new = walk->teleport.origin[2] - getFreeFallDistance(walk->gravity, t) * walk->grid;
/* jump */
z_new += t * walk->speed_jump * walk->grid;
@@ -1148,7 +1154,7 @@ static int walkApply(bContext *C, WalkInfo *walk)
if (difference > 0.0f) {
/* quit falling, lands at "view_height" from the floor */
dvec[2] -= difference;
- walk->gravity = WALK_GRAVITY_STATE_OFF;
+ walk->gravity_state = WALK_GRAVITY_STATE_OFF;
walk->speed_jump = 0.0f;
}
else {
@@ -1334,5 +1340,3 @@ void VIEW3D_OT_walk(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_BLOCKING;
}
-
-#undef EARTH_GRAVITY
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 7765dd511b4..0c360474b78 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -24,11 +24,13 @@ set(INC
../../blenkernel
../../blenlib
../../bmesh
+ ../../gpu
../../ikplugin
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -53,4 +55,6 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
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 f3c8c13647a..e249856b747 100644
--- a/source/blender/editors/transform/SConscript
+++ b/source/blender/editors/transform/SConscript
@@ -31,19 +31,21 @@ sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../bmesh',
+ '../../gpu',
'../../ikplugin',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
]
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index b88c388c257..24499688835 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -58,6 +58,7 @@
#include "BKE_particle.h"
#include "BKE_unit.h"
#include "BKE_mask.h"
+#include "BKE_report.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -86,6 +87,9 @@
#include "transform.h"
+/* Disabling, since when you type you know what you are doing, and being able to set it to zero is handy. */
+// #define USE_NUM_NO_ZERO
+
#define MAX_INFO_LEN 256
static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
@@ -190,9 +194,9 @@ static bool transdata_check_local_center(TransInfo *t, short around)
{
return ((around == V3D_LOCAL) && (
(t->flag & (T_OBJECT | T_POSE)) ||
- (t->obedit && ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
+ (t->obedit && ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE)) ||
(t->spacetype == SPACE_IPO) ||
- (t->options & (CTX_MOVIECLIP | CTX_MASK)))
+ (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))
);
}
@@ -263,17 +267,28 @@ static void convertViewVec2D_mask(View2D *v2d, float r_vec[3], int dx, int dy)
void convertViewVec(TransInfo *t, float r_vec[3], int dx, int dy)
{
if ((t->spacetype == SPACE_VIEW3D) && (t->ar->regiontype == RGN_TYPE_WINDOW)) {
- const float mval_f[2] = {(float)dx, (float)dy};
- ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac);
+ if (t->options & CTX_PAINT_CURVE) {
+ r_vec[0] = dx;
+ r_vec[1] = dy;
+ }
+ else {
+ const float mval_f[2] = {(float)dx, (float)dy};
+ ED_view3d_win_to_delta(t->ar, mval_f, r_vec, t->zfac);
+ }
}
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);
@@ -334,7 +349,6 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
SpaceImage *sima = t->sa->spacedata.first;
if (t->options & CTX_MASK) {
- /* not working quite right, TODO (see below too) */
float aspx, aspy;
float v[2];
@@ -347,14 +361,15 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
BKE_mask_coord_to_image(sima->image, &sima->iuser, v, v);
- v[0] = v[0] / aspx;
- v[1] = v[1] / aspy;
-
ED_image_point_pos__reverse(sima, t->ar, v, v);
adr[0] = v[0];
adr[1] = v[1];
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ adr[0] = vec[0];
+ adr[1] = vec[1];
+ }
else {
float aspx, aspy, v[2];
@@ -405,7 +420,6 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
MovieClip *clip = ED_space_clip_get_clip(sc);
if (clip) {
- /* not working quite right, TODO (see above too) */
float aspx, aspy;
float v[2];
@@ -418,9 +432,6 @@ void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DPr
BKE_mask_coord_to_movieclip(sc->clip, &sc->user, v, v);
- v[0] = v[0] / aspx;
- v[1] = v[1] / aspy;
-
ED_clip_point_stable_pos__reverse(sc, t->ar, v, v);
adr[0] = v[0];
@@ -460,7 +471,11 @@ void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV
switch (t->spacetype) {
case SPACE_VIEW3D:
{
- if (t->ar->regiontype == RGN_TYPE_WINDOW) {
+ if (t->options & CTX_PAINT_CURVE) {
+ adr[0] = vec[0];
+ adr[1] = vec[1];
+ }
+ else if (t->ar->regiontype == RGN_TYPE_WINDOW) {
/* allow points behind the view [#33643] */
if (ED_view3d_project_float_global(t->ar, vec, adr, flag) != V3D_PROJ_RET_OK) {
/* XXX, 2.64 and prior did this, weak! */
@@ -488,7 +503,7 @@ void projectFloatView(TransInfo *t, const float vec[3], float adr[2])
void applyAspectRatio(TransInfo *t, float vec[2])
{
- if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION)) {
+ if ((t->spacetype == SPACE_IMAGE) && (t->mode == TFM_TRANSLATION) && !(t->options & CTX_PAINT_CURVE)) {
SpaceImage *sima = t->sa->spacedata.first;
float aspx, aspy;
@@ -565,17 +580,23 @@ void removeAspectRatio(TransInfo *t, float vec[2])
static void viewRedrawForce(const bContext *C, TransInfo *t)
{
if (t->spacetype == SPACE_VIEW3D) {
- /* Do we need more refined tags? */
- if (t->flag & T_POSE)
- WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
- else
- WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
+ if (t->options & CTX_PAINT_CURVE) {
+ wmWindow *window = CTX_wm_window(C);
+ WM_paint_cursor_tag_redraw(window, t->ar);
+ }
+ else {
+ /* Do we need more refined tags? */
+ if (t->flag & T_POSE)
+ WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
+ else
+ WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
- /* for realtime animation record - send notifiers recognised by animation editors */
- // XXX: is this notifier a lame duck?
- if ((t->animtimer) && IS_AUTOKEY_ON(t->scene))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
-
+ /* for realtime animation record - send notifiers recognised by animation editors */
+ // XXX: is this notifier a lame duck?
+ if ((t->animtimer) && IS_AUTOKEY_ON(t->scene))
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
+
+ }
}
else if (t->spacetype == SPACE_ACTION) {
//SpaceAction *saction = (SpaceAction *)t->sa->spacedata.first;
@@ -601,6 +622,10 @@ static void viewRedrawForce(const bContext *C, TransInfo *t)
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ wmWindow *window = CTX_wm_window(C);
+ WM_paint_cursor_tag_redraw(window, t->ar);
+ }
else {
// XXX how to deal with lock?
SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
@@ -654,7 +679,7 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
allqueue(REDRAWIMAGE, 0);
allqueue(REDRAWVIEW3D, 0);
}
- else if (ELEM3(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
+ else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_IPO)) {
allqueue(REDRAWVIEW3D, 0);
allqueue(REDRAWACTION, 0);
allqueue(REDRAWNLA, 0);
@@ -977,7 +1002,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_TRANSLATE:
/* only switch when... */
- if (ELEM5(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
resetTransModal(t);
resetTransRestrictions(t);
restoreTransObjects(t);
@@ -994,11 +1019,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
else {
if (t->obedit && t->obedit->type == OB_MESH) {
- if ((t->mode == TFM_TRANSLATION) &&
- (t->spacetype == SPACE_VIEW3D) &&
- /* prevents accidental select-tweak, gkey. see: T40102 */
- (ISMOUSE(t->launch_event) == 0))
- {
+ if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) {
resetTransModal(t);
resetTransRestrictions(t);
restoreTransObjects(t);
@@ -1037,7 +1058,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case TFM_MODAL_ROTATE:
/* only switch when... */
if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) {
- if (ELEM6(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
resetTransModal(t);
resetTransRestrictions(t);
@@ -1057,7 +1078,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case TFM_MODAL_RESIZE:
/* only switch when... */
- if (ELEM5(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
/* Scale isn't normally very useful after extrude along normals, see T39756 */
if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_MANIP_NORMAL)) {
@@ -1320,7 +1341,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case GKEY:
/* only switch when... */
- if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL) ) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
resetTransModal(t);
resetTransRestrictions(t);
restoreTransObjects(t);
@@ -1332,7 +1353,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
break;
case SKEY:
/* only switch when... */
- if (ELEM3(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL) ) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) {
resetTransModal(t);
resetTransRestrictions(t);
restoreTransObjects(t);
@@ -1345,7 +1366,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
case RKEY:
/* only switch when... */
if (!(t->options & CTX_TEXTURE)) {
- if (ELEM4(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION) ) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) {
resetTransModal(t);
resetTransRestrictions(t);
@@ -1730,7 +1751,7 @@ static void drawHelpline(bContext *UNUSED(C), int x, int y, void *customdata)
{
float dx = t->mval[0] - cent[0], dy = t->mval[1] - cent[1];
float angle = atan2f(dy, dx);
- float dist = sqrtf(dx * dx + dy * dy);
+ float dist = hypotf(dx, dy);
float delta_angle = min_ff(15.0f / dist, (float)M_PI / 4.0f);
float spacing_angle = min_ff(5.0f / dist, (float)M_PI / 12.0f);
UI_ThemeColor(TH_VIEW_OVERLAY);
@@ -1819,24 +1840,26 @@ static void drawAutoKeyWarning(TransInfo *UNUSED(t), ARegion *ar)
BLF_width_and_height_default(printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]);
- xco = rect.xmax - (int)printable_size[0] - 10;
- yco = rect.ymax - (int)printable_size[1] - 10;
+ xco = (rect.xmax - U.widget_unit) - (int)printable_size[0];
+ yco = (rect.ymax - U.widget_unit);
/* warning text (to clarify meaning of overlays)
* - original color was red to match the icon, but that clashes badly with a less nasty border
*/
UI_ThemeColorShade(TH_TEXT_HI, -50);
#ifdef WITH_INTERNATIONAL
- BLF_draw_default(xco, ar->winy - 17, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
#else
- BLF_draw_default_ascii(xco, ar->winy - 17, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
+ BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX);
#endif
/* autokey recording icon... */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
- xco -= (ICON_DEFAULT_WIDTH + 2);
+ xco -= U.widget_unit;
+ yco -= (int)printable_size[1] / 2;
+
UI_icon_draw(xco, yco, ICON_REC);
glDisable(GL_BLEND);
@@ -2032,7 +2055,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
initTransInfo(C, t, op, event);
if (t->spacetype == SPACE_VIEW3D) {
- //calc_manipulator_stats(curarea);
initTransformOrientation(C, t);
t->draw_handle_apply = ED_region_draw_cb_activate(t->ar->type, drawTransformApply, t, REGION_DRAW_PRE_VIEW);
@@ -2077,7 +2099,7 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
* moded are available from manipulator and doing such check could
* lead to keymap conflicts for other modes (see #31584)
*/
- if (ELEM3(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
+ if (ELEM(mode, TFM_TRANSLATION, TFM_ROTATION, TFM_RESIZE)) {
wmKeyMapItem *kmi;
for (kmi = t->keymap->items.first; kmi; kmi = kmi->next) {
@@ -2853,7 +2875,7 @@ static void Bend(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN * 2];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bend Angle: %s Radius: %s Alt, Clamp %s"),
&c[0], &c[NUM_STR_REP_LEN],
@@ -3021,7 +3043,7 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shear: %s %s"), c, t->proptext);
}
@@ -3097,9 +3119,11 @@ static void initResize(TransInfo *t)
t->num.flag |= NUM_AFFECT_ALL;
if (!t->obedit) {
t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
t->num.val_flag[1] |= NUM_NO_ZERO;
t->num.val_flag[2] |= NUM_NO_ZERO;
+#endif
}
t->idx_max = 2;
@@ -3120,7 +3144,7 @@ static void headerResize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec);
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
}
else {
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
@@ -3389,9 +3413,11 @@ static void initSkinResize(TransInfo *t)
t->num.flag |= NUM_AFFECT_ALL;
if (!t->obedit) {
t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
t->num.val_flag[1] |= NUM_NO_ZERO;
t->num.val_flag[2] |= NUM_NO_ZERO;
+#endif
}
t->idx_max = 2;
@@ -3532,7 +3558,7 @@ static void applyToSphere(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("To Sphere: %s %s"), c, t->proptext);
}
@@ -3604,8 +3630,15 @@ static void initRotation(TransInfo *t)
if (t->flag & T_2D_EDIT)
t->flag |= T_NO_CONSTRAINT;
- negate_v3_v3(t->axis, t->viewinv[2]);
- normalize_v3(t->axis);
+ if (t->options & CTX_PAINT_CURVE) {
+ t->axis[0] = 0.0;
+ t->axis[1] = 0.0;
+ t->axis[2] = -1.0;
+ }
+ else {
+ negate_v3_v3(t->axis, t->viewinv[2]);
+ normalize_v3(t->axis);
+ }
copy_v3_v3(t->axis_orig, t->axis);
}
@@ -3639,7 +3672,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
if (td->flag & TD_USEQUAT) {
- mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(fmat, td->smtx, mat, td->mtx);
mat3_to_quat(quat, fmat); // Actual transform
if (td->ext->quat) {
@@ -3709,7 +3742,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
if ((t->flag & T_V3D_ALIGN) == 0) { /* align mode doesn't rotate objects itself */
/* euler or quaternion/axis-angle? */
if (td->ext->rotOrder == ROT_MODE_QUAT) {
- mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
mat3_to_quat(quat, fmat); /* Actual transform */
@@ -3724,7 +3757,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
- mul_serie_m3(fmat, td->ext->r_mtx, mat, td->ext->r_smtx, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(fmat, td->ext->r_smtx, mat, td->ext->r_mtx);
mat3_to_quat(quat, fmat); /* Actual transform */
mul_qt_qtqt(tquat, quat, iquat);
@@ -3781,7 +3814,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
if ((td->ext->rotOrder == ROT_MODE_QUAT) || (td->flag & TD_USEQUAT)) {
/* can be called for texture space translate for example, then opt out */
if (td->ext->quat) {
- mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(fmat, td->smtx, mat, td->mtx);
mat3_to_quat(quat, fmat); // Actual transform
mul_qt_qtqt(td->ext->quat, quat, td->ext->iquat);
@@ -3795,7 +3828,7 @@ static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short
axis_angle_to_quat(iquat, td->ext->irotAxis, td->ext->irotAngle);
- mul_serie_m3(fmat, td->mtx, mat, td->smtx, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(fmat, td->smtx, mat, td->mtx);
mat3_to_quat(quat, fmat); // Actual transform
mul_qt_qtqt(tquat, quat, iquat);
@@ -3889,7 +3922,7 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Rot: %s %s %s"), &c[0], t->con.text, t->proptext);
}
@@ -3993,7 +4026,7 @@ static void applyTrackball(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN * 2];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, IFACE_("Trackball: %s %s %s"),
&c[0], &c[NUM_STR_REP_LEN], t->proptext);
@@ -4034,6 +4067,9 @@ static void initTranslation(TransInfo *t)
{
if (t->spacetype == SPACE_ACTION) {
/* this space uses time translate */
+ BKE_report(t->reports, RPT_ERROR,
+ "Use 'Time_Translate' transform mode instead of 'Translation' mode "
+ "for translating keyframes in Dope Sheet Editor");
t->state = TRANS_CANCEL;
}
@@ -4095,7 +4131,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char str[MAX_INFO_LEN]
float dist;
if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec);
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
dist = len_v3(t->num.val);
}
else {
@@ -4343,7 +4379,7 @@ static void applyShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Shrink/Fatten:"), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
ofs += BLI_snprintf(str + ofs, MAX_INFO_LEN - ofs, " %s", c);
}
else {
@@ -4438,7 +4474,7 @@ static void applyTilt(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Tilt: %s° %s"), &c[0], t->proptext);
@@ -4492,7 +4528,9 @@ static void initCurveShrinkFatten(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
+#endif
t->flag |= T_NO_CONSTRAINT;
}
@@ -4514,7 +4552,7 @@ static void applyCurveShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Shrink/Fatten: %s"), c);
}
else {
@@ -4567,7 +4605,9 @@ static void initMaskShrinkFatten(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
t->flag |= T_NO_ZERO;
+#ifdef USE_NUM_NO_ZERO
t->num.val_flag[0] |= NUM_NO_ZERO;
+#endif
t->flag |= T_NO_CONSTRAINT;
}
@@ -4590,7 +4630,7 @@ static void applyMaskShrinkFatten(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Feather Shrink/Fatten: %s"), c);
}
else {
@@ -4683,7 +4723,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Push/Pull: %s%s %s"), c, t->con.text, t->proptext);
}
@@ -4742,7 +4782,7 @@ static void initBevelWeight(TransInfo *t)
t->mode = TFM_BWEIGHT;
t->transform = applyBevelWeight;
- initMouseInputMode(t, &t->mouse, INPUT_SPRING);
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
t->idx_max = 0;
t->num.idx_max = 0;
@@ -4766,7 +4806,6 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
weight = t->values[0];
- weight -= 1.0f;
if (weight > 1.0f) weight = 1.0f;
snapGridIncrement(t, &weight);
@@ -4777,7 +4816,7 @@ static void applyBevelWeight(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
if (weight >= 0.0f)
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Bevel Weight: +%s %s"), c, t->proptext);
@@ -4821,7 +4860,7 @@ static void initCrease(TransInfo *t)
t->mode = TFM_CREASE;
t->transform = applyCrease;
- initMouseInputMode(t, &t->mouse, INPUT_SPRING);
+ initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA);
t->idx_max = 0;
t->num.idx_max = 0;
@@ -4845,7 +4884,6 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
crease = t->values[0];
- crease -= 1.0f;
if (crease > 1.0f) crease = 1.0f;
snapGridIncrement(t, &crease);
@@ -4856,7 +4894,7 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
if (crease >= 0.0f)
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Crease: +%s %s"), c, t->proptext);
@@ -4926,7 +4964,7 @@ static void headerBoneSize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec);
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
}
else {
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", vec[0]);
@@ -5063,7 +5101,7 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Envelope: %s"), c);
}
else {
@@ -5436,7 +5474,17 @@ static bool createEdgeSlideVerts(TransInfo *t)
while (1) {
float vec_a[3], vec_b[3];
BMLoop *l_a, *l_b;
+ BMLoop *l_a_prev, *l_b_prev;
BMVert *v_first;
+ /* If this succeeds call get_next_loop()
+ * which calculates the direction to slide based on clever checks.
+ *
+ * otherwise we simply use 'e_dir' as an edge-rail.
+ * (which is better when the attached edge is a boundary, see: T40422)
+ */
+#define EDGESLIDE_VERT_IS_INNER(v, e_dir) \
+ ((BM_edge_is_boundary(e_dir) == false) && \
+ (BM_vert_edge_count_nonwire(v) == 2))
v = NULL;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@@ -5457,7 +5505,6 @@ static bool createEdgeSlideVerts(TransInfo *t)
e = v->e;
/*first, rewind*/
- numsel = 0;
do {
e = get_other_edge(v, e);
if (!e) {
@@ -5465,8 +5512,6 @@ static bool createEdgeSlideVerts(TransInfo *t)
break;
}
- numsel += 1;
-
if (!BM_elem_flag_test(BM_edge_other_vert(e, v), BM_ELEM_TAG))
break;
@@ -5486,10 +5531,12 @@ static bool createEdgeSlideVerts(TransInfo *t)
}
else {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
- if (BM_vert_edge_count_nonwire(v) == 2)
+ if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
get_next_loop(v, l_a, e, l_tmp->e, vec_a);
- else
+ }
+ else {
sub_v3_v3v3(vec_a, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
+ }
}
}
@@ -5501,17 +5548,21 @@ static bool createEdgeSlideVerts(TransInfo *t)
}
else {
BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
- if (BM_vert_edge_count_nonwire(v) == 2)
+ if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
get_next_loop(v, l_b, e, l_tmp->e, vec_b);
- else
+ }
+ else {
sub_v3_v3v3(vec_b, BM_edge_other_vert(l_tmp->e, v)->co, v->co);
-
+ }
}
}
else {
l_b = NULL;
}
+ l_a_prev = NULL;
+ l_b_prev = NULL;
+
/*iterate over the loop*/
v_first = v;
do {
@@ -5529,14 +5580,14 @@ static bool createEdgeSlideVerts(TransInfo *t)
copy_v3_v3(sv->v_co_orig, v->co);
sv->loop_nr = loop_nr;
- if (l_a) {
- BMLoop *l_tmp = BM_loop_other_edge_loop(l_a, v);
+ 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);
}
- if (l_b) {
- BMLoop *l_tmp = BM_loop_other_edge_loop(l_b, v);
+ 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);
}
@@ -5558,7 +5609,7 @@ 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);
- if (BM_vert_edge_count_nonwire(v) == 2) {
+ if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
get_next_loop(v, l_a, e_prev, l_tmp->e, sv->dir_a);
}
else {
@@ -5569,7 +5620,7 @@ static bool createEdgeSlideVerts(TransInfo *t)
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);
- if (BM_vert_edge_count_nonwire(v) == 2) {
+ if (EDGESLIDE_VERT_IS_INNER(v, l_tmp->e)) {
get_next_loop(v, l_b, e_prev, l_tmp->e, sv->dir_b);
}
else {
@@ -5585,29 +5636,54 @@ static bool createEdgeSlideVerts(TransInfo *t)
l_a_ok_prev = (l_a != NULL);
l_b_ok_prev = (l_b != NULL);
- l_a = l_a ? get_next_loop(v, l_a, e_prev, e, vec_a) : NULL;
- l_b = l_b ? get_next_loop(v, l_b, e_prev, e, vec_b) : NULL;
-
- /* find the opposite loop if it was missing previously */
- if (l_a == NULL && l_b && (l_b->radial_next != l_b)) l_a = l_b->radial_next;
- else if (l_b == NULL && l_a && (l_a->radial_next != l_a)) l_b = l_a->radial_next;
-
- /* if there are non-contiguous faces, we can still recover the loops of the new edges faces */
- /* note!, the behavior in this case means edges may move in opposite directions,
- * this could be made to work more usefully. */
- if (!(l_a && l_b) && (e->l != NULL)) {
- if (l_a_ok_prev) {
- l_a = e->l;
- if (l_a->radial_next != l_a) {
- l_b = l_a->radial_next;
- }
+ l_a_prev = l_a;
+ l_b_prev = l_b;
+
+ if (l_a) {
+ l_a = get_next_loop(v, l_a, e_prev, e, vec_a);
+ }
+ else {
+ zero_v3(vec_a);
+ }
+
+ if (l_b) {
+ l_b = get_next_loop(v, l_b, e_prev, e, vec_b);
+ }
+ else {
+ zero_v3(vec_b);
+ }
+
+
+ if (l_a && l_b) {
+ /* pass */
+ }
+ else {
+ if (l_a || l_b) {
+ /* find the opposite loop if it was missing previously */
+ if (l_a == NULL && l_b && (l_b->radial_next != l_b)) l_a = l_b->radial_next;
+ else if (l_b == NULL && l_a && (l_a->radial_next != l_a)) l_b = l_a->radial_next;
}
- else if (l_b_ok_prev) {
- l_b = e->l;
- if (l_b->radial_next != l_b) {
- l_a = l_b->radial_next;
+ else if (e->l != NULL) {
+ /* if there are non-contiguous faces, we can still recover the loops of the new edges faces */
+ /* note!, the behavior in this case means edges may move in opposite directions,
+ * this could be made to work more usefully. */
+
+ if (l_a_ok_prev) {
+ l_a = e->l;
+ l_b = (l_a->radial_next != l_a) ? l_a->radial_next : NULL;
+ }
+ else if (l_b_ok_prev) {
+ l_b = e->l;
+ l_a = (l_b->radial_next != l_b) ? l_b->radial_next : NULL;
}
}
+
+ if (!l_a_ok_prev && l_a) {
+ get_next_loop(v, l_a, e, e_prev, vec_a);
+ }
+ if (!l_b_ok_prev && l_b) {
+ get_next_loop(v, l_b, e, e_prev, vec_b);
+ }
}
BM_elem_flag_disable(v, BM_ELEM_TAG);
@@ -5615,6 +5691,8 @@ static bool createEdgeSlideVerts(TransInfo *t)
} while ((e != v_first->e) && (l_a || l_b));
loop_nr++;
+
+#undef EDGESLIDE_VERT_IS_INNER
}
/* use for visibility checks */
@@ -6198,7 +6276,7 @@ static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
if (is_proportional) {
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Edge Slide: %s (E)ven: %s"),
@@ -6721,7 +6799,7 @@ static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
ofs += BLI_strncpy_rlen(str + ofs, IFACE_("Vert Slide: "), MAX_INFO_LEN - ofs);
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
ofs += BLI_strncpy_rlen(str + ofs, &c[0], MAX_INFO_LEN - ofs);
}
else {
@@ -6788,7 +6866,7 @@ static void applyBoneRoll(TransInfo *t, const int UNUSED(mval[2]))
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Roll: %s"), &c[0]);
}
@@ -6862,7 +6940,7 @@ static void applyBakeTime(TransInfo *t, const int mval[2])
if (hasNumInput(&t->num)) {
char c[NUM_STR_REP_LEN];
- outputNumInput(&(t->num), c);
+ outputNumInput(&(t->num), c, &t->scene->unit);
if (time >= 0.0f)
BLI_snprintf(str, MAX_INFO_LEN, IFACE_("Time: +%s %s"), c, t->proptext);
@@ -7073,7 +7151,7 @@ static void headerSeqSlide(TransInfo *t, float val[2], char str[MAX_INFO_LEN])
size_t ofs = 0;
if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec);
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
}
else {
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.0f, %.0f", val[0], val[1]);
@@ -7299,7 +7377,7 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
/* if numeric input is active, use results from that, otherwise apply snapping to result */
if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec);
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
}
else {
const Scene *scene = t->scene;
@@ -7316,13 +7394,17 @@ static void headerTimeTranslate(TransInfo *t, char str[MAX_INFO_LEN])
/* second step */
val = floorf((double)val / secf + 0.5);
}
- else {
- /* nearest frame/second/marker */
+ else if (autosnap == SACTSNAP_SECOND) {
+ /* nearest second */
val = (float)((double)val / secf);
}
if (autosnap == SACTSNAP_FRAME)
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%d.00 (%.4f)", (int)val, val);
+ else if (autosnap == SACTSNAP_SECOND)
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%d.00 sec (%.4f)", (int)val, val);
+ else if (autosnap == SACTSNAP_TSTEP)
+ BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", val);
else
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", val);
}
@@ -7459,7 +7541,7 @@ static void headerTimeSlide(TransInfo *t, float sval, char str[MAX_INFO_LEN])
char tvec[NUM_STR_REP_LEN * 3];
if (hasNumInput(&t->num)) {
- outputNumInput(&(t->num), tvec);
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
}
else {
float minx = *((float *)(t->customData));
@@ -7607,7 +7689,7 @@ static void headerTimeScale(TransInfo *t, char str[MAX_INFO_LEN])
char tvec[NUM_STR_REP_LEN * 3];
if (hasNumInput(&t->num))
- outputNumInput(&(t->num), tvec);
+ outputNumInput(&(t->num), tvec, &t->scene->unit);
else
BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", t->values[0]);
@@ -7673,17 +7755,11 @@ static void applyTimeScale(TransInfo *t, const int UNUSED(mval[2]))
/* TODO, move to: transform_queries.c */
-bool checkUseLocalCenter_GraphEdit(TransInfo *t)
-{
- return ((t->around == V3D_LOCAL) &&
- !ELEM4(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE));
-}
-
bool checkUseAxisMatrix(TransInfo *t)
{
/* currently only checks for editmode */
if (t->flag & T_EDIT) {
- if ((t->around == V3D_LOCAL) && (ELEM4(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) {
+ if ((t->around == V3D_LOCAL) && (ELEM(t->obedit->type, OB_MESH, OB_CURVE, OB_MBALL, OB_ARMATURE))) {
/* not all editmode supports axis-matrix */
return true;
}
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index f34d2050853..67d55639528 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -61,6 +61,7 @@ struct wmEvent;
struct wmTimer;
struct ARegion;
struct ReportList;
+struct EditBone;
/* transinfo->redraw */
typedef enum {
@@ -129,15 +130,15 @@ typedef struct TransDataExtension {
// float drotAxis[3]; /* Initial object drotAxis, TODO: not yet implemented */
float dquat[4]; /* Initial object dquat */
float dscale[3]; /* Initial object dscale */
- float *rot; /* Rotation of the data to transform (Faculative) */
+ float *rot; /* Rotation of the data to transform */
float irot[3]; /* Initial rotation */
- float *quat; /* Rotation quaternion of the data to transform (Faculative) */
+ float *quat; /* Rotation quaternion of the data to transform */
float iquat[4]; /* Initial rotation quaternion */
- float *rotAngle; /* Rotation angle of the data to transform (Faculative) */
+ float *rotAngle; /* Rotation angle of the data to transform */
float irotAngle; /* Initial rotation angle */
- float *rotAxis; /* Rotation axis of the data to transform (Faculative) */
+ float *rotAxis; /* Rotation axis of the data to transform */
float irotAxis[4]; /* Initial rotation axis */
- float *size; /* Size of the data to transform (Faculative) */
+ float *size; /* Size of the data to transform */
float isize[3]; /* Initial size */
float obmat[4][4]; /* Object matrix */
float l_smtx[3][3]; /* use instead of td->smtx, It is the same but without the 'bone->bone_mat', see TD_PBONE_LOCAL_MTX_C */
@@ -251,6 +252,17 @@ typedef struct VertSlideData {
int curr_sv_index;
} VertSlideData;
+typedef struct BoneInitData {
+ struct EditBone *bone;
+ float tail[3];
+ float rad_tail;
+ float roll;
+ float head[3];
+ float dist;
+ float xwidth;
+ float zwidth;
+} BoneInitData;
+
typedef struct TransData {
float dist; /* Distance needed to affect element (for Proportionnal Editing) */
float rdist; /* Distance to the nearest element (for Proportionnal Editing) */
@@ -520,10 +532,11 @@ void flushTransNodes(TransInfo *t);
void flushTransSeq(TransInfo *t);
void flushTransTracking(TransInfo *t);
void flushTransMasking(TransInfo *t);
+void flushTransPaintCurve(TransInfo *t);
+void restoreBones(TransInfo *t);
/*********************** exported from transform_manipulator.c ********** */
bool gimbal_axis(struct Object *ob, float gmat[3][3]); /* return 0 when no gimbal for selection */
-int calc_manipulator_stats(const struct bContext *C);
/*********************** TransData Creation and General Handling *********** */
void createTransData(struct bContext *C, TransInfo *t);
@@ -600,6 +613,7 @@ typedef enum {
INPUT_VECTOR,
INPUT_SPRING,
INPUT_SPRING_FLIP,
+ INPUT_SPRING_DELTA,
INPUT_ANGLE,
INPUT_ANGLE_SPRING,
INPUT_TRACKBALL,
@@ -608,7 +622,7 @@ typedef enum {
INPUT_VERTICAL_RATIO,
INPUT_VERTICAL_ABSOLUTE,
INPUT_CUSTOM_RATIO,
- INPUT_CUSTOM_RATIO_FLIP
+ INPUT_CUSTOM_RATIO_FLIP,
} MouseInputMode;
void initMouseInput(TransInfo *t, MouseInput *mi, const float center[2], const int mval[2]);
@@ -679,7 +693,6 @@ void freeVertSlideVerts(TransInfo *t);
/* TODO. transform_queries.c */
-bool checkUseLocalCenter_GraphEdit(TransInfo *t);
bool checkUseAxisMatrix(TransInfo *t);
#endif
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index 79f266df607..d8f17315c01 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -663,7 +663,7 @@ void drawConstraint(TransInfo *t)
{
TransCon *tc = &(t->con);
- if (!ELEM3(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE))
+ if (!ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE))
return;
if (!(tc->mode & CON_APPLY))
return;
@@ -756,6 +756,9 @@ void drawPropCircle(const struct bContext *C, TransInfo *t)
/* 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);
}
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 949ee79a3dc..16c4a87b763 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -33,6 +33,7 @@
#include <math.h>
#include "DNA_anim_types.h"
+#include "DNA_brush_types.h"
#include "DNA_armature_types.h"
#include "DNA_lattice_types.h"
#include "DNA_mesh_types.h"
@@ -80,6 +81,7 @@
#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_particle.h"
+#include "BKE_paint.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
#include "BKE_rigidbody.h"
@@ -124,8 +126,8 @@
static void transform_around_single_fallback(TransInfo *t)
{
if ((t->total == 1) &&
- (ELEM3(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) &&
- (ELEM3(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL)))
+ (ELEM(t->around, V3D_CENTER, V3D_CENTROID, V3D_ACTIVE)) &&
+ (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL)))
{
t->around = V3D_LOCAL;
}
@@ -247,7 +249,7 @@ static void set_prop_dist(TransInfo *t, const bool with_dist)
}
dist_sq = len_squared_v3(vec);
- if ((tob->rdist == -1.0f) || (dist_sq < (tob->rdist * tob->rdist))) {
+ if ((tob->rdist == -1.0f) || (dist_sq < SQUARE(tob->rdist))) {
tob->rdist = sqrtf(dist_sq);
}
}
@@ -282,7 +284,7 @@ static void createTransTexspace(TransInfo *t)
}
id = ob->data;
- if (id == NULL || !ELEM3(GS(id->name), ID_ME, ID_CU, ID_MB)) {
+ if (id == NULL || !ELEM(GS(id->name), ID_ME, ID_CU, ID_MB)) {
BKE_report(t->reports, RPT_ERROR, "Unsupported object type for text-space transform");
t->total = 0;
return;
@@ -584,12 +586,12 @@ static void add_pose_transdata(TransInfo *t, bPoseChannel *pchan, Object *ob, Tr
if (constraints_list_needinv(t, &pchan->constraints)) {
copy_m3_m4(tmat, pchan->constinv);
invert_m3_m3(cmat, tmat);
- mul_serie_m3(td->mtx, pmat, omat, cmat, NULL, NULL, NULL, NULL, NULL);
- mul_serie_m3(td->ext->r_mtx, rpmat, omat, cmat, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(td->mtx, cmat, omat, pmat);
+ mul_m3_series(td->ext->r_mtx, cmat, omat, rpmat);
}
else {
- mul_serie_m3(td->mtx, pmat, omat, NULL, NULL, NULL, NULL, NULL, NULL);
- mul_serie_m3(td->ext->r_mtx, rpmat, omat, NULL, NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(td->mtx, omat, pmat);
+ mul_m3_series(td->ext->r_mtx, omat, rpmat);
}
invert_m3_m3(td->ext->r_smtx, td->ext->r_mtx);
}
@@ -1052,18 +1054,64 @@ static void createTransPose(TransInfo *t, Object *ob)
if (ik_on) transform_autoik_update(t, 0);
}
-/* ********************* armature ************** */
+void restoreBones(TransInfo *t)
+{
+ bArmature *arm = t->obedit->data;
+ BoneInitData *bid = t->customData;
+ EditBone *ebo;
+
+ while (bid->bone) {
+ ebo = bid->bone;
+
+ ebo->dist = bid->dist;
+ ebo->rad_tail = bid->rad_tail;
+ ebo->roll = bid->roll;
+ ebo->xwidth = bid->xwidth;
+ ebo->zwidth = bid->zwidth;
+ copy_v3_v3(ebo->head, bid->head);
+ copy_v3_v3(ebo->tail, bid->tail);
+
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ EditBone *ebo_child;
+
+ /* Also move connected ebo_child, in case ebo_child's name aren't mirrored properly */
+ for (ebo_child = arm->edbo->first; ebo_child; ebo_child = ebo_child->next) {
+ if ((ebo_child->flag & BONE_CONNECTED) && (ebo_child->parent == ebo)) {
+ copy_v3_v3(ebo_child->head, ebo->tail);
+ ebo_child->rad_head = ebo->rad_tail;
+ }
+ }
+ /* Also move connected parent, in case parent's name isn't mirrored properly */
+ if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
+ EditBone *parent = ebo->parent;
+ copy_v3_v3(parent->tail, ebo->head);
+ parent->rad_tail = ebo->rad_head;
+ }
+ }
+
+ bid++;
+ }
+}
+
+
+/* ********************* armature ************** */
static void createTransArmatureVerts(TransInfo *t)
{
- EditBone *ebo;
+ EditBone *ebo, *eboflip;
bArmature *arm = t->obedit->data;
ListBase *edbo = arm->edbo;
- TransData *td;
+ TransData *td, *td_old;
float mtx[3][3], smtx[3][3], bonemat[3][3];
+ bool mirror = ((arm->flag & ARM_MIRROR_EDIT) != 0);
+ int total_mirrored = 0, i;
+ int oldtot;
+ BoneInitData *bid;
t->total = 0;
for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ oldtot = t->total;
+
if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
if (t->mode == TFM_BONESIZE) {
if (ebo->flag & BONE_SELECTED)
@@ -1080,6 +1128,12 @@ static void createTransArmatureVerts(TransInfo *t)
t->total++;
}
}
+
+ if (mirror && (oldtot < t->total)) {
+ eboflip = ED_armature_bone_get_mirrored(arm->edbo, ebo);
+ if (eboflip)
+ total_mirrored++;
+ }
}
if (!t->total) return;
@@ -1091,7 +1145,15 @@ static void createTransArmatureVerts(TransInfo *t)
td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransEditBone");
+ if (mirror) {
+ t->customData = bid = MEM_mallocN((total_mirrored + 1) * sizeof(BoneInitData), "BoneInitData");
+ t->flag |= T_FREE_CUSTOMDATA;
+ }
+
+ i = 0;
+
for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ td_old = td;
ebo->oldlength = ebo->length; // length==0.0 on extrude, used for scaling radius of bone points
if (EBONE_VISIBLE(arm, ebo) && !(ebo->flag & BONE_EDITMODE_LOCKED)) {
@@ -1223,6 +1285,26 @@ static void createTransArmatureVerts(TransInfo *t)
}
}
}
+
+ if (mirror && (td_old != td)) {
+ eboflip = ED_armature_bone_get_mirrored(arm->edbo, ebo);
+ if (eboflip) {
+ bid[i].bone = eboflip;
+ bid[i].dist = eboflip->dist;
+ bid[i].rad_tail = eboflip->rad_tail;
+ bid[i].roll = eboflip->roll;
+ bid[i].xwidth = eboflip->xwidth;
+ bid[i].zwidth = eboflip->zwidth;
+ copy_v3_v3(bid[i].head, eboflip->head);
+ copy_v3_v3(bid[i].tail, eboflip->tail);
+ i++;
+ }
+ }
+ }
+
+ if (mirror) {
+ /* trick to terminate iteration */
+ bid[total_mirrored].bone = NULL;
}
}
@@ -1650,7 +1732,9 @@ static void createTransLatticeVerts(TransInfo *t)
if (bp->f1 & SELECT) {
td->flag = TD_SELECTED;
}
- else td->flag = 0;
+ else {
+ td->flag = 0;
+ }
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
@@ -1889,6 +1973,7 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
dists[i] = 0.0f;
}
}
+ bm->elem_index_dirty &= ~BM_VERT;
}
do {
@@ -1898,37 +1983,45 @@ static void editmesh_set_connectivity_distance(BMesh *bm, float mtx[3][3], float
memcpy(dists_prev, dists, sizeof(float) * bm->totvert);
while ((v = BLI_LINKSTACK_POP(queue))) {
- BMIter iter;
- BMEdge *e;
- BMLoop *l;
+ /* quick checks */
+ bool has_edges = (v->e != NULL);
+ bool has_faces = false;
/* connected edge-verts */
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == 0) {
- BMVert *v_other = BM_edge_other_vert(e, 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);
+ if (has_edges) {
+ BMIter iter;
+ BMEdge *e;
+
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ has_faces |= (BM_edge_is_wire(e) == false);
+
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN) == 0) {
+ BMVert *v_other = BM_edge_other_vert(e, 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);
+ }
}
}
}
}
- /* connected face-verts (excluding adjacent verts) */
- BM_ITER_ELEM (l, &iter, v, BM_LOOPS_OF_VERT) {
- if ((BM_elem_flag_test(l->f, BM_ELEM_HIDDEN) == 0) && (l->f->len > 3)) {
- BMLoop *l_end = l->prev;
- l = l->next->next;
- do {
- BMVert *v_other = l->v;
+ /* 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);
}
}
- } while ((l = l->next) != l_end);
+ }
}
}
}
@@ -2300,8 +2393,7 @@ static void createTransEditVerts(TransInfo *t)
quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]);
if (defmats)
- mul_serie_m3(mat, mtx, qmat, defmats[a],
- NULL, NULL, NULL, NULL, NULL);
+ mul_m3_series(mat, defmats[a], qmat, mtx);
else
mul_m3_m3m3(mat, mtx, qmat);
}
@@ -2622,7 +2714,7 @@ static void createTransUVs(bContext *C, TransInfo *t)
if (propconnected) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
- BLI_BITMAP_SET(island_enabled, element->island);
+ BLI_BITMAP_ENABLE(island_enabled, element->island);
}
}
@@ -2663,7 +2755,7 @@ static void createTransUVs(bContext *C, TransInfo *t)
if (propconnected) {
UvElement *element = BM_uv_element_get(elementmap, efa, l);
- if (!BLI_BITMAP_GET(island_enabled, element->island)) {
+ if (!BLI_BITMAP_TEST(island_enabled, element->island)) {
count_rejected++;
continue;
}
@@ -2702,8 +2794,8 @@ void flushTransUVs(TransInfo *t)
td->loc2d[1] = td->loc[1] * invy;
if ((sima->flag & SI_PIXELSNAP) && (t->state != TRANS_CANCEL)) {
- td->loc2d[0] = (float)floor(width * td->loc2d[0] + 0.5f) / width;
- td->loc2d[1] = (float)floor(height * td->loc2d[1] + 0.5f) / height;
+ td->loc2d[0] = floorf(width * td->loc2d[0] + 0.5f) / width;
+ td->loc2d[1] = floorf(height * td->loc2d[1] + 0.5f) / height;
}
}
}
@@ -2861,7 +2953,7 @@ static void createTransNlaData(bContext *C, TransInfo *t)
}
/* cleanup temp list */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return;
}
@@ -2994,15 +3086,15 @@ static void createTransNlaData(bContext *C, TransInfo *t)
}
/* cleanup temp list */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ********************* ACTION EDITOR ****************** */
-static int gpf_cmp_frame(void *thunk, void *a, void *b)
+static int gpf_cmp_frame(void *thunk, const void *a, const void *b)
{
- bGPDframe *frame_a = a;
- bGPDframe *frame_b = b;
+ const bGPDframe *frame_a = a;
+ const bGPDframe *frame_b = b;
if (frame_a->framenum < frame_b->framenum) return -1;
if (frame_a->framenum > frame_b->framenum) return 1;
@@ -3016,10 +3108,10 @@ static int gpf_cmp_frame(void *thunk, void *a, void *b)
return 0;
}
-static int masklay_shape_cmp_frame(void *thunk, void *a, void *b)
+static int masklay_shape_cmp_frame(void *thunk, const void *a, const void *b)
{
- MaskLayerShape *frame_a = a;
- MaskLayerShape *frame_b = b;
+ const MaskLayerShape *frame_a = a;
+ const MaskLayerShape *frame_b = b;
if (frame_a->frame < frame_b->frame) return -1;
if (frame_a->frame > frame_b->frame) return 1;
@@ -3183,7 +3275,7 @@ static void posttrans_action_clean(bAnimContext *ac, bAction *act)
}
/* free temp data */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ----------------------------- */
@@ -3458,7 +3550,7 @@ static void createTransActionData(bContext *C, TransInfo *t)
/* stop if trying to build list if nothing selected */
if (count == 0) {
/* cleanup temp list */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return;
}
@@ -3547,17 +3639,22 @@ static void createTransActionData(bContext *C, TransInfo *t)
}
/* cleanup temp list */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* ********************* GRAPH EDITOR ************************* */
+typedef struct TransDataGraph {
+ float unit_scale;
+} TransDataGraph;
+
/* Helper function for createTransGraphEditData, which is responsible for associating
* source data with transform data
*/
-static void bezt_to_transdata(TransData *td, TransData2D *td2d, AnimData *adt, BezTriple *bezt,
- int bi, short selected, short ishandle, short intvals,
- float mtx[3][3], float smtx[3][3])
+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 *loc = bezt->vec[bi];
const float *cent = bezt->vec[1];
@@ -3571,41 +3668,39 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, AnimData *adt, B
if (adt) {
td2d->loc[0] = BKE_nla_tweakedit_remap(adt, loc[0], NLATIME_CONVERT_MAP);
- td2d->loc[1] = loc[1];
+ td2d->loc[1] = loc[1] * 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];
+ td->center[1] = cent[1] * 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];
+ td2d->loc[1] = loc[1] * 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;
copy_v3_v3(td->iloc, td->loc);
}
- if (td->flag & TD_MOVEHANDLE1) {
+ if (!ishandle) {
td2d->h1 = bezt->vec[0];
- copy_v2_v2(td2d->ih1, td2d->h1);
- }
- else
- td2d->h1 = NULL;
-
- if (td->flag & TD_MOVEHANDLE2) {
td2d->h2 = bezt->vec[2];
+ copy_v2_v2(td2d->ih1, td2d->h1);
copy_v2_v2(td2d->ih2, td2d->h2);
}
- else
+ else {
+ td2d->h1 = NULL;
td2d->h2 = NULL;
+ }
memset(td->axismtx, 0, sizeof(td->axismtx));
td->axismtx[2][2] = 1.0f;
@@ -3630,6 +3725,18 @@ static void bezt_to_transdata(TransData *td, TransData2D *td2d, AnimData *adt, B
/* copy space-conversion matrices for dealing with non-uniform scales */
copy_m3_m3(td->mtx, mtx);
copy_m3_m3(td->smtx, smtx);
+
+ tdg->unit_scale = unit_scale;
+}
+
+static bool graph_edit_is_translation_mode(TransInfo *t)
+{
+ return ELEM(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE);
+}
+
+static bool graph_edit_use_local_center(TransInfo *t)
+{
+ return (t->around == V3D_LOCAL) && !graph_edit_is_translation_mode(t);
}
static void createTransGraphEditData(bContext *C, TransInfo *t)
@@ -3641,6 +3748,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
TransData *td = NULL;
TransData2D *td2d = NULL;
+ TransDataGraph *tdg = NULL;
bAnimContext ac;
ListBase anim_data = {NULL, NULL};
@@ -3651,8 +3759,9 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
int count = 0, i;
float cfra;
float mtx[3][3], smtx[3][3];
+ const bool is_translation_mode = graph_edit_is_translation_mode(t);
const bool use_handle = !(sipo->flag & SIPO_NOHANDLES);
- const bool use_local_center = checkUseLocalCenter_GraphEdit(t);
+ const bool use_local_center = graph_edit_use_local_center(t);
short anim_map_flag = ANIM_UNITCONV_ONLYSEL | ANIM_UNITCONV_SELVERTS;
/* determine what type of data we are operating on */
@@ -3699,11 +3808,11 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
/* only include BezTriples whose 'keyframe' occurs on the same side of the current frame as mouse */
for (i = 0, bezt = fcu->bezt; i < fcu->totvert; i++, bezt++) {
if (FrameOnMouseSide(t->frame_side, bezt->vec[1][0], cfra)) {
- const char sel2 = bezt->f2 & SELECT;
- const char sel1 = use_handle ? bezt->f1 & SELECT : sel2;
- const char sel3 = use_handle ? bezt->f3 & SELECT : sel2;
+ const bool sel2 = bezt->f2 & SELECT;
+ const bool sel1 = use_handle ? bezt->f1 & SELECT : sel2;
+ const bool sel3 = use_handle ? bezt->f3 & SELECT : sel2;
- if (ELEM4(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE)) {
+ if (is_translation_mode) {
/* for 'normal' pivots - just include anything that is selected.
* this works a bit differently in translation modes */
if (sel2) {
@@ -3714,9 +3823,9 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
if (sel3) count++;
}
}
- else if (sipo->around == V3D_LOCAL) {
- /* for local-pivot we only need to count the number of selected handles only, so that centerpoints don't
- * don't get moved wrong
+ else if (use_local_center) {
+ /* for local-pivot we only need to count the number of selected handles only,
+ * so that centerpoints don't get moved wrong
*/
if (bezt->ipo == BEZT_IPO_BEZ) {
if (sel1) count++;
@@ -3738,7 +3847,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
/* stop if trying to build list if nothing selected */
if (count == 0) {
/* cleanup temp list */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
return;
}
@@ -3748,9 +3857,12 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
t->data = MEM_callocN(t->total * sizeof(TransData), "TransData (Graph Editor)");
/* for each 2d vert a 3d vector is allocated, so that they can be treated just as if they were 3d verts */
t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D (Graph Editor)");
+ t->customData = MEM_callocN(t->total * sizeof(TransDataGraph), "TransDataGraph");
+ t->flag |= T_FREE_CUSTOMDATA;
td = t->data;
td2d = t->data2d;
+ tdg = t->customData;
/* precompute space-conversion matrices for dealing with non-uniform scaling of Graph Editor */
unit_m3(mtx);
@@ -3775,9 +3887,8 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
for (ale = anim_data.first; ale; ale = ale->next) {
AnimData *adt = ANIM_nla_mapping_get(&ac, ale);
FCurve *fcu = (FCurve *)ale->key_data;
- short intvals = (fcu->flag & FCURVE_INT_VALUES);
+ bool intvals = (fcu->flag & FCURVE_INT_VALUES);
float unit_scale;
- float scaled_mtx[3][3], scaled_smtx[3][3];
/* convert current-frame to action-time (slightly less accurate, especially under
* higher scaling ratios, but is faster than converting all points)
@@ -3793,17 +3904,12 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
unit_scale = ANIM_unit_mapping_get_factor(ac.scene, ale->id, ale->key_data, anim_map_flag);
- copy_m3_m3(scaled_mtx, mtx);
- copy_m3_m3(scaled_smtx, smtx);
- mul_v3_fl(scaled_mtx[1], unit_scale);
- mul_v3_fl(scaled_smtx[1], 1.0f / unit_scale);
-
/* 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 char sel2 = bezt->f2 & SELECT;
- const char sel1 = use_handle ? bezt->f1 & SELECT : sel2;
- const char sel3 = use_handle ? bezt->f3 & SELECT : sel2;
+ const bool sel2 = bezt->f2 & SELECT;
+ const bool sel1 = use_handle ? bezt->f1 & SELECT : sel2;
+ const bool sel3 = use_handle ? bezt->f3 & SELECT : sel2;
TransDataCurveHandleFlags *hdata = NULL;
/* short h1=1, h2=1; */ /* UNUSED */
@@ -3811,10 +3917,10 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
/* only include handles if selected, irrespective of the interpolation modes.
* also, only treat handles specially if the center point isn't selected.
*/
- if (!ELEM4(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE) || !(sel2)) {
+ if (!is_translation_mode || !(sel2)) {
if (sel1) {
hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, adt, bezt, 0, 1, 1, intvals, scaled_mtx, scaled_smtx);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 0, sel1, true, intvals, mtx, smtx, unit_scale);
}
else {
/* h1 = 0; */ /* UNUSED */
@@ -3823,7 +3929,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
if (sel3) {
if (hdata == NULL)
hdata = initTransDataCurveHandles(td, bezt);
- bezt_to_transdata(td++, td2d++, adt, bezt, 2, 1, 1, intvals, scaled_mtx, scaled_smtx);
+ bezt_to_transdata(td++, td2d++, tdg++, adt, bezt, 2, sel3, true, intvals, mtx, smtx, unit_scale);
}
else {
/* h2 = 0; */ /* UNUSED */
@@ -3831,10 +3937,9 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
}
/* only include main vert if selected */
- if (sel2 && (use_local_center == false)) {
-
+ if (sel2 && !use_local_center) {
/* move handles relative to center */
- if (ELEM4(t->mode, TFM_TRANSLATION, TFM_TIME_TRANSLATE, TFM_TIME_SLIDE, TFM_TIME_DUPLICATE)) {
+ if (is_translation_mode) {
if (sel1) td->flag |= TD_MOVEHANDLE1;
if (sel3) td->flag |= TD_MOVEHANDLE2;
}
@@ -3844,8 +3949,8 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
if (hdata == NULL)
hdata = initTransDataCurveHandles(td, bezt);
}
-
- bezt_to_transdata(td++, td2d++, adt, bezt, 1, 1, 0, intvals, scaled_mtx, scaled_smtx);
+
+ 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...):
@@ -3870,7 +3975,7 @@ static void createTransGraphEditData(bContext *C, TransInfo *t)
}
/* cleanup temp list */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
@@ -4083,14 +4188,19 @@ void flushTransGraphData(TransInfo *t)
SpaceIpo *sipo = (SpaceIpo *)t->sa->spacedata.first;
TransData *td;
TransData2D *td2d;
+ TransDataGraph *tdg;
Scene *scene = t->scene;
double secf = FPS;
int a;
/* flush to 2d vector from internally used 3d vector */
- for (a = 0, td = t->data, td2d = t->data2d; a < t->total; a++, td++, td2d++) {
+ for (a = 0, td = t->data, td2d = t->data2d, tdg = t->customData;
+ a < t->total;
+ a++, td++, td2d++, tdg++)
+ {
AnimData *adt = (AnimData *)td->extra; /* pointers to relevant AnimData blocks are stored in the td->extra pointers */
-
+ float inv_unit_scale = 1.0f / tdg->unit_scale;
+
/* handle snapping for time values
* - we should still be in NLA-mapping timespace
* - only apply to keyframes (but never to handles)
@@ -4147,16 +4257,16 @@ 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];
+ td2d->loc2d[1] = td2d->loc[1] * inv_unit_scale;
if ((td->flag & TD_MOVEHANDLE1) && td2d->h1) {
td2d->h1[0] = td2d->ih1[0] + td->loc[0] - td->iloc[0];
- td2d->h1[1] = td2d->ih1[1] + td->loc[1] - td->iloc[1];
+ td2d->h1[1] = td2d->ih1[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
}
if ((td->flag & TD_MOVEHANDLE2) && td2d->h2) {
td2d->h2[0] = td2d->ih2[0] + td->loc[0] - td->iloc[0];
- td2d->h2[1] = td2d->ih2[1] + td->loc[1] - td->iloc[1];
+ td2d->h2[1] = td2d->ih2[1] + (td->loc[1] - td->iloc[1]) * inv_unit_scale;
}
}
}
@@ -4681,18 +4791,24 @@ static bool constraints_list_needinv(TransInfo *t, ListBase *list)
if ((con->flag & CONSTRAINT_DISABLE) == 0 && (con->enforce != 0.0f)) {
/* (affirmative) returns for specific constraints here... */
/* constraints that require this regardless */
- if (ELEM5(con->type,
- CONSTRAINT_TYPE_CHILDOF,
- CONSTRAINT_TYPE_FOLLOWPATH,
- CONSTRAINT_TYPE_CLAMPTO,
- CONSTRAINT_TYPE_OBJECTSOLVER,
- CONSTRAINT_TYPE_FOLLOWTRACK))
+ if (ELEM(con->type,
+ CONSTRAINT_TYPE_FOLLOWPATH,
+ CONSTRAINT_TYPE_CLAMPTO,
+ CONSTRAINT_TYPE_OBJECTSOLVER,
+ CONSTRAINT_TYPE_FOLLOWTRACK))
{
return true;
}
/* constraints that require this only under special conditions */
- if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
+ if (con->type == CONSTRAINT_TYPE_CHILDOF) {
+ /* ChildOf constraint only works when using all location components, see T42256. */
+ bChildOfConstraint *data = (bChildOfConstraint *)con->data;
+
+ if ((data->flag & CHILDOF_LOCX) && (data->flag & CHILDOF_LOCY) && (data->flag & CHILDOF_LOCZ))
+ return true;
+ }
+ else if (con->type == CONSTRAINT_TYPE_ROTLIKE) {
/* CopyRot constraint only does this when rotating, and offset is on */
bRotateLikeConstraint *data = (bRotateLikeConstraint *)con->data;
@@ -5532,7 +5648,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
/* free temp memory */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
else if (ac.datatype == ANIMCONT_ACTION) { // TODO: just integrate into the above...
/* Depending on the lock status, draw necessary views */
@@ -5664,7 +5780,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
/* free temp memory */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* Make sure all F-Curves are set correctly, but not if transform was
@@ -5701,7 +5817,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
}
/* free temp memory */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
/* perform after-transfrom validation */
ED_nla_postop_refresh(&ac);
@@ -5762,6 +5878,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ /* pass */
+ }
else if ((t->scene->basact) &&
(ob = t->scene->basact->object) &&
(ob->mode & OB_MODE_PARTICLE_EDIT) &&
@@ -6627,6 +6746,8 @@ static void MaskHandleToTransData(MaskSplinePoint *point, eMaskWhichHandle which
td->flag = 0;
td->loc = td2d->loc;
mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
+ td->center[0] *= asp[0];
+ td->center[1] *= asp[1];
copy_v3_v3(td->iloc, td->loc);
memset(td->axismtx, 0, sizeof(td->axismtx));
@@ -6688,6 +6809,8 @@ static void MaskPointToTransData(Scene *scene, MaskSplinePoint *point,
td->flag = 0;
td->loc = td2d->loc;
mul_v2_m3v2(td->center, parent_matrix, bezt->vec[1]);
+ td->center[0] *= asp[0];
+ td->center[1] *= asp[1];
copy_v3_v3(td->iloc, td->loc);
memset(td->axismtx, 0, sizeof(td->axismtx));
@@ -6937,6 +7060,173 @@ void flushTransMasking(TransInfo *t)
}
}
+typedef struct TransDataPaintCurve {
+ PaintCurvePoint *pcp; /* initial curve point */
+ char id;
+} TransDataPaintCurve;
+
+
+#define PC_IS_ANY_SEL(pc) (((pc)->bez.f1 | (pc)->bez.f2 | (pc)->bez.f3) & SELECT)
+
+static void PaintCurveConvertHandle(PaintCurvePoint *pcp, int id, TransData2D *td2d, TransDataPaintCurve *tdpc, TransData *td)
+{
+ BezTriple *bezt = &pcp->bez;
+ copy_v2_v2(td2d->loc, bezt->vec[id]);
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = bezt->vec[id];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, bezt->vec[1]);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ tdpc->id = id;
+ tdpc->pcp = pcp;
+}
+
+static void PaintCurvePointToTransData(PaintCurvePoint *pcp, TransData *td, TransData2D *td2d, TransDataPaintCurve *tdpc)
+{
+ BezTriple *bezt = &pcp->bez;
+
+ if (pcp->bez.f2 == SELECT) {
+ int i;
+ for (i = 0; i < 3; i++) {
+ copy_v2_v2(td2d->loc, bezt->vec[i]);
+ td2d->loc[2] = 0.0f;
+ td2d->loc2d = bezt->vec[i];
+
+ td->flag = 0;
+ td->loc = td2d->loc;
+ copy_v3_v3(td->center, bezt->vec[1]);
+ copy_v3_v3(td->iloc, td->loc);
+
+ memset(td->axismtx, 0, sizeof(td->axismtx));
+ td->axismtx[2][2] = 1.0f;
+
+ td->ext = NULL;
+ td->val = NULL;
+ td->flag |= TD_SELECTED;
+ td->dist = 0.0;
+
+ unit_m3(td->mtx);
+ unit_m3(td->smtx);
+
+ tdpc->id = i;
+ tdpc->pcp = pcp;
+
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ }
+ else {
+ if (bezt->f3 & SELECT) {
+ PaintCurveConvertHandle(pcp, 2, td2d, tdpc, td);
+ td2d++;
+ tdpc++;
+ td++;
+ }
+
+ if (bezt->f1 & SELECT) {
+ PaintCurveConvertHandle(pcp, 0, td2d, tdpc, td);
+ }
+ }
+}
+
+static void createTransPaintCurveVerts(bContext *C, TransInfo *t)
+{
+ Paint *paint = BKE_paint_get_active_from_context(C);
+ PaintCurve *pc;
+ PaintCurvePoint *pcp;
+ Brush *br;
+ TransData *td = NULL;
+ TransData2D *td2d = NULL;
+ TransDataPaintCurve *tdpc = NULL;
+ int i;
+ int total = 0;
+
+ t->total = 0;
+
+ if (!paint || !paint->brush || !paint->brush->paint_curve)
+ return;
+
+ br = paint->brush;
+ pc = br->paint_curve;
+
+ for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
+ if (PC_IS_ANY_SEL(pcp)) {
+ if (pcp->bez.f2 & SELECT) {
+ total += 3;
+ continue;
+ }
+ else {
+ if (pcp->bez.f1 & SELECT)
+ total++;
+ if (pcp->bez.f3 & SELECT)
+ total++;
+ }
+ }
+ }
+
+ if (!total)
+ return;
+
+ t->total = total;
+ td2d = t->data2d = MEM_callocN(t->total * sizeof(TransData2D), "TransData2D");
+ td = t->data = MEM_callocN(t->total * sizeof(TransData), "TransData");
+ tdpc = t->customData = MEM_callocN(t->total * sizeof(TransDataPaintCurve), "TransDataPaintCurve");
+ t->flag |= T_FREE_CUSTOMDATA;
+
+ for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) {
+ if (PC_IS_ANY_SEL(pcp)) {
+ PaintCurvePointToTransData (pcp, td, td2d, tdpc);
+
+ if (pcp->bez.f2 & SELECT) {
+ td += 3;
+ td2d += 3;
+ tdpc += 3;
+ }
+ else {
+ if (pcp->bez.f1 & SELECT) {
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ if (pcp->bez.f3 & SELECT) {
+ td++;
+ td2d++;
+ tdpc++;
+ }
+ }
+ }
+ }
+}
+
+
+void flushTransPaintCurve(TransInfo *t)
+{
+ int i;
+ TransData2D *td2d = t->data2d;
+ TransDataPaintCurve *tdpc = (TransDataPaintCurve *)t->customData;
+
+ for (i = 0; i < t->total; i++, tdpc++, td2d++) {
+ PaintCurvePoint *pcp = tdpc->pcp;
+ copy_v2_v2(pcp->bez.vec[tdpc->id], td2d->loc);
+ }
+}
+
+
void createTransData(bContext *C, TransInfo *t)
{
Scene *scene = t->scene;
@@ -6969,6 +7259,10 @@ void createTransData(bContext *C, TransInfo *t)
sort_trans_data_dist(t);
}
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ if (!ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN))
+ createTransPaintCurveVerts(C, t);
+ }
else if (t->obedit) {
createTransUVs(C, t);
if (t->data && (t->flag & T_PROP_EDIT)) {
@@ -7075,7 +7369,7 @@ void createTransData(bContext *C, TransInfo *t)
// XXX active-layer checking isn't done as that should probably be checked through context instead
createTransPose(t, ob);
}
- else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT)) {
+ else if (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && !(t->options & CTX_PAINT_CURVE)) {
/* important that ob_armature can be set even when its not selected [#23412]
* lines below just check is also visible */
Object *ob_armature = modifiers_isDeformedByArmature(ob);
@@ -7100,12 +7394,11 @@ void createTransData(bContext *C, TransInfo *t)
sort_trans_data_dist(t);
}
}
- else if (ob && (ob->mode & (OB_MODE_ALL_PAINT))) {
- /* sculpt mode and project paint have own undo stack
- * transform ops redo clears sculpt/project undo stack.
- *
- * Could use 'OB_MODE_ALL_PAINT' since there are key conflicts,
- * transform + paint isn't well supported. */
+ else if (ob && (ob->mode & OB_MODE_ALL_PAINT)) {
+ if ((t->options & CTX_PAINT_CURVE) && !ELEM(t->mode, TFM_SHEAR, TFM_SHRINKFATTEN)) {
+ t->flag |= T_POINTS | T_2D_EDIT;
+ createTransPaintCurveVerts(C, t);
+ }
}
else {
createTransObject(C, t);
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index f813db04205..2f035949edc 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -38,6 +38,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_brush_types.h"
#include "DNA_lattice_types.h"
#include "DNA_screen_types.h"
#include "DNA_sequence_types.h"
@@ -74,6 +75,7 @@
#include "BKE_lattice.h"
#include "BKE_nla.h"
#include "BKE_context.h"
+#include "BKE_paint.h"
#include "BKE_sequencer.h"
#include "BKE_editmesh.h"
#include "BKE_tracking.h"
@@ -98,6 +100,7 @@
#include "WM_api.h"
#include "UI_resources.h"
+#include "UI_view2d.h"
#include "transform.h"
@@ -262,7 +265,7 @@ static void animrecord_check_state(Scene *scene, ID *id, wmTimer *animtimer)
ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
/* sanity checks */
- if (ELEM3(NULL, scene, id, sad))
+ if (ELEM(NULL, scene, id, sad))
return;
/* check if we need a new strip if:
@@ -363,7 +366,7 @@ static void recalcData_actedit(TransInfo *t)
}
/* now free temp channels */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
}
/* helper for recalcData() - for Graph Editor transforms */
@@ -423,7 +426,7 @@ static void recalcData_graphedit(TransInfo *t)
if (dosort) remake_graph_transdata(t, &anim_data);
/* now free temp channels */
- BLI_freelistN(&anim_data);
+ ANIM_animdata_freelist(&anim_data);
}
/* helper for recalcData() - for NLA Editor transforms */
@@ -653,6 +656,9 @@ static void recalcData_image(TransInfo *t)
if (t->options & CTX_MASK) {
recalcData_mask_common(t);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ flushTransPaintCurve(t);
+ }
else if (t->obedit && t->obedit->type == OB_MESH) {
SpaceImage *sima = t->sa->spacedata.first;
@@ -773,7 +779,7 @@ static void recalcData_objects(TransInfo *t)
else if (t->obedit->type == OB_ARMATURE) { /* no recalc flag, does pose */
bArmature *arm = t->obedit->data;
ListBase *edbo = arm->edbo;
- EditBone *ebo;
+ EditBone *ebo, *ebo_parent;
TransData *td = t->data;
int i;
@@ -783,17 +789,18 @@ static void recalcData_objects(TransInfo *t)
/* Ensure all bones are correctly adjusted */
for (ebo = edbo->first; ebo; ebo = ebo->next) {
+ ebo_parent = (ebo->flag & BONE_CONNECTED) ? ebo->parent : NULL;
- if ((ebo->flag & BONE_CONNECTED) && ebo->parent) {
+ if (ebo_parent) {
/* If this bone has a parent tip that has been moved */
- if (ebo->parent->flag & BONE_TIPSEL) {
- copy_v3_v3(ebo->head, ebo->parent->tail);
- if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo->parent->rad_tail;
+ if (ebo_parent->flag & BONE_TIPSEL) {
+ copy_v3_v3(ebo->head, ebo_parent->tail);
+ if (t->mode == TFM_BONE_ENVELOPE) ebo->rad_head = ebo_parent->rad_tail;
}
/* If this bone has a parent tip that has NOT been moved */
else {
- copy_v3_v3(ebo->parent->tail, ebo->head);
- if (t->mode == TFM_BONE_ENVELOPE) ebo->parent->rad_tail = ebo->rad_head;
+ copy_v3_v3(ebo_parent->tail, ebo->head);
+ if (t->mode == TFM_BONE_ENVELOPE) ebo_parent->rad_tail = ebo->rad_head;
}
}
@@ -817,7 +824,7 @@ static void recalcData_objects(TransInfo *t)
}
}
- if (!ELEM3(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) {
+ if (!ELEM(t->mode, TFM_BONE_ROLL, TFM_BONE_ENVELOPE, TFM_BONESIZE)) {
/* fix roll */
for (i = 0; i < t->total; i++, td++) {
if (td->extra) {
@@ -847,9 +854,12 @@ static void recalcData_objects(TransInfo *t)
}
}
- if (arm->flag & ARM_MIRROR_EDIT)
- transform_armature_mirror_update(t->obedit);
-
+ if (arm->flag & ARM_MIRROR_EDIT) {
+ if (t->state != TRANS_CANCEL)
+ transform_armature_mirror_update(t->obedit);
+ else
+ restoreBones(t);
+ }
}
else {
if (t->state != TRANS_CANCEL) {
@@ -962,6 +972,9 @@ void recalcData(TransInfo *t)
else if (t->options & CTX_EDGE) {
recalcData_objects(t);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ flushTransPaintCurve(t);
+ }
else if (t->spacetype == SPACE_IMAGE) {
recalcData_image(t);
}
@@ -1070,6 +1083,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
ARegion *ar = CTX_wm_region(C);
ScrArea *sa = CTX_wm_area(C);
Object *obedit = CTX_data_edit_object(C);
+ Object *ob = CTX_data_active_object(C);
PropertyRNA *prop;
t->scene = sce;
@@ -1190,11 +1204,18 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
/* exceptional case */
if (t->around == V3D_LOCAL && (t->settings->selectmode & SCE_SELECT_FACE)) {
- if (ELEM3(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
+ if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) {
t->options |= CTX_NO_PET;
}
}
+ if (ob && ob->mode & OB_MODE_ALL_PAINT) {
+ Paint *p = BKE_paint_get_active_from_context(C);
+ if (p && p->brush && (p->brush->flag & BRUSH_CURVE)) {
+ t->options |= CTX_PAINT_CURVE;
+ }
+ }
+
/* initialize UV transform from */
if (op && ((prop = RNA_struct_find_property(op->ptr, "correct_uv")))) {
if (RNA_property_is_set(op->ptr, prop)) {
@@ -1223,9 +1244,13 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
else if (sima->mode == SI_MODE_MASK) {
t->options |= CTX_MASK;
}
- else {
- /* image not in uv edit, nor in mask mode, can happen for some tools */
+ else if (sima->mode == SI_MODE_PAINT) {
+ Paint *p = &sce->toolsettings->imapaint.paint;
+ if (p->brush && (p->brush->flag & BRUSH_CURVE)) {
+ t->options |= CTX_PAINT_CURVE;
+ }
}
+ /* image not in uv edit, nor in mask mode, can happen for some tools */
}
else if (t->spacetype == SPACE_NODE) {
// XXX for now, get View2D from the active region
@@ -1406,7 +1431,7 @@ void postTrans(bContext *C, TransInfo *t)
}
if (t->spacetype == SPACE_IMAGE) {
- if (t->options & CTX_MASK) {
+ if (t->options & (CTX_MASK | CTX_PAINT_CURVE)) {
/* pass */
}
else {
@@ -1536,6 +1561,13 @@ void calculateCenterCursor(TransInfo *t, float r_center[3])
invert_m3_m3(imat, mat);
mul_m3_v3(imat, r_center);
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ if (ED_view3d_project_float_global(t->ar, cursor, r_center, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) {
+ r_center[0] = t->ar->winx / 2.0f;
+ r_center[1] = t->ar->winy / 2.0f;
+ }
+ r_center[2] = 0.0f;
+ }
}
void calculateCenterCursor2D(TransInfo *t, float r_center[2])
@@ -1567,19 +1599,14 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
if (cursor) {
if (t->options & CTX_MASK) {
float co[2];
- float frame_size[2];
if (t->spacetype == SPACE_IMAGE) {
SpaceImage *sima = (SpaceImage *)t->sa->spacedata.first;
- ED_space_image_get_size_fl(sima, frame_size);
- BKE_mask_coord_from_frame(co, cursor, frame_size);
- ED_space_image_get_aspect(sima, &aspx, &aspy);
+ BKE_mask_coord_from_image(sima->image, &sima->iuser, co, cursor);
}
else if (t->spacetype == SPACE_CLIP) {
SpaceClip *space_clip = (SpaceClip *) t->sa->spacedata.first;
- ED_space_clip_get_size_fl(space_clip, frame_size);
- BKE_mask_coord_from_frame(co, cursor, frame_size);
- ED_space_clip_get_aspect(space_clip, &aspx, &aspy);
+ BKE_mask_coord_from_movieclip(space_clip->clip, &space_clip->user, co, cursor);
}
else {
BLI_assert(!"Shall not happen");
@@ -1588,6 +1615,12 @@ void calculateCenterCursor2D(TransInfo *t, float r_center[2])
r_center[0] = co[0] * aspx;
r_center[1] = co[1] * aspy;
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ if (t->spacetype == SPACE_IMAGE) {
+ r_center[0] = UI_view2d_view_to_region_x(&t->ar->v2d, cursor[0]);
+ r_center[1] = UI_view2d_view_to_region_y(&t->ar->v2d, cursor[1]);
+ }
+ }
else {
r_center[0] = cursor[0] * aspx;
r_center[1] = cursor[1] * aspy;
@@ -1619,8 +1652,9 @@ void calculateCenterMedian(TransInfo *t, float r_center[3])
}
}
}
- if (i)
- mul_v3_fl(partial, 1.0f / total);
+ if (total) {
+ mul_v3_fl(partial, 1.0f / (float)total);
+ }
copy_v3_v3(r_center, partial);
}
@@ -1722,6 +1756,14 @@ bool calculateCenterActive(TransInfo *t, bool select_only, float r_center[3])
}
}
}
+ else if (t->options & CTX_PAINT_CURVE) {
+ Paint *p = BKE_paint_get_active(t->scene);
+ Brush *br = p->brush;
+ PaintCurve *pc = br->paint_curve;
+ copy_v3_v3(r_center, pc->points[pc->add_index - 1].bez.vec[1]);
+ r_center[2] = 0.0f;
+ ok = true;
+ }
else {
/* object mode */
Scene *scene = t->scene;
diff --git a/source/blender/editors/transform/transform_input.c b/source/blender/editors/transform/transform_input.c
index 70b565859f3..61b2deabe12 100644
--- a/source/blender/editors/transform/transform_input.c
+++ b/source/blender/editors/transform/transform_input.c
@@ -64,18 +64,18 @@ static void InputSpring(TransInfo *UNUSED(t), MouseInput *mi, const int mval[2],
/* calculate ratio for shiftkey pos, and for total, and blend these for precision */
dx = (float)(mi->center[0] - mi->precision_mval[0]);
dy = (float)(mi->center[1] - mi->precision_mval[1]);
- ratio = sqrtf(dx * dx + dy * dy);
+ ratio = hypotf(dx, dy);
dx = (float)(mi->center[0] - mval[0]);
dy = (float)(mi->center[1] - mval[1]);
- precise_ratio = sqrtf(dx * dx + dy * dy);
+ precise_ratio = hypotf(dx, dy);
ratio = (ratio + (precise_ratio - ratio) / 10.0f) / mi->factor;
}
else {
dx = (float)(mi->center[0] - mval[0]);
dy = (float)(mi->center[1] - mval[1]);
- ratio = sqrtf(dx * dx + dy * dy) / mi->factor;
+ ratio = hypotf(dx, dy) / mi->factor;
}
output[0] = ratio;
@@ -94,6 +94,12 @@ static void InputSpringFlip(TransInfo *t, MouseInput *mi, const int mval[2], flo
}
}
+static void InputSpringDelta(TransInfo *t, MouseInput *mi, const int mval[2], float output[3])
+{
+ InputSpring(t, mi, mval, output);
+ output[0] -= 1.0f;
+}
+
static void InputTrackBall(TransInfo *UNUSED(t), MouseInput *mi, const int mval[2], float output[3])
{
@@ -189,7 +195,7 @@ static void InputCustomRatioFlip(TransInfo *UNUSED(t), MouseInput *mi, const int
dx = data[2] - data[0];
dy = data[3] - data[1];
- length = sqrt(dx * dx + dy * dy);
+ length = hypot(dx, dy);
if (mi->precision) {
/* deal with Shift key by adding motion / 10 to motion before shift press */
@@ -333,6 +339,11 @@ void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode)
mi->apply = InputSpringFlip;
t->helpline = HLP_SPRING;
break;
+ case INPUT_SPRING_DELTA:
+ calcSpringFactor(mi);
+ mi->apply = InputSpringDelta;
+ t->helpline = HLP_SPRING;
+ break;
case INPUT_ANGLE:
mi->data = MEM_callocN(sizeof(double), "angle accumulator");
mi->apply = InputAngle;
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index 125975eb32b..37a6d50e149 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -72,6 +72,8 @@
/* local module include */
#include "transform.h"
+#include "GPU_select.h"
+
/* return codes for select, and drawing flags */
#define MAN_TRANS_X (1 << 0)
@@ -260,7 +262,7 @@ bool gimbal_axis(Object *ob, float gmat[3][3])
/* centroid, boundbox, of selection */
/* returns total items selected */
-int calc_manipulator_stats(const bContext *C)
+static int calc_manipulator_stats(const bContext *C)
{
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
@@ -858,8 +860,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co
/* axes */
if (flagx) {
if (is_picksel) {
- if (flagx & MAN_SCALE_X) glLoadName(MAN_SCALE_X);
- else if (flagx & MAN_TRANS_X) glLoadName(MAN_TRANS_X);
+ if (flagx & MAN_SCALE_X) GPU_select_load_id(MAN_SCALE_X);
+ else if (flagx & MAN_TRANS_X) GPU_select_load_id(MAN_TRANS_X);
}
else {
manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
@@ -873,8 +875,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co
case 1:
if (flagy) {
if (is_picksel) {
- if (flagy & MAN_SCALE_Y) glLoadName(MAN_SCALE_Y);
- else if (flagy & MAN_TRANS_Y) glLoadName(MAN_TRANS_Y);
+ if (flagy & MAN_SCALE_Y) GPU_select_load_id(MAN_SCALE_Y);
+ else if (flagy & MAN_TRANS_Y) GPU_select_load_id(MAN_TRANS_Y);
}
else {
manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
@@ -888,8 +890,8 @@ static void draw_manipulator_axes_single(View3D *v3d, RegionView3D *rv3d, int co
case 2:
if (flagz) {
if (is_picksel) {
- if (flagz & MAN_SCALE_Z) glLoadName(MAN_SCALE_Z);
- else if (flagz & MAN_TRANS_Z) glLoadName(MAN_TRANS_Z);
+ if (flagz & MAN_SCALE_Z) GPU_select_load_id(MAN_SCALE_Z);
+ else if (flagz & MAN_TRANS_Z) GPU_select_load_id(MAN_TRANS_Z);
}
else {
manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
@@ -975,7 +977,7 @@ static void draw_manipulator_rotate(
/* Screen aligned trackball rot circle */
if (drawflags & MAN_ROT_T) {
- if (is_picksel) glLoadName(MAN_ROT_T);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_T);
else UI_ThemeColor(TH_TRANSFORM);
drawcircball(GL_LINE_LOOP, unitmat[3], 0.2f * size, unitmat);
@@ -983,7 +985,7 @@ static void draw_manipulator_rotate(
/* Screen aligned view rot circle */
if (drawflags & MAN_ROT_V) {
- if (is_picksel) glLoadName(MAN_ROT_V);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_V);
else UI_ThemeColor(TH_TRANSFORM);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
@@ -1062,7 +1064,7 @@ static void draw_manipulator_rotate(
/* Z circle */
if (drawflags & MAN_ROT_Z) {
preOrthoFront(ortho, matt, 2);
- if (is_picksel) glLoadName(MAN_ROT_Z);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
else manipulator_setcolor(v3d, 'Z', colcode, 255);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
postOrtho(ortho);
@@ -1070,7 +1072,7 @@ static void draw_manipulator_rotate(
/* X circle */
if (drawflags & MAN_ROT_X) {
preOrthoFront(ortho, matt, 0);
- if (is_picksel) glLoadName(MAN_ROT_X);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_X);
else manipulator_setcolor(v3d, 'X', colcode, 255);
glRotatef(90.0, 0.0, 1.0, 0.0);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
@@ -1080,7 +1082,7 @@ static void draw_manipulator_rotate(
/* Y circle */
if (drawflags & MAN_ROT_Y) {
preOrthoFront(ortho, matt, 1);
- if (is_picksel) glLoadName(MAN_ROT_Y);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
else manipulator_setcolor(v3d, 'Y', colcode, 255);
glRotatef(-90.0, 1.0, 0.0, 0.0);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.0, unitmat);
@@ -1097,7 +1099,7 @@ static void draw_manipulator_rotate(
/* Z circle */
if (drawflags & MAN_ROT_Z) {
preOrthoFront(ortho, rv3d->twmat, 2);
- if (is_picksel) glLoadName(MAN_ROT_Z);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
else manipulator_setcolor(v3d, 'Z', colcode, 255);
partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
postOrtho(ortho);
@@ -1105,7 +1107,7 @@ static void draw_manipulator_rotate(
/* X circle */
if (drawflags & MAN_ROT_X) {
preOrthoFront(ortho, rv3d->twmat, 0);
- if (is_picksel) glLoadName(MAN_ROT_X);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_X);
else manipulator_setcolor(v3d, 'X', colcode, 255);
glRotatef(90.0, 0.0, 1.0, 0.0);
partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
@@ -1115,7 +1117,7 @@ static void draw_manipulator_rotate(
/* Y circle */
if (drawflags & MAN_ROT_Y) {
preOrthoFront(ortho, rv3d->twmat, 1);
- if (is_picksel) glLoadName(MAN_ROT_Y);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
else manipulator_setcolor(v3d, 'Y', colcode, 255);
glRotatef(-90.0, 1.0, 0.0, 0.0);
partial_doughnut(cusize / 4.0f, 1.0f, 0, 48, 8, 48);
@@ -1132,7 +1134,7 @@ static void draw_manipulator_rotate(
if (drawflags & MAN_ROT_Z) {
preOrthoFront(ortho, rv3d->twmat, 2);
glPushMatrix();
- if (is_picksel) glLoadName(MAN_ROT_Z);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
else manipulator_setcolor(v3d, 'Z', colcode, 255);
partial_doughnut(0.7f * cusize, 1.0f, 31, 33, 8, 64);
@@ -1145,7 +1147,7 @@ static void draw_manipulator_rotate(
if (drawflags & MAN_ROT_Y) {
preOrthoFront(ortho, rv3d->twmat, 1);
glPushMatrix();
- if (is_picksel) glLoadName(MAN_ROT_Y);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
else manipulator_setcolor(v3d, 'Y', colcode, 255);
glRotatef(90.0, 1.0, 0.0, 0.0);
@@ -1160,7 +1162,7 @@ static void draw_manipulator_rotate(
if (drawflags & MAN_ROT_X) {
preOrthoFront(ortho, rv3d->twmat, 0);
glPushMatrix();
- if (is_picksel) glLoadName(MAN_ROT_X);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_X);
else manipulator_setcolor(v3d, 'X', colcode, 255);
glRotatef(-90.0, 0.0, 1.0, 0.0);
@@ -1263,7 +1265,7 @@ static void draw_manipulator_scale(
int shift = 0; // XXX
/* center circle, do not add to selection when shift is pressed (planar constraint) */
- if (is_picksel && shift == 0) glLoadName(MAN_SCALE_C);
+ if (is_picksel && shift == 0) GPU_select_load_id(MAN_SCALE_C);
else manipulator_setcolor(v3d, 'C', colcode, 255);
glPushMatrix();
@@ -1304,7 +1306,7 @@ static void draw_manipulator_scale(
case 0: /* X cube */
if (drawflags & MAN_SCALE_X) {
glTranslatef(dz, 0.0, 0.0);
- if (is_picksel) glLoadName(MAN_SCALE_X);
+ if (is_picksel) GPU_select_load_id(MAN_SCALE_X);
else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
drawsolidcube(cusize);
glTranslatef(-dz, 0.0, 0.0);
@@ -1313,7 +1315,7 @@ static void draw_manipulator_scale(
case 1: /* Y cube */
if (drawflags & MAN_SCALE_Y) {
glTranslatef(0.0, dz, 0.0);
- if (is_picksel) glLoadName(MAN_SCALE_Y);
+ if (is_picksel) GPU_select_load_id(MAN_SCALE_Y);
else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
drawsolidcube(cusize);
glTranslatef(0.0, -dz, 0.0);
@@ -1322,7 +1324,7 @@ static void draw_manipulator_scale(
case 2: /* Z cube */
if (drawflags & MAN_SCALE_Z) {
glTranslatef(0.0, 0.0, dz);
- if (is_picksel) glLoadName(MAN_SCALE_Z);
+ if (is_picksel) GPU_select_load_id(MAN_SCALE_Z);
else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
drawsolidcube(cusize);
glTranslatef(0.0, 0.0, -dz);
@@ -1337,7 +1339,7 @@ static void draw_manipulator_scale(
if (shift) {
glTranslatef(0.0, -dz, 0.0);
- glLoadName(MAN_SCALE_C);
+ GPU_select_load_id(MAN_SCALE_C);
glBegin(GL_POINTS);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
@@ -1399,7 +1401,7 @@ static void draw_manipulator_translate(
glDisable(GL_DEPTH_TEST);
/* center circle, do not add to selection when shift is pressed (planar constraint) */
- if (is_picksel && shift == 0) glLoadName(MAN_TRANS_C);
+ if (is_picksel && shift == 0) GPU_select_load_id(MAN_TRANS_C);
else manipulator_setcolor(v3d, 'C', colcode, 255);
glPushMatrix();
@@ -1412,7 +1414,7 @@ static void draw_manipulator_translate(
glMultMatrixf(rv3d->twmat);
/* axis */
- glLoadName(-1);
+ GPU_select_load_id(-1);
// translate drawn as last, only axis when no combo with scale, or for ghosting
if ((combo & V3D_MANIP_SCALE) == 0 || colcode == MAN_GHOST) {
@@ -1435,7 +1437,7 @@ static void draw_manipulator_translate(
case 0: /* Z Cone */
if (drawflags & MAN_TRANS_Z) {
glTranslatef(0.0, 0.0, dz);
- if (is_picksel) glLoadName(MAN_TRANS_Z);
+ if (is_picksel) GPU_select_load_id(MAN_TRANS_Z);
else manipulator_setcolor(v3d, 'Z', colcode, axisBlendAngle(rv3d->tw_idot[2]));
draw_cone(qobj, cylen, cywid);
glTranslatef(0.0, 0.0, -dz);
@@ -1444,7 +1446,7 @@ static void draw_manipulator_translate(
case 1: /* X Cone */
if (drawflags & MAN_TRANS_X) {
glTranslatef(dz, 0.0, 0.0);
- if (is_picksel) glLoadName(MAN_TRANS_X);
+ if (is_picksel) GPU_select_load_id(MAN_TRANS_X);
else manipulator_setcolor(v3d, 'X', colcode, axisBlendAngle(rv3d->tw_idot[0]));
glRotatef(90.0, 0.0, 1.0, 0.0);
draw_cone(qobj, cylen, cywid);
@@ -1455,7 +1457,7 @@ static void draw_manipulator_translate(
case 2: /* Y Cone */
if (drawflags & MAN_TRANS_Y) {
glTranslatef(0.0, dz, 0.0);
- if (is_picksel) glLoadName(MAN_TRANS_Y);
+ if (is_picksel) GPU_select_load_id(MAN_TRANS_Y);
else manipulator_setcolor(v3d, 'Y', colcode, axisBlendAngle(rv3d->tw_idot[1]));
glRotatef(-90.0, 1.0, 0.0, 0.0);
draw_cone(qobj, cylen, cywid);
@@ -1503,7 +1505,7 @@ static void draw_manipulator_rotate_cyl(
unit_m4(unitmat);
- if (is_picksel) glLoadName(MAN_ROT_V);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_V);
UI_ThemeColor(TH_TRANSFORM);
drawcircball(GL_LINE_LOOP, unitmat[3], 1.2f * size, unitmat);
@@ -1556,7 +1558,7 @@ static void draw_manipulator_rotate_cyl(
case 0: /* X cylinder */
if (drawflags & MAN_ROT_X) {
glTranslatef(1.0, 0.0, 0.0);
- if (is_picksel) glLoadName(MAN_ROT_X);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_X);
glRotatef(90.0, 0.0, 1.0, 0.0);
manipulator_setcolor(v3d, 'X', colcode, 255);
draw_cylinder(qobj, cylen, cywid);
@@ -1567,7 +1569,7 @@ static void draw_manipulator_rotate_cyl(
case 1: /* Y cylinder */
if (drawflags & MAN_ROT_Y) {
glTranslatef(0.0, 1.0, 0.0);
- if (is_picksel) glLoadName(MAN_ROT_Y);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Y);
glRotatef(-90.0, 1.0, 0.0, 0.0);
manipulator_setcolor(v3d, 'Y', colcode, 255);
draw_cylinder(qobj, cylen, cywid);
@@ -1578,7 +1580,7 @@ static void draw_manipulator_rotate_cyl(
case 2: /* Z cylinder */
if (drawflags & MAN_ROT_Z) {
glTranslatef(0.0, 0.0, 1.0);
- if (is_picksel) glLoadName(MAN_ROT_Z);
+ if (is_picksel) GPU_select_load_id(MAN_ROT_Z);
manipulator_setcolor(v3d, 'Z', colcode, 255);
draw_cylinder(qobj, cylen, cywid);
glTranslatef(0.0, 0.0, -1.0);
@@ -1690,10 +1692,11 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
{
View3D *v3d = sa->spacedata.first;
RegionView3D *rv3d = ar->regiondata;
- rctf rect;
+ rctf rect, selrect;
GLuint buffer[64]; // max 4 items per select, so large enuf
short hits;
const bool is_picksel = true;
+ const bool do_passes = GPU_select_query_check_active();
/* XXX check a bit later on this... (ton) */
extern void view3d_winmatrix_set(ARegion *ar, View3D *v3d, rctf *rect);
@@ -1708,13 +1711,15 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
rect.ymin = mval[1] - hotspot;
rect.ymax = mval[1] + hotspot;
+ selrect = rect;
+
view3d_winmatrix_set(ar, v3d, &rect);
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
- glSelectBuffer(64, buffer);
- glRenderMode(GL_SELECT);
- glInitNames(); /* these two calls whatfor? It doesn't work otherwise */
- glPushName(-2);
+ if (do_passes)
+ GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_FIRST_PASS, 0);
+ else
+ GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_ALL, 0);
/* do the drawing */
if (v3d->twtype & V3D_MANIP_ROTATE) {
@@ -1726,8 +1731,23 @@ static int manipulator_selectbuf(ScrArea *sa, ARegion *ar, const int mval[2], fl
if (v3d->twtype & V3D_MANIP_TRANSLATE)
draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
- glPopName();
- hits = glRenderMode(GL_RENDER);
+ hits = GPU_select_end();
+
+ if (do_passes) {
+ GPU_select_begin(buffer, 64, &selrect, GPU_SELECT_NEAREST_SECOND_PASS, hits);
+
+ /* do the drawing */
+ if (v3d->twtype & V3D_MANIP_ROTATE) {
+ if (G.debug_value == 3) draw_manipulator_rotate_cyl(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
+ else draw_manipulator_rotate(v3d, rv3d, MAN_ROT_C & rv3d->twdrawflag, v3d->twtype, false, is_picksel);
+ }
+ if (v3d->twtype & V3D_MANIP_SCALE)
+ draw_manipulator_scale(v3d, rv3d, MAN_SCALE_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
+ if (v3d->twtype & V3D_MANIP_TRANSLATE)
+ draw_manipulator_translate(v3d, rv3d, MAN_TRANS_C & rv3d->twdrawflag, v3d->twtype, MAN_RGB, false, is_picksel);
+
+ GPU_select_end();
+ }
view3d_winmatrix_set(ar, v3d, NULL);
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
@@ -1866,11 +1886,14 @@ int BIF_do_manipulator(bContext *C, const struct wmEvent *event, wmOperator *op)
else if (drawflags == MAN_ROT_T) { /* trackball need special case, init is different */
/* Do not pass op->ptr!!! trackball has no "constraint" properties!
* See [#34621], it's a miracle it did not cause more problems!!! */
- /* However, we need to copy the "release_confirm" property... */
+ /* However, we need to copy the "release_confirm" property, but only if defined, see T41112. */
PointerRNA props_ptr;
+ PropertyRNA *prop;
wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_trackball", true);
WM_operator_properties_create_ptr(&props_ptr, ot);
- RNA_boolean_set(&props_ptr, "release_confirm", RNA_boolean_get(op->ptr, "release_confirm"));
+ if ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_boolean_set(&props_ptr, prop, RNA_property_boolean_get(op->ptr, prop));
+ }
WM_operator_name_call(C, ot->idname, WM_OP_INVOKE_DEFAULT, &props_ptr);
//wm_operator_invoke(C, WM_operatortype_find(ot->idname, 0), event, NULL, NULL, false);
WM_operator_properties_free(&props_ptr);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index f27ea4793fe..81e065ee33a 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -26,6 +26,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -49,6 +50,8 @@
#include "UI_resources.h"
#include "ED_screen.h"
+/* for USE_LOOPSLIDE_HACK only */
+#include "ED_mesh.h"
#include "transform.h"
@@ -391,6 +394,15 @@ static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
exit_code = transformEvent(t, event);
t->context = NULL;
+ /* XXX, workaround: active needs to be calculated before transforming,
+ * since we're not reading from 'td->center' in this case. see: T40241 */
+ if (t->tsnap.target == SCE_SNAP_TARGET_ACTIVE) {
+ /* In camera view, tsnap callback is not set (see initSnappingMode() in transfrom_snap.c, and T40348). */
+ if (t->tsnap.targetSnap && ((t->tsnap.status & TARGET_INIT) == 0)) {
+ t->tsnap.targetSnap(t);
+ }
+ }
+
transformApply(C, t);
exit_code |= transformEnd(C, t);
@@ -872,6 +884,27 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
Transform_Properties(ot, P_SNAP);
}
+static int edge_bevelweight_exec(bContext *C, wmOperator *op)
+{
+ Mesh *me = (Mesh *)CTX_data_edit_object(C)->data;
+
+ /* auto-enable bevel edge weight drawing, then chain to common transform code */
+ me->drawflag |= ME_DRAWBWEIGHTS;
+
+ return transform_exec(C, op);
+}
+
+static int edge_bevelweight_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Mesh *me = (Mesh *)CTX_data_edit_object(C)->data;
+
+ /* auto-enable bevel edge weight drawing, then chain to common transform code */
+ me->drawflag |= ME_DRAWBWEIGHTS;
+
+ return transform_invoke(C, op, event);
+}
+
+
static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
{
/* identifiers */
@@ -881,8 +914,8 @@ static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* api callbacks */
- ot->invoke = transform_invoke;
- ot->exec = transform_exec;
+ ot->invoke = edge_bevelweight_invoke;
+ ot->exec = edge_bevelweight_exec;
ot->modal = transform_modal;
ot->cancel = transform_cancel;
ot->poll = ED_operator_editmesh;
diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c
index ba90926df3b..c7d63da8281 100644
--- a/source/blender/editors/transform/transform_orientations.c
+++ b/source/blender/editors/transform/transform_orientations.c
@@ -509,6 +509,87 @@ void initTransformOrientation(bContext *C, TransInfo *t)
}
}
+/**
+ * utility function - get first n, selected vert/edge/faces
+ */
+static unsigned int bm_mesh_elems_select_get_n__internal(
+ BMesh *bm, BMElem **elems, const unsigned int n,
+ const BMIterType itype, const char htype)
+{
+ BMIter iter;
+ BMElem *ele;
+ unsigned int i;
+
+ BLI_assert(ELEM(htype, BM_VERT, BM_EDGE, BM_FACE));
+ BLI_assert(ELEM(itype, BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH));
+
+ if (!BLI_listbase_is_empty(&bm->selected)) {
+ /* quick check */
+ BMEditSelection *ese;
+ i = 0;
+ for (ese = bm->selected.last; ese; ese = ese->prev) {
+ /* shouldn't need this check */
+ if (BM_elem_flag_test(ese->ele, BM_ELEM_SELECT)) {
+
+ /* only use contiguous selection */
+ if (ese->htype != htype) {
+ i = 0;
+ break;
+ }
+
+ elems[i++] = ese->ele;
+ if (n == i) {
+ break;
+ }
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
+
+ if (i == 0) {
+ /* pass */
+ }
+ else {
+ return i;
+ }
+ }
+
+ i = 0;
+ BM_ITER_MESH (ele, &iter, bm, itype) {
+ BLI_assert(ele->head.htype == htype);
+ if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
+ elems[i++] = ele;
+ if (n == i) {
+ break;
+ }
+ }
+ }
+
+ return i;
+}
+
+static unsigned int bm_mesh_verts_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
+{
+ return bm_mesh_elems_select_get_n__internal(
+ bm, (BMElem **)elems, min_ii(n, bm->totvertsel),
+ BM_VERTS_OF_MESH, BM_VERT);
+}
+static unsigned int bm_mesh_edges_select_get_n(BMesh *bm, BMEdge **elems, const unsigned int n)
+{
+ return bm_mesh_elems_select_get_n__internal(
+ bm, (BMElem **)elems, min_ii(n, bm->totedgesel),
+ BM_EDGES_OF_MESH, BM_EDGE);
+}
+#if 0
+static unsigned int bm_mesh_faces_select_get_n(BMesh *bm, BMVert **elems, const unsigned int n)
+{
+ return bm_mesh_elems_select_get_n__internal(
+ bm, (BMElem **)elems, min_ii(n, bm->totfacesel),
+ BM_FACES_OF_MESH, BM_FACE);
+}
+#endif
+
int getTransformOrientation(const bContext *C, float normal[3], float plane[3], const bool activeOnly)
{
Scene *scene = CTX_data_scene(C);
@@ -534,7 +615,6 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
if (ob->type == OB_MESH) {
BMEditMesh *em = BKE_editmesh_from_object(ob);
- BMVert *eve;
BMEditSelection ese;
float vec[3] = {0, 0, 0};
@@ -571,97 +651,78 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
result = ORIENTATION_FACE;
}
else if (em->bm->totvertsel == 3) {
- BMVert *v1 = NULL, *v2 = NULL, *v3 = NULL;
- BMIter iter;
-
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- if (v1 == NULL) {
- v1 = eve;
- }
- else if (v2 == NULL) {
- v2 = eve;
- }
- else {
- float no_test[3];
+ BMVert *v_tri[3];
- float tan_a[3], tan_b[3], tan_c[3];
- float len_a, len_b, len_c;
- const float *tan_best;
+ if (bm_mesh_verts_select_get_n(em->bm, v_tri, 3) == 3) {
+ BMEdge *e = NULL;
+ float no_test[3];
+ normal_tri_v3(normal, v_tri[0]->co, v_tri[1]->co, v_tri[2]->co);
- v3 = eve;
- sub_v3_v3v3(tan_a, v2->co, v1->co);
- sub_v3_v3v3(tan_b, v3->co, v2->co);
- sub_v3_v3v3(tan_c, v1->co, v3->co);
- cross_v3_v3v3(normal, tan_b, tan_a);
+ /* check if the normal is pointing opposite to vert normals */
+ no_test[0] = v_tri[0]->no[0] + v_tri[1]->no[0] + v_tri[2]->no[0];
+ no_test[1] = v_tri[0]->no[1] + v_tri[1]->no[1] + v_tri[2]->no[1];
+ no_test[2] = v_tri[0]->no[2] + v_tri[1]->no[2] + v_tri[2]->no[2];
+ if (dot_v3v3(no_test, normal) < 0.0f) {
+ negate_v3(normal);
+ }
- /* check if the normal is pointing opposite to vert normals */
- no_test[0] = v1->no[0] + v2->no[0] + v3->no[0];
- no_test[1] = v1->no[1] + v2->no[1] + v3->no[1];
- no_test[2] = v1->no[2] + v2->no[2] + v3->no[2];
- if (dot_v3v3(no_test, normal) < 0.0f) {
- negate_v3(normal);
+ if (em->bm->totedgesel >= 1) {
+ /* find an edge thats apart of v_tri (no need to search all edges) */
+ float e_length;
+ int j;
+
+ for (j = 0; j < 3; j++) {
+ BMEdge *e_test = BM_edge_exists(v_tri[j], v_tri[(j + 1) % 3]);
+ if (e_test && BM_elem_flag_test(e_test, BM_ELEM_SELECT)) {
+ const float e_test_length = BM_edge_calc_length_squared(e_test);
+ if ((e == NULL) || (e_length < e_test_length)) {
+ e = e_test;
+ e_length = e_test_length;
+ }
}
-
- /* always give the plane to the 2 most distant verts */
- len_a = len_squared_v3(tan_a);
- len_b = len_squared_v3(tan_b);
- len_c = len_squared_v3(tan_c);
-
- tan_best = MAX3_PAIR(len_a, len_b, len_c,
- tan_a, tan_b, tan_c);
-
- copy_v3_v3(plane, tan_best);
-
- break;
}
}
- }
- /* if there's an edge available, use that for the tangent */
- if (em->bm->totedgesel >= 1) {
- BMEdge *eed = NULL;
-
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- sub_v3_v3v3(plane, eed->v2->co, eed->v1->co);
- break;
+ if (e) {
+ BMVert *v_pair[2];
+ if (BM_edge_is_boundary(e)) {
+ BM_edge_ordered_verts(e, &v_pair[0], &v_pair[1]);
}
+ else {
+ v_pair[0] = e->v1;
+ v_pair[1] = e->v2;
+ }
+ sub_v3_v3v3(plane, v_pair[0]->co, v_pair[1]->co);
+ }
+ else {
+ BM_vert_tri_calc_plane(v_tri, plane);
}
}
+ else {
+ BLI_assert(0);
+ }
result = ORIENTATION_FACE;
}
else if (em->bm->totedgesel == 1 || em->bm->totvertsel == 2) {
- BMVert *v1 = NULL, *v2 = NULL;
- BMIter iter;
+ BMVert *v_pair[2] = {NULL, NULL};
+ BMEdge *eed = NULL;
if (em->bm->totedgesel == 1) {
- BMEdge *eed = NULL;
- BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) {
- v1 = eed->v1;
- v2 = eed->v2;
- }
+ if (bm_mesh_edges_select_get_n(em->bm, &eed, 1) == 1) {
+ v_pair[0] = eed->v1;
+ v_pair[1] = eed->v2;
}
}
else {
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- if (v1 == NULL) {
- v1 = eve;
- }
- else {
- v2 = eve;
- break;
- }
- }
- }
+ BLI_assert(em->bm->totvertsel == 2);
+ bm_mesh_verts_select_get_n(em->bm, v_pair, 2);
}
/* should never fail */
- if (LIKELY(v1 && v2)) {
+ if (LIKELY(v_pair[0] && v_pair[1])) {
+ bool v_pair_swap = false;
/* Logic explained:
*
* - Edges and vert-pairs treated the same way.
@@ -672,13 +733,23 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
* which point the Z axis along the normal, however in both cases Z is the dominant axis.
*/
- /* be deterministic where possible and ensure v1 is active */
- if (BM_mesh_active_vert_get(em->bm) == v2) {
- SWAP(BMVert *, v1, v2);
+ /* be deterministic where possible and ensure v_pair[0] is active */
+ if (BM_mesh_active_vert_get(em->bm) == v_pair[1]) {
+ v_pair_swap = true;
+ }
+ else if (eed && BM_edge_is_boundary(eed)) {
+ /* pradictable direction for boundary edges */
+ if (eed->l->v != v_pair[0]) {
+ v_pair_swap = true;
+ }
+ }
+
+ if (v_pair_swap) {
+ SWAP(BMVert *, v_pair[0], v_pair[1]);
}
- add_v3_v3v3(plane, v1->no, v2->no);
- sub_v3_v3v3(normal, v1->co, v2->co);
+ add_v3_v3v3(plane, v_pair[0]->no, v_pair[1]->no);
+ sub_v3_v3v3(normal, v_pair[0]->co, v_pair[1]->co);
/* flip the plane normal so we point outwards */
negate_v3(plane);
}
@@ -686,24 +757,57 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
result = ORIENTATION_EDGE;
}
else if (em->bm->totvertsel == 1) {
- BMIter iter;
+ BMVert *v = NULL;
+
+ if (bm_mesh_verts_select_get_n(em->bm, &v, 1) == 1) {
+ copy_v3_v3(normal, v->no);
+
+ if (BM_vert_is_edge_pair(v)) {
+ bool v_pair_swap = false;
+ BMEdge *e_pair[2] = {v->e, BM_DISK_EDGE_NEXT(v->e, v)};
+ BMVert *v_pair[2] = {BM_edge_other_vert(e_pair[0], v), BM_edge_other_vert(e_pair[1], v)};
+ float dir_pair[2][3];
+
+ if (BM_edge_is_boundary(e_pair[0])) {
+ if (e_pair[0]->l->v != v) {
+ v_pair_swap = true;
+ }
+ }
+ else {
+ if (BM_edge_calc_length_squared(e_pair[0]) < BM_edge_calc_length_squared(e_pair[1])) {
+ v_pair_swap = true;
+ }
+ }
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- copy_v3_v3(normal, eve->no);
- break;
+ if (v_pair_swap) {
+ SWAP(BMVert *, v_pair[0], v_pair[1]);
+ }
+
+ sub_v3_v3v3(dir_pair[0], v->co, v_pair[0]->co);
+ sub_v3_v3v3(dir_pair[1], v_pair[1]->co, v->co);
+ normalize_v3(dir_pair[0]);
+ normalize_v3(dir_pair[1]);
+
+ add_v3_v3v3(plane, dir_pair[0], dir_pair[1]);
}
}
- result = ORIENTATION_VERT;
+
+ if (is_zero_v3(plane)) {
+ result = ORIENTATION_VERT;
+ }
+ else {
+ result = ORIENTATION_EDGE;
+ }
}
else if (em->bm->totvertsel > 3) {
BMIter iter;
+ BMVert *v;
zero_v3(normal);
- BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
- add_v3_v3(normal, eve->no);
+ BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ add_v3_v3(normal, v->no);
}
}
normalize_v3(normal);
@@ -756,7 +860,7 @@ int getTransformOrientation(const bContext *C, float normal[3], float plane[3],
if (flag) {
float tvec[3];
if ((v3d->around == V3D_LOCAL) ||
- ELEM3(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3))
+ ELEM(flag, SEL_F2, SEL_F1 | SEL_F3, SEL_F1 | SEL_F2 | SEL_F3))
{
BKE_nurb_bezt_calc_normal(nu, bezt, tvec);
add_v3_v3(normal, tvec);
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index 9afc12a5270..8a3e8f19db4 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -117,8 +117,8 @@ int BIF_snappingSupported(Object *obedit)
{
int status = 0;
- if (obedit == NULL || ELEM5(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) /* only support object mesh, armature, curves */
- {
+ /* only support object mesh, armature, curves */
+ if (obedit == NULL || ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) {
status = 1;
}
@@ -337,6 +337,46 @@ void applyProject(TransInfo *t)
mul_m3_v3(td->smtx, tvec);
add_v3_v3(td->loc, tvec);
+
+ if (t->tsnap.align && (t->flag & T_OBJECT)) {
+ /* handle alignment as well */
+ const float *original_normal;
+ float axis[3];
+ float mat[3][3];
+ float angle;
+ float totmat[3][3], smat[3][3];
+ float eul[3], fmat[3][3], quat[4];
+ float obmat[3][3];
+
+ /* In pose mode, we want to align normals with Y axis of bones... */
+ original_normal = td->axismtx[2];
+
+ cross_v3_v3v3(axis, original_normal, no);
+ angle = saacos(dot_v3v3(original_normal, no));
+
+ axis_angle_to_quat(quat, axis, angle);
+
+ quat_to_mat3(mat, quat);
+
+ mul_m3_m3m3(totmat, mat, td->mtx);
+ mul_m3_m3m3(smat, td->smtx, totmat);
+
+ /* calculate the total rotatation in eulers */
+ add_v3_v3v3(eul, td->ext->irot, td->ext->drot); /* we have to correct for delta rot */
+ eulO_to_mat3(obmat, eul, td->ext->rotOrder);
+ /* mat = transform, obmat = object rotation */
+ mul_m3_m3m3(fmat, smat, obmat);
+
+ mat3_to_compatible_eulO(eul, td->ext->rot, td->ext->rotOrder, fmat);
+
+ /* correct back for delta rot */
+ sub_v3_v3v3(eul, eul, td->ext->drot);
+
+ /* and apply */
+ copy_v3_v3(td->ext->rot, eul);
+
+ /* TODO support constraints for rotation too? see ElementRotation */
+ }
}
}
@@ -505,7 +545,7 @@ static void initSnappingMode(TransInfo *t)
/* Edit mode */
if (t->tsnap.applySnap != NULL && // A snapping function actually exist
- (obedit != NULL && ELEM5(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
+ (obedit != NULL && ELEM(obedit->type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) ) // Temporary limited to edit mode meshes, armature, curves, mballs
{
/* Exclude editmesh if using proportional edit */
if ((obedit->type == OB_MESH) && (t->flag & T_PROP_EDIT)) {
@@ -588,7 +628,7 @@ void initSnapping(TransInfo *t, wmOperator *op)
}
/* use scene defaults only when transform is modal */
else if (t->flag & T_MODAL) {
- if (ELEM3(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) {
+ if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE)) {
if (ts->snap_flag & SCE_SNAP) {
t->modifiers |= MOD_SNAP;
}
@@ -658,7 +698,8 @@ static void setSnappingCallback(TransInfo *t)
void addSnapPoint(TransInfo *t)
{
- if (t->tsnap.status & POINT_INIT) {
+ /* Currently only 3D viewport works for snapping points. */
+ if (t->tsnap.status & POINT_INIT && t->spacetype == SPACE_VIEW3D) {
TransSnapPoint *p = MEM_callocN(sizeof(TransSnapPoint), "SnapPoint");
t->tsnap.selectedPoint = p;
@@ -831,9 +872,9 @@ static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
cross_v3_v3v3(tmp, start, end);
if (dot_v3v3(tmp, axis) < 0.0f)
- angle = -acos(dot_v3v3(start, end));
+ angle = -acosf(dot_v3v3(start, end));
else
- angle = acos(dot_v3v3(start, end));
+ angle = acosf(dot_v3v3(start, end));
}
else {
float mtx[3][3];
@@ -843,7 +884,7 @@ static float RotationBetween(TransInfo *t, const float p1[3], const float p2[3])
mul_m3_v3(mtx, end);
mul_m3_v3(mtx, start);
- angle = atan2(start[1], start[0]) - atan2(end[1], end[0]);
+ angle = atan2f(start[1], start[0]) - atan2f(end[1], end[0]);
}
if (angle > (float)M_PI) {
@@ -1489,13 +1530,14 @@ static bool snapCurve(short snap_mode, ARegion *ar, Object *ob, Curve *cu, float
static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMesh *dm, BMEditMesh *em, float obmat[4][4],
const float ray_start[3], const float ray_normal[3], const float ray_origin[3],
- const float mval[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth)
+ const float mval[2], float r_loc[3], float r_no[3], float *r_dist_px, float *r_depth, bool do_bb)
{
bool retval = false;
+ const bool do_ray_start_correction = (snap_mode == SCE_SNAP_MODE_FACE && ar &&
+ !((RegionView3D *)ar->regiondata)->is_persp);
int totvert = dm->getNumVerts(dm);
if (totvert > 0) {
- BoundBox *bb;
float imat[4][4];
float timat[3][3]; /* transpose inverse matrix for normals */
float ray_start_local[3], ray_normal_local[3], local_scale, len_diff = TRANSFORM_DIST_MAX_RAY;
@@ -1513,9 +1555,33 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
/* local scale in normal direction */
local_scale = normalize_v3(ray_normal_local);
- bb = BKE_object_boundbox_get(ob);
- if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
- return retval;
+ if (do_bb) {
+ BoundBox *bb = BKE_object_boundbox_get(ob);
+ if (!BKE_boundbox_ray_hit_check(bb, ray_start_local, ray_normal_local, &len_diff)) {
+ return retval;
+ }
+ }
+ else if (do_ray_start_correction) {
+ /* We *need* a reasonably valid len_diff in this case.
+ * Use BHVTree to find the closest face from ray_start_local.
+ */
+ BVHTreeFromMesh treeData;
+ BVHTreeNearest nearest;
+ len_diff = 0.0f; /* In case BVHTree would fail for some reason... */
+
+ treeData.em_evil = em;
+ bvhtree_from_mesh_faces(&treeData, dm, 0.0f, 2, 6);
+ if (treeData.tree != NULL) {
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ /* Compute and store result. */
+ BLI_bvhtree_find_nearest(treeData.tree, ray_start_local, &nearest,
+ treeData.nearest_callback, &treeData);
+ if (nearest.index != -1) {
+ len_diff = sqrtf(nearest.dist_sq);
+ }
+ }
+ free_bvhtree_from_mesh(&treeData);
}
switch (snap_mode) {
@@ -1528,7 +1594,7 @@ static bool snapDerivedMesh(short snap_mode, ARegion *ar, Object *ob, DerivedMes
* been *inside* boundbox, leading to snap failures (see T38409).
* Note also ar might be null (see T38435), in this case we assume ray_start is ok!
*/
- if (ar && !((RegionView3D *)ar->regiondata)->is_persp) {
+ if (do_ray_start_correction) {
float ray_org_local[3];
copy_v3_v3(ray_org_local, ray_origin);
@@ -1813,17 +1879,19 @@ static bool snapObject(Scene *scene, short snap_mode, ARegion *ar, Object *ob, f
if (ob->type == OB_MESH) {
BMEditMesh *em;
DerivedMesh *dm;
+ bool do_bb = true;
if (use_obedit) {
em = BKE_editmesh_from_object(ob);
dm = editbmesh_get_derived_cage(scene, ob, em, CD_MASK_BAREMESH);
+ do_bb = false;
}
else {
em = NULL;
dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
}
- retval = snapDerivedMesh(snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_depth);
+ retval = snapDerivedMesh(snap_mode, ar, ob, dm, em, obmat, ray_start, ray_normal, ray_origin, mval, r_loc, r_no, r_dist_px, r_depth, do_bb);
dm->release(dm);
}
@@ -1968,10 +2036,10 @@ bool snapObjectsRayEx(Scene *scene, Base *base_act, View3D *v3d, ARegion *ar, Ob
/******************** PEELING *********************************/
-static int cmpPeel(void *arg1, void *arg2)
+static int cmpPeel(const void *arg1, const void *arg2)
{
- DepthPeel *p1 = arg1;
- DepthPeel *p2 = arg2;
+ const DepthPeel *p1 = arg1;
+ const DepthPeel *p2 = arg2;
int val = 0;
if (p1->depth < p2->depth) {
@@ -2328,7 +2396,7 @@ bool snapNodesContext(bContext *C, const int mval[2], float *r_dist_px, float r_
/*================================================================*/
-static void applyGridIncrement(TransInfo *t, float *val, int max_index, float fac[3], GearsType action);
+static void applyGridIncrement(TransInfo *t, float *val, int max_index, const float fac[3], GearsType action);
void snapGridIncrementAction(TransInfo *t, float *val, GearsType action)
@@ -2361,7 +2429,7 @@ void snapGridIncrement(TransInfo *t, float *val)
}
-static void applyGridIncrement(TransInfo *t, float *val, int max_index, float fac[3], GearsType action)
+static void applyGridIncrement(TransInfo *t, float *val, int max_index, const float fac[3], GearsType action)
{
int i;
float asp[3] = {1.0f, 1.0f, 1.0f}; // TODO: Remove hard coded limit here (3)
@@ -2380,12 +2448,15 @@ static void applyGridIncrement(TransInfo *t, float *val, int max_index, float fa
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);
}
}
for (i = 0; i <= max_index; i++) {
- val[i] = fac[action] * asp[i] * (float)floor(val[i] / (fac[action] * asp[i]) + 0.5f);
+ val[i] = fac[action] * asp[i] * floorf(val[i] / (fac[action] * asp[i]) + 0.5f);
}
}
diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt
index 3c051586282..f4189a18da4 100644
--- a/source/blender/editors/util/CMakeLists.txt
+++ b/source/blender/editors/util/CMakeLists.txt
@@ -24,10 +24,12 @@ set(INC
../../blenkernel
../../blenlib
../../bmesh
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -67,6 +69,7 @@ set(SRC
../include/ED_node.h
../include/ED_numinput.h
../include/ED_object.h
+ ../include/ED_paint.h
../include/ED_particle.h
../include/ED_physics.h
../include/ED_render.h
@@ -90,7 +93,7 @@ set(SRC
../include/UI_view2d.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
diff --git a/source/blender/editors/util/SConscript b/source/blender/editors/util/SConscript
index 0876fe48c91..d695a848f4e 100644
--- a/source/blender/editors/util/SConscript
+++ b/source/blender/editors/util/SConscript
@@ -28,16 +28,19 @@
Import ('env')
sources = env.Glob('*.c')
-defs = [ 'GLEW_STATIC' ]
+
+defs = env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../include',
'../../blenfont',
'../../blenkernel',
'../../blenlib',
'../../bmesh',
+ '../../gpu',
'../../makesdna',
'../../makesrna',
'../../windowmanager',
diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c
index 1fa1e5bdc49..104b628c25a 100644
--- a/source/blender/editors/util/ed_transverts.c
+++ b/source/blender/editors/util/ed_transverts.c
@@ -21,7 +21,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/editors/space_view3d/ed_transverts.c
+/** \file blender/editors/util/ed_transverts.c
* \ingroup edutil
*/
@@ -192,7 +192,7 @@ static void set_mapped_co(void *vuserdata, int index, const float co[3],
bool ED_transverts_check_obedit(Object *obedit)
{
- return (ELEM6(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL));
+ return (ELEM(obedit->type, OB_ARMATURE, OB_LATTICE, OB_MESH, OB_SURF, OB_CURVE, OB_MBALL));
}
void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const int mode)
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 2580836cad9..ec0471da8d3 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -41,7 +41,9 @@
#include "DNA_scene_types.h"
#include "DNA_packedFile_types.h"
-#include "BLI_blenlib.h"
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_path_util.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -59,7 +61,7 @@
#include "ED_image.h"
#include "ED_mesh.h"
#include "ED_object.h"
-#include "ED_sculpt.h"
+#include "ED_paint.h"
#include "ED_space_api.h"
#include "ED_util.h"
@@ -82,14 +84,20 @@ void ED_editors_init(bContext *C)
Object *ob, *obact = (sce && sce->basact) ? sce->basact->object : NULL;
ID *data;
+ /* This is called during initialization, so we don't want to store any reports */
+ ReportList *reports = CTX_wm_reports(C);
+ int reports_flag_prev = reports->flag & ~RPT_STORE;
+
+ SWAP(int, reports->flag, reports_flag_prev);
+
/* toggle on modes for objects that were saved with these enabled. for
* e.g. linked objects we have to ensure that they are actually the
* active object in this scene. */
for (ob = bmain->object.first; ob; ob = ob->id.next) {
int mode = ob->mode;
- if (mode && (mode != OB_MODE_POSE)) {
- ob->mode = 0;
+ if (!ELEM(mode, OB_MODE_OBJECT, OB_MODE_POSE)) {
+ ob->mode = OB_MODE_OBJECT;
data = ob->data;
if (ob == obact && !ob->id.lib && !(data && data->lib))
@@ -101,6 +109,8 @@ void ED_editors_init(bContext *C)
if (sce) {
ED_space_image_paint_update(wm, sce->toolsettings);
}
+
+ SWAP(int, reports->flag, reports_flag_prev);
}
/* frees all editmode stuff */
@@ -143,29 +153,39 @@ void ED_editors_exit(bContext *C)
/* flush any temp data from object editing to DNA before writing files,
* rendering, copying, etc. */
-void ED_editors_flush_edits(const bContext *C, bool for_render)
+bool ED_editors_flush_edits(const bContext *C, bool for_render)
{
- Object *obact = CTX_data_active_object(C);
- Object *obedit = CTX_data_edit_object(C);
-
- /* get editmode results */
- if (obedit)
- ED_object_editmode_load(obedit);
-
- if (obact && (obact->mode & OB_MODE_SCULPT)) {
- /* flush multires changes (for sculpt) */
- multires_force_update(obact);
+ bool has_edited = false;
+ Object *ob;
+ Main *bmain = CTX_data_main(C);
- if (for_render) {
- /* flush changes from dynamic topology sculpt */
- BKE_sculptsession_bm_to_me_for_render(obact);
- }
- else {
- /* Set reorder=false so that saving the file doesn't reorder
+ /* loop through all data to find edit mode or object mode, because during
+ * exiting we might not have a context for edit object and multiple sculpt
+ * objects can exist at the same time */
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
+ if (ob->mode & OB_MODE_SCULPT) {
+ /* flush multires changes (for sculpt) */
+ multires_force_update(ob);
+ has_edited = true;
+
+ if (for_render) {
+ /* flush changes from dynamic topology sculpt */
+ BKE_sculptsession_bm_to_me_for_render(ob);
+ }
+ else {
+ /* Set reorder=false so that saving the file doesn't reorder
* the BMesh's elements */
- BKE_sculptsession_bm_to_me(obact, false);
+ BKE_sculptsession_bm_to_me(ob, false);
+ }
+ }
+ else if (ob->mode & OB_MODE_EDIT) {
+ /* get editmode results */
+ has_edited = true;
+ ED_object_editmode_load(ob);
}
}
+
+ return has_edited;
}
/* ***** XXX: functions are using old blender names, cleanup later ***** */
diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c
index ee391af185d..a154f12a786 100644
--- a/source/blender/editors/util/numinput.c
+++ b/source/blender/editors/util/numinput.c
@@ -33,6 +33,7 @@
#include "BLI_string_cursor_utf8.h"
#include "BKE_context.h"
+#include "BKE_scene.h"
#include "BKE_unit.h"
#include "DNA_scene_types.h"
@@ -87,15 +88,18 @@ void initNumInput(NumInput *n)
}
/* str must be NUM_STR_REP_LEN * (idx_max + 1) length. */
-void outputNumInput(NumInput *n, char *str)
+void outputNumInput(NumInput *n, char *str, UnitSettings *unit_settings)
{
- short i, j;
+ short j;
const int ln = NUM_STR_REP_LEN;
int prec = 2; /* draw-only, and avoids too much issues with radian->degrees conversion. */
for (j = 0; j <= n->idx_max; j++) {
/* if AFFECTALL and no number typed and cursor not on number, use first number */
- i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j;
+ const short i = (n->flag & NUM_AFFECT_ALL && n->idx != j && !(n->val_flag[j] & NUM_EDITED)) ? 0 : j;
+
+ /* Use scale_length if needed! */
+ const float fac = (float)BKE_scene_unit_scale(unit_settings, n->unit_type[j], 1.0);
if (n->val_flag[i] & NUM_EDITED) {
/* Get the best precision, allows us to draw '10.0001' as '10' instead! */
@@ -118,7 +122,7 @@ void outputNumInput(NumInput *n, char *str)
BLI_strncpy(val, "Invalid", sizeof(val));
}
else {
- bUnit_AsString(val, sizeof(val), (double)n->val[i], prec,
+ bUnit_AsString(val, sizeof(val), (double)(n->val[i] * fac), prec,
n->unit_sys, n->unit_type[i], true, false);
}
@@ -186,15 +190,15 @@ bool applyNumInput(NumInput *n, float *vec)
if (n->val_flag[i] & NUM_NO_NEGATIVE && val < 0.0f) {
val = 0.0f;
}
- if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
- val = 0.0001f;
- }
if (n->val_flag[i] & NUM_NO_FRACTION && val != floorf(val)) {
val = floorf(val + 0.5f);
if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
val = 1.0f;
}
}
+ else if (n->val_flag[i] & NUM_NO_ZERO && val == 0.0f) {
+ val = 0.0001f;
+ }
}
vec[j] = val;
}
@@ -256,7 +260,6 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
short idx = n->idx, idx_max = n->idx_max;
short dir = STRCUR_DIR_NEXT, mode = STRCUR_JUMP_NONE;
int cur;
- double val;
switch (event->type) {
case EVT_MODAL_MAP:
@@ -440,6 +443,13 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
}
}
+ /* Up to this point, if we have a ctrl modifier, skip.
+ * This allows to still access most of modals' shortcuts even in numinput mode.
+ */
+ if (!updated && event->ctrl) {
+ return false;
+ }
+
if ((!utf8_buf || !utf8_buf[0]) && ascii[0]) {
/* Fallback to ascii. */
utf8_buf = ascii;
@@ -467,16 +477,21 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
/* At this point, our value has changed, try to interpret it with python (if str is not empty!). */
if (n->str[0]) {
#ifdef WITH_PYTHON
+ Scene *sce = CTX_data_scene(C);
+ double val;
char str_unit_convert[NUM_STR_REP_LEN * 6]; /* Should be more than enough! */
const char *default_unit = NULL;
+ /* Use scale_length if needed! */
+ const float fac = (float)BKE_scene_unit_scale(&sce->unit, n->unit_type[idx], 1.0);
+
/* Make radian default unit when needed. */
if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION)
default_unit = "r";
BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert));
- bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), default_unit, 1.0,
+ bUnit_ReplaceString(str_unit_convert, sizeof(str_unit_convert), default_unit, fac,
n->unit_sys, n->unit_type[idx]);
/* Note: with angles, we always get values as radians here... */
@@ -489,6 +504,7 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
}
#else /* Very unlikely, but does not harm... */
n->val[idx] = (float)atof(n->str);
+ (void)C;
#endif /* WITH_PYTHON */
if (n->val_flag[idx] & NUM_NEGATE) {
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index a4f2c36f250..189a938e3d8 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -58,7 +58,7 @@
#include "ED_object.h"
#include "ED_render.h"
#include "ED_screen.h"
-#include "ED_sculpt.h"
+#include "ED_paint.h"
#include "ED_util.h"
#include "ED_text.h"
@@ -105,6 +105,9 @@ void ED_undo_push(bContext *C, const char *str)
PE_undo_push(CTX_data_scene(C), str);
}
+ else if (obact && obact->mode & OB_MODE_SCULPT) {
+ /* do nothing for now */
+ }
else {
BKE_write_undo(C, str);
}
@@ -210,6 +213,7 @@ static int ed_undo_step(bContext *C, int step, const char *undoname)
}
WM_event_add_notifier(C, NC_WINDOW, NULL);
+ WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL);
if (win) {
win->addmousemove = true;
@@ -382,7 +386,13 @@ int ED_undo_operator_repeat(bContext *C, struct wmOperator *op)
ED_undo_pop_op(C, op);
if (op->type->check) {
- op->type->check(C, op); /* ignore return value since its running again anyway */
+ if (op->type->check(C, op)) {
+ /* check for popup and re-layout buttons */
+ ARegion *ar_menu = CTX_wm_menu(C);
+ if (ar_menu) {
+ ED_region_tag_refresh_ui(ar_menu);
+ }
+ }
}
retval = WM_operator_repeat(C, op);
@@ -489,7 +499,7 @@ static EnumPropertyItem *rna_undo_itemf(bContext *C, int undosys, int *totitem)
name = undo_editmode_get_name(C, i, &active);
}
else if (undosys == UNDOSYSTEM_IMAPAINT) {
- name = ED_undo_paint_get_name(UNDO_PAINT_IMAGE, i, &active);
+ name = ED_undo_paint_get_name(C, UNDO_PAINT_IMAGE, i, &active);
}
else {
name = BKE_undo_get_name(i, &active);
diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt
index 45edbde7482..74ba1672485 100644
--- a/source/blender/editors/uvedit/CMakeLists.txt
+++ b/source/blender/editors/uvedit/CMakeLists.txt
@@ -24,10 +24,12 @@ set(INC
../../blenlib
../../blenfont
../../bmesh
+ ../../gpu
../../makesdna
../../makesrna
../../windowmanager
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -57,4 +59,6 @@ if(WITH_OPENNL)
)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_editor_uvedit "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/uvedit/SConscript b/source/blender/editors/uvedit/SConscript
index 413503191cd..7153d25188b 100644
--- a/source/blender/editors/uvedit/SConscript
+++ b/source/blender/editors/uvedit/SConscript
@@ -27,13 +27,14 @@
Import ('env')
-defs = []
+defs = env['BF_GL_DEFINITIONS']
sources = env.Glob('*.c')
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/opennl/extern',
'../include',
'../../blenfont',
diff --git a/source/blender/editors/uvedit/uvedit_buttons.c b/source/blender/editors/uvedit/uvedit_buttons.c
index 78e3811a5fc..6816e785c1f 100644
--- a/source/blender/editors/uvedit/uvedit_buttons.c
+++ b/source/blender/editors/uvedit/uvedit_buttons.c
@@ -135,6 +135,7 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
BMEditMesh *em;
float center[2];
int imx, imy, step, digits;
+ float width = 8 * UI_UNIT_X;
ED_space_image_get_size(sima, &imx, &imy);
@@ -158,9 +159,9 @@ static void uvedit_vertex_buttons(const bContext *C, uiBlock *block)
}
uiBlockBeginAlign(block);
- uiDefButF(block, NUM, B_UVEDIT_VERTEX, IFACE_("X:"), 10, 10, 145, 19, &uvedit_old_center[0],
+ uiDefButF(block, NUM, B_UVEDIT_VERTEX, IFACE_("X:"), 0, 0, width, UI_UNIT_Y, &uvedit_old_center[0],
-10 * imx, 10.0 * imx, step, digits, "");
- uiDefButF(block, NUM, B_UVEDIT_VERTEX, IFACE_("Y:"), 165, 10, 145, 19, &uvedit_old_center[1],
+ uiDefButF(block, NUM, B_UVEDIT_VERTEX, IFACE_("Y:"), width, 0, width, UI_UNIT_Y, &uvedit_old_center[1],
-10 * imy, 10.0 * imy, step, digits, "");
uiBlockEndAlign(block);
}
diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c
index ce4b97e7108..83fd7e6505d 100644
--- a/source/blender/editors/uvedit/uvedit_draw.c
+++ b/source/blender/editors/uvedit/uvedit_draw.c
@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <string.h>
+#include "DNA_material_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -42,11 +43,15 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_alloca.h"
+#include "BLI_buffer.h"
+#include "BLI_bitmap.h"
#include "BKE_DerivedMesh.h"
#include "BKE_editmesh.h"
+#include "BKE_material.h"
-#include "BLI_buffer.h"
+#include "BKE_scene.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
@@ -64,6 +69,7 @@
/* use editmesh tessface */
#define USE_EDBM_LOOPTRIS
+static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset);
void draw_image_cursor(ARegion *ar, const float cursor[2])
{
@@ -130,9 +136,7 @@ static void draw_uvs_shadow(Object *obedit)
BMEditMesh *em = BKE_editmesh_from_object(obedit);
BMesh *bm = em->bm;
BMFace *efa;
- BMLoop *l;
- BMIter iter, liter;
- MLoopUV *luv;
+ BMIter iter;
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
@@ -140,12 +144,7 @@ static void draw_uvs_shadow(Object *obedit)
UI_ThemeColor(TH_UV_SHADOW);
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
- glBegin(GL_LINE_LOOP);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
}
}
@@ -354,7 +353,113 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTe
BLI_buffer_free(&tf_uvorig_buf);
}
-static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage)
+static void draw_uvs_lineloop_bmface(BMFace *efa, const int cd_loop_uv_offset)
+{
+ BMIter liter;
+ BMLoop *l;
+ MLoopUV *luv;
+
+ glBegin(GL_LINE_LOOP);
+ BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+ luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
+ glVertex2fv(luv->uv);
+ }
+ glEnd();
+}
+
+static void draw_uvs_lineloop_mpoly(Mesh *me, MPoly *mpoly)
+{
+ MLoopUV *mloopuv;
+ int i;
+
+ glBegin(GL_LINE_LOOP);
+ mloopuv = &me->mloopuv[mpoly->loopstart];
+ for (i = mpoly->totloop; i != 0; i--, mloopuv++) {
+ glVertex2fv(mloopuv->uv);
+ }
+ glEnd();
+}
+
+static void draw_uvs_other_mesh_texface(Object *ob, const Image *curimage)
+{
+ Mesh *me = ob->data;
+ MPoly *mpoly = me->mpoly;
+ MTexPoly *mtpoly = me->mtpoly;
+ int a;
+
+ if (me->mloopuv == NULL) {
+ return;
+ }
+
+ for (a = me->totpoly; a != 0; a--, mpoly++, mtpoly++) {
+ if (mtpoly->tpage != curimage) {
+ continue;
+ }
+
+ draw_uvs_lineloop_mpoly(me, mpoly);
+ }
+}
+static void draw_uvs_other_mesh_new_shading(Object *ob, const Image *curimage)
+{
+ Mesh *me = ob->data;
+ MPoly *mpoly = me->mpoly;
+ int a;
+ BLI_bitmap *mat_test_array;
+ bool ok = false;
+ int totcol = 0;
+
+ if (me->mloopuv == NULL) {
+ return;
+ }
+
+ if (curimage && ob->totcol == 0) {
+ return;
+ }
+
+ totcol = max_ii(ob->totcol, 1);
+ mat_test_array = BLI_BITMAP_NEW_ALLOCA(totcol);
+
+ for (a = 0; a < totcol; a++) {
+ Image *image;
+
+ /* if no materials, assume a default material with no image */
+ if (ob->totcol)
+ ED_object_get_active_image(ob, a + 1, &image, NULL, NULL, NULL);
+ else
+ image = NULL;
+
+ if (image == curimage) {
+ BLI_BITMAP_ENABLE(mat_test_array, a);
+ ok = true;
+ }
+ }
+
+ if (ok == false) {
+ return;
+ }
+
+ for (a = me->totpoly; a != 0; a--, mpoly++) {
+ const int mat_nr = mpoly->mat_nr;
+ if ((mat_nr >= totcol) ||
+ (BLI_BITMAP_TEST(mat_test_array, mat_nr)) == 0)
+ {
+ continue;
+ }
+
+ draw_uvs_lineloop_mpoly(me, mpoly);
+ }
+}
+static void draw_uvs_other_mesh(Object *ob, const Image *curimage, const bool new_shading_nodes)
+{
+ if (new_shading_nodes) {
+ draw_uvs_other_mesh_new_shading(ob, curimage);
+ }
+ else {
+ draw_uvs_other_mesh_texface(ob, curimage);
+ }
+}
+
+static void draw_uvs_other(Scene *scene, Object *obedit, const Image *curimage, const bool new_shading_nodes)
{
Base *base;
@@ -367,57 +472,47 @@ static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage)
if (!(base->lay & scene->lay)) continue;
if (ob->restrictflag & OB_RESTRICT_VIEW) continue;
- if ((ob->type == OB_MESH) && (ob != obedit)) {
- Mesh *me = ob->data;
-
- if (me->mtpoly) {
- MPoly *mpoly = me->mpoly;
- MTexPoly *mtpoly = me->mtpoly;
- MLoopUV *mloopuv;
- int a, b;
-
- for (a = me->totpoly; a > 0; a--, mtpoly++, mpoly++) {
- if (mtpoly->tpage == curimage) {
- glBegin(GL_LINE_LOOP);
-
- mloopuv = me->mloopuv + mpoly->loopstart;
- for (b = 0; b < mpoly->totloop; b++, mloopuv++) {
- glVertex2fv(mloopuv->uv);
- }
- glEnd();
- }
- }
- }
+ if ((ob->type == OB_MESH) && (ob != obedit) && ((Mesh *)ob->data)->mloopuv) {
+ draw_uvs_other_mesh(ob, curimage, new_shading_nodes);
}
}
}
static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
{
- Mesh *me = ob->data;
+ const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
Image *curimage = ED_space_image(sima);
+ Mesh *me = ob->data;
+ Material *ma;
- if (sima->flag & SI_DRAW_OTHER)
- draw_uvs_other(scene, ob, curimage);
+ if (sima->flag & SI_DRAW_OTHER) {
+ draw_uvs_other(scene, ob, curimage, new_shading_nodes);
+ }
UI_ThemeColor(TH_UV_SHADOW);
+ ma = give_current_material(ob, ob->actcol);
+
if (me->mtpoly) {
MPoly *mpoly = me->mpoly;
- MTexPoly *tface = me->mtpoly;
- MLoopUV *mloopuv;
+ MLoopUV *mloopuv, *mloopuv_base;
int a, b;
+ if (!(ma && ma->texpaintslot && ma->texpaintslot[ma->paint_active_slot].uvname &&
+ (mloopuv = CustomData_get_layer_named(&me->ldata, CD_MLOOPUV, ma->texpaintslot[ma->paint_active_slot].uvname))))
+ {
+ mloopuv = me->mloopuv;
+ }
- for (a = me->totpoly; a > 0; a--, tface++, mpoly++) {
- if (tface->tpage == curimage) {
- glBegin(GL_LINE_LOOP);
+ mloopuv_base = mloopuv;
- mloopuv = me->mloopuv + mpoly->loopstart;
- for (b = 0; b < mpoly->totloop; b++, mloopuv++) {
- glVertex2fv(mloopuv->uv);
- }
- glEnd();
+ for (a = me->totpoly; a > 0; a--, mpoly++) {
+ glBegin(GL_LINE_LOOP);
+
+ mloopuv = mloopuv_base + mpoly->loopstart;
+ for (b = 0; b < mpoly->totloop; b++, mloopuv++) {
+ glVertex2fv(mloopuv->uv);
}
+ glEnd();
}
}
}
@@ -442,6 +537,7 @@ static void draw_uvs_looptri(BMEditMesh *em, unsigned int *r_loop_index, const i
/* draws uv's in the image space */
static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
{
+ const bool new_shading_nodes = BKE_scene_use_new_shading_nodes(scene);
ToolSettings *ts;
Mesh *me = obedit->data;
BMEditMesh *em = me->edit_btmesh;
@@ -477,9 +573,21 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
/* draw other uvs */
if (sima->flag & SI_DRAW_OTHER) {
- Image *curimage = (activetf) ? activetf->tpage : ima;
+ Image *curimage;
+
+ if (new_shading_nodes) {
+ if (efa_act) {
+ ED_object_get_active_image(obedit, efa_act->mat_nr + 1, &curimage, NULL, NULL, NULL);
+ }
+ else {
+ curimage = ima;
+ }
+ }
+ else {
+ curimage = (activetf) ? activetf->tpage : ima;
+ }
- draw_uvs_other(scene, obedit, curimage);
+ draw_uvs_other(scene, obedit, curimage, new_shading_nodes);
}
/* 1. draw shadow mesh */
@@ -636,22 +744,12 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if (tf) {
cpack(0x111111);
- glBegin(GL_LINE_LOOP);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
setlinestyle(2);
cpack(0x909090);
- glBegin(GL_LINE_LOOP);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
setlinestyle(0);
}
@@ -666,12 +764,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
- glBegin(GL_LINE_LOOP);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
}
break;
case SI_UVDT_OUTLINE:
@@ -682,12 +775,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
- glBegin(GL_LINE_LOOP);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
}
glLineWidth(1);
@@ -745,12 +833,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
if (!BM_elem_flag_test(efa, BM_ELEM_TAG))
continue;
- glBegin(GL_LINE_LOOP);
- BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
- luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
- glVertex2fv(luv->uv);
- }
- glEnd();
+ draw_uvs_lineloop_bmface(efa, cd_loop_uv_offset);
}
}
@@ -863,14 +946,30 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
glPointSize(1.0);
}
+
+static void draw_uv_shadows_get(SpaceImage *sima, Object *ob, Object *obedit, bool *show_shadow, bool *show_texpaint)
+{
+ *show_shadow = *show_texpaint = false;
+
+ if (ED_space_image_show_render(sima) || (sima->flag & SI_NO_DRAW_TEXPAINT))
+ return;
+
+ if ((sima->mode == SI_MODE_PAINT) && obedit && obedit->type == OB_MESH) {
+ struct BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ *show_shadow = EDBM_mtexpoly_check(em);
+ }
+
+ *show_texpaint = (ob && ob->type == OB_MESH && ob->mode == OB_MODE_TEXTURE_PAINT);
+}
+
void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact)
{
ToolSettings *toolsettings = scene->toolsettings;
- int show_uvedit, show_uvshadow, show_texpaint_uvshadow;
+ bool show_uvedit, show_uvshadow, show_texpaint_uvshadow;
- show_texpaint_uvshadow = (obact && obact->type == OB_MESH && obact->mode == OB_MODE_TEXTURE_PAINT);
show_uvedit = ED_space_image_show_uvedit(sima, obedit);
- show_uvshadow = ED_space_image_show_uvshadow(sima, obedit);
+ draw_uv_shadows_get(sima, obact, obedit, &show_uvshadow, &show_texpaint_uvshadow);
if (show_uvedit || show_uvshadow || show_texpaint_uvshadow) {
if (show_uvshadow)
diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c
index 5169cc73052..4b341547370 100644
--- a/source/blender/editors/uvedit/uvedit_ops.c
+++ b/source/blender/editors/uvedit/uvedit_ops.c
@@ -137,21 +137,24 @@ static bool is_image_texture_node(bNode *node)
}
bool ED_object_get_active_image(Object *ob, int mat_nr,
- Image **r_ima, ImageUser **r_iuser, bNode **r_node)
+ Image **r_ima, ImageUser **r_iuser, bNode **r_node, bNodeTree **r_ntree)
{
Material *ma = give_current_material(ob, mat_nr);
- bNode *node = (ma && ma->use_nodes) ? nodeGetActiveTexture(ma->nodetree) : NULL;
+ bNodeTree *ntree = (ma && ma->use_nodes) ? ma->nodetree : NULL;
+ bNode *node = (ntree) ? nodeGetActiveTexture(ntree) : NULL;
if (node && is_image_texture_node(node)) {
if (r_ima) *r_ima = (Image *)node->id;
if (r_iuser) *r_iuser = NULL;
if (r_node) *r_node = node;
+ if (r_ntree) *r_ntree = ntree;
return true;
}
if (r_ima) *r_ima = NULL;
if (r_iuser) *r_iuser = NULL;
if (r_node) *r_node = node;
+ if (r_ntree) *r_ntree = ntree;
return false;
}
@@ -3026,14 +3029,15 @@ static void UV_OT_circle_select(wmOperatorType *ot)
/* properties */
RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
- RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
+ RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX);
RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
}
/* ******************** lasso select operator **************** */
-static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves, const bool select)
+static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short moves,
+ const bool select, const bool extend)
{
SpaceImage *sima = CTX_wm_space_image(C);
Image *ima = CTX_data_edit_image(C);
@@ -3060,6 +3064,10 @@ static bool do_lasso_select_mesh_uv(bContext *C, const int mcords[][2], short mo
BLI_lasso_boundbox(&rect, mcords, moves);
+ if (!extend && select) {
+ uv_select_all_perform(scene, ima, em, SEL_DESELECT);
+ }
+
if (use_face_center) { /* Face Center Sel */
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
BM_elem_flag_disable(efa, BM_ELEM_TAG);
@@ -3122,11 +3130,12 @@ static int uv_lasso_select_exec(bContext *C, wmOperator *op)
const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) {
- bool select;
+ bool select, extend;
bool changed;
select = !RNA_boolean_get(op->ptr, "deselect");
- changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, select);
+ extend = RNA_boolean_get(op->ptr, "extend");
+ changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, select, extend);
MEM_freeN((void *)mcords);
@@ -3827,7 +3836,8 @@ static void UV_OT_reveal(wmOperatorType *ot)
static int uv_set_2d_cursor_poll(bContext *C)
{
return ED_operator_uvedit_space_image(C) ||
- ED_space_image_maskedit_poll(C);
+ ED_space_image_maskedit_poll(C) ||
+ ED_space_image_paint_curve(C);
}
static int uv_set_2d_cursor_exec(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 5f22a201600..79f53e1d971 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -372,7 +372,7 @@ static float p_vec_angle(float *v1, float *v2, float *v3)
else if (dot >= 1.0f)
return 0.0f;
else
- return (float)acos(dot);
+ return acosf(dot);
}
static float p_vec2_angle(float *v1, float *v2, float *v3)
@@ -433,7 +433,7 @@ static float p_edge_length(PEdge *e)
d[1] = v2->co[1] - v1->co[1];
d[2] = v2->co[2] - v1->co[2];
- return sqrt(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
+ return sqrtf(d[0] * d[0] + d[1] * d[1] + d[2] * d[2]);
}
static float p_edge_uv_length(PEdge *e)
@@ -444,7 +444,7 @@ static float p_edge_uv_length(PEdge *e)
d[0] = v2->uv[0] - v1->uv[0];
d[1] = v2->uv[1] - v1->uv[1];
- return sqrt(d[0] * d[0] + d[1] * d[1]);
+ return sqrtf(d[0] * d[0] + d[1] * d[1]);
}
static void p_chart_uv_bbox(PChart *chart, float minv[2], float maxv[2])
@@ -2353,8 +2353,8 @@ static void p_abf_compute_sines(PAbfSystem *sys)
float *sine = sys->sine, *cosine = sys->cosine, *alpha = sys->alpha;
for (i = 0; i < sys->nangles; i++, sine++, cosine++, alpha++) {
- *sine = sin(*alpha);
- *cosine = cos(*alpha);
+ *sine = sinf(*alpha);
+ *cosine = cosf(*alpha);
}
}
@@ -3163,9 +3163,9 @@ static PBool p_chart_lscm_solve(PHandle *handle, PChart *chart)
SWAP(PVert *, v2, v3);
}
- sina1 = sin(a1);
- sina2 = sin(a2);
- sina3 = sin(a3);
+ sina1 = sinf(a1);
+ sina2 = sinf(a2);
+ sina3 = sinf(a3);
sinmax = max_fff(sina1, sina2, sina3);
@@ -3314,7 +3314,7 @@ static float p_face_stretch(PFace *f)
a = dot_v3v3(Ps, Ps);
c = dot_v3v3(Pt, Pt);
- T = sqrt(0.5f * (a + c));
+ T = sqrtf(0.5f * (a + c));
if (f->flag & PFACE_FILLED)
T *= 0.2f;
@@ -3630,8 +3630,8 @@ static float p_chart_minimum_area_angle(PChart *chart)
static void p_chart_rotate_minimum_area(PChart *chart)
{
float angle = p_chart_minimum_area_angle(chart);
- float sine = sin(angle);
- float cosine = cos(angle);
+ float sine = sinf(angle);
+ float cosine = cosf(angle);
PVert *v;
for (v = chart->verts; v; v = v->nextlink) {
@@ -4045,7 +4045,7 @@ static void p_smooth(PChart *chart)
diff[0] = p[0] - oldp[0];
diff[1] = p[1] - oldp[1];
- length = sqrt(diff[0] * diff[0] + diff[1] * diff[1]);
+ length = len_v2(diff);
d = max_ff(d, length);
moved += length;
}
@@ -4559,7 +4559,7 @@ void param_pack(ParamHandle *handle, float margin, bool do_rotate)
box->index = i; /* warning this index skips PCHART_NOPACK boxes */
if (margin > 0.0f)
- area += sqrt(box->w * box->h);
+ area += sqrtf(box->w * box->h);
}
if (margin > 0.0f) {
@@ -4661,7 +4661,7 @@ void param_average(ParamHandle *handle)
/* Move center to 0,0 */
p_chart_uv_translate(chart, trans);
- p_chart_uv_scale(chart, sqrt(fac / tot_fac));
+ p_chart_uv_scale(chart, sqrtf(fac / tot_fac));
/* Move to original center */
trans[0] = -trans[0];
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index ba4b65f4ed4..fcd5267fd44 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1360,7 +1360,7 @@ static unsigned int uv_edge_hash(const void *key)
BLI_ghashutil_uinthash(edge->uv1);
}
-static int uv_edge_compare(const void *a, const void *b)
+static bool uv_edge_compare(const void *a, const void *b)
{
UvEdge *edge1 = (UvEdge *)a;
UvEdge *edge2 = (UvEdge *)b;
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index 21e7bb00204..335d8e6589e 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -201,7 +201,7 @@ void uvedit_get_aspect(Scene *scene, Object *ob, BMEditMesh *em, float *aspx, fl
if (efa) {
if (BKE_scene_use_new_shading_nodes(scene)) {
- ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL);
+ ED_object_get_active_image(ob, efa->mat_nr + 1, &ima, NULL, NULL, NULL);
}
else {
MTexPoly *tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
@@ -938,7 +938,7 @@ static void uv_map_rotation_matrix(float result[4][4], RegionView3D *rv3d, Objec
rotup[0][0] = 1.0f / radius;
/* calculate transforms*/
- mul_serie_m4(result, rotup, rotside, viewmatrix, rotobj, NULL, NULL, NULL, NULL);
+ mul_m4_series(result, rotup, rotside, viewmatrix, rotobj);
}
static void uv_map_transform(bContext *C, wmOperator *op, float center[3], float rotmat[4][4])
diff --git a/source/blender/freestyle/CMakeLists.txt b/source/blender/freestyle/CMakeLists.txt
index c94a5ac9f92..cb187eca6ac 100644
--- a/source/blender/freestyle/CMakeLists.txt
+++ b/source/blender/freestyle/CMakeLists.txt
@@ -189,8 +189,6 @@ set(SRC
intern/python/StrokeShader/BPy_CalligraphicShader.h
intern/python/StrokeShader/BPy_ColorNoiseShader.cpp
intern/python/StrokeShader/BPy_ColorNoiseShader.h
- intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp
- intern/python/StrokeShader/BPy_ColorVariationPatternShader.h
intern/python/StrokeShader/BPy_ConstantColorShader.cpp
intern/python/StrokeShader/BPy_ConstantColorShader.h
intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp
@@ -211,22 +209,12 @@ set(SRC
intern/python/StrokeShader/BPy_SmoothingShader.h
intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp
intern/python/StrokeShader/BPy_SpatialNoiseShader.h
- intern/python/StrokeShader/BPy_StrokeTextureShader.cpp
- intern/python/StrokeShader/BPy_StrokeTextureShader.h
intern/python/StrokeShader/BPy_StrokeTextureStepShader.cpp
intern/python/StrokeShader/BPy_StrokeTextureStepShader.h
- intern/python/StrokeShader/BPy_TextureAssignerShader.cpp
- intern/python/StrokeShader/BPy_TextureAssignerShader.h
intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp
intern/python/StrokeShader/BPy_ThicknessNoiseShader.h
- intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp
- intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h
intern/python/StrokeShader/BPy_TipRemoverShader.cpp
intern/python/StrokeShader/BPy_TipRemoverShader.h
- intern/python/StrokeShader/BPy_fstreamShader.cpp
- intern/python/StrokeShader/BPy_fstreamShader.h
- intern/python/StrokeShader/BPy_streamShader.cpp
- intern/python/StrokeShader/BPy_streamShader.h
intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.cpp
intern/python/UnaryFunction0D/BPy_UnaryFunction0DDouble.h
intern/python/UnaryFunction0D/BPy_UnaryFunction0DEdgeNature.cpp
@@ -412,6 +400,8 @@ set(SRC
intern/scene_graph/OrientedLineRep.h
intern/scene_graph/Rep.cpp
intern/scene_graph/Rep.h
+ intern/scene_graph/SceneHash.cpp
+ intern/scene_graph/SceneHash.h
intern/scene_graph/ScenePrettyPrinter.cpp
intern/scene_graph/ScenePrettyPrinter.h
intern/scene_graph/SceneVisitor.cpp
diff --git a/source/blender/freestyle/FRS_freestyle.h b/source/blender/freestyle/FRS_freestyle.h
index 7be51b37f7a..9766372507b 100644
--- a/source/blender/freestyle/FRS_freestyle.h
+++ b/source/blender/freestyle/FRS_freestyle.h
@@ -30,8 +30,9 @@ extern "C" {
#endif
struct Render;
+struct Material;
struct FreestyleConfig;
-struct bContext;
+struct FreestyleLineStyle;
extern struct Scene *freestyle_scene;
extern float freestyle_viewpoint[3];
@@ -47,6 +48,7 @@ int FRS_is_freestyle_enabled(struct SceneRenderLayer *srl);
void FRS_init_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_free_view_map_cache(void);
void FRS_composite_result(struct Render *re, struct SceneRenderLayer *srl, struct Render *freestyle_render);
void FRS_exit(void);
@@ -57,6 +59,9 @@ void FRS_delete_active_lineset(struct FreestyleConfig *config);
void FRS_move_active_lineset_up(struct FreestyleConfig *config);
void FRS_move_active_lineset_down(struct FreestyleConfig *config);
+/* Testing */
+struct Material *FRS_create_stroke_material(struct Main *bmain, struct FreestyleLineStyle *linestyle);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index 2bd31ea03a1..7ecb4164caf 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -118,6 +118,7 @@ Controller::Controller()
_Canvas = new AppCanvas;
_inter = new PythonInterpreter();
+ _EnableViewMapCache = false;
_EnableQI = true;
_EnableFaceSmoothness = false;
_ComputeRidges = true;
@@ -126,6 +127,7 @@ Controller::Controller()
_ComputeMaterialBoundaries = true;
_sphereRadius = 1.0;
_creaseAngle = 134.43;
+ prevSceneHash = -1.0;
init_options();
}
@@ -212,6 +214,19 @@ void Controller::setContext(bContext *C)
py_inter->setContext(C);
}
+bool Controller::hitViewMapCache()
+{
+ if (!_EnableViewMapCache) {
+ return false;
+ }
+ real hashCode = sceneHashFunc.getValue();
+ if (prevSceneHash == hashCode) {
+ return (NULL != _ViewMap);
+ }
+ prevSceneHash = hashCode;
+ return false;
+}
+
int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
{
BlenderFileLoader loader(re, srl);
@@ -242,6 +257,7 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Scene loaded" << endl;
printf("Mesh cleaning : %lf\n", duration);
+ printf("View map cache : %s\n", _EnableViewMapCache ? "enabled" : "disabled");
}
_SceneNumFaces += loader.numFacesRead();
@@ -263,6 +279,22 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
if (_pRenderMonitor->testBreak())
return 0;
+ if (_EnableViewMapCache) {
+ sceneHashFunc.reset();
+ blenderScene->accept(sceneHashFunc);
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("Scene hash : %.16e\n", sceneHashFunc.getValue());
+ }
+ if (hitViewMapCache()) {
+ ClearRootNode();
+ return 0;
+ }
+ else {
+ delete _ViewMap;
+ _ViewMap = NULL;
+ }
+ }
+
_Chrono.start();
WXEdgeBuilder wx_builder;
@@ -298,12 +330,19 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
_bboxDiag = (_RootNode->bbox().getMax() - _RootNode->bbox().getMin()).norm();
if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "Triangles nb : " << _SceneNumFaces << endl;
+ cout << "Triangles nb : " << _SceneNumFaces << " imported, " <<
+ _winged_edge->getNumFaces() << " retained" << endl;
cout << "Bounding Box : " << _bboxDiag << endl;
}
ClearRootNode();
+ _SceneNumFaces = _winged_edge->getNumFaces();
+ if (_SceneNumFaces == 0) {
+ DeleteWingedEdge();
+ return 1;
+ }
+
return 0;
}
@@ -350,7 +389,7 @@ void Controller::DeleteWingedEdge()
_minEdgeSize = DBL_MAX;
}
-void Controller::DeleteViewMap()
+void Controller::DeleteViewMap(bool freeCache)
{
_pView->DetachSilhouette();
if (NULL != _SilhouetteNode) {
@@ -380,14 +419,20 @@ void Controller::DeleteViewMap()
_pView->DetachDebug();
if (NULL != _DebugNode) {
- int ref = _DebugNode->destroy();
+ int ref = _DebugNode->destroy();
if (0 == ref)
_DebugNode->addRef();
}
if (NULL != _ViewMap) {
- delete _ViewMap;
- _ViewMap = NULL;
+ if (freeCache || !_EnableViewMapCache) {
+ delete _ViewMap;
+ _ViewMap = NULL;
+ prevSceneHash = -1.0;
+ }
+ else {
+ _ViewMap->Clean();
+ }
}
}
@@ -396,40 +441,7 @@ void Controller::ComputeViewMap()
if (!_ListOfModels.size())
return;
- if (NULL != _ViewMap) {
- delete _ViewMap;
- _ViewMap = NULL;
- }
-
- _pView->DetachDebug();
- if (NULL != _DebugNode) {
- int ref = _DebugNode->destroy();
- if (0 == ref)
- _DebugNode->addRef();
- }
-
- _pView->DetachSilhouette();
- if (NULL != _SilhouetteNode) {
- int ref = _SilhouetteNode->destroy();
- if (0 == ref)
- delete _SilhouetteNode;
- }
-
-#if 0
- if (NULL != _ProjectedSilhouette) {
- int ref = _ProjectedSilhouette->destroy();
- if (0 == ref)
- delete _ProjectedSilhouette;
- }
-
- if (NULL != _VisibleProjectedSilhouette) {
- int ref = _VisibleProjectedSilhouette->destroy();
- if (0 == ref) {
- delete _VisibleProjectedSilhouette;
- _VisibleProjectedSilhouette = NULL;
- }
- }
-#endif
+ DeleteViewMap(true);
// retrieve the 3D viewpoint and transformations information
//----------------------------------------------------------
@@ -756,6 +768,16 @@ int Controller::getVisibilityAlgo()
return FREESTYLE_ALGO_ADAPTIVE_TRADITIONAL;
}
+void Controller::setViewMapCache(bool iBool)
+{
+ _EnableViewMapCache = iBool;
+}
+
+bool Controller::getViewMapCache() const
+{
+ return _EnableViewMapCache;
+}
+
void Controller::setQuantitativeInvisibility(bool iBool)
{
_EnableQI = iBool;
diff --git a/source/blender/freestyle/intern/application/Controller.h b/source/blender/freestyle/intern/application/Controller.h
index f5e50347d0f..9fe57d92cf4 100644
--- a/source/blender/freestyle/intern/application/Controller.h
+++ b/source/blender/freestyle/intern/application/Controller.h
@@ -32,6 +32,7 @@
//#include "ConfigIO.h"
#include "../geometry/FastGrid.h"
+#include "../scene_graph/SceneHash.h"
#include "../system/Interpreter.h"
#include "../system/ProgressBar.h"
#include "../system/Precision.h"
@@ -96,7 +97,7 @@ public:
void Clear();
void ClearRootNode();
void DeleteWingedEdge();
- void DeleteViewMap();
+ void DeleteViewMap(bool freeCache = false);
void toggleLayer(unsigned index, bool iDisplay);
void setModified(unsigned index, bool iMod);
void resetModified(bool iMod=false);
@@ -118,6 +119,8 @@ public:
void setVisibilityAlgo(int algo);
int getVisibilityAlgo();
+ void setViewMapCache(bool iBool);
+ bool getViewMapCache() const;
void setQuantitativeInvisibility(bool iBool); // if true, we compute quantitativeInvisibility
bool getQuantitativeInvisibility() const;
void setFaceSmoothness(bool iBool);
@@ -144,6 +147,8 @@ public:
void setModulesDir(const string& dir);
string getModulesDir() const;
+ bool hitViewMapCache();
+
void resetInterpreter();
public:
@@ -231,6 +236,7 @@ private:
string _help_index;
string _browser_cmd;
+ bool _EnableViewMapCache;
bool _EnableQI;
bool _EnableFaceSmoothness;
bool _ComputeRidges;
@@ -244,6 +250,9 @@ private:
FEdgeXDetector edgeDetector;
+ SceneHash sceneHashFunc;
+ real prevSceneHash;
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Controller")
#endif
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
index a26bb0fa81e..57882cbce0c 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp
@@ -28,6 +28,8 @@
#include "BKE_global.h"
+#include <sstream>
+
namespace Freestyle {
BlenderFileLoader::BlenderFileLoader(Render *re, SceneRenderLayer *srl)
@@ -38,6 +40,7 @@ BlenderFileLoader::BlenderFileLoader(Render *re, SceneRenderLayer *srl)
_numFacesRead = 0;
_minEdgeSize = DBL_MAX;
_smooth = (srl->freestyleConfig.flags & FREESTYLE_FACE_SMOOTHNESS_FLAG) != 0;
+ _pRenderMonitor = NULL;
}
BlenderFileLoader::~BlenderFileLoader()
@@ -86,9 +89,21 @@ NodeGroup *BlenderFileLoader::Load()
#endif
int id = 0;
+ unsigned cnt = 1;
+ unsigned cntStep = (unsigned)ceil(0.01f * _re->totinstance);
for (obi = (ObjectInstanceRen *)_re->instancetable.first; obi; obi = obi->next) {
- if (_pRenderMonitor && _pRenderMonitor->testBreak())
- break;
+ if (_pRenderMonitor) {
+ if (_pRenderMonitor->testBreak())
+ break;
+ if (cnt % cntStep == 0) {
+ stringstream ss;
+ ss << "Freestyle: Mesh loading " << (100 * cnt / _re->totinstance) << "%";
+ _pRenderMonitor->setInfo(ss.str());
+ _pRenderMonitor->progress((float)cnt / _re->totinstance);
+ }
+ cnt++;
+ }
+
if (!(obi->lay & _srl->lay))
continue;
char *name = obi->ob->id.name;
@@ -380,6 +395,8 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
vlr = obr->vlaknodes[a>>8].vlak;
else
vlr++;
+ if (vlr->mat->mode & MA_ONLYCAST)
+ continue;
if (vlr->mat->material_type == MA_TYPE_WIRE) {
wire_material = 1;
continue;
@@ -432,7 +449,7 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
return;
// We allocate memory for the meshes to be imported
- NodeTransform *currentMesh = new NodeTransform;
+ NodeGroup *currentMesh = new NodeGroup;
NodeShape *shape = new NodeShape;
unsigned vSize = 3 * 3 * numFaces;
@@ -473,15 +490,11 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
// by the near and far view planes.
int p;
for (p = 0; p < obr->totvlak; ++p) { // we parse the faces of the mesh
-#if 0
- Lib3dsFace *f = &mesh->faceL[p];
- Lib3dsMaterial *mat = NULL;
-#endif
if ((p & 255) == 0)
vlr = obr->vlaknodes[p>>8].vlak;
else
vlr++;
- if (vlr->mat->material_type == MA_TYPE_WIRE)
+ if ((vlr->mat->mode & MA_ONLYCAST) || vlr->mat->material_type == MA_TYPE_WIRE)
continue;
copy_v3_v3(v1, vlr->v1->co);
copy_v3_v3(v2, vlr->v2->co);
@@ -521,6 +534,11 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
}
else {
RE_vlakren_get_normal(_re, obi, vlr, facenormal);
+#ifndef NDEBUG
+ float tnor[3];
+ normal_tri_v3(tnor, v3, v2, v1); /* normals are inverted in rendering */
+ BLI_assert(dot_v3v3(tnor, facenormal) > 0.0f);
+#endif
copy_v3_v3(n1, facenormal);
copy_v3_v3(n2, facenormal);
copy_v3_v3(n3, facenormal);
@@ -560,12 +578,14 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
Material *mat = vlr->mat;
if (mat) {
+ tmpMat.setLine(mat->line_col[0], mat->line_col[1], mat->line_col[2], mat->line_col[3]);
tmpMat.setDiffuse(mat->r, mat->g, mat->b, mat->alpha);
tmpMat.setSpecular(mat->specr, mat->specg, mat->specb, mat->spectra);
float s = 1.0 * (mat->har + 1) / 4 ; // in Blender: [1;511] => in OpenGL: [0;128]
if (s > 128.f)
s = 128.f;
tmpMat.setShininess(s);
+ tmpMat.setPriority(mat->line_priority);
}
if (meshFrsMaterials.empty()) {
@@ -779,10 +799,6 @@ void BlenderFileLoader::insertShapeNode(ObjectInstanceRen *obi, int id)
rep->setBBox(bbox);
shape->AddRep(rep);
- Matrix44r meshMat = Matrix44r::identity();
- currentMesh->setMatrix(meshMat);
- currentMesh->Translate(0, 0, 0);
-
currentMesh->AddChild(shape);
_Scene->AddChild(currentMesh);
}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 6fff2feec95..456118d4d2f 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -30,26 +30,36 @@
extern "C" {
#include "MEM_guardedalloc.h"
+#include "RNA_access.h"
+#include "RNA_types.h"
+
#include "DNA_camera_types.h"
#include "DNA_listBase.h"
+#include "DNA_linestyle_types.h"
+#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
#include "BKE_customdata.h"
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_library.h" /* free_libblock */
-#include "BKE_main.h" /* struct Main */
#include "BKE_material.h"
#include "BKE_mesh.h"
+#include "BKE_node.h"
#include "BKE_object.h"
#include "BKE_scene.h"
+#include "BLI_ghash.h"
+#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "RE_pipeline.h"
+
+#include "render_types.h"
}
#include <limits.h>
@@ -58,7 +68,7 @@ namespace Freestyle {
BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : StrokeRenderer()
{
- freestyle_bmain = &re->freestyle_bmain;
+ freestyle_bmain = re->freestyle_bmain;
// for stroke mesh generation
_width = re->winx;
@@ -104,7 +114,7 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
BKE_scene_disable_color_management(freestyle_scene);
if (G.debug & G_DEBUG_FREESTYLE) {
- printf("%s: %d threads\n", __func__, freestyle_scene->r.threads);
+ printf("%s: %d thread(s)\n", __func__, BKE_render_num_threads(&freestyle_scene->r));
}
// Render layer
@@ -133,6 +143,15 @@ BlenderStrokeRenderer::BlenderStrokeRenderer(Render *re, int render_count) : Str
// Reset serial mesh ID (used for BlenderStrokeRenderer::NewMesh())
_mesh_id = 0xffffffff;
+
+ // Check if the rendering engine uses new shading nodes
+ _use_shading_nodes = BKE_scene_use_new_shading_nodes(freestyle_scene);
+
+ // Create a bNodeTree-to-Material hash table
+ if (_use_shading_nodes)
+ _nodetree_hash = BLI_ghash_ptr_new("BlenderStrokeRenderer::_nodetree_hash");
+ else
+ _nodetree_hash = NULL;
}
BlenderStrokeRenderer::~BlenderStrokeRenderer()
@@ -186,6 +205,9 @@ BlenderStrokeRenderer::~BlenderStrokeRenderer()
lnk = lnk->next;
BKE_libblock_free(freestyle_bmain, ma);
}
+
+ if (_use_shading_nodes)
+ BLI_ghash_free(_nodetree_hash, NULL, NULL);
}
float BlenderStrokeRenderer::get_stroke_vertex_z(void) const
@@ -206,56 +228,298 @@ unsigned int BlenderStrokeRenderer::get_stroke_mesh_id(void) const
return mesh_id;
}
-void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
+Material* BlenderStrokeRenderer::GetStrokeShader(Main *bmain, bNodeTree *iNodeTree, bool do_id_user)
{
- bool has_mat = false;
- int a = 0;
-
- // Look for a good existing material
- for (Link *lnk = (Link *)freestyle_bmain->mat.first; lnk; lnk = lnk->next) {
- Material *ma = (Material*) lnk;
- bool texs_are_good = true;
- // as soon as textures differ it's not the right one
- for (int a = 0; a < MAX_MTEX; a++) {
- if (ma->mtex[a] != iStrokeRep->getMTex(a)) {
- texs_are_good = false;
+ Material *ma = BKE_material_add(bmain, "stroke_shader");
+ bNodeTree *ntree;
+ bNode *output_linestyle = NULL;
+ bNodeSocket *fromsock, *tosock;
+ PointerRNA fromptr, toptr;
+ NodeShaderAttribute *storage;
+
+ if (iNodeTree) {
+ // make a copy of linestyle->nodetree
+ ntree = ntreeCopyTree_ex(iNodeTree, bmain, do_id_user);
+
+ // find the active Output Line Style node
+ for (bNode *node = (bNode *)ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_OUTPUT_LINESTYLE && (node->flag & NODE_DO_OUTPUT)) {
+ output_linestyle = node;
break;
}
}
+ }
+ else {
+ ntree = ntreeAddTree(NULL, "stroke_shader", "ShaderNodeTree");
+ }
+ ma->nodetree = ntree;
+ ma->use_nodes = 1;
+
+ bNode *input_attr_color = nodeAddStaticNode(NULL, ntree, SH_NODE_ATTRIBUTE);
+ input_attr_color->locx = 0.0f;
+ input_attr_color->locy = -200.0f;
+ storage = (NodeShaderAttribute *)input_attr_color->storage;
+ BLI_strncpy(storage->name, "Color", sizeof(storage->name));
+
+ bNode *mix_rgb_color = nodeAddStaticNode(NULL, ntree, SH_NODE_MIX_RGB);
+ mix_rgb_color->custom1 = MA_RAMP_BLEND; // Mix
+ mix_rgb_color->locx = 200.0f;
+ mix_rgb_color->locy = -200.0f;
+ tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr);
+ RNA_float_set(&toptr, "default_value", 0.0f);
+
+ bNode *input_attr_alpha = nodeAddStaticNode(NULL, ntree, SH_NODE_ATTRIBUTE);
+ input_attr_alpha->locx = 400.0f;
+ input_attr_alpha->locy = 300.0f;
+ storage = (NodeShaderAttribute *)input_attr_alpha->storage;
+ BLI_strncpy(storage->name, "Alpha", sizeof(storage->name));
+
+ bNode *mix_rgb_alpha = nodeAddStaticNode(NULL, ntree, SH_NODE_MIX_RGB);
+ mix_rgb_alpha->custom1 = MA_RAMP_BLEND; // Mix
+ mix_rgb_alpha->locx = 600.0f;
+ mix_rgb_alpha->locy = 300.0f;
+ tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr);
+ RNA_float_set(&toptr, "default_value", 0.0f);
+
+ bNode *shader_emission = nodeAddStaticNode(NULL, ntree, SH_NODE_EMISSION);
+ shader_emission->locx = 400.0f;
+ shader_emission->locy = -200.0f;
+
+ bNode *input_light_path = nodeAddStaticNode(NULL, ntree, SH_NODE_LIGHT_PATH);
+ input_light_path->locx = 400.0f;
+ input_light_path->locy = 100.0f;
+
+ bNode *mix_shader_color = nodeAddStaticNode(NULL, ntree, SH_NODE_MIX_SHADER);
+ mix_shader_color->locx = 600.0f;
+ mix_shader_color->locy = -100.0f;
+
+ bNode *shader_transparent = nodeAddStaticNode(NULL, ntree, SH_NODE_BSDF_TRANSPARENT);
+ shader_transparent->locx = 600.0f;
+ shader_transparent->locy = 100.0f;
+
+ bNode *mix_shader_alpha = nodeAddStaticNode(NULL, ntree, SH_NODE_MIX_SHADER);
+ mix_shader_alpha->locx = 800.0f;
+ mix_shader_alpha->locy = 100.0f;
+
+ bNode *output_material = nodeAddStaticNode(NULL, ntree, SH_NODE_OUTPUT_MATERIAL);
+ output_material->locx = 1000.0f;
+ output_material->locy = 100.0f;
+
+ fromsock = (bNodeSocket *)BLI_findlink(&input_attr_color->outputs, 0); // Color
+ tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 1); // Color1
+ nodeAddLink(ntree, input_attr_color, fromsock, mix_rgb_color, tosock);
+
+ fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->outputs, 0); // Color
+ tosock = (bNodeSocket *)BLI_findlink(&shader_emission->inputs, 0); // Color
+ nodeAddLink(ntree, mix_rgb_color, fromsock, shader_emission, tosock);
+
+ fromsock = (bNodeSocket *)BLI_findlink(&shader_emission->outputs, 0); // Emission
+ tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 2); // Shader (second)
+ nodeAddLink(ntree, shader_emission, fromsock, mix_shader_color, tosock);
+
+ fromsock = (bNodeSocket *)BLI_findlink(&input_light_path->outputs, 0); // In Camera Ray
+ tosock = (bNodeSocket *)BLI_findlink(&mix_shader_color->inputs, 0); // Fac
+ nodeAddLink(ntree, input_light_path, fromsock, mix_shader_color, tosock);
+
+ fromsock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->outputs, 0); // Color
+ tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 0); // Fac
+ nodeAddLink(ntree, mix_rgb_alpha, fromsock, mix_shader_alpha, tosock);
+
+ fromsock = (bNodeSocket *)BLI_findlink(&input_attr_alpha->outputs, 0); // Color
+ tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 1); // Color1
+ nodeAddLink(ntree, input_attr_alpha, fromsock, mix_rgb_alpha, tosock);
+
+ fromsock = (bNodeSocket *)BLI_findlink(&shader_transparent->outputs, 0); // BSDF
+ tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 1); // Shader (first)
+ nodeAddLink(ntree, shader_transparent, fromsock, mix_shader_alpha, tosock);
+
+ fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_color->outputs, 0); // Shader
+ tosock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->inputs, 2); // Shader (second)
+ nodeAddLink(ntree, mix_shader_color, fromsock, mix_shader_alpha, tosock);
+
+ fromsock = (bNodeSocket *)BLI_findlink(&mix_shader_alpha->outputs, 0); // Shader
+ tosock = (bNodeSocket *)BLI_findlink(&output_material->inputs, 0); // Surface
+ nodeAddLink(ntree, mix_shader_alpha, fromsock, output_material, tosock);
+
+ if (output_linestyle) {
+ bNodeSocket *outsock;
+ bNodeLink *link;
+
+ mix_rgb_color->custom1 = output_linestyle->custom1; // blend_type
+ mix_rgb_color->custom2 = output_linestyle->custom2; // use_clamp
+
+ outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 0); // Color
+ tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 2); // Color2
+ link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
+ if (link) {
+ nodeAddLink(ntree, link->fromnode, link->fromsock, mix_rgb_color, tosock);
+ }
+ else {
+ float color[4];
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock, &fromptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr);
+ RNA_float_get_array(&fromptr, "default_value", color);
+ RNA_float_set_array(&toptr, "default_value", color);
+ }
- if (texs_are_good) {
- iStrokeRep->setMaterial(ma);
- has_mat = true;
- break; // if textures are good, no need to search anymore
+ outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 1); // Color Fac
+ tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_color->inputs, 0); // Fac
+ link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
+ if (link) {
+ nodeAddLink(ntree, link->fromnode, link->fromsock, mix_rgb_color, tosock);
+ }
+ else {
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock, &fromptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr);
+ RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value"));
}
- }
- // If still no material, create one
- if (!has_mat) {
- Material *ma = BKE_material_add(freestyle_bmain, "stroke_material");
+ outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 2); // Alpha
+ tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 2); // Color2
+ link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
+ if (link) {
+ nodeAddLink(ntree, link->fromnode, link->fromsock, mix_rgb_alpha, tosock);
+ }
+ else {
+ float color[4];
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock, &fromptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr);
+ color[0] = color[1] = color[2] = RNA_float_get(&fromptr, "default_value");
+ color[3] = 1.0f;
+ RNA_float_set_array(&toptr, "default_value", color);
+ }
- ma->mode |= MA_VERTEXCOLP;
- ma->mode |= MA_TRANSP;
- ma->mode |= MA_SHLESS;
- ma->vcol_alpha = 1;
+ outsock = (bNodeSocket *)BLI_findlink(&output_linestyle->inputs, 3); // Alpha Fac
+ tosock = (bNodeSocket *)BLI_findlink(&mix_rgb_alpha->inputs, 0); // Fac
+ link = (bNodeLink *)BLI_findptr(&ntree->links, outsock, offsetof(bNodeLink, tosock));
+ if (link) {
+ nodeAddLink(ntree, link->fromnode, link->fromsock, mix_rgb_alpha, tosock);
+ }
+ else {
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, outsock, &fromptr);
+ RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, tosock, &toptr);
+ RNA_float_set(&toptr, "default_value", RNA_float_get(&fromptr, "default_value"));
+ }
- // Textures
- //for (int a = 0; a < MAX_MTEX; a++) {
- while (iStrokeRep->getMTex(a)) {
- ma->mtex[a] = (MTex *) iStrokeRep->getMTex(a);
+ for (bNode *node = (bNode *)ntree->nodes.first; node; node = node->next) {
+ if (node->type == SH_NODE_UVALONGSTROKE) {
+ // UV output of the UV Along Stroke node
+ bNodeSocket *sock = (bNodeSocket *)BLI_findlink(&node->outputs, 0);
+
+ // add new UV Map node
+ bNode *input_uvmap = nodeAddStaticNode(NULL, ntree, SH_NODE_UVMAP);
+ input_uvmap->locx = node->locx - 200.0f;
+ input_uvmap->locy = node->locy;
+ NodeShaderUVMap *storage = (NodeShaderUVMap *)input_uvmap->storage;
+ if (node->custom1 & 1) { // use_tips
+ BLI_strncpy(storage->uv_map, "along_stroke_tips", sizeof(storage->uv_map));
+ }
+ else {
+ BLI_strncpy(storage->uv_map, "along_stroke", sizeof(storage->uv_map));
+ }
+ fromsock = (bNodeSocket *)BLI_findlink(&input_uvmap->outputs, 0); // UV
- // We'll generate both with tips and without tips
- // coordinates, on two different UV layers.
- if (ma->mtex[a]->texflag & MTEX_TIPS) {
- BLI_strncpy(ma->mtex[a]->uvname, "along_stroke_tips", sizeof(ma->mtex[a]->uvname));
+ // replace links from the UV Along Stroke node by links from the UV Map node
+ for (bNodeLink *link = (bNodeLink *)ntree->links.first; link; link = link->next) {
+ if (link->fromnode == node && link->fromsock == sock) {
+ nodeAddLink(ntree, input_uvmap, fromsock, link->tonode, link->tosock);
+ }
+ }
+ nodeRemSocketLinks(ntree, sock);
}
- else {
- BLI_strncpy(ma->mtex[a]->uvname, "along_stroke", sizeof(ma->mtex[a]->uvname));
+ }
+ }
+
+ nodeSetActive(ntree, output_material);
+ ntreeUpdateTree(bmain, ntree);
+
+ return ma;
+}
+
+void BlenderStrokeRenderer::RenderStrokeRep(StrokeRep *iStrokeRep) const
+{
+ if (_use_shading_nodes) {
+ bNodeTree *nt = iStrokeRep->getNodeTree();
+ Material *ma = (Material *)BLI_ghash_lookup(_nodetree_hash, nt);
+ if (!ma) {
+ ma = BlenderStrokeRenderer::GetStrokeShader(freestyle_bmain, nt, false);
+ BLI_ghash_insert(_nodetree_hash, nt, ma);
+ }
+
+ if (strcmp(freestyle_scene->r.engine, "CYCLES") == 0) {
+ PointerRNA scene_ptr, freestyle_scene_ptr;
+ RNA_pointer_create(NULL, &RNA_Scene, old_scene, &scene_ptr);
+ RNA_pointer_create(NULL, &RNA_Scene, freestyle_scene, &freestyle_scene_ptr);
+
+ PointerRNA cycles_ptr = RNA_pointer_get(&scene_ptr, "cycles");
+ PointerRNA freestyle_cycles_ptr = RNA_pointer_get(&freestyle_scene_ptr, "cycles");
+
+ int flag;
+ RNA_STRUCT_BEGIN(&freestyle_cycles_ptr, prop)
+ {
+ flag = RNA_property_flag(prop);
+ if (flag & PROP_HIDDEN)
+ continue;
+ RNA_property_copy(&freestyle_cycles_ptr, &cycles_ptr, prop, -1);
}
- a++;
+ RNA_STRUCT_END;
+
+ RNA_boolean_set(&freestyle_cycles_ptr, "film_transparent", 1);
}
+
iStrokeRep->setMaterial(ma);
}
+ else {
+ bool has_mat = false;
+ int a = 0;
+
+ // Look for a good existing material
+ for (Link *lnk = (Link *)freestyle_bmain->mat.first; lnk; lnk = lnk->next) {
+ Material *ma = (Material*)lnk;
+ bool texs_are_good = true;
+ // as soon as textures differ it's not the right one
+ for (int a = 0; a < MAX_MTEX; a++) {
+ if (ma->mtex[a] != iStrokeRep->getMTex(a)) {
+ texs_are_good = false;
+ break;
+ }
+ }
+
+ if (texs_are_good) {
+ iStrokeRep->setMaterial(ma);
+ has_mat = true;
+ break; // if textures are good, no need to search anymore
+ }
+ }
+
+ // If still no material, create one
+ if (!has_mat) {
+ Material *ma = BKE_material_add(freestyle_bmain, "stroke_material");
+ ma->mode |= MA_VERTEXCOLP;
+ ma->mode |= MA_TRANSP;
+ ma->mode |= MA_SHLESS;
+ ma->vcol_alpha = 1;
+
+ // Textures
+ while (iStrokeRep->getMTex(a)) {
+ ma->mtex[a] = (MTex *)iStrokeRep->getMTex(a);
+
+ // We'll generate both with tips and without tips
+ // coordinates, on two different UV layers.
+ if (ma->mtex[a]->texflag & MTEX_TIPS) {
+ BLI_strncpy(ma->mtex[a]->uvname, "along_stroke_tips", sizeof(ma->mtex[a]->uvname));
+ }
+ else {
+ BLI_strncpy(ma->mtex[a]->uvname, "along_stroke", sizeof(ma->mtex[a]->uvname));
+ }
+ a++;
+ }
+
+ iStrokeRep->setMaterial(ma);
+ }
+ }
RenderStrokeRepBasic(iStrokeRep);
}
@@ -318,7 +582,7 @@ void BlenderStrokeRenderer::test_strip_visibility(Strip::vertex_container& strip
void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
{
vector<Strip*>& strips = iStrokeRep->getStrips();
- const bool hasTex = iStrokeRep->getMTex(0) != NULL;
+ const bool hasTex = iStrokeRep->hasTex();
Strip::vertex_container::iterator v[3];
StrokeVertexRep *svRep[3];
unsigned int vertex_index, edge_index, loop_index;
@@ -355,22 +619,35 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
// vertices allocation
mesh->totvert = totvert; // visible_faces + visible_segments * 2;
- mesh->mvert = (MVert *)CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
+ CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert);
// edges allocation
mesh->totedge = totedge; // visible_faces * 2 + visible_segments;
- mesh->medge = (MEdge *)CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
+ CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge);
// faces allocation
mesh->totpoly = totpoly; // visible_faces;
- mesh->mpoly = (MPoly *)CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
+ CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly);
// loops allocation
mesh->totloop = totloop; // visible_faces * 3;
- mesh->mloop = (MLoop *)CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
+ CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop);
- // colors allocation
- mesh->mloopcol = (MLoopCol *)CustomData_add_layer(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop);
+ // uv maps
+ MLoopUV *loopsuv[2] = { NULL };
+ if (hasTex) {
+ loopsuv[0] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke");
+ loopsuv[1] = (MLoopUV *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke_tips");
+
+ CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke");
+ CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke_tips");
+ }
+
+ // colors and transparency (the latter represented by grayscale colors)
+ MLoopCol *colors = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Color");
+ MLoopCol *transp = (MLoopCol *)CustomData_add_layer_named(&mesh->ldata, CD_MLOOPCOL, CD_CALLOC, NULL, mesh->totloop, "Alpha");
+
+ BKE_mesh_update_customdata_pointers(mesh, true);
////////////////////
// Data copy
@@ -380,28 +657,6 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
MEdge *edges = mesh->medge;
MPoly *polys = mesh->mpoly;
MLoop *loops = mesh->mloop;
- MLoopCol *colors = mesh->mloopcol;
- MLoopUV *loopsuv[2] = {NULL};
-
- if (hasTex) {
- // First UV layer
- CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke");
- CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke");
- CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 0);
- CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 0);
- BKE_mesh_update_customdata_pointers(mesh, true);
-
- loopsuv[0] = mesh->mloopuv;
-
- // Second UV layer
- CustomData_add_layer_named(&mesh->pdata, CD_MTEXPOLY, CD_CALLOC, NULL, mesh->totpoly, "along_stroke_tips");
- CustomData_add_layer_named(&mesh->ldata, CD_MLOOPUV, CD_CALLOC, NULL, mesh->totloop, "along_stroke_tips");
- CustomData_set_layer_active(&mesh->pdata, CD_MTEXPOLY, 1);
- CustomData_set_layer_active(&mesh->ldata, CD_MLOOPUV, 1);
- BKE_mesh_update_customdata_pointers(mesh, true);
-
- loopsuv[1] = mesh->mloopuv;
- }
vertex_index = edge_index = loop_index = 0;
@@ -536,15 +791,11 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
loopsuv[L][2].uv[0] = svRep[0]->texCoord(L).x();
loopsuv[L][2].uv[1] = svRep[0]->texCoord(L).y();
}
- /* freestyle tex-origin is upside-down */
- for (int i = 0; i < 3; i++) {
- loopsuv[L][i].uv[1] *= -1;
- }
loopsuv[L] += 3;
}
}
- // colors
+ // colors and alpha transparency
if (is_odd) {
colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
@@ -560,7 +811,7 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
colors[2].g = (short)(255.0f * svRep[1]->color()[1]);
colors[2].b = (short)(255.0f * svRep[1]->color()[2]);
colors[2].a = (short)(255.0f * svRep[1]->alpha());
- }
+ }
else {
colors[0].r = (short)(255.0f * svRep[2]->color()[0]);
colors[0].g = (short)(255.0f * svRep[2]->color()[1]);
@@ -577,7 +828,11 @@ void BlenderStrokeRenderer::RenderStrokeRepBasic(StrokeRep *iStrokeRep) const
colors[2].b = (short)(255.0f * svRep[0]->color()[2]);
colors[2].a = (short)(255.0f * svRep[0]->alpha());
}
+ transp[0].r = transp[0].g = transp[0].b = colors[0].a;
+ transp[1].r = transp[1].g = transp[1].b = colors[1].a;
+ transp[2].r = transp[2].g = transp[2].b = colors[2].a;
colors += 3;
+ transp += 3;
}
} // loop over strip vertices
} // loop over strips
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
index 0025d48e77f..74e5d321df2 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
@@ -29,12 +29,14 @@
#include "../system/FreestyleConfig.h"
extern "C" {
-#include "DNA_material_types.h"
-#include "DNA_scene_types.h"
-
-#include "BKE_main.h"
-
-#include "render_types.h"
+struct GHash;
+struct Main;
+struct Material;
+struct Object;
+struct Render;
+struct Scene;
+struct bContext;
+struct bNodeTree;
}
namespace Freestyle {
@@ -53,13 +55,18 @@ public:
Render *RenderScene(Render *re, bool render);
+ static Material* GetStrokeShader(Main *bmain, bNodeTree *iNodeTree, bool do_id_user);
+
protected:
Main *freestyle_bmain;
Scene *old_scene;
Scene *freestyle_scene;
+ bContext *_context;
float _width, _height;
float _z, _z_delta;
unsigned int _mesh_id;
+ bool _use_shading_nodes;
+ struct GHash *_nodetree_hash;
float get_stroke_vertex_z(void) const;
unsigned int get_stroke_mesh_id(void) const;
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
index a1fb9fade58..21776396ebc 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStyleModule.h
@@ -29,10 +29,10 @@
#include "../system/PythonInterpreter.h"
extern "C" {
-#include "BKE_global.h"
-#include "BKE_library.h"
-#include "BKE_text.h"
-#include "BLI_utildefines.h"
+#include "BLI_utildefines.h" // BLI_assert()
+
+struct Scene;
+struct Text;
}
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 49c3fdce251..4dd4598cc91 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -31,6 +31,8 @@
#include "../application/AppView.h"
#include "../application/Controller.h"
+#include "BlenderStrokeRenderer.h"
+
using namespace std;
using namespace Freestyle;
@@ -41,6 +43,7 @@ extern "C" {
#include "DNA_camera_types.h"
#include "DNA_freestyle_types.h"
#include "DNA_group_types.h"
+#include "DNA_material_types.h"
#include "DNA_text_types.h"
#include "BKE_freestyle.h"
@@ -84,8 +87,6 @@ int freestyle_viewport[4];
// current scene
Scene *freestyle_scene;
-static string default_module_path;
-
static void load_post_callback(struct Main *main, struct ID *id, void *arg)
{
lineset_copied = false;
@@ -115,9 +116,6 @@ void FRS_initialize()
freestyle_scene = NULL;
lineset_copied = false;
- default_module_path = pathconfig->getProjectDir() + Config::DIR_SEP + "style_modules" +
- Config::DIR_SEP + "contour.py";
-
BLI_callback_add(&load_post_callback_funcstore, BLI_CB_EVT_LOAD_POST);
freestyle_is_initialized = 1;
@@ -476,6 +474,9 @@ static void prepare(Main *bmain, Render *re, SceneRenderLayer *srl)
cout << " Z = " << (z ? "enabled" : "disabled") << endl;
}
+ if (controller->hitViewMapCache())
+ return;
+
// compute view map
re->i.infostr = "Freestyle: View map creation";
re->stats_draw(re->sdh, &re->i);
@@ -582,7 +583,7 @@ void FRS_init_stroke_rendering(Render *re)
Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
{
- Main bmain = {0};
+ Main *freestyle_bmain = re->freestyle_bmain;
Render *freestyle_render = NULL;
Text *text, *next_text;
@@ -591,6 +592,7 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
RenderMonitor monitor(re);
controller->setRenderMonitor(&monitor);
+ controller->setViewMapCache((srl->freestyleConfig.flags & FREESTYLE_VIEW_MAP_CACHE) ? true : false);
if (G.debug & G_DEBUG_FREESTYLE) {
cout << endl;
@@ -604,40 +606,40 @@ Render *FRS_do_stroke_rendering(Render *re, SceneRenderLayer *srl, int render)
// - add style modules
// - set parameters
// - compute view map
- prepare(&bmain, re, srl);
+ prepare(freestyle_bmain, re, srl);
if (re->test_break(re->tbh)) {
controller->CloseFile();
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Break" << endl;
}
- return NULL;
}
-
- // render and composite Freestyle result
- if (controller->_ViewMap) {
- // render strokes
- re->i.infostr = "Freestyle: Stroke rendering";
- re->stats_draw(re->sdh, &re->i);
- re->i.infostr = NULL;
- freestyle_scene = re->scene;
- controller->DrawStrokes();
- freestyle_render = controller->RenderStrokes(re, true);
- controller->CloseFile();
- freestyle_scene = NULL;
-
- // composite result
- FRS_composite_result(re, srl, freestyle_render);
- RE_FreeRenderResult(freestyle_render->result);
- freestyle_render->result = NULL;
+ else {
+ // render and composite Freestyle result
+ if (controller->_ViewMap) {
+ // render strokes
+ re->i.infostr = "Freestyle: Stroke rendering";
+ re->stats_draw(re->sdh, &re->i);
+ re->i.infostr = NULL;
+ freestyle_scene = re->scene;
+ controller->DrawStrokes();
+ freestyle_render = controller->RenderStrokes(re, true);
+ controller->CloseFile();
+ freestyle_scene = NULL;
+
+ // composite result
+ FRS_composite_result(re, srl, freestyle_render);
+ RE_FreeRenderResult(freestyle_render->result);
+ freestyle_render->result = NULL;
+ }
}
// Free temp main (currently only text blocks are stored there)
- for (text = (Text *) bmain.text.first; text; text = next_text) {
+ for (text = (Text *)freestyle_bmain->text.first; text; text = next_text) {
next_text = (Text *) text->id.next;
- BKE_text_unlink(&bmain, text);
- BKE_libblock_free(&bmain, text);
+ BKE_text_unlink(freestyle_bmain, text);
+ BKE_libblock_free(freestyle_bmain, text);
}
return freestyle_render;
@@ -649,6 +651,17 @@ void FRS_finish_stroke_rendering(Render *re)
controller->Clear();
}
+void FRS_free_view_map_cache(void)
+{
+ // free cache
+ controller->DeleteViewMap(true);
+#if 0
+ if (G.debug & G_DEBUG_FREESTYLE) {
+ printf("View map cache freed\n");
+ }
+#endif
+}
+
//=======================================================
// Freestyle Panel Configuration
//=======================================================
@@ -735,4 +748,14 @@ void FRS_move_active_lineset_down(FreestyleConfig *config)
}
}
+// Testing
+
+Material *FRS_create_stroke_material(Main *bmain, struct FreestyleLineStyle *linestyle)
+{
+ bNodeTree *nt = (linestyle->use_nodes) ? linestyle->nodetree : NULL;
+ Material *ma = BlenderStrokeRenderer::GetStrokeShader(bmain, nt, true);
+ ma->id.us = 0;
+ return ma;
+}
+
} // extern "C"
diff --git a/source/blender/freestyle/intern/geometry/Grid.h b/source/blender/freestyle/intern/geometry/Grid.h
index c0cab2a05db..c1d04f6b4cc 100644
--- a/source/blender/freestyle/intern/geometry/Grid.h
+++ b/source/blender/freestyle/intern/geometry/Grid.h
@@ -30,9 +30,7 @@
#include <cstring> // for memset
#include <float.h>
-#if !defined(_MSC_VER) || _MSC_VER >= 1700
#include <stdint.h> // For SET_UINT_IN_POINTER, i.e. uintptr_t.
-#endif
#include <vector>
#include "Geom.h"
diff --git a/source/blender/freestyle/intern/geometry/Polygon.h b/source/blender/freestyle/intern/geometry/Polygon.h
index d8b891c77cc..f6dfae55d8d 100644
--- a/source/blender/freestyle/intern/geometry/Polygon.h
+++ b/source/blender/freestyle/intern/geometry/Polygon.h
@@ -97,14 +97,14 @@ public:
max = _max;
}
- inline Point& getBBoxCenter()
+ inline Point getBBoxCenter()
{
Point result;
result = (_min + _max) / 2;
return result;
}
- inline Point& getCenter()
+ inline Point getCenter()
{
Point result;
for (typename vector<Point>::iterator it = _vertices.begin(); it != _vertices.end(); it++)
diff --git a/source/blender/freestyle/intern/python/BPy_Convert.cpp b/source/blender/freestyle/intern/python/BPy_Convert.cpp
index 746d5e75f4c..dbd836bc562 100644
--- a/source/blender/freestyle/intern/python/BPy_Convert.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Convert.cpp
@@ -201,7 +201,7 @@ PyObject *BPy_Interface0D_from_Interface0D(Interface0D& if0D)
{
PyObject *py_if0D = Interface0D_Type.tp_new(&Interface0D_Type, 0, 0);
((BPy_Interface0D *)py_if0D)->if0D = &if0D;
- ((BPy_Interface0D *)py_if0D)->borrowed = 1;
+ ((BPy_Interface0D *)py_if0D)->borrowed = true;
return py_if0D;
}
@@ -209,7 +209,7 @@ PyObject *BPy_Interface1D_from_Interface1D(Interface1D& if1D)
{
PyObject *py_if1D = Interface1D_Type.tp_new(&Interface1D_Type, 0, 0);
((BPy_Interface1D *)py_if1D)->if1D = &if1D;
- ((BPy_Interface1D *)py_if1D)->borrowed = 1;
+ ((BPy_Interface1D *)py_if1D)->borrowed = true;
return py_if1D;
}
@@ -218,7 +218,7 @@ PyObject *BPy_SVertex_from_SVertex(SVertex& sv)
PyObject *py_sv = SVertex_Type.tp_new(&SVertex_Type, 0, 0);
((BPy_SVertex *)py_sv)->sv = &sv;
((BPy_SVertex *)py_sv)->py_if0D.if0D = ((BPy_SVertex *)py_sv)->sv;
- ((BPy_SVertex *)py_sv)->py_if0D.borrowed = 1;
+ ((BPy_SVertex *)py_sv)->py_if0D.borrowed = true;
return py_sv;
}
@@ -228,7 +228,7 @@ PyObject *BPy_FEdgeSharp_from_FEdgeSharp(FEdgeSharp& fes)
((BPy_FEdgeSharp *)py_fe)->fes = &fes;
((BPy_FEdgeSharp *)py_fe)->py_fe.fe = ((BPy_FEdgeSharp *)py_fe)->fes;
((BPy_FEdgeSharp *)py_fe)->py_fe.py_if1D.if1D = ((BPy_FEdgeSharp *)py_fe)->fes;
- ((BPy_FEdgeSharp *)py_fe)->py_fe.py_if1D.borrowed = 1;
+ ((BPy_FEdgeSharp *)py_fe)->py_fe.py_if1D.borrowed = true;
return py_fe;
}
@@ -238,7 +238,7 @@ PyObject *BPy_FEdgeSmooth_from_FEdgeSmooth(FEdgeSmooth& fes)
((BPy_FEdgeSmooth *)py_fe)->fes = &fes;
((BPy_FEdgeSmooth *)py_fe)->py_fe.fe = ((BPy_FEdgeSmooth *)py_fe)->fes;
((BPy_FEdgeSmooth *)py_fe)->py_fe.py_if1D.if1D = ((BPy_FEdgeSmooth *)py_fe)->fes;
- ((BPy_FEdgeSmooth *)py_fe)->py_fe.py_if1D.borrowed = 1;
+ ((BPy_FEdgeSmooth *)py_fe)->py_fe.py_if1D.borrowed = true;
return py_fe;
}
@@ -247,7 +247,7 @@ PyObject *BPy_FEdge_from_FEdge(FEdge& fe)
PyObject *py_fe = FEdge_Type.tp_new(&FEdge_Type, 0, 0);
((BPy_FEdge *)py_fe)->fe = &fe;
((BPy_FEdge *)py_fe)->py_if1D.if1D = ((BPy_FEdge *)py_fe)->fe;
- ((BPy_FEdge *)py_fe)->py_if1D.borrowed = 1;
+ ((BPy_FEdge *)py_fe)->py_if1D.borrowed = true;
return py_fe;
}
@@ -265,7 +265,7 @@ PyObject *BPy_Stroke_from_Stroke(Stroke& s)
PyObject *py_s = Stroke_Type.tp_new(&Stroke_Type, 0, 0);
((BPy_Stroke *)py_s)->s = &s;
((BPy_Stroke *)py_s)->py_if1D.if1D = ((BPy_Stroke *)py_s)->s;
- ((BPy_Stroke *)py_s)->py_if1D.borrowed = 1;
+ ((BPy_Stroke *)py_s)->py_if1D.borrowed = true;
return py_s;
}
@@ -273,7 +273,7 @@ PyObject *BPy_StrokeAttribute_from_StrokeAttribute(StrokeAttribute& sa)
{
PyObject *py_sa = StrokeAttribute_Type.tp_new(&StrokeAttribute_Type, 0, 0);
((BPy_StrokeAttribute *)py_sa)->sa = &sa;
- ((BPy_StrokeAttribute *)py_sa)->borrowed = 1;
+ ((BPy_StrokeAttribute *)py_sa)->borrowed = true;
return py_sa;
}
@@ -292,7 +292,7 @@ PyObject *BPy_StrokeVertex_from_StrokeVertex(StrokeVertex& sv)
((BPy_StrokeVertex *)py_sv)->sv = &sv;
((BPy_StrokeVertex *)py_sv)->py_cp.cp = ((BPy_StrokeVertex *)py_sv)->sv;
((BPy_StrokeVertex *)py_sv)->py_cp.py_if0D.if0D = ((BPy_StrokeVertex *)py_sv)->sv;
- ((BPy_StrokeVertex *)py_sv)->py_cp.py_if0D.borrowed = 1;
+ ((BPy_StrokeVertex *)py_sv)->py_cp.py_if0D.borrowed = true;
return py_sv;
}
@@ -301,7 +301,7 @@ PyObject *BPy_ViewVertex_from_ViewVertex(ViewVertex& vv)
PyObject *py_vv = ViewVertex_Type.tp_new(&ViewVertex_Type, 0, 0);
((BPy_ViewVertex *)py_vv)->vv = &vv;
((BPy_ViewVertex *)py_vv)->py_if0D.if0D = ((BPy_ViewVertex *)py_vv)->vv;
- ((BPy_ViewVertex *)py_vv)->py_if0D.borrowed = 1;
+ ((BPy_ViewVertex *)py_vv)->py_if0D.borrowed = true;
return py_vv;
}
@@ -311,7 +311,7 @@ PyObject *BPy_NonTVertex_from_NonTVertex(NonTVertex& ntv)
((BPy_NonTVertex *)py_ntv)->ntv = &ntv;
((BPy_NonTVertex *)py_ntv)->py_vv.vv = ((BPy_NonTVertex *)py_ntv)->ntv;
((BPy_NonTVertex *)py_ntv)->py_vv.py_if0D.if0D = ((BPy_NonTVertex *)py_ntv)->ntv;
- ((BPy_NonTVertex *)py_ntv)->py_vv.py_if0D.borrowed = 1;
+ ((BPy_NonTVertex *)py_ntv)->py_vv.py_if0D.borrowed = true;
return py_ntv;
}
@@ -321,7 +321,7 @@ PyObject *BPy_TVertex_from_TVertex(TVertex& tv)
((BPy_TVertex *)py_tv)->tv = &tv;
((BPy_TVertex *)py_tv)->py_vv.vv = ((BPy_TVertex *)py_tv)->tv;
((BPy_TVertex *)py_tv)->py_vv.py_if0D.if0D = ((BPy_TVertex *)py_tv)->tv;
- ((BPy_TVertex *)py_tv)->py_vv.py_if0D.borrowed = 1;
+ ((BPy_TVertex *)py_tv)->py_vv.py_if0D.borrowed = true;
return py_tv;
}
@@ -337,7 +337,7 @@ PyObject *BPy_ViewEdge_from_ViewEdge(ViewEdge& ve)
PyObject *py_ve = ViewEdge_Type.tp_new(&ViewEdge_Type, 0, 0);
((BPy_ViewEdge *)py_ve)->ve = &ve;
((BPy_ViewEdge *)py_ve)->py_if1D.if1D = ((BPy_ViewEdge *)py_ve)->ve;
- ((BPy_ViewEdge *)py_ve)->py_if1D.borrowed = 1;
+ ((BPy_ViewEdge *)py_ve)->py_if1D.borrowed = true;
return py_ve;
}
@@ -347,7 +347,7 @@ PyObject *BPy_Chain_from_Chain(Chain& c)
((BPy_Chain *)py_c)->c = &c;
((BPy_Chain *)py_c)->py_c.c = ((BPy_Chain *)py_c)->c;
((BPy_Chain *)py_c)->py_c.py_if1D.if1D = ((BPy_Chain *)py_c)->c;
- ((BPy_Chain *)py_c)->py_c.py_if1D.borrowed = 1;
+ ((BPy_Chain *)py_c)->py_c.py_if1D.borrowed = true;
return py_c;
}
@@ -355,7 +355,7 @@ PyObject *BPy_SShape_from_SShape(SShape& ss)
{
PyObject *py_ss = SShape_Type.tp_new(&SShape_Type, 0, 0);
((BPy_SShape *)py_ss)->ss = &ss;
- ((BPy_SShape *)py_ss)->borrowed = 1;
+ ((BPy_SShape *)py_ss)->borrowed = true;
return py_ss;
}
@@ -363,7 +363,7 @@ PyObject *BPy_ViewShape_from_ViewShape(ViewShape& vs)
{
PyObject *py_vs = ViewShape_Type.tp_new(&ViewShape_Type, 0, 0);
((BPy_ViewShape *)py_vs)->vs = &vs;
- ((BPy_ViewShape *)py_vs)->borrowed = 1;
+ ((BPy_ViewShape *)py_vs)->borrowed = true;
((BPy_ViewShape *)py_vs)->py_ss = NULL;
return py_vs;
}
@@ -387,9 +387,14 @@ PyObject *BPy_IntegrationType_from_IntegrationType(IntegrationType i)
PyObject *BPy_CurvePoint_from_CurvePoint(CurvePoint& cp)
{
PyObject *py_cp = CurvePoint_Type.tp_new(&CurvePoint_Type, 0, 0);
- ((BPy_CurvePoint *) py_cp)->cp = &cp;
+ // CurvePointIterator::operator*() returns a reference of a class data
+ // member whose value is mutable upon iteration over different CurvePoints.
+ // It is likely that such a mutable reference is passed to this function,
+ // so that a new allocated CurvePoint instance is created here to avoid
+ // nasty bugs (cf. T41464).
+ ((BPy_CurvePoint *) py_cp)->cp = new CurvePoint(cp);
((BPy_CurvePoint *) py_cp)->py_if0D.if0D = ((BPy_CurvePoint *)py_cp)->cp;
- ((BPy_CurvePoint *) py_cp)->py_if0D.borrowed = 1;
+ ((BPy_CurvePoint *) py_cp)->py_if0D.borrowed = false;
return py_cp;
}
@@ -718,7 +723,7 @@ bool Vec3r_ptr_from_PyTuple(PyObject *obj, Vec3r &vec)
return true;
}
-// helper for argument parsing
+// helpers for argument parsing
bool float_array_from_PyObject(PyObject *obj, float *v, int n)
{
@@ -745,6 +750,22 @@ bool float_array_from_PyObject(PyObject *obj, float *v, int n)
return 0;
}
+int convert_v4(PyObject *obj, void *v)
+{
+ return mathutils_array_parse((float *)v, 4, 4, obj, "Error parsing 4D vector");
+}
+
+int convert_v3(PyObject *obj, void *v)
+{
+ return mathutils_array_parse((float *)v, 3, 3, obj, "Error parsing 3D vector");
+}
+
+int convert_v2(PyObject *obj, void *v)
+{
+ return mathutils_array_parse((float *)v, 2, 2, obj, "Error parsing 2D vector");
+}
+
+
///////////////////////////////////////////////////////////////////////////////////////////
#ifdef __cplusplus
diff --git a/source/blender/freestyle/intern/python/BPy_Convert.h b/source/blender/freestyle/intern/python/BPy_Convert.h
index cf55ba335cd..e6e763e763e 100644
--- a/source/blender/freestyle/intern/python/BPy_Convert.h
+++ b/source/blender/freestyle/intern/python/BPy_Convert.h
@@ -170,6 +170,9 @@ bool Vec3r_ptr_from_PyTuple(PyObject *obj, Vec3r &vec);
bool float_array_from_PyObject(PyObject *obj, float *v, int n);
+int convert_v4(PyObject *obj, void *v);
+int convert_v3(PyObject *obj, void *v);
+int convert_v2(PyObject *obj, void *v);
///////////////////////////////////////////////////////////////////////////////////////////
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index f390e937aac..5b8d50eb5eb 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -60,6 +60,7 @@ extern "C" {
#include "FRS_freestyle.h"
#include "RNA_access.h"
+#include "DNA_scene_types.h"
#include "bpy_rna.h" /* pyrna_struct_CreatePyObject() */
static char Freestyle_getCurrentScene___doc__[] =
@@ -77,7 +78,7 @@ static PyObject *Freestyle_getCurrentScene(PyObject *self)
return NULL;
}
PointerRNA ptr_scene;
- RNA_pointer_create(NULL, &RNA_Scene, freestyle_scene, &ptr_scene);
+ RNA_pointer_create(&freestyle_scene->id, &RNA_Scene, freestyle_scene, &ptr_scene);
return pyrna_struct_CreatePyObject(&ptr_scene);
}
@@ -138,14 +139,16 @@ static PyObject *Freestyle_blendRamp(PyObject *self, PyObject *args)
PyErr_SetString(PyExc_TypeError, "argument 1 is an unknown ramp blend type");
return NULL;
}
- if (!float_array_from_PyObject(obj1, a, 3)) {
- PyErr_SetString(PyExc_TypeError,
- "argument 2 must be a 3D vector (either a tuple/list of 3 elements or Vector)");
+ if (mathutils_array_parse(a, 3, 3, obj1,
+ "argument 2 must be a 3D vector "
+ "(either a tuple/list of 3 elements or Vector)") == -1)
+ {
return NULL;
}
- if (!float_array_from_PyObject(obj2, b, 3)) {
- PyErr_SetString(PyExc_TypeError,
- "argument 4 must be a 3D vector (either a tuple/list of 3 elements or Vector)");
+ if (mathutils_array_parse(b, 3, 3, obj2,
+ "argument 4 must be a 3D vector "
+ "(either a tuple/list of 3 elements or Vector)") == -1)
+ {
return NULL;
}
ramp_blend(type, a, fac, b);
diff --git a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
index 7fe03dcc9a0..4d0d140474a 100644
--- a/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
+++ b/source/blender/freestyle/intern/python/BPy_FrsMaterial.cpp
@@ -64,11 +64,13 @@ PyDoc_STRVAR(FrsMaterial_doc,
" :arg brother: A Material object.\n"
" :type brother: :class:`Material`\n"
"\n"
-".. method:: __init__(diffuse, ambient, specular, emission, shininess)\n"
+".. method:: __init__(line, diffuse, ambient, specular, emission, shininess, priority)\n"
"\n"
-" Builds a Material from its diffuse, ambient, specular, emissive\n"
-" colors and a shininess coefficient.\n"
+" Builds a Material from its line, diffuse, ambient, specular, emissive\n"
+" colors, a shininess coefficient and line color priority.\n"
"\n"
+" :arg line: The line color.\n"
+" :type line: :class:`mathutils.Vector`, list or tuple of 4 float values\n"
" :arg diffuse: The diffuse color.\n"
" :type diffuse: :class:`mathutils.Vector`, list or tuple of 4 float values\n"
" :arg ambient: The ambient color.\n"
@@ -78,19 +80,17 @@ PyDoc_STRVAR(FrsMaterial_doc,
" :arg emission: The emissive color.\n"
" :type emission: :class:`mathutils.Vector`, list or tuple of 4 float values\n"
" :arg shininess: The shininess coefficient.\n"
-" :type shininess: :class:float");
-
-static int convert_v4(PyObject *obj, void *v)
-{
- return float_array_from_PyObject(obj, (float *)v, 4);
-}
+" :type shininess: float\n"
+" :arg priority: The line color priority.\n"
+" :type priority: int");
static int FrsMaterial_init(BPy_FrsMaterial *self, PyObject *args, PyObject *kwds)
{
static const char *kwlist_1[] = {"brother", NULL};
- static const char *kwlist_2[] = {"diffuse", "ambient", "specular", "emission", "shininess", NULL};
+ static const char *kwlist_2[] = {"line", "diffuse", "ambient", "specular", "emission", "shininess", "priority", NULL};
PyObject *brother = 0;
- float diffuse[4], ambient[4], specular[4], emission[4], shininess;
+ float line[4], diffuse[4], ambient[4], specular[4], emission[4], shininess;
+ int priority;
if (PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist_1, &FrsMaterial_Type, &brother)) {
if (!brother) {
@@ -106,14 +106,15 @@ static int FrsMaterial_init(BPy_FrsMaterial *self, PyObject *args, PyObject *kwd
}
}
else if (PyErr_Clear(),
- PyArg_ParseTupleAndKeywords(args, kwds, "O&O&O&O&f", (char **)kwlist_2,
+ PyArg_ParseTupleAndKeywords(args, kwds, "O&O&O&O&O&fi", (char **)kwlist_2,
+ convert_v4, line,
convert_v4, diffuse,
convert_v4, ambient,
convert_v4, specular,
convert_v4, emission,
- &shininess))
+ &shininess, &priority))
{
- self->m = new FrsMaterial(diffuse, ambient, specular, emission, shininess);
+ self->m = new FrsMaterial(line, diffuse, ambient, specular, emission, shininess, priority);
}
else {
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
@@ -140,6 +141,7 @@ static PyObject *FrsMaterial_repr(BPy_FrsMaterial *self)
#define MATHUTILS_SUBTYPE_SPECULAR 2
#define MATHUTILS_SUBTYPE_AMBIENT 3
#define MATHUTILS_SUBTYPE_EMISSION 4
+#define MATHUTILS_SUBTYPE_LINE 5
static int FrsMaterial_mathutils_check(BaseMathObject *bmo)
{
@@ -152,6 +154,12 @@ static int FrsMaterial_mathutils_get(BaseMathObject *bmo, int subtype)
{
BPy_FrsMaterial *self = (BPy_FrsMaterial *)bmo->cb_user;
switch (subtype) {
+ case MATHUTILS_SUBTYPE_LINE:
+ bmo->data[0] = self->m->lineR();
+ bmo->data[1] = self->m->lineG();
+ bmo->data[2] = self->m->lineB();
+ bmo->data[3] = self->m->lineA();
+ break;
case MATHUTILS_SUBTYPE_DIFFUSE:
bmo->data[0] = self->m->diffuseR();
bmo->data[1] = self->m->diffuseG();
@@ -186,6 +194,9 @@ static int FrsMaterial_mathutils_set(BaseMathObject *bmo, int subtype)
{
BPy_FrsMaterial *self = (BPy_FrsMaterial *)bmo->cb_user;
switch (subtype) {
+ case MATHUTILS_SUBTYPE_LINE:
+ self->m->setLine(bmo->data[0], bmo->data[1], bmo->data[2], bmo->data[3]);
+ break;
case MATHUTILS_SUBTYPE_DIFFUSE:
self->m->setDiffuse(bmo->data[0], bmo->data[1], bmo->data[2], bmo->data[3]);
break;
@@ -208,6 +219,12 @@ static int FrsMaterial_mathutils_get_index(BaseMathObject *bmo, int subtype, int
{
BPy_FrsMaterial *self = (BPy_FrsMaterial *)bmo->cb_user;
switch (subtype) {
+ case MATHUTILS_SUBTYPE_LINE:
+ {
+ const float *color = self->m->line();
+ bmo->data[index] = color[index];
+ }
+ break;
case MATHUTILS_SUBTYPE_DIFFUSE:
{
const float *color = self->m->diffuse();
@@ -243,6 +260,11 @@ static int FrsMaterial_mathutils_set_index(BaseMathObject *bmo, int subtype, int
BPy_FrsMaterial *self = (BPy_FrsMaterial *)bmo->cb_user;
float color[4];
switch (subtype) {
+ case MATHUTILS_SUBTYPE_LINE:
+ copy_v4_v4(color, self->m->line());
+ color[index] = bmo->data[index];
+ self->m->setLine(color[0], color[1], color[2], color[3]);
+ break;
case MATHUTILS_SUBTYPE_DIFFUSE:
copy_v4_v4(color, self->m->diffuse());
color[index] = bmo->data[index];
@@ -286,10 +308,32 @@ void FrsMaterial_mathutils_register_callback()
/*----------------------FrsMaterial get/setters ----------------------------*/
+PyDoc_STRVAR(FrsMaterial_line_doc,
+"RGBA components of the line color of the material.\n"
+"\n"
+":type: :class:`mathutils.Vector`");
+
+static PyObject *FrsMaterial_line_get(BPy_FrsMaterial *self, void *UNUSED(closure))
+{
+ return Vector_CreatePyObject_cb((PyObject *)self, 4, FrsMaterial_mathutils_cb_index, MATHUTILS_SUBTYPE_LINE);
+}
+
+static int FrsMaterial_line_set(BPy_FrsMaterial *self, PyObject *value, void *UNUSED(closure))
+{
+ float color[4];
+ if (mathutils_array_parse(color, 4, 4, value,
+ "value must be a 4-dimensional vector") == -1)
+ {
+ return -1;
+ }
+ self->m->setLine(color[0], color[1], color[2], color[3]);
+ return 0;
+}
+
PyDoc_STRVAR(FrsMaterial_diffuse_doc,
"RGBA components of the diffuse color of the material.\n"
"\n"
-":type: mathutils.Vector");
+":type: :class:`mathutils.Vector`");
static PyObject *FrsMaterial_diffuse_get(BPy_FrsMaterial *self, void *UNUSED(closure))
{
@@ -299,8 +343,9 @@ static PyObject *FrsMaterial_diffuse_get(BPy_FrsMaterial *self, void *UNUSED(clo
static int FrsMaterial_diffuse_set(BPy_FrsMaterial *self, PyObject *value, void *UNUSED(closure))
{
float color[4];
- if (!float_array_from_PyObject(value, color, 4)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 4-dimensional vector");
+ if (mathutils_array_parse(color, 4, 4, value,
+ "value must be a 4-dimensional vector") == -1)
+ {
return -1;
}
self->m->setDiffuse(color[0], color[1], color[2], color[3]);
@@ -310,7 +355,7 @@ static int FrsMaterial_diffuse_set(BPy_FrsMaterial *self, PyObject *value, void
PyDoc_STRVAR(FrsMaterial_specular_doc,
"RGBA components of the specular color of the material.\n"
"\n"
-":type: mathutils.Vector");
+":type: :class:`mathutils.Vector`");
static PyObject *FrsMaterial_specular_get(BPy_FrsMaterial *self, void *UNUSED(closure))
{
@@ -320,8 +365,9 @@ static PyObject *FrsMaterial_specular_get(BPy_FrsMaterial *self, void *UNUSED(cl
static int FrsMaterial_specular_set(BPy_FrsMaterial *self, PyObject *value, void *UNUSED(closure))
{
float color[4];
- if (!float_array_from_PyObject(value, color, 4)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 4-dimensional vector");
+ if (mathutils_array_parse(color, 4, 4, value,
+ "value must be a 4-dimensional vector") == -1)
+ {
return -1;
}
self->m->setSpecular(color[0], color[1], color[2], color[3]);
@@ -331,7 +377,7 @@ static int FrsMaterial_specular_set(BPy_FrsMaterial *self, PyObject *value, void
PyDoc_STRVAR(FrsMaterial_ambient_doc,
"RGBA components of the ambient color of the material.\n"
"\n"
-":type: mathutils.Color");
+":type: :class:`mathutils.Color`");
static PyObject *FrsMaterial_ambient_get(BPy_FrsMaterial *self, void *UNUSED(closure))
{
@@ -341,8 +387,9 @@ static PyObject *FrsMaterial_ambient_get(BPy_FrsMaterial *self, void *UNUSED(clo
static int FrsMaterial_ambient_set(BPy_FrsMaterial *self, PyObject *value, void *UNUSED(closure))
{
float color[4];
- if (!float_array_from_PyObject(value, color, 4)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 4-dimensional vector");
+ if (mathutils_array_parse(color, 4, 4, value,
+ "value must be a 4-dimensional vector") == -1)
+ {
return -1;
}
self->m->setAmbient(color[0], color[1], color[2], color[3]);
@@ -352,7 +399,7 @@ static int FrsMaterial_ambient_set(BPy_FrsMaterial *self, PyObject *value, void
PyDoc_STRVAR(FrsMaterial_emission_doc,
"RGBA components of the emissive color of the material.\n"
"\n"
-":type: mathutils.Color");
+":type: :class:`mathutils.Color`");
static PyObject *FrsMaterial_emission_get(BPy_FrsMaterial *self, void *UNUSED(closure))
{
@@ -362,8 +409,9 @@ static PyObject *FrsMaterial_emission_get(BPy_FrsMaterial *self, void *UNUSED(cl
static int FrsMaterial_emission_set(BPy_FrsMaterial *self, PyObject *value, void *UNUSED(closure))
{
float color[4];
- if (!float_array_from_PyObject(value, color, 4)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 4-dimensional vector");
+ if (mathutils_array_parse(color, 4, 4, value,
+ "value must be a 4-dimensional vector") == -1)
+ {
return -1;
}
self->m->setEmission(color[0], color[1], color[2], color[3]);
@@ -391,7 +439,30 @@ static int FrsMaterial_shininess_set(BPy_FrsMaterial *self, PyObject *value, voi
return 0;
}
+PyDoc_STRVAR(FrsMaterial_priority_doc,
+"Line color priority of the material.\n"
+"\n"
+":type: int");
+
+static PyObject *FrsMaterial_priority_get(BPy_FrsMaterial *self, void *UNUSED(closure))
+{
+ return PyLong_FromLong(self->m->priority());
+}
+
+static int FrsMaterial_priority_set(BPy_FrsMaterial *self, PyObject *value, void *UNUSED(closure))
+{
+ int scalar;
+ if ((scalar = PyLong_AsLong(value)) == -1 && PyErr_Occurred()) {
+ PyErr_SetString(PyExc_TypeError, "value must be an integer");
+ return -1;
+ }
+ self->m->setPriority(scalar);
+ return 0;
+}
+
static PyGetSetDef BPy_FrsMaterial_getseters[] = {
+ {(char *)"line", (getter)FrsMaterial_line_get, (setter)FrsMaterial_line_set,
+ (char *)FrsMaterial_line_doc, NULL},
{(char *)"diffuse", (getter)FrsMaterial_diffuse_get, (setter)FrsMaterial_diffuse_set,
(char *)FrsMaterial_diffuse_doc, NULL},
{(char *)"specular", (getter)FrsMaterial_specular_get, (setter)FrsMaterial_specular_set,
@@ -402,6 +473,8 @@ static PyGetSetDef BPy_FrsMaterial_getseters[] = {
(char *)FrsMaterial_emission_doc, NULL},
{(char *)"shininess", (getter)FrsMaterial_shininess_get, (setter)FrsMaterial_shininess_set,
(char *)FrsMaterial_shininess_doc, NULL},
+ {(char *)"priority", (getter)FrsMaterial_priority_get, (setter)FrsMaterial_priority_set,
+ (char *)FrsMaterial_priority_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/BPy_Interface0D.cpp b/source/blender/freestyle/intern/python/BPy_Interface0D.cpp
index 0861952689b..8f23800fb7a 100644
--- a/source/blender/freestyle/intern/python/BPy_Interface0D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Interface0D.cpp
@@ -103,7 +103,7 @@ static int Interface0D_init(BPy_Interface0D *self, PyObject *args, PyObject *kwd
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist))
return -1;
self->if0D = new Interface0D();
- self->borrowed = 0;
+ self->borrowed = false;
return 0;
}
@@ -165,7 +165,7 @@ static PyObject *Interface0D_name_get(BPy_Interface0D *self, void *UNUSED(closur
PyDoc_STRVAR(Interface0D_point_3d_doc,
"The 3D point of this 0D element.\n"
"\n"
-":type: mathutils.Vector");
+":type: :class:`mathutils.Vector`");
static PyObject *Interface0D_point_3d_get(BPy_Interface0D *self, void *UNUSED(closure))
{
@@ -217,7 +217,7 @@ static PyObject *Interface0D_projected_z_get(BPy_Interface0D *self, void *UNUSED
PyDoc_STRVAR(Interface0D_point_2d_doc,
"The 2D point of this 0D element.\n"
"\n"
-":type: mathutils.Vector");
+":type: :class:`mathutils.Vector`");
static PyObject *Interface0D_point_2d_get(BPy_Interface0D *self, void *UNUSED(closure))
{
diff --git a/source/blender/freestyle/intern/python/BPy_Interface0D.h b/source/blender/freestyle/intern/python/BPy_Interface0D.h
index b8a4a6b21bd..ec1a6f1c42d 100644
--- a/source/blender/freestyle/intern/python/BPy_Interface0D.h
+++ b/source/blender/freestyle/intern/python/BPy_Interface0D.h
@@ -47,7 +47,7 @@ extern PyTypeObject Interface0D_Type;
typedef struct {
PyObject_HEAD
Interface0D *if0D;
- int borrowed; /* non-zero if *if0D is a borrowed object */
+ bool borrowed; /* true if *if0D is a borrowed object */
} BPy_Interface0D;
/*---------------------------Python BPy_Interface0D visible prototypes-----------*/
diff --git a/source/blender/freestyle/intern/python/BPy_Interface1D.cpp b/source/blender/freestyle/intern/python/BPy_Interface1D.cpp
index a4bcea869fd..0fc3ec41dec 100644
--- a/source/blender/freestyle/intern/python/BPy_Interface1D.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Interface1D.cpp
@@ -113,7 +113,7 @@ static int Interface1D_init(BPy_Interface1D *self, PyObject *args, PyObject *kwd
if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist))
return -1;
self->if1D = new Interface1D();
- self->borrowed = 0;
+ self->borrowed = false;
return 0;
}
@@ -141,7 +141,7 @@ PyDoc_STRVAR(Interface1D_vertices_begin_doc,
static PyObject * Interface1D_vertices_begin(BPy_Interface1D *self)
{
Interface0DIterator if0D_it(self->if1D->verticesBegin());
- return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, 0);
+ return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, false);
}
PyDoc_STRVAR(Interface1D_vertices_end_doc,
@@ -156,7 +156,7 @@ PyDoc_STRVAR(Interface1D_vertices_end_doc,
static PyObject * Interface1D_vertices_end(BPy_Interface1D *self)
{
Interface0DIterator if0D_it(self->if1D->verticesEnd());
- return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, 1);
+ return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, true);
}
PyDoc_STRVAR(Interface1D_points_begin_doc,
@@ -181,7 +181,7 @@ static PyObject * Interface1D_points_begin(BPy_Interface1D *self, PyObject *args
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|f", (char **)kwlist, &f))
return NULL;
Interface0DIterator if0D_it(self->if1D->pointsBegin(f));
- return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, 0);
+ return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, false);
}
PyDoc_STRVAR(Interface1D_points_end_doc,
@@ -206,7 +206,7 @@ static PyObject * Interface1D_points_end(BPy_Interface1D *self, PyObject *args,
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|f", (char **)kwlist, &f))
return NULL;
Interface0DIterator if0D_it(self->if1D->pointsEnd(f));
- return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, 1);
+ return BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, true);
}
static PyMethodDef BPy_Interface1D_methods[] = {
diff --git a/source/blender/freestyle/intern/python/BPy_Interface1D.h b/source/blender/freestyle/intern/python/BPy_Interface1D.h
index 17c0752b2e8..0c731bb1755 100644
--- a/source/blender/freestyle/intern/python/BPy_Interface1D.h
+++ b/source/blender/freestyle/intern/python/BPy_Interface1D.h
@@ -47,7 +47,7 @@ extern PyTypeObject Interface1D_Type;
typedef struct {
PyObject_HEAD
Interface1D *if1D;
- int borrowed; /* non-zero if *if1D is a borrowed object */
+ bool borrowed; /* true if *if1D is a borrowed object */
} BPy_Interface1D;
/*---------------------------Python BPy_Interface1D visible prototypes-----------*/
diff --git a/source/blender/freestyle/intern/python/BPy_Operators.cpp b/source/blender/freestyle/intern/python/BPy_Operators.cpp
index 123fbab7b30..d3cb44f5903 100644
--- a/source/blender/freestyle/intern/python/BPy_Operators.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Operators.cpp
@@ -74,7 +74,7 @@ PyDoc_STRVAR(Operators_select_doc,
" condition.\n"
"\n"
" :arg pred: The predicate expressing this condition.\n"
-" :type pred: UnaryPredicate1D");
+" :type pred: :class:`UnaryPredicate1D`");
static PyObject *Operators_select(BPy_Operators *self, PyObject *args, PyObject *kwds)
{
@@ -372,7 +372,7 @@ PyDoc_STRVAR(Operators_recursive_split_doc,
" condition. This predicate is evaluated for each curve before it\n"
" actually gets split. If pred_1d(chain) is true, the curve won't be\n"
" split anymore.\n"
-" :type pred: :class:`UnaryPredicate1D`\n"
+" :type pred_1d: :class:`UnaryPredicate1D`\n"
" :arg sampling: The resolution used to sample the chain for the\n"
" predicates evaluation. (The chain is not actually resampled, a\n"
" virtual point only progresses along the curve using this\n"
@@ -404,7 +404,7 @@ PyDoc_STRVAR(Operators_recursive_split_doc,
" condition. This predicate is evaluated for each curve before it\n"
" actually gets split. If pred_1d(chain) is true, the curve won't be\n"
" split anymore.\n"
-" :type pred: :class:`UnaryPredicate1D`\n"
+" :type pred_1d: :class:`UnaryPredicate1D`\n"
" :arg sampling: The resolution used to sample the chain for the\n"
" predicates evaluation. (The chain is not actually resampled; a\n"
" virtual point only progresses along the curve using this\n"
@@ -484,7 +484,7 @@ PyDoc_STRVAR(Operators_sort_doc,
" comparison predicate given as argument.\n"
"\n"
" :arg pred: The binary predicate used for the comparison.\n"
-" :type pred: BinaryPredicate1D");
+" :type pred: :class:`BinaryPredicate1D`");
static PyObject *Operators_sort(BPy_Operators *self, PyObject *args, PyObject *kwds)
{
@@ -515,7 +515,7 @@ PyDoc_STRVAR(Operators_create_doc,
" transform as a stroke.\n"
" :type pred: :class:`UnaryPredicate1D`\n"
" :arg shaders: The list of shaders used to shade the strokes.\n"
-" :type shaders: List of StrokeShader objects");
+" :type shaders: list of :class:`StrokeShader` objects");
static PyObject *Operators_create(BPy_Operators *self, PyObject *args, PyObject *kwds)
{
@@ -548,6 +548,30 @@ static PyObject *Operators_create(BPy_Operators *self, PyObject *args, PyObject
Py_RETURN_NONE;
}
+PyDoc_STRVAR(Operators_reset_doc,
+".. staticmethod:: reset(delete_strokes=True)\n"
+"\n"
+" Resets the line stylization process to the initial state. The results of\n"
+" stroke creation are accumulated if **delete_strokes** is set to False.\n"
+"\n"
+" :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 const char *kwlist[] = {"delete_strokes", NULL};
+ PyObject *obj1 = 0;
+ if (PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist, &PyBool_Type, &obj1)) {
+ // true is the default
+ Operators::reset(obj1 ? bool_from_PyBool(obj1) : true);
+ }
+ else {
+ PyErr_SetString(PyExc_RuntimeError, "Operators.reset() failed");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
PyDoc_STRVAR(Operators_get_viewedge_from_index_doc,
".. staticmethod:: get_viewedge_from_index(i)\n"
"\n"
@@ -671,6 +695,7 @@ static PyMethodDef BPy_Operators_methods[] = {
Operators_recursive_split_doc},
{"sort", (PyCFunction) Operators_sort, METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_sort_doc},
{"create", (PyCFunction) Operators_create, METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_create_doc},
+ {"reset", (PyCFunction) Operators_reset, METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_reset_doc},
{"get_viewedge_from_index", (PyCFunction) Operators_get_viewedge_from_index,
METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_get_viewedge_from_index_doc},
{"get_chain_from_index", (PyCFunction) Operators_get_chain_from_index, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
diff --git a/source/blender/freestyle/intern/python/BPy_SShape.cpp b/source/blender/freestyle/intern/python/BPy_SShape.cpp
index ffa9dc47e67..e5a38171ecd 100644
--- a/source/blender/freestyle/intern/python/BPy_SShape.cpp
+++ b/source/blender/freestyle/intern/python/BPy_SShape.cpp
@@ -78,7 +78,7 @@ static int SShape_init(BPy_SShape *self, PyObject *args, PyObject *kwds)
self->ss = new SShape();
else
self->ss = new SShape(*(((BPy_SShape *)brother)->ss));
- self->borrowed = 0;
+ self->borrowed = false;
return 0;
}
diff --git a/source/blender/freestyle/intern/python/BPy_SShape.h b/source/blender/freestyle/intern/python/BPy_SShape.h
index 4919a34bf6d..2bfec42cbdd 100644
--- a/source/blender/freestyle/intern/python/BPy_SShape.h
+++ b/source/blender/freestyle/intern/python/BPy_SShape.h
@@ -47,7 +47,7 @@ extern PyTypeObject SShape_Type;
typedef struct {
PyObject_HEAD
SShape *ss;
- int borrowed; /* non-zero if *ss is a borrowed object */
+ bool borrowed; /* true if *ss is a borrowed object */
} BPy_SShape;
/*---------------------------Python BPy_SShape visible prototypes-----------*/
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
index f36cbafa61a..43313ef5213 100644
--- a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
+++ b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.cpp
@@ -124,7 +124,7 @@ static int StrokeAttribute_init(BPy_StrokeAttribute *self, PyObject *args, PyObj
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
return -1;
}
- self->borrowed = 0;
+ self->borrowed = false;
return 0;
}
@@ -515,7 +515,7 @@ static int StrokeAttribute_alpha_set(BPy_StrokeAttribute *self, PyObject *value,
PyDoc_STRVAR(StrokeAttribute_color_doc,
"RGB components of the stroke color.\n"
"\n"
-":type: mathutils.Color");
+":type: :class:`mathutils.Color`");
static PyObject *StrokeAttribute_color_get(BPy_StrokeAttribute *self, void *UNUSED(closure))
{
@@ -525,8 +525,9 @@ static PyObject *StrokeAttribute_color_get(BPy_StrokeAttribute *self, void *UNUS
static int StrokeAttribute_color_set(BPy_StrokeAttribute *self, PyObject *value, void *UNUSED(closure))
{
float v[3];
- if (!float_array_from_PyObject(value, v, 3)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 3-dimensional vector");
+ if (mathutils_array_parse(v, 3, 3, value,
+ "value must be a 3-dimensional vector") == -1)
+ {
return -1;
}
self->sa->setColor(v[0], v[1], v[2]);
@@ -538,7 +539,7 @@ PyDoc_STRVAR(StrokeAttribute_thickness_doc,
"The right (left) component is the thickness on the right (left) of the vertex\n"
"when following the stroke.\n"
"\n"
-":type: mathutils.Vector");
+":type: :class:`mathutils.Vector`");
static PyObject *StrokeAttribute_thickness_get(BPy_StrokeAttribute *self, void *UNUSED(closure))
{
@@ -549,8 +550,9 @@ static PyObject *StrokeAttribute_thickness_get(BPy_StrokeAttribute *self, void *
static int StrokeAttribute_thickness_set(BPy_StrokeAttribute *self, PyObject *value, void *UNUSED(closure))
{
float v[2];
- if (!float_array_from_PyObject(value, v, 2)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 2-dimensional vector");
+ if (mathutils_array_parse(v, 2, 2, value,
+ "value must be a 2-dimensional vector") == -1)
+ {
return -1;
}
self->sa->setThickness(v[0], v[1]);
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.h b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.h
index ce2384ea7d6..48a61cc9f07 100644
--- a/source/blender/freestyle/intern/python/BPy_StrokeAttribute.h
+++ b/source/blender/freestyle/intern/python/BPy_StrokeAttribute.h
@@ -47,7 +47,7 @@ extern PyTypeObject StrokeAttribute_Type;
typedef struct {
PyObject_HEAD
StrokeAttribute *sa;
- int borrowed; /* non-zero if *sa is a borrowed reference */
+ bool borrowed; /* true if *sa is a borrowed reference */
} BPy_StrokeAttribute;
/*---------------------------Python BPy_StrokeAttribute visible prototypes-----------*/
diff --git a/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp b/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp
index a6c7a40e780..6b4a1872b61 100644
--- a/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp
+++ b/source/blender/freestyle/intern/python/BPy_StrokeShader.cpp
@@ -32,11 +32,9 @@
#include "StrokeShader/BPy_BlenderTextureShader.h"
#include "StrokeShader/BPy_CalligraphicShader.h"
#include "StrokeShader/BPy_ColorNoiseShader.h"
-#include "StrokeShader/BPy_ColorVariationPatternShader.h"
#include "StrokeShader/BPy_ConstantColorShader.h"
#include "StrokeShader/BPy_ConstantThicknessShader.h"
#include "StrokeShader/BPy_ConstrainedIncreasingThicknessShader.h"
-#include "StrokeShader/BPy_fstreamShader.h"
#include "StrokeShader/BPy_GuidingLinesShader.h"
#include "StrokeShader/BPy_IncreasingColorShader.h"
#include "StrokeShader/BPy_IncreasingThicknessShader.h"
@@ -44,12 +42,8 @@
#include "StrokeShader/BPy_SamplingShader.h"
#include "StrokeShader/BPy_SmoothingShader.h"
#include "StrokeShader/BPy_SpatialNoiseShader.h"
-#include "StrokeShader/BPy_streamShader.h"
-#include "StrokeShader/BPy_StrokeTextureShader.h"
#include "StrokeShader/BPy_StrokeTextureStepShader.h"
-#include "StrokeShader/BPy_TextureAssignerShader.h"
#include "StrokeShader/BPy_ThicknessNoiseShader.h"
-#include "StrokeShader/BPy_ThicknessVariationPatternShader.h"
#include "StrokeShader/BPy_TipRemoverShader.h"
#ifdef __cplusplus
@@ -94,11 +88,6 @@ int StrokeShader_Init(PyObject *module)
Py_INCREF(&ColorNoiseShader_Type);
PyModule_AddObject(module, "ColorNoiseShader", (PyObject *)&ColorNoiseShader_Type);
- if (PyType_Ready(&ColorVariationPatternShader_Type) < 0)
- return -1;
- Py_INCREF(&ColorVariationPatternShader_Type);
- PyModule_AddObject(module, "ColorVariationPatternShader", (PyObject *)&ColorVariationPatternShader_Type);
-
if (PyType_Ready(&ConstantColorShader_Type) < 0)
return -1;
Py_INCREF(&ConstantColorShader_Type);
@@ -115,11 +104,6 @@ int StrokeShader_Init(PyObject *module)
PyModule_AddObject(module, "ConstrainedIncreasingThicknessShader",
(PyObject *)&ConstrainedIncreasingThicknessShader_Type);
- if (PyType_Ready(&fstreamShader_Type) < 0)
- return -1;
- Py_INCREF(&fstreamShader_Type);
- PyModule_AddObject(module, "fstreamShader", (PyObject *)&fstreamShader_Type);
-
if (PyType_Ready(&GuidingLinesShader_Type) < 0)
return -1;
Py_INCREF(&GuidingLinesShader_Type);
@@ -155,36 +139,16 @@ int StrokeShader_Init(PyObject *module)
Py_INCREF(&SpatialNoiseShader_Type);
PyModule_AddObject(module, "SpatialNoiseShader", (PyObject *)&SpatialNoiseShader_Type);
- if (PyType_Ready(&streamShader_Type) < 0)
- return -1;
- Py_INCREF(&streamShader_Type);
- PyModule_AddObject(module, "streamShader", (PyObject *)&streamShader_Type);
-
- if (PyType_Ready(&StrokeTextureShader_Type) < 0)
- return -1;
- Py_INCREF(&StrokeTextureShader_Type);
- PyModule_AddObject(module, "StrokeTextureShader", (PyObject *)&StrokeTextureShader_Type);
-
if (PyType_Ready(&StrokeTextureStepShader_Type) < 0)
return -1;
Py_INCREF(&StrokeTextureStepShader_Type);
PyModule_AddObject(module, "StrokeTextureStepShader", (PyObject *)&StrokeTextureStepShader_Type);
- if (PyType_Ready(&TextureAssignerShader_Type) < 0)
- return -1;
- Py_INCREF(&TextureAssignerShader_Type);
- PyModule_AddObject(module, "TextureAssignerShader", (PyObject *)&TextureAssignerShader_Type);
-
if (PyType_Ready(&ThicknessNoiseShader_Type) < 0)
return -1;
Py_INCREF(&ThicknessNoiseShader_Type);
PyModule_AddObject(module, "ThicknessNoiseShader", (PyObject *)&ThicknessNoiseShader_Type);
- if (PyType_Ready(&ThicknessVariationPatternShader_Type) < 0)
- return -1;
- Py_INCREF(&ThicknessVariationPatternShader_Type);
- PyModule_AddObject(module, "ThicknessVariationPatternShader", (PyObject *)&ThicknessVariationPatternShader_Type);
-
if (PyType_Ready(&TipRemoverShader_Type) < 0)
return -1;
Py_INCREF(&TipRemoverShader_Type);
diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
index 93d4607e15a..2c767eacaec 100644
--- a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
+++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
@@ -101,7 +101,7 @@ static int ViewShape_init(BPy_ViewShape *self, PyObject *args, PyObject *kwds)
PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
return -1;
}
- self->borrowed = 0;
+ self->borrowed = false;
Py_XINCREF(self->py_ss);
return 0;
}
diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.h b/source/blender/freestyle/intern/python/BPy_ViewShape.h
index 3151ebe8cbd..09bf36edfcd 100644
--- a/source/blender/freestyle/intern/python/BPy_ViewShape.h
+++ b/source/blender/freestyle/intern/python/BPy_ViewShape.h
@@ -49,7 +49,7 @@ extern PyTypeObject ViewShape_Type;
typedef struct {
PyObject_HEAD
ViewShape *vs;
- int borrowed; /* non-zero if *vs a borrowed object */
+ bool borrowed; /* true if *vs a borrowed object */
BPy_SShape *py_ss;
} BPy_ViewShape;
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp
index 67cf28eb7cb..8fa87166c7d 100644
--- a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_FalseBP1D.cpp
@@ -33,16 +33,16 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char FalseBP1D___doc__[] =
-"Class hierarchy: :class:`BinaryPredicate1D` > :class:`FalseBP1D`\n"
+"Class hierarchy: :class:`freestyle.types.BinaryPredicate1D` > :class:`FalseBP1D`\n"
"\n"
".. method:: __call__(inter1, inter2)\n"
"\n"
" Always returns false.\n"
"\n"
" :arg inter1: The first Interface1D object.\n"
-" :type inter1: :class:`Interface1D`\n"
+" :type inter1: :class:`freestyle.types.Interface1D`\n"
" :arg inter2: The second Interface1D object.\n"
-" :type inter2: :class:`Interface1D`\n"
+" :type inter2: :class:`freestyle.types.Interface1D`\n"
" :return: False.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp
index 155cc29502b..8a0a4ded58d 100644
--- a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_Length2DBP1D.cpp
@@ -33,7 +33,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char Length2DBP1D___doc__[] =
-"Class hierarchy: :class:`BinaryPredicate1D` > :class:`Length2DBP1D`\n"
+"Class hierarchy: :class:`freestyle.types.BinaryPredicate1D` > :class:`Length2DBP1D`\n"
"\n"
".. method:: __call__(inter1, inter2)\n"
"\n"
@@ -41,9 +41,9 @@ static char Length2DBP1D___doc__[] =
" of inter2.\n"
"\n"
" :arg inter1: The first Interface1D object.\n"
-" :type inter1: :class:`Interface1D`\n"
+" :type inter1: :class:`freestyle.types.Interface1D`\n"
" :arg inter2: The second Interface1D object.\n"
-" :type inter2: :class:`Interface1D`\n"
+" :type inter2: :class:`freestyle.types.Interface1D`\n"
" :return: True or false.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp
index 77147745389..b4a256e6f66 100644
--- a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_SameShapeIdBP1D.cpp
@@ -33,16 +33,16 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char SameShapeIdBP1D___doc__[] =
-"Class hierarchy: :class:`BinaryPredicate1D` > :class:`SameShapeIdBP1D`\n"
+"Class hierarchy: :class:`freestyle.types.BinaryPredicate1D` > :class:`SameShapeIdBP1D`\n"
"\n"
".. method:: __call__(inter1, inter2)\n"
"\n"
" Returns true if inter1 and inter2 belong to the same shape.\n"
"\n"
" :arg inter1: The first Interface1D object.\n"
-" :type inter1: :class:`Interface1D`\n"
+" :type inter1: :class:`freestyle.types.Interface1D`\n"
" :arg inter2: The second Interface1D object.\n"
-" :type inter2: :class:`Interface1D`\n"
+" :type inter2: :class:`freestyle.types.Interface1D`\n"
" :return: True or false.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp
index f7d702da28d..6306905b4aa 100644
--- a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_TrueBP1D.cpp
@@ -33,16 +33,16 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char TrueBP1D___doc__[] =
-"Class hierarchy: :class:`BinaryPredicate1D` > :class:`TrueBP1D`\n"
+"Class hierarchy: :class:`freestyle.types.BinaryPredicate1D` > :class:`TrueBP1D`\n"
"\n"
".. method:: __call__(inter1, inter2)\n"
"\n"
" Always returns true.\n"
"\n"
" :arg inter1: The first Interface1D object.\n"
-" :type inter1: :class:`Interface1D`\n"
+" :type inter1: :class:`freestyle.types.Interface1D`\n"
" :arg inter2: The second Interface1D object.\n"
-" :type inter2: :class:`Interface1D`\n"
+" :type inter2: :class:`freestyle.types.Interface1D`\n"
" :return: True.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp
index f029e434988..2072faa43ef 100644
--- a/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp
+++ b/source/blender/freestyle/intern/python/BinaryPredicate1D/BPy_ViewMapGradientNormBP1D.cpp
@@ -38,7 +38,7 @@ extern "C" {
//ViewMapGradientNormBP1D(int level, IntegrationType iType=MEAN, float sampling=2.0)
static char ViewMapGradientNormBP1D___doc__[] =
-"Class hierarchy: :class:`BinaryPredicate1D` > :class:`ViewMapGradientNormBP1D`\n"
+"Class hierarchy: :class:`freestyle.types.BinaryPredicate1D` > :class:`ViewMapGradientNormBP1D`\n"
"\n"
".. method:: __init__(level, integration_type=IntegrationType.MEAN, sampling=2.0)\n"
"\n"
@@ -49,7 +49,7 @@ static char ViewMapGradientNormBP1D___doc__[] =
" :type level: int\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
" :arg sampling: The resolution used to sample the chain:\n"
" GetViewMapGradientNormF0D is evaluated at each sample point and\n"
" the result is obtained by combining the resulting values into a\n"
@@ -62,9 +62,9 @@ static char ViewMapGradientNormBP1D___doc__[] =
" higher for inter1 than for inter2.\n"
"\n"
" :arg inter1: The first Interface1D object.\n"
-" :type inter1: :class:`Interface1D`\n"
+" :type inter1: :class:`freestyle.types.Interface1D`\n"
" :arg inter2: The second Interface1D object.\n"
-" :type inter2: :class:`Interface1D`\n"
+" :type inter2: :class:`freestyle.types.Interface1D`\n"
" :return: True or false.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/Director.cpp b/source/blender/freestyle/intern/python/Director.cpp
index f03aa0bcc97..653fd0b1d29 100644
--- a/source/blender/freestyle/intern/python/Director.cpp
+++ b/source/blender/freestyle/intern/python/Director.cpp
@@ -74,7 +74,7 @@ int Director_BPy_BinaryPredicate0D___call__(BinaryPredicate0D *bp0D, Interface0D
Py_XDECREF(arg2);
return -1;
}
- PyObject *result = PyObject_CallMethod((PyObject *)bp0D->py_bp0D, (char *)"__call__", (char *)"OO", arg1, arg2);
+ PyObject *result = PyObject_CallMethod((PyObject *)bp0D->py_bp0D, "__call__", "OO", arg1, arg2);
Py_DECREF(arg1);
Py_DECREF(arg2);
if (!result)
@@ -101,7 +101,7 @@ int Director_BPy_BinaryPredicate1D___call__(BinaryPredicate1D *bp1D, Interface1D
Py_XDECREF(arg2);
return -1;
}
- PyObject *result = PyObject_CallMethod((PyObject *)bp1D->py_bp1D, (char *)"__call__", (char *)"OO", arg1, arg2);
+ PyObject *result = PyObject_CallMethod((PyObject *)bp1D->py_bp1D, "__call__", "OO", arg1, arg2);
Py_DECREF(arg1);
Py_DECREF(arg2);
if (!result)
@@ -121,10 +121,10 @@ int Director_BPy_UnaryPredicate0D___call__(UnaryPredicate0D *up0D, Interface0DIt
PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_up0D) not initialized");
return -1;
}
- PyObject *arg = BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, 0);
+ PyObject *arg = BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, false);
if (!arg)
return -1;
- PyObject *result = PyObject_CallMethod((PyObject *)up0D->py_up0D, (char *)"__call__", (char *)"O", arg);
+ PyObject *result = PyObject_CallMethod((PyObject *)up0D->py_up0D, "__call__", "O", arg);
Py_DECREF(arg);
if (!result)
return -1;
@@ -146,7 +146,7 @@ int Director_BPy_UnaryPredicate1D___call__(UnaryPredicate1D *up1D, Interface1D&
PyObject *arg = Any_BPy_Interface1D_from_Interface1D(if1D);
if (!arg)
return -1;
- PyObject *result = PyObject_CallMethod((PyObject *)up1D->py_up1D, (char *)"__call__", (char *)"O", arg);
+ PyObject *result = PyObject_CallMethod((PyObject *)up1D->py_up1D, "__call__", "O", arg);
Py_DECREF(arg);
if (!result)
return -1;
@@ -168,7 +168,7 @@ int Director_BPy_StrokeShader_shade(StrokeShader *ss, Stroke& s)
PyObject *arg = BPy_Stroke_from_Stroke(s);
if (!arg)
return -1;
- PyObject *result = PyObject_CallMethod((PyObject *)ss->py_ss, (char *)"shade", (char *)"O", arg);
+ PyObject *result = PyObject_CallMethod((PyObject *)ss->py_ss, "shade", "O", arg);
Py_DECREF(arg);
if (!result)
return -1;
@@ -183,7 +183,7 @@ int Director_BPy_ChainingIterator_init(ChainingIterator *c_it)
PyErr_SetString(PyExc_RuntimeError, "Reference to Python object (py_c_it) not initialized");
return -1;
}
- PyObject *result = PyObject_CallMethod((PyObject *)c_it->py_c_it, (char *)"init", NULL);
+ PyObject *result = PyObject_CallMethod((PyObject *)c_it->py_c_it, "init", NULL);
if (!result)
return -1;
Py_DECREF(result);
@@ -199,7 +199,7 @@ int Director_BPy_ChainingIterator_traverse(ChainingIterator *c_it, AdjacencyIter
PyObject *arg = BPy_AdjacencyIterator_from_AdjacencyIterator(a_it);
if (!arg)
return -1;
- PyObject *result = PyObject_CallMethod((PyObject *)c_it->py_c_it, (char *)"traverse", (char *)"O", arg);
+ PyObject *result = PyObject_CallMethod((PyObject *)c_it->py_c_it, "traverse", "O", arg);
Py_DECREF(arg);
if (!result)
return -1;
@@ -226,10 +226,10 @@ int Director_BPy_UnaryFunction0D___call__(void *uf0D, void *py_uf0D, Interface0D
return -1;
}
PyObject *obj = (PyObject *)py_uf0D;
- PyObject *arg = BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, 0);
+ PyObject *arg = BPy_Interface0DIterator_from_Interface0DIterator(if0D_it, false);
if (!arg)
return -1;
- PyObject *result = PyObject_CallMethod(obj, (char *)"__call__", (char *)"O", arg);
+ PyObject *result = PyObject_CallMethod(obj, "__call__", "O", arg);
Py_DECREF(arg);
if (!result)
return -1;
@@ -288,7 +288,7 @@ int Director_BPy_UnaryFunction1D___call__(void *uf1D, void *py_uf1D, Interface1D
PyObject *arg = Any_BPy_Interface1D_from_Interface1D(if1D);
if (!arg)
return -1;
- PyObject *result = PyObject_CallMethod(obj, (char *)"__call__", (char *)"O", arg);
+ PyObject *result = PyObject_CallMethod(obj, "__call__", "O", arg);
Py_DECREF(arg);
if (!result)
return -1;
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
index 50c9d031d0d..1ef29792d56 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_CurvePoint.cpp
@@ -124,7 +124,7 @@ static int CurvePoint_init(BPy_CurvePoint *self, PyObject *args, PyObject *kwds)
return -1;
}
self->py_if0D.if0D = self->cp;
- self->py_if0D.borrowed = 0;
+ self->py_if0D.borrowed = false;
return 0;
}
@@ -178,6 +178,19 @@ static int CurvePoint_second_svertex_set(BPy_CurvePoint *self, PyObject *value,
return 0;
}
+PyDoc_STRVAR(CurvePoint_fedge_doc,
+"Gets the FEdge for the two SVertices that given CurvePoints consists out of.\n"
+"A shortcut for CurvePoint.first_svertex.get_fedge(CurvePoint.second_svertex).\n"
+"\n"
+":type: :class:`FEdge`");
+
+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)));
+}
+
PyDoc_STRVAR(CurvePoint_t2d_doc,
"The 2D interpolation parameter.\n"
"\n"
@@ -204,6 +217,8 @@ static PyGetSetDef BPy_CurvePoint_getseters[] = {
(char *)CurvePoint_first_svertex_doc, NULL},
{(char *)"second_svertex", (getter)CurvePoint_second_svertex_get, (setter)CurvePoint_second_svertex_set,
(char *)CurvePoint_second_svertex_doc, NULL},
+ {(char *)"fedge", (getter)CurvePoint_fedge_get, NULL,
+ CurvePoint_fedge_doc, NULL},
{(char *)"t2d", (getter)CurvePoint_t2d_get, (setter)CurvePoint_t2d_set, (char *)CurvePoint_t2d_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
index 7ce34142c77..6f47ce93ca8 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_SVertex.cpp
@@ -61,11 +61,6 @@ PyDoc_STRVAR(SVertex_doc,
" :arg id: An Id object.\n"
" :type id: :class:`Id`");
-static int convert_v3(PyObject *obj, void *v)
-{
- return float_array_from_PyObject(obj, (float *)v, 3);
-}
-
static int SVertex_init(BPy_SVertex *self, PyObject *args, PyObject *kwds)
{
static const char *kwlist_1[] = {"brother", NULL};
@@ -90,7 +85,7 @@ static int SVertex_init(BPy_SVertex *self, PyObject *args, PyObject *kwds)
return -1;
}
self->py_if0D.if0D = self->sv;
- self->py_if0D.borrowed = 0;
+ self->py_if0D.borrowed = false;
return 0;
}
@@ -273,7 +268,7 @@ void SVertex_mathutils_register_callback()
PyDoc_STRVAR(SVertex_point_3d_doc,
"The 3D coordinates of the SVertex.\n"
"\n"
-":type: mathutils.Vector");
+":type: :class:`mathutils.Vector`");
static PyObject *SVertex_point_3d_get(BPy_SVertex *self, void *UNUSED(closure))
{
@@ -283,8 +278,9 @@ static PyObject *SVertex_point_3d_get(BPy_SVertex *self, void *UNUSED(closure))
static int SVertex_point_3d_set(BPy_SVertex *self, PyObject *value, void *UNUSED(closure))
{
float v[3];
- if (!float_array_from_PyObject(value, v, 3)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 3-dimensional vector");
+ if (mathutils_array_parse(v, 3, 3, value,
+ "value must be a 3-dimensional vector") == -1)
+ {
return -1;
}
Vec3r p(v[0], v[1], v[2]);
@@ -295,7 +291,7 @@ static int SVertex_point_3d_set(BPy_SVertex *self, PyObject *value, void *UNUSED
PyDoc_STRVAR(SVertex_point_2d_doc,
"The projected 3D coordinates of the SVertex.\n"
"\n"
-":type: mathutils.Vector");
+":type: :class:`mathutils.Vector`");
static PyObject *SVertex_point_2d_get(BPy_SVertex *self, void *UNUSED(closure))
{
@@ -305,8 +301,9 @@ static PyObject *SVertex_point_2d_get(BPy_SVertex *self, void *UNUSED(closure))
static int SVertex_point_2d_set(BPy_SVertex *self, PyObject *value, void *UNUSED(closure))
{
float v[3];
- if (!float_array_from_PyObject(value, v, 3)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 3-dimensional vector");
+ if (mathutils_array_parse(v, 3, 3, value,
+ "value must be a 3-dimensional vector") == -1)
+ {
return -1;
}
Vec3r p(v[0], v[1], v[2]);
diff --git a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
index 0b200dbf3ca..5e2130ac8e7 100644
--- a/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/BPy_ViewVertex.cpp
@@ -70,7 +70,7 @@ PyDoc_STRVAR(ViewVertex_edges_begin_doc,
static PyObject *ViewVertex_edges_begin(BPy_ViewVertex *self)
{
ViewVertexInternal::orientedViewEdgeIterator ove_it(self->vv->edgesBegin());
- return BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator(ove_it, 0);
+ return BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator(ove_it, false);
}
PyDoc_STRVAR(ViewVertex_edges_end_doc,
@@ -113,7 +113,7 @@ static PyObject *ViewVertex_edges_iterator(BPy_ViewVertex *self, PyObject *args,
return NULL;
ViewEdge *ve = ((BPy_ViewEdge *)py_ve)->ve;
ViewVertexInternal::orientedViewEdgeIterator ove_it(self->vv->edgesIterator(ve));
- return BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator(ove_it, 0);
+ return BPy_orientedViewEdgeIterator_from_orientedViewEdgeIterator(ove_it, false);
}
static PyMethodDef BPy_ViewVertex_methods[] = {
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 e08aa47d954..ae4fe0764b6 100644
--- a/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/CurvePoint/BPy_StrokeVertex.cpp
@@ -150,7 +150,7 @@ static int StrokeVertex_init(BPy_StrokeVertex *self, PyObject *args, PyObject *k
}
self->py_cp.cp = self->sv;
self->py_cp.py_if0D.if0D = self->sv;
- self->py_cp.py_if0D.borrowed = 0;
+ self->py_cp.py_if0D.borrowed = false;
return 0;
}
@@ -226,7 +226,7 @@ void StrokeVertex_mathutils_register_callback()
PyDoc_STRVAR(StrokeVertex_attribute_doc,
"StrokeAttribute for this StrokeVertex.\n"
"\n"
-":type: StrokeAttribute");
+":type: :class:`StrokeAttribute`");
static PyObject *StrokeVertex_attribute_get(BPy_StrokeVertex *self, void *UNUSED(closure))
{
@@ -267,7 +267,7 @@ static int StrokeVertex_curvilinear_abscissa_set(BPy_StrokeVertex *self, PyObjec
PyDoc_STRVAR(StrokeVertex_point_doc,
"2D point coordinates.\n"
"\n"
-":type: mathutils.Vector");
+":type: :class:`mathutils.Vector`");
static PyObject *StrokeVertex_point_get(BPy_StrokeVertex *self, void *UNUSED(closure))
{
@@ -277,8 +277,9 @@ static PyObject *StrokeVertex_point_get(BPy_StrokeVertex *self, void *UNUSED(clo
static int StrokeVertex_point_set(BPy_StrokeVertex *self, PyObject *value, void *UNUSED(closure))
{
float v[2];
- if (!float_array_from_PyObject(value, v, 2)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 2-dimensional vector");
+ if (mathutils_array_parse(v, 2, 2, value,
+ "value must be a 2-dimensional vector") == -1)
+ {
return -1;
}
self->sv->setX(v[0]);
diff --git a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp
index 985c89b5c36..555f93effa0 100644
--- a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_NonTVertex.cpp
@@ -67,7 +67,7 @@ static int NonTVertex_init(BPy_NonTVertex *self, PyObject *args, PyObject *kwds)
self->ntv = new NonTVertex(((BPy_SVertex *)obj)->sv);
self->py_vv.vv = self->ntv;
self->py_vv.py_if0D.if0D = self->ntv;
- self->py_vv.py_if0D.borrowed = 0;
+ self->py_vv.py_if0D.borrowed = false;
return 0;
}
diff --git a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp
index 2881148f241..d047d9ae914 100644
--- a/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp
+++ b/source/blender/freestyle/intern/python/Interface0D/ViewVertex/BPy_TVertex.cpp
@@ -62,7 +62,7 @@ static int TVertex_init(BPy_TVertex *self, PyObject *args, PyObject *kwds)
self->tv = new TVertex();
self->py_vv.vv = self->tv;
self->py_vv.py_if0D.if0D = self->tv;
- self->py_vv.py_if0D.borrowed = 0;
+ self->py_vv.py_if0D.borrowed = false;
return 0;
}
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
index 7365ee8ac36..7592508902b 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FEdge.cpp
@@ -94,7 +94,7 @@ static int FEdge_init(BPy_FEdge *self, PyObject *args, PyObject *kwds)
return -1;
}
self->py_if1D.if1D = self->fe;
- self->py_if1D.borrowed = 0;
+ self->py_if1D.borrowed = false;
return 0;
}
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
index 9bbb0405e49..744556e415c 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_FrsCurve.cpp
@@ -84,7 +84,7 @@ static int FrsCurve_init(BPy_FrsCurve *self, PyObject *args, PyObject *kwds)
return -1;
}
self->py_if1D.if1D = self->c;
- self->py_if1D.borrowed = 0;
+ self->py_if1D.borrowed = false;
return 0;
}
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
index 80765e794fb..5c816bdfea1 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_Stroke.cpp
@@ -73,14 +73,14 @@ static int Stroke_init(BPy_Stroke *self, PyObject *args, PyObject *kwds)
else
self->s = new Stroke(*(((BPy_Stroke *)brother)->s));
self->py_if1D.if1D = self->s;
- self->py_if1D.borrowed = 0;
+ self->py_if1D.borrowed = false;
return 0;
}
static PyObject *Stroke_iter(PyObject *self)
{
StrokeInternal::StrokeVertexIterator sv_it( ((BPy_Stroke *)self)->s->strokeVerticesBegin() );
- return BPy_StrokeVertexIterator_from_StrokeVertexIterator( sv_it, 0 );
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator(sv_it, false);
}
static Py_ssize_t Stroke_sq_length(BPy_Stroke *self)
@@ -151,10 +151,16 @@ static PyObject *Stroke_resample(BPy_Stroke *self, PyObject *args, PyObject *kwd
float f;
if (PyArg_ParseTupleAndKeywords(args, kwds, "i", (char **)kwlist_1, &i)) {
- self->s->Resample(i);
+ if (self->s->Resample(i) < 0) {
+ PyErr_SetString(PyExc_RuntimeError, "Stroke resampling (by vertex count) failed");
+ return NULL;
+ }
}
else if (PyErr_Clear(), PyArg_ParseTupleAndKeywords(args, kwds, "f", (char **)kwlist_2, &f)) {
- self->s->Resample(f);
+ if (self->s->Resample(f) < 0) {
+ PyErr_SetString(PyExc_RuntimeError, "Stroke resampling (by vertex interval) failed");
+ return NULL;
+ }
}
else {
PyErr_SetString(PyExc_TypeError, "invalid argument");
@@ -186,7 +192,7 @@ static PyObject *Stroke_insert_vertex(BPy_Stroke *self, PyObject *args, PyObject
{
return NULL;
}
- ((BPy_StrokeVertex *)py_sv)->py_cp.py_if0D.borrowed = 1; /* make the wrapped StrokeVertex internal */
+ ((BPy_StrokeVertex *)py_sv)->py_cp.py_if0D.borrowed = true; /* make the wrapped StrokeVertex internal */
StrokeVertex *sv = ((BPy_StrokeVertex *)py_sv)->sv;
StrokeInternal::StrokeVertexIterator sv_it(*(((BPy_StrokeVertexIterator *)py_sv_it)->sv_it));
self->s->InsertVertex(sv, sv_it);
@@ -245,7 +251,7 @@ PyDoc_STRVAR(Stroke_stroke_vertices_begin_doc,
".. method:: stroke_vertices_begin(t=0.0)\n"
"\n"
" Returns a StrokeVertexIterator pointing on the first StrokeVertex of\n"
-" the Stroke. O ne can specify a sampling value to resample the Stroke\n"
+" the Stroke. One can specify a sampling value to resample the Stroke\n"
" on the fly if needed.\n"
"\n"
" :arg t: The resampling value with which we want our Stroke to be\n"
@@ -262,7 +268,7 @@ static PyObject *Stroke_stroke_vertices_begin(BPy_Stroke *self, PyObject *args,
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|f", (char **)kwlist, &f))
return NULL;
StrokeInternal::StrokeVertexIterator sv_it(self->s->strokeVerticesBegin(f));
- return BPy_StrokeVertexIterator_from_StrokeVertexIterator(sv_it, 0);
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator(sv_it, false);
}
PyDoc_STRVAR(Stroke_stroke_vertices_end_doc,
@@ -277,7 +283,22 @@ PyDoc_STRVAR(Stroke_stroke_vertices_end_doc,
static PyObject *Stroke_stroke_vertices_end(BPy_Stroke *self)
{
StrokeInternal::StrokeVertexIterator sv_it(self->s->strokeVerticesEnd());
- return BPy_StrokeVertexIterator_from_StrokeVertexIterator(sv_it, 1);
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator(sv_it, true);
+}
+
+PyDoc_STRVAR(Stroke_reversed_doc,
+".. method:: __reversed__()\n"
+"\n"
+" Returns a StrokeVertexIterator iterating over the vertices of the Stroke\n"
+" in the reversed order (from the last to the first).\n"
+"\n"
+" :return: A StrokeVertexIterator pointing after the last StrokeVertex.\n"
+" :rtype: :class:`StrokeVertexIterator`");
+
+static PyObject *Stroke_reversed(BPy_Stroke *self)
+{
+ StrokeInternal::StrokeVertexIterator sv_it(self->s->strokeVerticesEnd());
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator(sv_it, true);
}
PyDoc_STRVAR(Stroke_stroke_vertices_size_doc,
@@ -304,6 +325,7 @@ static PyMethodDef BPy_Stroke_methods[] = {
{"stroke_vertices_begin", (PyCFunction)Stroke_stroke_vertices_begin, METH_VARARGS | METH_KEYWORDS,
Stroke_stroke_vertices_begin_doc},
{"stroke_vertices_end", (PyCFunction)Stroke_stroke_vertices_end, METH_NOARGS, Stroke_stroke_vertices_end_doc},
+ {"__reversed__", (PyCFunction)Stroke_reversed, METH_NOARGS, Stroke_reversed_doc},
{"stroke_vertices_size", (PyCFunction)Stroke_stroke_vertices_size, METH_NOARGS, Stroke_stroke_vertices_size_doc},
{NULL, NULL, 0, NULL}
};
diff --git a/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp
index 869ada0d058..bcae5a2c2a4 100644
--- a/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/BPy_ViewEdge.cpp
@@ -70,7 +70,7 @@ static int ViewEdge_init(BPy_ViewEdge *self, PyObject *args, PyObject *kwds)
else
self->ve = new ViewEdge(*(((BPy_ViewEdge *)brother)->ve));
self->py_if1D.if1D = self->ve;
- self->py_if1D.borrowed = 0;
+ self->py_if1D.borrowed = false;
return 0;
}
diff --git a/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp b/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp
index 3a0141da153..2d62918e291 100644
--- a/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/Curve/BPy_Chain.cpp
@@ -84,7 +84,7 @@ static int Chain_init(BPy_Chain *self, PyObject *args, PyObject *kwds)
}
self->py_c.c = self->c;
self->py_c.py_if1D.if1D = self->c;
- self->py_c.py_if1D.borrowed = 0;
+ self->py_c.py_if1D.borrowed = false;
return 0;
}
diff --git a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
index eeae10412fc..acdd5989511 100644
--- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSharp.cpp
@@ -89,7 +89,7 @@ static int FEdgeSharp_init(BPy_FEdgeSharp *self, PyObject *args, PyObject *kwds)
}
self->py_fe.fe = self->fes;
self->py_fe.py_if1D.if1D = self->fes;
- self->py_fe.py_if1D.borrowed = 0;
+ self->py_fe.py_if1D.borrowed = false;
return 0;
}
@@ -231,8 +231,9 @@ static PyObject *FEdgeSharp_normal_right_get(BPy_FEdgeSharp *self, void *UNUSED(
static int FEdgeSharp_normal_right_set(BPy_FEdgeSharp *self, PyObject *value, void *UNUSED(closure))
{
float v[3];
- if (!float_array_from_PyObject(value, v, 3)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 3-dimensional vector");
+ if (mathutils_array_parse(v, 3, 3, value,
+ "value must be a 3-dimensional vector") == -1)
+ {
return -1;
}
Vec3r p(v[0], v[1], v[2]);
@@ -253,8 +254,9 @@ static PyObject *FEdgeSharp_normal_left_get(BPy_FEdgeSharp *self, void *UNUSED(c
static int FEdgeSharp_normal_left_set(BPy_FEdgeSharp *self, PyObject *value, void *UNUSED(closure))
{
float v[3];
- if (!float_array_from_PyObject(value, v, 3)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 3-dimensional vector");
+ if (mathutils_array_parse(v, 3, 3, value,
+ "value must be a 3-dimensional vector") == -1)
+ {
return -1;
}
Vec3r p(v[0], v[1], v[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 8d45c5b81c4..a2079c7d685 100644
--- a/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
+++ b/source/blender/freestyle/intern/python/Interface1D/FEdge/BPy_FEdgeSmooth.cpp
@@ -86,7 +86,7 @@ static int FEdgeSmooth_init(BPy_FEdgeSmooth *self, PyObject *args, PyObject *kwd
}
self->py_fe.fe = self->fes;
self->py_fe.py_if1D.if1D = self->fes;
- self->py_fe.py_if1D.borrowed = 0;
+ self->py_fe.py_if1D.borrowed = false;
return 0;
}
@@ -164,8 +164,9 @@ static PyObject *FEdgeSmooth_normal_get(BPy_FEdgeSmooth *self, void *UNUSED(clos
static int FEdgeSmooth_normal_set(BPy_FEdgeSmooth *self, PyObject *value, void *UNUSED(closure))
{
float v[3];
- if (!float_array_from_PyObject(value, v, 3)) {
- PyErr_SetString(PyExc_ValueError, "value must be a 3-dimensional vector");
+ if (mathutils_array_parse(v, 3, 3, value,
+ "value must be a 3-dimensional vector") == -1)
+ {
return -1;
}
Vec3r p(v[0], v[1], v[2]);
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
index 99ac72db028..6e253b7bf5d 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainPredicateIterator.cpp
@@ -38,7 +38,10 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
PyDoc_STRVAR(ChainPredicateIterator_doc,
-"Class hierarchy: :class:`Iterator` > :class:`ViewEdgeIterator` > :class:`ChainingIterator` > "
+
+"Class hierarchy: :class:`freestyle.types.Iterator` >\n"
+":class:`freestyle.types.ViewEdgeIterator` >\n"
+":class:`freestyle.types.ChainingIterator` >\n"
":class:`ChainPredicateIterator`\n"
"\n"
"A \"generic\" user-controlled ViewEdge iterator. This iterator is in\n"
@@ -63,7 +66,7 @@ PyDoc_STRVAR(ChainPredicateIterator_doc,
" already been chained must be ignored ot not.\n"
" :type restrict_to_unvisited: bool\n"
" :arg begin: The ViewEdge from where to start the iteration.\n"
-" :type begin: :class:`ViewEdge` or None\n"
+" :type begin: :class:`freestyle.types.ViewEdge` or None\n"
" :arg orientation: If true, we'll look for the next ViewEdge among\n"
" the ViewEdges that surround the ending ViewVertex of begin. If\n"
" false, we'll search over the ViewEdges surrounding the ending\n"
@@ -77,10 +80,10 @@ PyDoc_STRVAR(ChainPredicateIterator_doc,
" predicate, a starting ViewEdge and its orientation.\n"
"\n"
" :arg upred: The unary predicate that the next ViewEdge must satisfy.\n"
-" :type upred: :class:`UnaryPredicate1D`\n"
+" :type upred: :class:`freestyle.types.UnaryPredicate1D`\n"
" :arg bpred: The binary predicate that the next ViewEdge must\n"
" satisfy together with the actual pointed ViewEdge.\n"
-" :type bpred: :class:`BinaryPredicate1D`\n"
+" :type bpred: :class:`freestyle.types.BinaryPredicate1D`\n"
" :arg restrict_to_selection: Indicates whether to force the chaining\n"
" to stay within the set of selected ViewEdges or not.\n"
" :type restrict_to_selection: bool\n"
@@ -88,7 +91,7 @@ PyDoc_STRVAR(ChainPredicateIterator_doc,
" already been chained must be ignored ot not.\n"
" :type restrict_to_unvisited: bool\n"
" :arg begin: The ViewEdge from where to start the iteration.\n"
-" :type begin: :class:`ViewEdge` or None\n"
+" :type begin: :class:`freestyle.types.ViewEdge` or None\n"
" :arg orientation: If true, we'll look for the next ViewEdge among\n"
" the ViewEdges that surround the ending ViewVertex of begin. If\n"
" false, we'll search over the ViewEdges surrounding the ending\n"
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp
index 1a082ac93bb..08cfffec860 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_ChainSilhouetteIterator.cpp
@@ -39,7 +39,9 @@ extern "C" {
// ChainSilhouetteIterator (const ChainSilhouetteIterator &brother)
PyDoc_STRVAR(ChainSilhouetteIterator_doc,
-"Class hierarchy: :class:`Iterator` > :class:`ViewEdgeIterator` > :class:`ChainingIterator` > "
+"Class hierarchy: :class:`freestyle.types.Iterator` >\n"
+":class:`freestyle.types.ViewEdgeIterator` >\n"
+":class:`freestyle.types.ChainingIterator` >\n"
":class:`ChainSilhouetteIterator`\n"
"\n"
"A ViewEdge Iterator used to follow ViewEdges the most naturally. For\n"
@@ -58,7 +60,7 @@ PyDoc_STRVAR(ChainSilhouetteIterator_doc,
" to stay within the set of selected ViewEdges or not.\n"
" :type restrict_to_selection: bool\n"
" :arg begin: The ViewEdge from where to start the iteration.\n"
-" :type begin: :class:`ViewEdge` or None\n"
+" :type begin: :class:`freestyle.types.ViewEdge` or None\n"
" :arg orientation: If true, we'll look for the next ViewEdge among\n"
" the ViewEdges that surround the ending ViewVertex of begin. If\n"
" false, we'll search over the ViewEdges surrounding the ending\n"
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
index f85bcddf186..7419f0ed127 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_Interface0DIterator.cpp
@@ -25,6 +25,7 @@
#include "BPy_Interface0DIterator.h"
#include "../BPy_Convert.h"
+#include "../BPy_Interface1D.h"
#ifdef __cplusplus
extern "C" {
@@ -70,9 +71,10 @@ static int convert_nested_it(PyObject *obj, void *v)
static int Interface0DIterator_init(BPy_Interface0DIterator *self, PyObject *args, PyObject *kwds)
{
static const char *kwlist_1[] = {"it", NULL};
- static const char *kwlist_2[] = {"brother", NULL};
+ static const char *kwlist_2[] = {"inter", NULL};
+ static const char *kwlist_3[] = {"brother", NULL};
Interface0DIteratorNested *nested_it;
- PyObject *brother;
+ PyObject *brother, *inter;
if (PyArg_ParseTupleAndKeywords(args, kwds, "O&", (char **)kwlist_1, convert_nested_it, &nested_it)) {
self->if0D_it = new Interface0DIterator(nested_it->copy());
@@ -80,7 +82,14 @@ static int Interface0DIterator_init(BPy_Interface0DIterator *self, PyObject *arg
self->reversed = false;
}
else if (PyErr_Clear(),
- PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_2, &Interface0DIterator_Type, &brother))
+ PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_2, &Interface1D_Type, &inter))
+ {
+ self->if0D_it = new Interface0DIterator(((BPy_Interface1D *)inter)->if1D->verticesBegin());
+ self->at_start = true;
+ self->reversed = false;
+ }
+ else if (PyErr_Clear(),
+ PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_3, &Interface0DIterator_Type, &brother))
{
self->if0D_it = new Interface0DIterator(*(((BPy_Interface0DIterator *)brother)->if0D_it));
self->at_start = ((BPy_Interface0DIterator *)brother)->at_start;
@@ -115,14 +124,15 @@ static PyObject *Interface0DIterator_iternext(BPy_Interface0DIterator *self)
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
- if (self->at_start)
+ else if (self->at_start) {
self->at_start = false;
+ }
+ else if (self->if0D_it->atLast()) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
else {
self->if0D_it->increment();
- if (self->if0D_it->isEnd()) {
- PyErr_SetNone(PyExc_StopIteration);
- return NULL;
- }
}
}
Interface0D *if0D = self->if0D_it->operator->();
@@ -132,9 +142,12 @@ static PyObject *Interface0DIterator_iternext(BPy_Interface0DIterator *self)
/*----------------------Interface0DIterator get/setters ----------------------------*/
PyDoc_STRVAR(Interface0DIterator_object_doc,
-"The Interface0D object currently pointed to by this iterator.\n"
+"The 0D object currently pointed to by this iterator. Note that the object\n"
+"may be an instance of an Interface0D subclass. For example if the iterator\n"
+"has been created from the `vertices_begin()` method of the :class:`Stroke`\n"
+"class, the .object property refers to a :class:`StrokeVertex` object.\n"
"\n"
-":type: :class:`Interface0D`");
+":type: :class:`Interface0D` or one of its subclasses.");
static PyObject *Interface0DIterator_object_get(BPy_Interface0DIterator *self, void *UNUSED(closure))
{
@@ -165,11 +178,24 @@ static PyObject *Interface0DIterator_u_get(BPy_Interface0DIterator *self, void *
return PyFloat_FromDouble(self->if0D_it->u());
}
+PyDoc_STRVAR(Interface0DIterator_at_last_doc,
+"True if the interator points to the last valid element.\n"
+"For its counterpart (pointing to the first valid element), use it.is_begin.\n"
+"\n"
+":type: bool");
+
+static PyObject *Interface0DIterator_at_last_get(BPy_Interface0DIterator *self, void *UNUSED(closure))
+{
+ return PyBool_from_bool(self->if0D_it->atLast());
+}
+
static PyGetSetDef BPy_Interface0DIterator_getseters[] = {
{(char *)"object", (getter)Interface0DIterator_object_get, (setter)NULL,
(char *)Interface0DIterator_object_doc, NULL},
{(char *)"t", (getter)Interface0DIterator_t_get, (setter)NULL, (char *)Interface0DIterator_t_doc, NULL},
{(char *)"u", (getter)Interface0DIterator_u_get, (setter)NULL, (char *)Interface0DIterator_u_doc, NULL},
+ {(char *)"at_last", (getter)Interface0DIterator_at_last_get, (setter)NULL,
+ (char *)Interface0DIterator_at_last_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
index 3e5051049bd..e35076ec7fe 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp
@@ -25,6 +25,7 @@
#include "BPy_StrokeVertexIterator.h"
#include "../BPy_Convert.h"
+#include "../Interface1D/BPy_Stroke.h"
#include "BPy_Interface0DIterator.h"
#ifdef __cplusplus
@@ -48,7 +49,7 @@ PyDoc_STRVAR(StrokeVertexIterator_doc,
"specialized StrokeVertex type. In this case, one should use a\n"
"StrokeVertexIterator. To call functions of the UnaryFuntion0D type,\n"
"a StrokeVertexIterator can be converted to an Interface0DIterator by\n"
-"by calling Interface0DIterator(it)."
+"by calling Interface0DIterator(it).\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -63,20 +64,29 @@ PyDoc_STRVAR(StrokeVertexIterator_doc,
static int StrokeVertexIterator_init(BPy_StrokeVertexIterator *self, PyObject *args, PyObject *kwds)
{
- static const char *kwlist[] = {"brother", NULL};
- PyObject *brother = 0;
+ static const char *kwlist_1[] = {"brother", NULL};
+ static const char *kwlist_2[] = {"stroke", NULL};
+ PyObject *brother = 0, *stroke = 0;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist, &StrokeVertexIterator_Type, &brother))
- return -1;
- if (!brother) {
- self->sv_it = new StrokeInternal::StrokeVertexIterator();
+ if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist_1, &StrokeVertexIterator_Type, &brother)) {
+ self->sv_it = new StrokeInternal::StrokeVertexIterator(*(((BPy_StrokeVertexIterator *)brother)->sv_it));
+ self->reversed = ((BPy_StrokeVertexIterator *)brother)->reversed;
+ self->at_start = ((BPy_StrokeVertexIterator *)brother)->at_start;
+ }
+
+ else if (PyErr_Clear(),
+ PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist_2, &Stroke_Type, &stroke))
+ {
+ if (!stroke)
+ self->sv_it = new StrokeInternal::StrokeVertexIterator();
+ else
+ self->sv_it = new StrokeInternal::StrokeVertexIterator(((BPy_Stroke *)stroke)->s->strokeVerticesBegin());
self->reversed = false;
self->at_start = true;
}
else {
- self->sv_it = new StrokeInternal::StrokeVertexIterator(*(((BPy_StrokeVertexIterator *)brother)->sv_it));
- self->reversed = ((BPy_StrokeVertexIterator *)brother)->reversed;
- self->at_start = ((BPy_StrokeVertexIterator *)brother)->at_start;
+ PyErr_SetString(PyExc_TypeError, "argument 1 must be StrokeVertexIterator or Stroke");
+ return -1;
}
self->py_it.it = self->sv_it;
return 0;
@@ -91,6 +101,12 @@ static PyObject *StrokeVertexIterator_iter(BPy_StrokeVertexIterator *self)
static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self)
{
+ /* Because Freestyle iterators for which it.isEnd() holds true have no valid object
+ * (they point to the past-the-end element and can't be dereferenced), we have to check
+ * iterators for validity.
+ * Additionally, the at_start attribute is used to keep Freestyle iterator objects
+ * and Python for loops in sync. */
+
if (self->reversed) {
if (self->sv_it->isBegin()) {
PyErr_SetNone(PyExc_StopIteration);
@@ -99,28 +115,91 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self)
self->sv_it->decrement();
}
else {
+ /* If sv_it.isEnd() is true, the iterator can't be incremented. */
if (self->sv_it->isEnd()) {
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
- /* if at the start of the iterator, only return the object
- * and don't increment, to keep for-loops in sync */
- if (self->at_start)
+ /* If at the start of the iterator, only return the object
+ * and don't increment, to keep for-loops in sync */
+ else if (self->at_start) {
self->at_start = false;
- /* after incrementing, check if the iterator is at its end
- * exit the loop if it is. not doing so will result in a crash */
+ }
+ /* If sv_it.atLast() is true, the iterator is currently pointing to the final valid element.
+ * Incrementing it further would lead to a state that the iterator can't be dereferenced. */
+ else if (self->sv_it->atLast()) {
+ PyErr_SetNone(PyExc_StopIteration);
+ return NULL;
+ }
else {
self->sv_it->increment();
- if (self->sv_it->isEnd()) {
- PyErr_SetNone(PyExc_StopIteration);
- return NULL;
- }
}
}
StrokeVertex *sv = self->sv_it->operator->();
return BPy_StrokeVertex_from_StrokeVertex(*sv);
}
+/*----------------------StrokeVertexIterator methods ----------------------------*/
+
+PyDoc_STRVAR(StrokeVertexIterator_incremented_doc,
+".. method:: incremented()\n"
+"\n"
+" Returns a copy of an incremented StrokeVertexIterator.\n"
+"\n"
+" :return: A StrokeVertexIterator pointing the next StrokeVertex.\n"
+" :rtype: :class:`StrokeVertexIterator`");
+
+static PyObject *StrokeVertexIterator_incremented(BPy_StrokeVertexIterator *self)
+{
+ if (self->sv_it->isEnd()) {
+ PyErr_SetString(PyExc_RuntimeError, "cannot increment any more");
+ return NULL;
+ }
+ StrokeInternal::StrokeVertexIterator copy(*self->sv_it);
+ copy.increment();
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator(copy, self->reversed);
+}
+
+PyDoc_STRVAR(StrokeVertexIterator_decremented_doc,
+".. method:: decremented()\n"
+"\n"
+" Returns a copy of a decremented StrokeVertexIterator.\n"
+"\n"
+" :return: A StrokeVertexIterator pointing the previous StrokeVertex.\n"
+" :rtype: :class:`StrokeVertexIterator`");
+
+static PyObject *StrokeVertexIterator_decremented(BPy_StrokeVertexIterator *self)
+{
+ if (self->sv_it->isBegin()) {
+ PyErr_SetString(PyExc_RuntimeError, "cannot decrement any more");
+ return NULL;
+ }
+ StrokeInternal::StrokeVertexIterator copy(*self->sv_it);
+ copy.decrement();
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator(copy, self->reversed);
+}
+
+PyDoc_STRVAR(StrokeVertexIterator_reversed_doc,
+".. method:: reversed()\n"
+"\n"
+" Returns a StrokeVertexIterator that traverses stroke vertices in the\n"
+" reversed order.\n"
+"\n"
+" :return: A StrokeVertexIterator traversing stroke vertices backward.\n"
+" :rtype: :class:`StrokeVertexIterator`");
+
+static PyObject *StrokeVertexIterator_reversed(BPy_StrokeVertexIterator *self)
+{
+ return BPy_StrokeVertexIterator_from_StrokeVertexIterator(*self->sv_it, !self->reversed);
+}
+
+static PyMethodDef BPy_StrokeVertexIterator_methods[] = {
+ {"incremented", (PyCFunction)StrokeVertexIterator_incremented, METH_NOARGS, StrokeVertexIterator_incremented_doc},
+ {"decremented", (PyCFunction)StrokeVertexIterator_decremented, METH_NOARGS, StrokeVertexIterator_decremented_doc},
+ {"reversed", (PyCFunction)StrokeVertexIterator_reversed, METH_NOARGS, StrokeVertexIterator_reversed_doc},
+ {NULL, NULL, 0, NULL}
+};
+
/*----------------------StrokeVertexIterator get/setters ----------------------------*/
PyDoc_STRVAR(StrokeVertexIterator_object_doc,
@@ -130,7 +209,7 @@ PyDoc_STRVAR(StrokeVertexIterator_object_doc,
static PyObject *StrokeVertexIterator_object_get(BPy_StrokeVertexIterator *self, void *UNUSED(closure))
{
- if (!self->reversed && self->sv_it->isEnd()) {
+ if (self->sv_it->isEnd()) {
PyErr_SetString(PyExc_RuntimeError, "iteration has stopped");
return NULL;
}
@@ -160,11 +239,25 @@ static PyObject *StrokeVertexIterator_u_get(BPy_StrokeVertexIterator *self, void
return PyFloat_FromDouble(self->sv_it->u());
}
+PyDoc_STRVAR(StrokeVertexIterator_at_last_doc,
+"True if the interator points to the last valid element.\n"
+"For its counterpart (pointing to the first valid element), use it.is_begin.\n"
+"\n"
+":type: bool");
+
+static PyObject *StrokeVertexIterator_at_last_get(BPy_StrokeVertexIterator *self)
+{
+ return PyBool_from_bool(self->sv_it->atLast());
+
+}
+
static PyGetSetDef BPy_StrokeVertexIterator_getseters[] = {
{(char *)"object", (getter)StrokeVertexIterator_object_get, (setter)NULL,
(char *)StrokeVertexIterator_object_doc, NULL},
{(char *)"t", (getter)StrokeVertexIterator_t_get, (setter)NULL, (char *)StrokeVertexIterator_t_doc, NULL},
{(char *)"u", (getter)StrokeVertexIterator_u_get, (setter)NULL, (char *)StrokeVertexIterator_u_doc, NULL},
+ {(char *)"at_last", (getter)StrokeVertexIterator_at_last_get, (setter)NULL,
+ (char *)StrokeVertexIterator_at_last_doc, NULL},
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -198,7 +291,7 @@ PyTypeObject StrokeVertexIterator_Type = {
0, /* tp_weaklistoffset */
(getiterfunc)StrokeVertexIterator_iter, /* tp_iter */
(iternextfunc)StrokeVertexIterator_iternext, /* tp_iternext */
- 0, /* tp_methods */
+ BPy_StrokeVertexIterator_methods, /* tp_methods */
0, /* tp_members */
BPy_StrokeVertexIterator_getseters, /* tp_getset */
&Iterator_Type, /* tp_base */
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp
index e4476cf9bcf..d879ac53aaa 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_orientedViewEdgeIterator.cpp
@@ -116,7 +116,7 @@ PyDoc_STRVAR(orientedViewEdgeIterator_object_doc,
"value) currently pointed to by this iterator. If the boolean value is true,\n"
"the ViewEdge is incoming.\n"
"\n"
-":type: (:class:`directedViewEdge`, bool)");
+":type: (:class:`ViewEdge`, bool)");
static PyObject *orientedViewEdgeIterator_object_get(BPy_orientedViewEdgeIterator *self, void *UNUSED(closure))
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp
index 045377e747e..26b83791585 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BackboneStretcherShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char BackboneStretcherShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`BackboneStretcherShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`BackboneStretcherShader`\n"
"\n"
"[Geometry shader]\n"
"\n"
@@ -52,7 +52,7 @@ static char BackboneStretcherShader___doc__[] =
" respective directions: v(1)v(0) and v(n-1)v(n).\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int BackboneStretcherShader___init__(BPy_BackboneStretcherShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.cpp
index 002d6798df9..df076e0453a 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BezierCurveShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char BezierCurveShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`BezierCurveShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`BezierCurveShader`\n"
"\n"
"[Geometry shader]\n"
"\n"
@@ -54,7 +54,7 @@ static char BezierCurveShader___doc__[] =
" Bezier Curve approximation of the original backbone geometry.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int BezierCurveShader___init__(BPy_BezierCurveShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.cpp
index c8b9d7098e4..0e603e00f97 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_BlenderTextureShader.cpp
@@ -37,42 +37,51 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char BlenderTextureShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`BlenderTextureShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`BlenderTextureShader`\n"
"\n"
"[Texture shader]\n"
"\n"
-".. method:: __init__(LineStyleTextureSlot)\n"
+".. method:: __init__(texture)\n"
"\n"
" Builds a BlenderTextureShader object.\n"
"\n"
-" :arg mtex: texture slot to add to stroke shading.\n"
-" :type mtex: LineStyleTextureSlot\n"
-
+" :arg texture: A line style texture slot or a shader node tree to define\n"
+" a set of textures.\n"
+" :type texture: :class:`bpy.types.LineStyleTextureSlot` or\n"
+" :class:`bpy.types.ShaderNodeTree`\n"
"\n"
".. method:: shade(stroke)\n"
"\n"
-" Assigns a blender texture slot to the stroke shading\n"
-" in order to simulate marks.\n"
+" Assigns a blender texture slot to the stroke shading in order to\n"
+" simulate marks.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int BlenderTextureShader___init__(BPy_BlenderTextureShader *self, PyObject *args, PyObject *kwds)
{
- static const char *kwlist[] = {"LineStyleTextureSlot", NULL};
- PyObject *py_mtex;
+ static const char *kwlist[] = {"texture", NULL};
+ PyObject *obj;
MTex *_mtex;
+ bNodeTree *_nodetree;
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", (char **)kwlist, &py_mtex))
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", (char **)kwlist, &obj))
return -1;
-
- _mtex = (MTex*)PyC_RNA_AsPointer(py_mtex, "LineStyleTextureSlot");
-
+ _mtex = (MTex *)PyC_RNA_AsPointer(obj, "LineStyleTextureSlot");
if (_mtex) {
self->py_ss.ss = new StrokeShaders::BlenderTextureShader(_mtex);
+ return 0;
}
-
- return 0;
+ PyErr_Clear();
+ _nodetree = (bNodeTree *)PyC_RNA_AsPointer(obj, "ShaderNodeTree");
+ if (_nodetree) {
+ self->py_ss.ss = new StrokeShaders::BlenderTextureShader(_nodetree);
+ return 0;
+ }
+ PyErr_Format(PyExc_TypeError,
+ "expected either 'LineStyleTextureSlot' or 'ShaderNodeTree', "
+ "found '%.200s' instead", Py_TYPE(obj)->tp_name);
+ return -1;
}
/*-----------------------BPy_BlenderTextureShader type definition ------------------------------*/
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.cpp
index 814d03b42d4..fb85ee5a792 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_CalligraphicShader.cpp
@@ -36,7 +36,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char CalligraphicShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`CalligraphicShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`CalligraphicShader`\n"
"\n"
"[Thickness Shader]\n"
"\n"
@@ -65,12 +65,7 @@ static char CalligraphicShader___doc__[] =
" perpendicular to this one, and an interpolation inbetween.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
-
-static int convert_v2(PyObject *obj, void *v)
-{
- return float_array_from_PyObject(obj, (float *)v, 2);
-}
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int CalligraphicShader___init__(BPy_CalligraphicShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.cpp
index f3b9167de09..c4ed45ec820 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorNoiseShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ColorNoiseShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`ColorNoiseShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`ColorNoiseShader`\n"
"\n"
"[Color shader]\n"
"\n"
@@ -53,7 +53,7 @@ static char ColorNoiseShader___doc__[] =
" Shader to add noise to the stroke colors.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int ColorNoiseShader___init__(BPy_ColorNoiseShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp
deleted file mode 100644
index 183edd1f6a0..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp
+++ /dev/null
@@ -1,122 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.cpp
- * \ingroup freestyle
- */
-
-#include "BPy_ColorVariationPatternShader.h"
-
-#include "../../stroke/BasicStrokeShaders.h"
-#include "../BPy_Convert.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-//------------------------INSTANCE METHODS ----------------------------------
-
-static char ColorVariationPatternShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`ColorVariationPatternShader`\n"
-"\n"
-"[Color shader]\n"
-"\n"
-".. method:: __init__(pattern_name, stretch=True)\n"
-"\n"
-" Builds a ColorVariationPatternShader object.\n"
-"\n"
-" :arg pattern_name: The file name of the texture file to use as\n"
-" pattern.\n"
-" :type pattern_name: str\n"
-" :arg stretch: Tells whether the texture must be strecthed or\n"
-" repeted to fit the stroke.\n"
-" :type stretch: bool\n"
-"\n"
-".. method:: shade(stroke)\n"
-"\n"
-" Applies a pattern to vary the original color. The new color is the\n"
-" result of the multiplication of the pattern and the original color.\n"
-"\n"
-" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
-
-static int ColorVariationPatternShader___init__(BPy_ColorVariationPatternShader *self, PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"pattern_name", "stretch", NULL};
- const char *s;
- PyObject *obj = 0;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O!", (char **)kwlist, &s, &PyBool_Type, &obj))
- return -1;
- bool b = (!obj) ? true : bool_from_PyBool(obj);
- self->py_ss.ss = new StrokeShaders::ColorVariationPatternShader(s, b);
- return 0;
-}
-
-/*-----------------------BPy_ColorVariationPatternShader type definition ------------------------------*/
-
-PyTypeObject ColorVariationPatternShader_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "ColorVariationPatternShader", /* tp_name */
- sizeof(BPy_ColorVariationPatternShader), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- ColorVariationPatternShader___doc__, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &StrokeShader_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)ColorVariationPatternShader___init__, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.h
deleted file mode 100644
index af5cf17caff..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.h
+++ /dev/null
@@ -1,54 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_ColorVariationPatternShader.h
- * \ingroup freestyle
- */
-
-#ifndef __FREESTYLE_PYTHON_COLORVARIATIONPATTERNSHADER_H__
-#define __FREESTYLE_PYTHON_COLORVARIATIONPATTERNSHADER_H__
-
-#include "../BPy_StrokeShader.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-extern PyTypeObject ColorVariationPatternShader_Type;
-
-#define BPy_ColorVariationPatternShader_Check(v) \
- (PyObject_IsInstance((PyObject *)v, (PyObject *)&ColorVariationPatternShader_Type))
-
-/*---------------------------Python BPy_ColorVariationPatternShader structure definition----------*/
-typedef struct {
- BPy_StrokeShader py_ss;
-} BPy_ColorVariationPatternShader;
-
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* __FREESTYLE_PYTHON_COLORVARIATIONPATTERNSHADER_H__ */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.cpp
index b5607f7a7b4..6607d5798f4 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantColorShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ConstantColorShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`ConstantColorShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`ConstantColorShader`\n"
"\n"
"[Color shader]\n"
"\n"
@@ -57,7 +57,7 @@ static char ConstantColorShader___doc__[] =
" Assigns a constant color to every vertex of the Stroke.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int ConstantColorShader___init__(BPy_ConstantColorShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp
index 6bc348dd7c5..c8cc41303d8 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstantThicknessShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ConstantThicknessShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`ConstantThicknessShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`ConstantThicknessShader`\n"
"\n"
"[Thickness shader]\n"
"\n"
@@ -51,7 +51,7 @@ static char ConstantThicknessShader___doc__[] =
" Assigns an absolute constant thickness to every vertex of the Stroke.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int ConstantThicknessShader___init__(BPy_ConstantThicknessShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp
index 119ba84abd3..6e1886398b6 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ConstrainedIncreasingThicknessShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ConstrainedIncreasingThicknessShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`ConstrainedIncreasingThicknessShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`ConstrainedIncreasingThicknessShader`\n"
"\n"
"[Thickness shader]\n"
"\n"
@@ -57,7 +57,7 @@ static char ConstrainedIncreasingThicknessShader___doc__[] =
" fat short lines.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int ConstrainedIncreasingThicknessShader___init__(BPy_ConstrainedIncreasingThicknessShader *self,
PyObject *args, PyObject *kwds)
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.cpp
index e2a9a99a392..0c9b26fa434 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_GuidingLinesShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GuidingLinesShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`GuidingLinesShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`GuidingLinesShader`\n"
"\n"
"[Geometry shader]\n"
"\n"
@@ -59,7 +59,7 @@ static char GuidingLinesShader___doc__[] =
" approximation is.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int GuidingLinesShader___init__(BPy_GuidingLinesShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.cpp
index cec0aeba58c..1ed98d62dd9 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingColorShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char IncreasingColorShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`IncreasingColorShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`IncreasingColorShader`\n"
"\n"
"[Color shader]\n"
"\n"
@@ -67,7 +67,7 @@ static char IncreasingColorShader___doc__[] =
" between the first and the last vertex.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int IncreasingColorShader___init__(BPy_IncreasingColorShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp
index ef84b9d6fd3..c9c38a9b70a 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_IncreasingThicknessShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char IncreasingThicknessShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`IncreasingThicknessShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`IncreasingThicknessShader`\n"
"\n"
"[Thickness shader]\n"
"\n"
@@ -57,7 +57,7 @@ static char IncreasingThicknessShader___doc__[] =
" linearly interpolated from A to B.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int IncreasingThicknessShader___init__(BPy_IncreasingThicknessShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.cpp
index f405162a918..f5df1ed929f 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_PolygonalizationShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char PolygonalizationShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`PolygonalizationShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`PolygonalizationShader`\n"
"\n"
"[Geometry shader]\n"
"\n"
@@ -58,7 +58,7 @@ static char PolygonalizationShader___doc__[] =
" error is reached.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int PolygonalizationShader___init__(BPy_PolygonalizationShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.cpp
index 94e95362ce7..2fa7b00a3b7 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SamplingShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char SamplingShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`SamplingShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`SamplingShader`\n"
"\n"
"[Geometry shader]\n"
"\n"
@@ -51,7 +51,7 @@ static char SamplingShader___doc__[] =
" Resamples the stroke.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int SamplingShader___init__(BPy_SamplingShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
index ca69561d8e0..750dc6b9eb1 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SmoothingShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char SmoothingShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`SmoothingShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`SmoothingShader`\n"
"\n"
"[Geometry shader]\n"
"\n"
@@ -71,7 +71,7 @@ static char SmoothingShader___doc__[] =
" prevent the diffusion across corners.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int SmoothingShader___init__(BPy_SmoothingShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp
index ae96400de8f..b28c3bd0f96 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_SpatialNoiseShader.cpp
@@ -36,7 +36,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char SpatialNoiseShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`SpatialNoiseShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`SpatialNoiseShader`\n"
"\n"
"[Geometry shader]\n"
"\n"
@@ -61,7 +61,7 @@ static char SpatialNoiseShader___doc__[] =
" more noisy.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int SpatialNoiseShader___init__(BPy_SpatialNoiseShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.cpp
deleted file mode 100644
index 5522dd46f0a..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.cpp
+++ /dev/null
@@ -1,143 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.cpp
- * \ingroup freestyle
- */
-
-#include "BPy_StrokeTextureShader.h"
-
-#include "../../stroke/BasicStrokeShaders.h"
-#include "../BPy_Convert.h"
-#include "../BPy_MediumType.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-//------------------------INSTANCE METHODS ----------------------------------
-
-static char StrokeTextureShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`StrokeTextureShader`\n"
-"\n"
-"[Texture shader]\n"
-"\n"
-".. method:: __init__(texture_file, medium_type=Stroke.OPAQUE_MEDIUM, tips=False)\n"
-"\n"
-" Builds a StrokeTextureShader object.\n"
-"\n"
-" :arg texture_file: \n"
-" :type texture_file: str\n"
-" :arg medium_type: The medium type and therefore, the blending mode\n"
-" that must be used for the rendering of this stroke.\n"
-" :type medium_type: :class:`MediumType`\n"
-" :arg tips: Tells whether the texture includes tips or not. If it\n"
-" is the case, the texture image must respect the following format.\n"
-" :type tips: bool\n"
-"\n"
-" The format of a texture image including tips::\n"
-"\n"
-" ___________\n"
-" | |\n"
-" | A |\n"
-" |___________|\n"
-" | | |\n"
-" | B | C |\n"
-" |_____|_____|\n"
-"\n"
-" * A : The stroke's corpus texture.\n"
-" * B : The stroke's left extremity texture.\n"
-" * C : The stroke's right extremity texture.\n"
-"\n"
-".. method:: shade(stroke)\n"
-"\n"
-" Assigns a texture and a blending mode to the stroke in order to\n"
-" simulate its marks system.\n"
-"\n"
-" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
-
-static int StrokeTextureShader___init__(BPy_StrokeTextureShader *self, PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"texture_file", "medium_type", "tips", NULL};
- const char *s1;
- PyObject *obj2 = 0, *obj3 = 0;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|O!O!", (char **)kwlist,
- &s1, &MediumType_Type, &obj2, &PyBool_Type, &obj3))
- {
- return -1;
- }
- Stroke::MediumType mt = (!obj2) ? Stroke::OPAQUE_MEDIUM : MediumType_from_BPy_MediumType(obj2);
- bool b = (!obj3) ? false : bool_from_PyBool(obj3);
- self->py_ss.ss = new StrokeShaders::StrokeTextureShader(s1, mt, b);
- return 0;
-}
-
-/*-----------------------BPy_StrokeTextureShader type definition ------------------------------*/
-
-PyTypeObject StrokeTextureShader_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "StrokeTextureShader", /* tp_name */
- sizeof(BPy_StrokeTextureShader), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- StrokeTextureShader___doc__, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &StrokeShader_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)StrokeTextureShader___init__, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.h
deleted file mode 100644
index d025e8b7c2d..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.h
+++ /dev/null
@@ -1,53 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureShader.h
- * \ingroup freestyle
- */
-
-#ifndef __FREESTYLE_PYTHON_STROKETEXTURESHADER_H__
-#define __FREESTYLE_PYTHON_STROKETEXTURESHADER_H__
-
-#include "../BPy_StrokeShader.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-extern PyTypeObject StrokeTextureShader_Type;
-
-#define BPy_StrokeTextureShader_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&StrokeTextureShader_Type))
-
-/*---------------------------Python BPy_StrokeTextureShader structure definition----------*/
-typedef struct {
- BPy_StrokeShader py_ss;
-} BPy_StrokeTextureShader;
-
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* __FREESTYLE_PYTHON_STROKETEXTURESHADER_H__ */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureStepShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureStepShader.cpp
index 5a7657f2dad..33962f8e41a 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureStepShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_StrokeTextureStepShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char StrokeTextureStepShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`StrokeTextureStepShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`StrokeTextureStepShader`\n"
"\n"
"[Texture shader]\n"
"\n"
@@ -51,7 +51,7 @@ static char StrokeTextureStepShader___doc__[] =
" Assigns a spacing factor to the texture coordinates of the Stroke.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int StrokeTextureStepShader___init__(BPy_StrokeTextureStepShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.cpp
deleted file mode 100644
index 11bac684cf0..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.cpp
+++ /dev/null
@@ -1,130 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.cpp
- * \ingroup freestyle
- */
-
-#include "BPy_TextureAssignerShader.h"
-
-#include "../../stroke/BasicStrokeShaders.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-//------------------------INSTANCE METHODS ----------------------------------
-
-static char TextureAssignerShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`TextureAssignerShader`\n"
-"\n"
-"[Texture shader]\n"
-"\n"
-".. method:: __init__(preset)\n"
-"\n"
-" Builds a TextureAssignerShader object.\n"
-"\n"
-" :arg preset: The preset number to use.\n"
-" :type preset: int\n"
-"\n"
-".. method:: shade(stroke)\n"
-"\n"
-" Assigns a texture to the stroke in order to simulate its marks\n"
-" system. This shader takes as input an integer value telling which\n"
-" texture and blending mode to use among a set of predefined\n"
-" textures. Here are the different presets:\n"
-"\n"
-" * 0: `/brushes/charcoalAlpha.bmp`, `Stroke.HUMID_MEDIUM`\n"
-" * 1: `/brushes/washbrushAlpha.bmp`, `Stroke.HUMID_MEDIUM`\n"
-" * 2: `/brushes/oil.bmp`, `Stroke.HUMID_MEDIUM`\n"
-" * 3: `/brushes/oilnoblend.bmp`, `Stroke.HUMID_MEDIUM`\n"
-" * 4: `/brushes/charcoalAlpha.bmp`, `Stroke.DRY_MEDIUM`\n"
-" * 5: `/brushes/washbrushAlpha.bmp`, `Stroke.DRY_MEDIUM`\n"
-" * 6: `/brushes/opaqueDryBrushAlpha.bmp`, `Stroke.OPAQUE_MEDIUM`\n"
-" * 7: `/brushes/opaqueBrushAlpha.bmp`, `Stroke.OPAQUE_MEDIUM`\n"
-"\n"
-" Any other value will lead to the following preset:\n"
-"\n"
-" * Default: `/brushes/smoothAlpha.bmp`, `Stroke.OPAQUE_MEDIUM`\n"
-"\n"
-" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
-
-static int TextureAssignerShader___init__(BPy_TextureAssignerShader *self, PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"preset", NULL};
- int i;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", (char **)kwlist, &i))
- return -1;
- self->py_ss.ss = new StrokeShaders::TextureAssignerShader(i);
- return 0;
-}
-
-/*-----------------------BPy_TextureAssignerShader type definition ------------------------------*/
-
-PyTypeObject TextureAssignerShader_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "TextureAssignerShader", /* tp_name */
- sizeof(BPy_TextureAssignerShader), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- TextureAssignerShader___doc__, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &StrokeShader_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)TextureAssignerShader___init__, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.h
deleted file mode 100644
index 046f785dc57..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.h
+++ /dev/null
@@ -1,53 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_TextureAssignerShader.h
- * \ingroup freestyle
- */
-
-#ifndef __FREESTYLE_PYTHON_TEXTUREASSIGNERSHADER_H__
-#define __FREESTYLE_PYTHON_TEXTUREASSIGNERSHADER_H__
-
-#include "../BPy_StrokeShader.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-extern PyTypeObject TextureAssignerShader_Type;
-
-#define BPy_TextureAssignerShader_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&TextureAssignerShader_Type))
-
-/*---------------------------Python BPy_TextureAssignerShader structure definition----------*/
-typedef struct {
- BPy_StrokeShader py_ss;
-} BPy_TextureAssignerShader;
-
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* __FREESTYLE_PYTHON_TEXTUREASSIGNERSHADER_H__ */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp
index 655a5c8fe98..acd4f4172fb 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessNoiseShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ThicknessNoiseShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`ThicknessNoiseShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`ThicknessNoiseShader`\n"
"\n"
"[Thickness shader]\n"
"\n"
@@ -53,7 +53,7 @@ static char ThicknessNoiseShader___doc__[] =
" Adds some noise to the stroke thickness.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int ThicknessNoiseShader___init__(BPy_ThicknessNoiseShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp
deleted file mode 100644
index 1f892455b29..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp
+++ /dev/null
@@ -1,128 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.cpp
- * \ingroup freestyle
- */
-
-#include "BPy_ThicknessVariationPatternShader.h"
-
-#include "../../stroke/BasicStrokeShaders.h"
-#include "../BPy_Convert.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-//------------------------INSTANCE METHODS ----------------------------------
-
-static char ThicknessVariationPatternShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`ThicknessVariationPatternShader`\n"
-"\n"
-"[Thickness shader]\n"
-"\n"
-".. method:: __init__(pattern_name, thickness_min=1.0, thickness_max=5.0, stretch=True)\n"
-"\n"
-" Builds a ThicknessVariationPatternShader object.\n"
-"\n"
-" :arg pattern_name: The texture file name.\n"
-" :type pattern_name: str\n"
-" :arg thickness_min: The minimum thickness we don't want to exceed.\n"
-" :type thickness_min: float\n"
-" :arg thickness_max: The maximum thickness we don't want to exceed.\n"
-" :type thickness_max: float\n"
-" :arg stretch: Tells whether the pattern texture must be stretched\n"
-" or repeated to fit the stroke.\n"
-" :type stretch: bool\n"
-"\n"
-".. method:: shade(stroke)\n"
-"\n"
-" Applies a pattern (texture) to vary thickness. The new thicknesses\n"
-" are the result of the multiplication of the pattern and the\n"
-" original thickness.\n"
-"\n"
-" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
-
-static int ThicknessVariationPatternShader___init__(BPy_ThicknessVariationPatternShader *self,
- PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"pattern_name", "thickness_min", "thickness_max", "stretch", NULL};
- const char *s1;
- float f2 = 1.0, f3 = 5.0;
- PyObject *obj4 = 0;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|ffO!", (char **)kwlist, &s1, &f2, &f3, &PyBool_Type, &obj4))
- return -1;
- bool b = (!obj4) ? true : bool_from_PyBool(obj4);
- self->py_ss.ss = new StrokeShaders::ThicknessVariationPatternShader(s1, f2, f3, b);
- return 0;
-}
-
-/*-----------------------BPy_ThicknessVariationPatternShader type definition ------------------------------*/
-
-PyTypeObject ThicknessVariationPatternShader_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "ThicknessVariationPatternShader", /* tp_name */
- sizeof(BPy_ThicknessVariationPatternShader), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- ThicknessVariationPatternShader___doc__, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &StrokeShader_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)ThicknessVariationPatternShader___init__, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h b/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h
deleted file mode 100644
index 604e875f815..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h
+++ /dev/null
@@ -1,54 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_ThicknessVariationPatternShader.h
- * \ingroup freestyle
- */
-
-#ifndef __FREESTYLE_PYTHON_THICKNESSVARIATIONPATTERNSHADER_H__
-#define __FREESTYLE_PYTHON_THICKNESSVARIATIONPATTERNSHADER_H__
-
-#include "../BPy_StrokeShader.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-extern PyTypeObject ThicknessVariationPatternShader_Type;
-
-#define BPy_ThicknessVariationPatternShader_Check(v) \
- (PyObject_IsInstance((PyObject *)v, (PyObject *)&ThicknessVariationPatternShader_Type))
-
-/*---------------------------Python BPy_ThicknessVariationPatternShader structure definition----------*/
-typedef struct {
- BPy_StrokeShader py_ss;
-} BPy_ThicknessVariationPatternShader;
-
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif /* __FREESTYLE_PYTHON_THICKNESSVARIATIONPATTERNSHADER_H__ */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.cpp
index 8b04ee0886f..543cd17c01e 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.cpp
+++ b/source/blender/freestyle/intern/python/StrokeShader/BPy_TipRemoverShader.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char TipRemoverShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`TipRemoverShader`\n"
+"Class hierarchy: :class:`freestyle.types.StrokeShader` > :class:`TipRemoverShader`\n"
"\n"
"[Geometry shader]\n"
"\n"
@@ -52,7 +52,7 @@ static char TipRemoverShader___doc__[] =
" Removes the stroke's extremities.\n"
"\n"
" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
+" :type stroke: :class:`freestyle.types.Stroke`\n";
static int TipRemoverShader___init__(BPy_TipRemoverShader *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.cpp
deleted file mode 100644
index 0c060ef6ed9..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.cpp
+++ /dev/null
@@ -1,114 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.cpp
- * \ingroup freestyle
- */
-
-#include "BPy_fstreamShader.h"
-
-#include "../../stroke/AdvancedStrokeShaders.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-//------------------------INSTANCE METHODS ----------------------------------
-
-static char fstreamShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`fstreamShader`\n"
-"\n"
-"[Output shader]\n"
-"\n"
-".. method:: __init__(filename)\n"
-"\n"
-" Builds a fstreamShader object.\n"
-"\n"
-" :arg filename: The output file name.\n"
-" :type filename: str\n"
-"\n"
-".. method:: shade(stroke)\n"
-"\n"
-" Streams the Stroke in a file.\n"
-"\n"
-" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
-
-static int fstreamShader___init__(BPy_fstreamShader *self, PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {"filename", NULL};
- const char *s;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", (char **)kwlist, &s))
- return -1;
- self->py_ss.ss = new StrokeShaders::fstreamShader(s);
- return 0;
-}
-
-/*-----------------------BPy_fstreamShader type definition ------------------------------*/
-
-PyTypeObject fstreamShader_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "fstreamShader", /* tp_name */
- sizeof(BPy_fstreamShader), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- fstreamShader___doc__, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &StrokeShader_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)fstreamShader___init__, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.cpp b/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.cpp
deleted file mode 100644
index daa10e1b38f..00000000000
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.cpp
+++ /dev/null
@@ -1,110 +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 source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.cpp
- * \ingroup freestyle
- */
-
-#include "BPy_streamShader.h"
-
-#include "../../stroke/BasicStrokeShaders.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-//------------------------INSTANCE METHODS ----------------------------------
-
-static char streamShader___doc__[] =
-"Class hierarchy: :class:`StrokeShader` > :class:`streamShader`\n"
-"\n"
-"[Output shader]\n"
-"\n"
-".. method:: __init__()\n"
-"\n"
-" Builds a streamShader object.\n"
-"\n"
-".. method:: shade(stroke)\n"
-"\n"
-" Streams the Stroke into stdout.\n"
-"\n"
-" :arg stroke: A Stroke object.\n"
-" :type stroke: :class:`Stroke`\n";
-
-static int streamShader___init__(BPy_streamShader *self, PyObject *args, PyObject *kwds)
-{
- static const char *kwlist[] = {NULL};
-
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "", (char **)kwlist))
- return -1;
- self->py_ss.ss = new StrokeShaders::streamShader();
- return 0;
-}
-
-/*-----------------------BPy_streamShader type definition ------------------------------*/
-
-PyTypeObject streamShader_Type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "streamShader", /* tp_name */
- sizeof(BPy_streamShader), /* tp_basicsize */
- 0, /* tp_itemsize */
- 0, /* tp_dealloc */
- 0, /* tp_print */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_reserved */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- streamShader___doc__, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- 0, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- &StrokeShader_Type, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)streamShader___init__, /* tp_init */
- 0, /* tp_alloc */
- 0, /* tp_new */
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////
-
-#ifdef __cplusplus
-}
-#endif
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp
index e2e49116106..841338ef81c 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Id/BPy_ShapeIdF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ShapeIdF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DId` > :class:`ShapeIdF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DId` > :class:`ShapeIdF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,19 +43,20 @@ static char ShapeIdF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the :class:`Id` of the Shape the :class:`Interface0D`\n"
-" pointed by the Interface0DIterator belongs to. This evaluation can\n"
-" be ambiguous (in the case of a :class:`TVertex` for example). This\n"
+" Returns the :class:`freestyle.types.Id` of the Shape the\n"
+" :class:`freestyle.types.Interface0D` pointed by the\n"
+" Interface0DIterator belongs to. This evaluation can be ambiguous (in\n"
+" the case of a :class:`freestyle.types.TVertex` for example). This\n"
" functor tries to remove this ambiguity using the context offered by\n"
-" the 1D element to which the Interface0DIterator belongs to.\n"
-" However, there still can be problematic cases, and the user willing\n"
-" to deal with this cases in a specific way should implement its own\n"
+" the 1D element to which the Interface0DIterator belongs to. However,\n"
+" there still can be problematic cases, and the user willing to deal\n"
+" with this cases in a specific way should implement its own\n"
" getShapeIdF0D functor.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The Id of the Shape the pointed Interface0D belongs to.\n"
-" :rtype: :class:`Id`\n";
+" :rtype: :class:`freestyle.types.Id`\n";
static int ShapeIdF0D___init__(BPy_ShapeIdF0D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp
index b54ed48edc3..cbb905dcf2e 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Material/BPy_MaterialF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char MaterialF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DMaterial` > :class:`MaterialF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DMaterial` > :class:`MaterialF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -44,22 +44,22 @@ static char MaterialF0D___doc__[] =
".. method:: __call__(it)\n"
"\n"
" Returns the material of the object evaluated at the\n"
-" :class:`Interface0D` pointed by the Interface0DIterator. This\n"
-" evaluation can be ambiguous (in the case of a :class:`TVertex` for\n"
-" example. This functor tries to remove this ambiguity using the\n"
-" context offered by the 1D element to which the Interface0DIterator\n"
-" belongs to and by arbitrary choosing the material of the face that\n"
-" lies on its left when following the 1D element if there are two\n"
-" different materials on each side of the point. However, there\n"
-" still can be problematic cases, and the user willing to deal with\n"
-" this cases in a specific way should implement its own getMaterial\n"
-" functor.\n"
+" :class:`freestyle.types.Interface0D` pointed by the\n"
+" Interface0DIterator. This evaluation can be ambiguous (in the case of\n"
+" a :class:`freestyle.types.TVertex` for example. This functor tries to\n"
+" remove this ambiguity using the context offered by the 1D element to\n"
+" which the Interface0DIterator belongs to and by arbitrary choosing the\n"
+" material of the face that lies on its left when following the 1D\n"
+" element if there are two different materials on each side of the\n"
+" point. However, there still can be problematic cases, and the user\n"
+" willing to deal with this cases in a specific way should implement its\n"
+" own getMaterial functor.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The material of the object evaluated at the pointed\n"
" Interface0D.\n"
-" :rtype: :class:`Material`\n";
+" :rtype: :class:`freestyle.types.Material`\n";
static int MaterialF0D___init__(BPy_MaterialF0D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp
index 63c32655da3..41ce2f5d197 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Nature_EdgeNature/BPy_CurveNatureF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char CurveNatureF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DEdgeNature` > :class:`CurveNatureF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DEdgeNature` > :class:`CurveNatureF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,14 +43,14 @@ static char CurveNatureF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the :class:`Nature` of the 1D element the Interface0D pointed\n"
-" by the Interface0DIterator belongs to.\n"
+" Returns the :class:`freestyle.types.Nature` of the 1D element the\n"
+" Interface0D pointed by the Interface0DIterator belongs to.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The nature of the 1D element to which the pointed Interface0D\n"
" belongs.\n"
-" :rtype: :class:`Nature`\n";
+" :rtype: :class:`freestyle.types.Nature`\n";
static int CurveNatureF0D___init__(BPy_CurveNatureF0D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp
index 10152f594c9..bfe060bc046 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_Normal2DF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char Normal2DF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVec2f` > :class:`Normal2DF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DVec2f` > :class:`Normal2DF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -44,12 +44,12 @@ static char Normal2DF0D___doc__[] =
".. method:: __call__(it)\n"
"\n"
" Returns a two-dimensional vector giving the normalized 2D normal to\n"
-" the 1D element to which the :class:`Interface0D` pointed by the\n"
-" Interface0DIterator belongs. The normal is evaluated at the pointed\n"
-" Interface0D.\n"
+" the 1D element to which the :class:`freestyle.types.Interface0D`\n"
+" pointed by the Interface0DIterator belongs. The normal is evaluated\n"
+" at the pointed Interface0D.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The 2D normal of the 1D element evaluated at the pointed\n"
" Interface0D.\n"
" :rtype: :class:`mathutils.Vector`\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp
index a97b53451c7..70d122bd97a 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec2f/BPy_VertexOrientation2DF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char VertexOrientation2DF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVec2f` > :class:`VertexOrientation2DF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DVec2f` > :class:`VertexOrientation2DF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,13 +43,13 @@ static char VertexOrientation2DF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns a two-dimensional vector giving the 2D oriented tangent to\n"
-" the 1D element to which the :class:`Interface0D` pointed by the\n"
-" Interface0DIterator belongs. The 2D oriented tangent is evaluated\n"
-" at the pointed Interface0D.\n"
+" Returns a two-dimensional vector giving the 2D oriented tangent to the\n"
+" 1D element to which the :class:`freestyle.types.Interface0D` pointed\n"
+" by the Interface0DIterator belongs. The 2D oriented tangent is\n"
+" evaluated at the pointed Interface0D.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The 2D oriented tangent to the 1D element evaluated at the\n"
" pointed Interface0D.\n"
" :rtype: :class:`mathutils.Vector`\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp
index ffa8996f9b2..6b010af4228 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_Vec3f/BPy_VertexOrientation3DF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char VertexOrientation3DF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVec3f` > :class:`VertexOrientation3DF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DVec3f` > :class:`VertexOrientation3DF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,13 +43,13 @@ static char VertexOrientation3DF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns a three-dimensional vector giving the 3D oriented tangent\n"
-" to the 1D element to which the :class:`Interface0D` pointed by the\n"
-" Interface0DIterator belongs. The 3D oriented tangent is evaluated\n"
-" at the pointed Interface0D.\n"
+" Returns a three-dimensional vector giving the 3D oriented tangent to\n"
+" the 1D element to which the :class:`freestyle.types.Interface0D`\n"
+" pointed by the Interface0DIterator belongs. The 3D oriented tangent\n"
+" is evaluated at the pointed Interface0D.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The 3D oriented tangent to the 1D element evaluated at the\n"
" pointed Interface0D.\n"
" :rtype: :class:`mathutils.Vector`\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp
index 3523b08982a..ba16fec1539 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetOccludeeF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetOccludeeF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DViewShape` > :class:`GetOccludeeF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DViewShape` > :class:`GetOccludeeF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,13 +43,13 @@ static char GetOccludeeF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the :class:`ViewShape` that the Interface0D pointed by the\n"
-" Interface0DIterator occludes.\n"
+" Returns the :class:`freestyle.types.ViewShape` that the Interface0D\n"
+" pointed by the Interface0DIterator occludes.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The ViewShape occluded by the pointed Interface0D.\n"
-" :rtype: :class:`ViewShape`\n";
+" :rtype: :class:`freestyle.types.ViewShape`\n";
static int GetOccludeeF0D___init__(BPy_GetOccludeeF0D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp
index 234dc648ff5..5e4111de924 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_ViewShape/BPy_GetShapeF0D.cpp
@@ -35,21 +35,21 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetShapeF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DViewShape` > :class:`GetShapeF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DViewShape` > :class:`GetShapeF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
-" Builds a GetShapeF0D.cpp object.\n"
+" Builds a GetShapeF0D object.\n"
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the :class:`ViewShape` containing the Interface0D pointed\n"
-" by the Interface0DIterator.\n"
+" Returns the :class:`freestyle.types.ViewShape` containing the\n"
+" Interface0D pointed by the Interface0DIterator.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The ViewShape containing the pointed Interface0D.\n"
-" :rtype: :class:`ViewShape`\n";
+" :rtype: :class:`freestyle.types.ViewShape`\n";
static int GetShapeF0D___init__(BPy_GetShapeF0D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp
index 3d343762b8e..55f7bab3bb3 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_Curvature2DAngleF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char Curvature2DAngleF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`Curvature2DAngleF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`Curvature2DAngleF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,13 +43,13 @@ static char Curvature2DAngleF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns a real value giving the 2D curvature (as an angle) of the\n"
-" 1D element to which the :class:`Interface0D` pointed by the\n"
-" Interface0DIterator belongs. The 2D curvature is evaluated at the\n"
+" Returns a real value giving the 2D curvature (as an angle) of the 1D\n"
+" element to which the :class:`freestyle.types.Interface0D` pointed by\n"
+" the Interface0DIterator belongs. The 2D curvature is evaluated at the\n"
" Interface0D.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The 2D curvature of the 1D element evaluated at the\n"
" pointed Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp
index 84a3fd79608..2aac3f4f1f0 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_DensityF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char DensityF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`DensityF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`DensityF0D`\n"
"\n"
".. method:: __init__(sigma=2.0)\n"
"\n"
@@ -49,12 +49,13 @@ static char DensityF0D___doc__[] =
".. method:: __call__(it)\n"
"\n"
" Returns the density of the (result) image evaluated at the\n"
-" :class:`Interface0D` pointed by the Interface0DIterator. This\n"
-" density is evaluated using a pixels square window around the\n"
-" evaluation point and integrating these values using a gaussian.\n"
+" :class:`freestyle.types.Interface0D` pointed by the\n"
+" Interface0DIterator. This density is evaluated using a pixels square\n"
+" window around the evaluation point and integrating these values using\n"
+" a gaussian.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The density of the image evaluated at the pointed\n"
" Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp
index d901b245247..123772b3fc7 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedXF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetProjectedXF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetProjectedXF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`GetProjectedXF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,11 +43,11 @@ static char GetProjectedXF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the X 3D projected coordinate of the :class:`Interface0D`\n"
+" Returns the X 3D projected coordinate of the :class:`freestyle.types.Interface0D`\n"
" pointed by the Interface0DIterator.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The X 3D projected coordinate of the pointed Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp
index 2d82182f011..f4e3d6ba76f 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedYF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetProjectedYF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetProjectedYF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`GetProjectedYF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,11 +43,11 @@ static char GetProjectedYF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the Y 3D projected coordinate of the :class:`Interface0D`\n"
+" Returns the Y 3D projected coordinate of the :class:`freestyle.types.Interface0D`\n"
" pointed by the Interface0DIterator.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The Y 3D projected coordinate of the pointed Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp
index 9766985954b..116bb75fc55 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetProjectedZF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetProjectedZF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetProjectedZF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`GetProjectedZF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,11 +43,11 @@ static char GetProjectedZF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the Z 3D projected coordinate of the :class:`Interface0D`\n"
+" Returns the Z 3D projected coordinate of the :class:`freestyle.types.Interface0D`\n"
" pointed by the Interface0DIterator.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The Z 3D projected coordinate of the pointed Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp
index 9ee87c63bdd..614e92cf7c2 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetXF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetXF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetXF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`GetXF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,11 +43,11 @@ static char GetXF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the X 3D coordinate of the :class:`Interface0D` pointed by\n"
+" Returns the X 3D coordinate of the :class:`freestyle.types.Interface0D` pointed by\n"
" the Interface0DIterator.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The X 3D coordinate of the pointed Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp
index 90f8f74e989..1a953b9ebca 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetYF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetYF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetYF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`GetYF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,11 +43,11 @@ static char GetYF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the Y 3D coordinate of the :class:`Interface0D` pointed by\n"
+" Returns the Y 3D coordinate of the :class:`freestyle.types.Interface0D` pointed by\n"
" the Interface0DIterator.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The Y 3D coordinate of the pointed Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp
index 8876f2200c2..c985e0f5c99 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_GetZF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetZF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`GetZF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`GetZF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,11 +43,11 @@ static char GetZF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the Z 3D coordinate of the :class:`Interface0D` pointed by\n"
+" Returns the Z 3D coordinate of the :class:`freestyle.types.Interface0D` pointed by\n"
" the Interface0DIterator.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The Z 3D coordinate of the pointed Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp
index af5edb4eac7..3c7f3b412fe 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_LocalAverageDepthF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char LocalAverageDepthF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`LocalAverageDepthF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`LocalAverageDepthF0D`\n"
"\n"
".. method:: __init__(mask_size=5.0)\n"
"\n"
@@ -46,12 +46,13 @@ static char LocalAverageDepthF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the average depth around the :class:`Interface0D` pointed\n"
-" by the Interface0DIterator. The result is obtained by querying the\n"
-" depth buffer on a window around that point.\n"
+" Returns the average depth around the\n"
+" :class:`freestyle.types.Interface0D` pointed by the\n"
+" Interface0DIterator. The result is obtained by querying the depth\n"
+" buffer on a window around that point.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The average depth around the pointed Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp
index b64f6c06e93..f0c58352f4a 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_double/BPy_ZDiscontinuityF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ZDiscontinuityF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DDouble` > :class:`ZDiscontinuityF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DDouble` > :class:`ZDiscontinuityF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -44,14 +44,14 @@ static char ZDiscontinuityF0D___doc__[] =
".. method:: __call__(it)\n"
"\n"
" Returns a real value giving the distance between the\n"
-" :class:`Interface0D` pointed by the Interface0DIterator and the\n"
-" shape that lies behind (occludee). This distance is evaluated in\n"
-" the camera space and normalized between 0 and 1. Therefore, if no\n"
-" object is occluded by the shape to which the Interface0D belongs to,\n"
-" 1 is returned.\n"
+" :class:`freestyle.types.Interface0D` pointed by the\n"
+" Interface0DIterator and the shape that lies behind (occludee). This\n"
+" distance is evaluated in the camera space and normalized between 0 and\n"
+" 1. Therefore, if no object is occluded by the shape to which the\n"
+" Interface0D belongs to, 1 is returned.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The normalized distance between the pointed Interface0D\n"
" and the occludee.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp
index 96db3ca7375..a2358e6ebae 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetCurvilinearAbscissaF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetCurvilinearAbscissaF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`GetCurvilinearAbscissaF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DFloat` > :class:`GetCurvilinearAbscissaF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,12 +43,12 @@ static char GetCurvilinearAbscissaF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the curvilinear abscissa of the :class:`Interface0D`\n"
-" pointed by the Interface0DIterator in the context of its 1D\n"
-" element.\n"
+" Returns the curvilinear abscissa of the\n"
+" :class:`freestyle.types.Interface0D` pointed by the\n"
+" Interface0DIterator in the context of its 1D element.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The curvilinear abscissa of the pointed Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp
index 045a5041b9c..43061747398 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetParameterF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetParameterF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`GetParameterF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DFloat` > :class:`GetParameterF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,11 +43,11 @@ static char GetParameterF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the parameter of the :class:`Interface0D` pointed by the\n"
-" Interface0DIterator in the context of its 1D element.\n"
+" Returns the parameter of the :class:`freestyle.types.Interface0D`\n"
+" pointed by the Interface0DIterator in the context of its 1D element.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The parameter of an Interface0D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp
index 43aebe8c4ec..cecec01dcb5 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_GetViewMapGradientNormF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetViewMapGradientNormF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`GetViewMapGradientNormF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DFloat` > :class:`GetViewMapGradientNormF0D`\n"
"\n"
".. method:: __init__(level)\n"
"\n"
@@ -51,7 +51,7 @@ static char GetViewMapGradientNormF0D___doc__[] =
" image.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The norm of the gradient of the global viewmap density\n"
" image.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp
index c1f316a45d3..313826f9307 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadCompleteViewMapPixelF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ReadCompleteViewMapPixelF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`ReadCompleteViewMapPixelF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DFloat` > :class:`ReadCompleteViewMapPixelF0D`\n"
"\n"
".. method:: __init__(level)\n"
"\n"
@@ -50,7 +50,7 @@ static char ReadCompleteViewMapPixelF0D___doc__[] =
" Reads a pixel in one of the level of the complete viewmap.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: A pixel in one of the level of the complete viewmap.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp
index a5c8c0c3b04..8bfccf4c80a 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadMapPixelF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ReadMapPixelF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`ReadMapPixelF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DFloat` > :class:`ReadMapPixelF0D`\n"
"\n"
".. method:: __init__(map_name, level)\n"
"\n"
@@ -52,7 +52,7 @@ static char ReadMapPixelF0D___doc__[] =
" Reads a pixel in a map.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: A pixel in a map.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp
index e46d9f316eb..b36ddf84e71 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_float/BPy_ReadSteerableViewMapPixelF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ReadSteerableViewMapPixelF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DFloat` > :class:`ReadSteerableViewMapPixelF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DFloat` > :class:`ReadSteerableViewMapPixelF0D`\n"
"\n"
".. method:: __init__(orientation, level)\n"
"\n"
@@ -53,7 +53,7 @@ static char ReadSteerableViewMapPixelF0D___doc__[] =
" Reads a pixel in one of the level of one of the steerable viewmaps.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: A pixel in one of the level of one of the steerable viewmaps.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp
index bcd17213c55..8ec982815c8 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_unsigned_int/BPy_QuantitativeInvisibilityF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char QuantitativeInvisibilityF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DUnsigned` > :class:`QuantitativeInvisibilityF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DUnsigned` > :class:`QuantitativeInvisibilityF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,17 +43,17 @@ static char QuantitativeInvisibilityF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns the quantitative invisibility of the :class:`Interface0D`\n"
-" pointed by the Interface0DIterator. This evaluation can be\n"
-" ambiguous (in the case of a :class:`TVertex` for example). This\n"
-" functor tries to remove this ambiguity using the context offered by\n"
-" the 1D element to which the Interface0D belongs to. However, there\n"
-" still can be problematic cases, and the user willing to deal with\n"
-" this cases in a specific way should implement its own getQIF0D\n"
-" functor.\n"
+" Returns the quantitative invisibility of the\n"
+" :class:`freestyle.types.Interface0D` pointed by the\n"
+" Interface0DIterator. This evaluation can be ambiguous (in the case of\n"
+" a :class:`freestyle.types.TVertex` for example). This functor tries\n"
+" to remove this ambiguity using the context offered by the 1D element\n"
+" to which the Interface0D belongs to. However, there still can be\n"
+" problematic cases, and the user willing to deal with this cases in a\n"
+" specific way should implement its own getQIF0D functor.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: The quantitative invisibility of the pointed Interface0D.\n"
" :rtype: int\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp
index e6dce989822..5504bff74ae 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction0D/UnaryFunction0D_vector_ViewShape/BPy_GetOccludersF0D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetOccludersF0D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction0D` > :class:`UnaryFunction0DVectorViewShape` > :class:`GetOccludersF0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction0D` > :class:`freestyle.types.UnaryFunction0DVectorViewShape` > :class:`GetOccludersF0D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -43,14 +43,14 @@ static char GetOccludersF0D___doc__[] =
"\n"
".. method:: __call__(it)\n"
"\n"
-" Returns a list of :class:`ViewShape` objects occluding the\n"
-" :class:`Interface0D` pointed by the Interface0DIterator.\n"
+" Returns a list of :class:`freestyle.types.ViewShape` objects occluding the\n"
+" :class:`freestyle.types.Interface0D` pointed by the Interface0DIterator.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: A list of ViewShape objects occluding the pointed\n"
" Interface0D.\n"
-" :rtype: list of :class:`ViewShape` objects\n";
+" :rtype: list of :class:`freestyle.types.ViewShape` objects\n";
static int GetOccludersF0D___init__(BPy_GetOccludersF0D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp
index 70c454c2c71..55092416cc2 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Nature_EdgeNature/BPy_CurveNatureF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char CurveNatureF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DEdgeNature` > :class:`CurveNatureF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DEdgeNature` > :class:`CurveNatureF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,21 +45,22 @@ static char CurveNatureF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
-" Returns the nature of the Interface1D (silhouette, ridge, crease,\n"
-" and so on). Except if the Interface1D is a :class:`ViewEdge`, this\n"
-" result might be ambiguous. Indeed, the Interface1D might result\n"
-" from the gathering of several 1D elements, each one being of a\n"
-" different nature. An integration method, such as the MEAN, might\n"
-" give, in this case, irrelevant results.\n"
+" Returns the nature of the Interface1D (silhouette, ridge, crease, and\n"
+" so on). Except if the Interface1D is a\n"
+" :class:`freestyle.types.ViewEdge`, this result might be ambiguous.\n"
+" Indeed, the Interface1D might result from the gathering of several 1D\n"
+" elements, each one being of a different nature. An integration\n"
+" method, such as the MEAN, might give, in this case, irrelevant\n"
+" results.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The nature of the Interface1D.\n"
-" :rtype: :class:`Nature`\n";
+" :rtype: :class:`freestyle.types.Nature`\n";
static int CurveNatureF1D___init__(BPy_CurveNatureF1D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp
index 6be8b81f43f..76330c77927 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Normal2DF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char Normal2DF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVec2f` > :class:`Normal2DF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DVec2f` > :class:`Normal2DF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char Normal2DF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the 2D normal for the Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The 2D normal for the Interface1D.\n"
" :rtype: :class:`mathutils.Vector`\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp
index 01a6f8bd602..07aa9071c57 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec2f/BPy_Orientation2DF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char Orientation2DF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVec2f` > :class:`Orientation2DF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DVec2f` > :class:`Orientation2DF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char Orientation2DF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the 2D orientation of the Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The 2D orientation of the Interface1D.\n"
" :rtype: :class:`mathutils.Vector`\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp
index 4d76fb709d8..56dd67b1d2f 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_Vec3f/BPy_Orientation3DF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char Orientation3DF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVec3f` > :class:`Orientation3DF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DVec3f` > :class:`Orientation3DF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char Orientation3DF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the 3D orientation of the Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The 3D orientation of the Interface1D.\n"
" :rtype: :class:`mathutils.Vector`\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp
index 4278f088863..e5779ce36e1 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_Curvature2DAngleF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char Curvature2DAngleF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`Curvature2DAngleF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`Curvature2DAngleF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char Curvature2DAngleF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the 2D curvature as an angle for an Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The 2D curvature as an angle.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp
index 5beb724e9af..ffee3ec81f2 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_DensityF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char DensityF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`DensityF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`DensityF1D`\n"
"\n"
".. method:: __init__(sigma=2.0, integration_type=IntegrationType.MEAN, sampling=2.0)\n"
"\n"
@@ -48,7 +48,7 @@ static char DensityF1D___doc__[] =
" :type sigma: float\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
" :arg sampling: The resolution used to sample the chain: the\n"
" corresponding 0D function is evaluated at each sample point and\n"
" the result is obtained by combining the resulting values into a\n"
@@ -59,12 +59,12 @@ static char DensityF1D___doc__[] =
"\n"
" Returns the density evaluated for an Interface1D. The density is\n"
" evaluated for a set of points along the Interface1D (using the\n"
-" :class:`DensityF0D` functor) with a user-defined sampling and then\n"
-" integrated into a single value using a user-defined integration\n"
-" method.\n"
+" :class:`freestyle.functions.DensityF0D` functor) with a user-defined\n"
+" sampling and then integrated into a single value using a user-defined\n"
+" integration method.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The density evaluated for an Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp
index 1a0588383fc..9164032488e 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetCompleteViewMapDensityF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetCompleteViewMapDensityF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetCompleteViewMapDensityF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`GetCompleteViewMapDensityF1D`\n"
"\n"
".. method:: __init__(level, integration_type=IntegrationType.MEAN, sampling=2.0)\n"
"\n"
@@ -48,7 +48,7 @@ static char GetCompleteViewMapDensityF1D___doc__[] =
" :type level: int\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
" :arg sampling: The resolution used to sample the chain: the\n"
" corresponding 0D function is evaluated at each sample point and\n"
" the result is obtained by combining the resulting values into a\n"
@@ -58,13 +58,14 @@ static char GetCompleteViewMapDensityF1D___doc__[] =
".. method:: __call__(inter)\n"
"\n"
" Returns the density evaluated for an Interface1D in the complete\n"
-" viewmap image. The density is evaluated for a set of points along\n"
-" the Interface1D (using the :class:`ReadCompleteViewMapPixelF0D`\n"
-" functor) and then integrated into a single value using a\n"
-" user-defined integration method.\n"
+" viewmap image. The density is evaluated for a set of points along the\n"
+" Interface1D (using the\n"
+" :class:`freestyle.functions.ReadCompleteViewMapPixelF0D` functor) and\n"
+" then integrated into a single value using a user-defined integration\n"
+" method.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The density evaluated for the Interface1D in the complete\n"
" viewmap image.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp
index 41841a83374..517b07f5c7f 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetDirectionalViewMapDensityF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetDirectionalViewMapDensityF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` "
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` "
"> :class:`GetDirectionalViewMapDensityF1D`\n"
"\n"
".. method:: __init__(orientation, level, integration_type=IntegrationType.MEAN, sampling=2.0)\n"
@@ -52,7 +52,7 @@ static char GetDirectionalViewMapDensityF1D___doc__[] =
" :type level: int\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
" :arg sampling: The resolution used to sample the chain: the\n"
" corresponding 0D function is evaluated at each sample point and\n"
" the result is obtained by combining the resulting values into a\n"
@@ -61,15 +61,16 @@ static char GetDirectionalViewMapDensityF1D___doc__[] =
"\n"
".. method:: __call__(inter)\n"
"\n"
-" Returns the density evaluated for an Interface1D in of the\n"
-" steerable viewmaps image. The direction telling which Directional\n"
-" map to choose is explicitely specified by the user. The density is\n"
-" evaluated for a set of points along the Interface1D (using the\n"
-" :class:`ReadSteerableViewMapPixelF0D` functor) and then integrated\n"
-" into a single value using a user-defined integration method.\n"
+" Returns the density evaluated for an Interface1D in of the steerable\n"
+" viewmaps image. The direction telling which Directional map to choose\n"
+" is explicitely specified by the user. The density is evaluated for a\n"
+" set of points along the Interface1D (using the\n"
+" :class:`freestyle.functions.ReadSteerableViewMapPixelF0D` functor) and\n"
+" then integrated into a single value using a user-defined integration\n"
+" method.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: the density evaluated for an Interface1D in of the\n"
" steerable viewmaps image.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp
index 9baec0fe70a..290b43e5ea6 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedXF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetProjectedXF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetProjectedXF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`GetProjectedXF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char GetProjectedXF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values. \n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the projected X 3D coordinate of an Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The projected X 3D coordinate of an Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp
index 004f014cc0d..7d9f7461908 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedYF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetProjectedYF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetProjectedYF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`GetProjectedYF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char GetProjectedYF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values. \n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the projected Y 3D coordinate of an Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The projected Y 3D coordinate of an Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp
index daafe1a3b6f..b8e8cf5e57e 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetProjectedZF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetProjectedZF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetProjectedZF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`GetProjectedZF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char GetProjectedZF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values. \n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the projected Z 3D coordinate of an Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The projected Z 3D coordinate of an Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp
index 199e437639f..c67485e7d36 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetSteerableViewMapDensityF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetSteerableViewMapDensityF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetSteerableViewMapDensityF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`GetSteerableViewMapDensityF1D`\n"
"\n"
".. method:: __init__(level, integration_type=IntegrationType.MEAN, sampling=2.0)\n"
"\n"
@@ -48,7 +48,7 @@ static char GetSteerableViewMapDensityF1D___doc__[] =
" :type level: int\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
" :arg sampling: The resolution used to sample the chain: the\n"
" corresponding 0D function is evaluated at each sample point and\n"
" the result is obtained by combining the resulting values into a\n"
@@ -58,11 +58,12 @@ static char GetSteerableViewMapDensityF1D___doc__[] =
".. method:: __call__(inter)\n"
"\n"
" Returns the density of the ViewMap for a given Interface1D. The\n"
-" density of each :class:`FEdge` is evaluated in the proper steerable\n"
-" :class:`ViewMap` depending on its orientation.\n"
+" density of each :class:`freestyle.types.FEdge` is evaluated in the\n"
+" proper steerable :class:`freestyle.types.ViewMap` depending on its\n"
+" orientation.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The density of the ViewMap for a given Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp
index 5c9bd76a4b3..ebcb273082e 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetViewMapGradientNormF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetViewMapGradientNormF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetViewMapGradientNormF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`GetViewMapGradientNormF1D`\n"
"\n"
".. method:: __init__(level, integration_type=IntegrationType.MEAN, sampling=2.0)\n"
"\n"
@@ -48,7 +48,7 @@ static char GetViewMapGradientNormF1D___doc__[] =
" :type level: int\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
" :arg sampling: The resolution used to sample the chain: the\n"
" corresponding 0D function is evaluated at each sample point and\n"
" the result is obtained by combining the resulting values into a\n"
@@ -58,11 +58,12 @@ static char GetViewMapGradientNormF1D___doc__[] =
".. method:: __call__(inter)\n"
"\n"
" Returns the density of the ViewMap for a given Interface1D. The\n"
-" density of each :class:`FEdge` is evaluated in the proper steerable\n"
-" :class:`ViewMap` depending on its orientation.\n"
+" density of each :class:`freestyle.types.FEdge` is evaluated in the\n"
+" proper steerable :class:`freestyle.types.ViewMap` depending on its\n"
+" orientation.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The density of the ViewMap for a given Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp
index fa749a05c69..b55a4a79fe9 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetXF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetXF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetXF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`GetXF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char GetXF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the X 3D coordinate of an Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The X 3D coordinate of the Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp
index 96022997763..d760ef948f0 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetYF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetYF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetYF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`GetYF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char GetYF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the Y 3D coordinate of an Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The Y 3D coordinate of the Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp
index 46695affe49..72a8b22630d 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_GetZF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetZF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`GetZF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`GetZF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,14 +45,14 @@ static char GetZF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Returns the Z 3D coordinate of an Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The Z 3D coordinate of the Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp
index 3638908c5bd..424f08c07c0 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_LocalAverageDepthF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char LocalAverageDepthF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`LocalAverageDepthF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`LocalAverageDepthF1D`\n"
"\n"
".. method:: __init__(sigma, integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -48,18 +48,18 @@ static char LocalAverageDepthF1D___doc__[] =
" :type sigma: float\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
-" Returns the average depth evaluated for an Interface1D. The\n"
-" average depth is evaluated for a set of points along the\n"
-" Interface1D (using the :class:`LocalAverageDepthF0D` functor) with\n"
-" a user-defined sampling and then integrated into a single value\n"
-" using a user-defined integration method.\n"
+" Returns the average depth evaluated for an Interface1D. The average\n"
+" depth is evaluated for a set of points along the Interface1D (using\n"
+" the :class:`freestyle.functions.LocalAverageDepthF0D` functor) with a\n"
+" user-defined sampling and then integrated into a single value using a\n"
+" user-defined integration method.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The average depth evaluated for the Interface1D.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp
index 65fde596e23..488675142b6 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_double/BPy_ZDiscontinuityF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ZDiscontinuityF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DDouble` > :class:`ZDiscontinuityF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DDouble` > :class:`ZDiscontinuityF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,7 +45,7 @@ static char ZDiscontinuityF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
@@ -56,7 +56,7 @@ static char ZDiscontinuityF1D___doc__[] =
" Interface1D belongs to, 1 is returned.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The normalized distance between the Interface1D and the occludee.\n"
" :rtype: float\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp
index c70493e9140..a21efd655ab 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_unsigned_int/BPy_QuantitativeInvisibilityF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char QuantitativeInvisibilityF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DUnsigned` > :class:`QuantitativeInvisibilityF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DUnsigned` > :class:`QuantitativeInvisibilityF1D`\n"
"\n"
".. method:: __init__(integration_type=IntegrationType.MEAN)\n"
"\n"
@@ -45,18 +45,18 @@ static char QuantitativeInvisibilityF1D___doc__[] =
"\n"
" :arg integration_type: The integration method used to compute a single value\n"
" from a set of values.\n"
-" :type integration_type: :class:`IntegrationType`\n"
+" :type integration_type: :class:`freestyle.types.IntegrationType`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
-" Returns the Quantitative Invisibility of an Interface1D element.\n"
-" If the Interface1D is a :class:`ViewEdge`, then there is no\n"
-" ambiguity concerning the result. But, if the Interface1D results\n"
+" Returns the Quantitative Invisibility of an Interface1D element. If\n"
+" the Interface1D is a :class:`freestyle.types.ViewEdge`, then there is\n"
+" no ambiguity concerning the result. But, if the Interface1D results\n"
" of a chaining (chain, stroke), then it might be made of several 1D\n"
" elements of different Quantitative Invisibilities.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: The Quantitative Invisibility of the Interface1D.\n"
" :rtype: int\n";
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp
index d0c16f8dae2..e4e7560822d 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludeeF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetOccludeeF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVectorViewShape` > :class:`GetOccludeeF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DVectorViewShape` > :class:`GetOccludeeF1D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -48,9 +48,9 @@ static char GetOccludeeF1D___doc__[] =
" Returns a list of occluded shapes covered by this Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: A list of occluded shapes covered by the Interface1D.\n"
-" :rtype: list of :class:`ViewShape` objects\n";
+" :rtype: list of :class:`freestyle.types.ViewShape` objects\n";
static int GetOccludeeF1D___init__(BPy_GetOccludeeF1D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp
index 62612c7cc19..ced04a5077a 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetOccludersF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetOccludersF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVectorViewShape` > :class:`GetOccludersF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DVectorViewShape` > :class:`GetOccludersF1D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -48,9 +48,9 @@ static char GetOccludersF1D___doc__[] =
" Returns a list of occluding shapes that cover this Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: A list of occluding shapes that cover the Interface1D.\n"
-" :rtype: list of :class:`ViewShape` objects\n";
+" :rtype: list of :class:`freestyle.types.ViewShape` objects\n";
static int GetOccludersF1D___init__(BPy_GetOccludersF1D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp
index 1dab3962ec2..f26f8105a9e 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_vector_ViewShape/BPy_GetShapeF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char GetShapeF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVectorViewShape` > :class:`GetShapeF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DVectorViewShape` > :class:`GetShapeF1D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -48,9 +48,9 @@ static char GetShapeF1D___doc__[] =
" Returns a list of shapes covered by this Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: A list of shapes covered by the Interface1D.\n"
-" :rtype: list of :class:`ViewShape` objects\n";
+" :rtype: list of :class:`freestyle.types.ViewShape` objects\n";
static int GetShapeF1D___init__(BPy_GetShapeF1D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp
index e585829ff0a..128deeccd11 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_ChainingTimeStampF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ChainingTimeStampF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVoid` > :class:`ChainingTimeStampF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DVoid` > :class:`ChainingTimeStampF1D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -48,7 +48,7 @@ static char ChainingTimeStampF1D___doc__[] =
" Sets the chaining time stamp of the Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n";
+" :type inter: :class:`freestyle.types.Interface1D`\n";
static int ChainingTimeStampF1D___init__(BPy_ChainingTimeStampF1D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp
index 96d594ff56e..64a92a8e357 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_IncrementChainingTimeStampF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char IncrementChainingTimeStampF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVoid` > :class:`IncrementChainingTimeStampF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DVoid` > :class:`IncrementChainingTimeStampF1D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -48,7 +48,7 @@ static char IncrementChainingTimeStampF1D___doc__[] =
" Increments the chaining time stamp of the Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n";
+" :type inter: :class:`freestyle.types.Interface1D`\n";
static int IncrementChainingTimeStampF1D___init__(BPy_IncrementChainingTimeStampF1D *self,
PyObject *args, PyObject *kwds)
diff --git a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp
index 715bbaafdba..2cd359eea61 100644
--- a/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryFunction1D/UnaryFunction1D_void/BPy_TimeStampF1D.cpp
@@ -37,7 +37,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char TimeStampF1D___doc__[] =
-"Class hierarchy: :class:`UnaryFunction1D` > :class:`UnaryFunction1DVoid` > :class:`TimeStampF1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryFunction1D` > :class:`freestyle.types.UnaryFunction1DVoid` > :class:`TimeStampF1D`\n"
"\n"
".. method:: __init__()\n"
"\n"
@@ -48,7 +48,7 @@ static char TimeStampF1D___doc__[] =
" Returns the time stamp of the Interface1D.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n";
+" :type inter: :class:`freestyle.types.Interface1D`\n";
static int TimeStampF1D___init__(BPy_TimeStampF1D *self, PyObject *args, PyObject *kwds)
{
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp
index 896348d143c..36511e01358 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_FalseUP0D.cpp
@@ -33,14 +33,14 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char FalseUP0D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate0D` > :class:`FalseUP0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate0D` > :class:`FalseUP0D`\n"
"\n"
".. method:: __call__(it)\n"
"\n"
" Always returns false.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: False.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp
index c4c157dd689..f5da320a31c 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate0D/BPy_TrueUP0D.cpp
@@ -33,14 +33,14 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char TrueUP0D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate0D` > :class:`TrueUP0D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate0D` > :class:`TrueUP0D`\n"
"\n"
".. method:: __call__(it)\n"
"\n"
" Always returns true.\n"
"\n"
" :arg it: An Interface0DIterator object.\n"
-" :type it: :class:`Interface0DIterator`\n"
+" :type it: :class:`freestyle.types.Interface0DIterator`\n"
" :return: True.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp
index 8365f9b832a..d0ced2ad4c3 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ContourUP1D.cpp
@@ -33,7 +33,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ContourUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`ContourUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`ContourUP1D`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
@@ -41,7 +41,7 @@ static char ContourUP1D___doc__[] =
" contour if it is borded by a different shape on each of its sides.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: True if the Interface1D is a contour, false otherwise.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp
index b0bd67744c5..807d76f4731 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_DensityLowerThanUP1D.cpp
@@ -35,7 +35,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char DensityLowerThanUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`DensityLowerThanUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`DensityLowerThanUP1D`\n"
"\n"
".. method:: __init__(threshold, sigma=2.0)\n"
"\n"
@@ -45,7 +45,7 @@ static char DensityLowerThanUP1D___doc__[] =
" having a density lower than this threshold will match.\n"
" :type threshold: float\n"
" :arg sigma: The sigma value defining the density evaluation window\n"
-" size used in the :class:`DensityF0D` functor.\n"
+" size used in the :class:`freestyle.functions.DensityF0D` functor.\n"
" :type sigma: float\n"
"\n"
".. method:: __call__(inter)\n"
@@ -54,7 +54,7 @@ static char DensityLowerThanUP1D___doc__[] =
" than a user-defined density value.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: True if the density is lower than a threshold.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp
index 5cc5e0cf12a..f8a7ff8650c 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToChainingTimeStampUP1D.cpp
@@ -33,7 +33,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char EqualToChainingTimeStampUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`EqualToChainingTimeStampUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`freestyle.types.EqualToChainingTimeStampUP1D`\n"
"\n"
".. method:: __init__(ts)\n"
"\n"
@@ -48,7 +48,7 @@ static char EqualToChainingTimeStampUP1D___doc__[] =
" user-defined value.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: True if the time stamp is equal to a user-defined value.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp
index a2cafcf5fd2..ffed4f966e6 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_EqualToTimeStampUP1D.cpp
@@ -33,7 +33,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char EqualToTimeStampUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`EqualToTimeStampUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`EqualToTimeStampUP1D`\n"
"\n"
".. method:: __init__(ts)\n"
"\n"
@@ -48,7 +48,7 @@ static char EqualToTimeStampUP1D___doc__[] =
" user-defined value.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: True if the time stamp is equal to a user-defined value.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp
index 486b020ef6a..140ebb86454 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ExternalContourUP1D.cpp
@@ -33,7 +33,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ExternalContourUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`ExternalContourUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`ExternalContourUP1D`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
@@ -42,7 +42,7 @@ static char ExternalContourUP1D___doc__[] =
" one of its sides.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: True if the Interface1D is an external contour, false\n"
" otherwise.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp
index 098f449048e..2d1e99aed2b 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_FalseUP1D.cpp
@@ -33,14 +33,14 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char FalseUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`FalseUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`FalseUP1D`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Always returns false.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: False.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp
index 143aac7d4c5..806ad8168ac 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_QuantitativeInvisibilityUP1D.cpp
@@ -33,7 +33,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char QuantitativeInvisibilityUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`QuantitativeInvisibilityUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`QuantitativeInvisibilityUP1D`\n"
"\n"
".. method:: __init__(qi=0)\n"
"\n"
@@ -46,11 +46,12 @@ static char QuantitativeInvisibilityUP1D___doc__[] =
".. method:: __call__(inter)\n"
"\n"
" Returns true if the Quantitative Invisibility evaluated at an\n"
-" Interface1D, using the :class:`QuantitativeInvisibilityF1D`\n"
-" functor, equals a certain user-defined value.\n"
+" Interface1D, using the\n"
+" :class:`freestyle.functions.QuantitativeInvisibilityF1D` functor,\n"
+" equals a certain user-defined value.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: True if Quantitative Invisibility equals a user-defined\n"
" value.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp
index 998d6b1ed61..93970972aac 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_ShapeUP1D.cpp
@@ -33,7 +33,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char ShapeUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`ShapeUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`ShapeUP1D`\n"
"\n"
".. method:: __init__(first, second=0)\n"
"\n"
@@ -46,11 +46,11 @@ static char ShapeUP1D___doc__[] =
"\n"
".. method:: __call__(inter)\n"
"\n"
-" Returns true if the shape to which the Interface1D belongs to has\n"
-" the same :class:`Id` as the one specified by the user.\n"
+" Returns true if the shape to which the Interface1D belongs to has the\n"
+" same :class:`freestyle.types.Id` as the one specified by the user.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: True if Interface1D belongs to the shape of the\n"
" user-specified Id.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp
index 8444fbfc365..d4ca82721d5 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_TrueUP1D.cpp
@@ -33,14 +33,14 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char TrueUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`TrueUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`TrueUP1D`\n"
"\n"
".. method:: __call__(inter)\n"
"\n"
" Always returns true.\n"
"\n"
" :arg inter: An Interface1D object.\n"
-" :type inter: :class:`Interface1D`\n"
+" :type inter: :class:`freestyle.types.Interface1D`\n"
" :return: True.\n"
" :rtype: bool\n";
diff --git a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp
index 7e310fe593d..6f08cd1c796 100644
--- a/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp
+++ b/source/blender/freestyle/intern/python/UnaryPredicate1D/BPy_WithinImageBoundaryUP1D.cpp
@@ -33,7 +33,7 @@ extern "C" {
//------------------------INSTANCE METHODS ----------------------------------
static char WithinImageBoundaryUP1D___doc__[] =
-"Class hierarchy: :class:`UnaryPredicate1D` > :class:`WithinImageBoundaryUP1D`\n"
+"Class hierarchy: :class:`freestyle.types.UnaryPredicate1D` > :class:`WithinImageBoundaryUP1D`\n"
"\n"
".. method:: __init__(xmin, ymin, xmax, ymax)\n"
"\n"
diff --git a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
index 4d1fc4e69c9..a00f983bbcf 100644
--- a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
+++ b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h
@@ -43,7 +43,10 @@ public:
/*! Default constructor */
inline FrsMaterial();
- /*! Builds a Material from its diffuse, ambiant, specular, emissive colors and a shininess coefficient.
+ /*! Builds a Material from its line, diffuse, ambiant, specular, emissive
+ * colors, a shininess coefficient and line color priority.
+ * \param iLine
+ * A 4 element float-array containing the line color.
* \param iDiffuse
* A 4 element float-array containing the diffuse color.
* \param iAmbiant
@@ -54,9 +57,11 @@ public:
* A 4 element float-array containing the emissive color.
* \param iShininess
* The shininess coefficient.
+ * \param iPriority
+ * The line color priority.
*/
- inline FrsMaterial(const float *iDiffuse, const float *iAmbiant, const float *iSpecular, const float *iEmission,
- const float iShininess);
+ inline FrsMaterial(const float *iLine, const float *iDiffuse, const float *iAmbiant, const float *iSpecular,
+ const float *iEmission, const float iShininess, const int iPriority);
/*! Copy constructor */
inline FrsMaterial(const FrsMaterial& m);
@@ -64,6 +69,35 @@ public:
/*! Destructor */
virtual ~FrsMaterial() {}
+ /*! Returns the line color as a 4 float array */
+ inline const float *line() const
+ {
+ return Line;
+ }
+
+ /*! Returns the red component of the line color */
+ inline const float lineR() const
+ {
+ return Line[0];
+ }
+
+ /*! Returns the green component of the line color */
+ inline const float lineG() const
+ {
+ return Line[1];
+ }
+
+ /*! Returns the blue component of the line color */
+ inline const float lineB() const
+ {
+ return Line[2];
+ }
+
+ /*! Returns the alpha component of the line color */
+ inline const float lineA() const
+ {
+ return Line[3];
+ }
/*! Returns the diffuse color as a 4 float array */
inline const float *diffuse() const
@@ -191,6 +225,24 @@ public:
return Shininess;
}
+ /*! Returns the line color priority */
+ inline const int priority() const
+ {
+ return Priority;
+ }
+
+ /*! Sets the line color.
+ * \param r
+ * Red component
+ * \param g
+ * Green component
+ * \param b
+ * Blue component
+ * \param a
+ * Alpha component
+ */
+ inline void setLine(const float r, const float g, const float b, const float a);
+
/*! Sets the diffuse color.
* \param r
* Red component
@@ -245,6 +297,12 @@ public:
*/
inline void setShininess(const float s);
+ /*! Sets the line color priority.
+ * \param priority
+ * Priority
+ */
+ inline void setPriority(const int priority);
+
/* operators */
inline FrsMaterial& operator=(const FrsMaterial& m);
inline bool operator!=(const FrsMaterial& m) const;
@@ -252,11 +310,13 @@ public:
private:
/*! Material properties */
+ float Line[4];
float Diffuse[4];
float Specular[4];
float Ambient[4];
float Emission[4];
float Shininess;
+ int Priority;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FrsMaterial")
@@ -265,6 +325,9 @@ private:
FrsMaterial::FrsMaterial()
{
+ Line[0] = Line[1] = Line[2] = 0.0f;
+ Line[3] = 1.0f;
+
Ambient[0] = Ambient[1] = Ambient[2] = 0.2f;
Ambient[3] = 1.0f;
@@ -278,12 +341,14 @@ FrsMaterial::FrsMaterial()
Specular[3] = 1.0f;
Shininess = 0.0f;
+ Priority = 0;
}
-FrsMaterial::FrsMaterial(const float *iDiffuse, const float *iAmbiant, const float *iSpecular, const float *iEmission,
- const float iShininess)
+FrsMaterial::FrsMaterial(const float *iLine, const float *iDiffuse, const float *iAmbiant, const float *iSpecular,
+ const float *iEmission, const float iShininess, const int iPriority)
{
for (int i = 0; i < 4; i++) {
+ Line[i] = iLine[i];
Diffuse[i] = iDiffuse[i];
Specular[i] = iSpecular[i];
Ambient[i] = iAmbiant[i];
@@ -291,11 +356,13 @@ FrsMaterial::FrsMaterial(const float *iDiffuse, const float *iAmbiant, const flo
}
Shininess = iShininess;
+ Priority = iPriority;
}
FrsMaterial::FrsMaterial(const FrsMaterial& m)
{
for (int i = 0; i < 4; i++) {
+ Line[i] = m.line()[i];
Diffuse[i] = m.diffuse()[i];
Specular[i] = m.specular()[i];
Ambient[i] = m.ambient()[i];
@@ -303,6 +370,15 @@ FrsMaterial::FrsMaterial(const FrsMaterial& m)
}
Shininess = m.shininess();
+ Priority = m.priority();
+}
+
+void FrsMaterial::setLine(const float r, const float g, const float b, const float a)
+{
+ Line[0] = r;
+ Line[1] = g;
+ Line[2] = b;
+ Line[3] = a;
}
void FrsMaterial::setDiffuse(const float r, const float g, const float b, const float a)
@@ -342,9 +418,15 @@ void FrsMaterial::setShininess(const float s)
Shininess = s;
}
+void FrsMaterial::setPriority(const int priority)
+{
+ Priority = priority;
+}
+
FrsMaterial& FrsMaterial::operator=(const FrsMaterial& m)
{
for (int i = 0; i < 4; i++) {
+ Line[i] = m.line()[i];
Diffuse[i] = m.diffuse()[i];
Specular[i] = m.specular()[i];
Ambient[i] = m.ambient()[i];
@@ -352,6 +434,7 @@ FrsMaterial& FrsMaterial::operator=(const FrsMaterial& m)
}
Shininess = m.shininess();
+ Priority = m.priority();
return *this;
}
@@ -359,8 +442,12 @@ bool FrsMaterial::operator!=(const FrsMaterial& m) const
{
if (Shininess != m.shininess())
return true;
+ if (Priority != m.priority())
+ return true;
for (int i = 0; i < 4; i++) {
+ if (Line[i] != m.line()[i])
+ return true;
if (Diffuse[i] != m.diffuse()[i])
return true;
if (Specular[i] != m.specular()[i])
diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
new file mode 100644
index 00000000000..6e8856f1b93
--- /dev/null
+++ b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
@@ -0,0 +1,39 @@
+/*
+ * ***** 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/freestyle/intern/scene_graph/SceneHash.cpp
+ * \ingroup freestyle
+ */
+
+#include "SceneHash.h"
+
+namespace Freestyle {
+
+void SceneHash::visitIndexedFaceSet(IndexedFaceSet& ifs)
+{
+ const real *v = ifs.vertices();
+ const unsigned n = ifs.vsize();
+
+ for (unsigned i = 0; i < n; i++) {
+ _hashcode += v[i];
+ }
+}
+
+} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.h b/source/blender/freestyle/intern/scene_graph/SceneHash.h
index 9f2371a3756..8f5f847eaab 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.h
+++ b/source/blender/freestyle/intern/scene_graph/SceneHash.h
@@ -18,36 +18,50 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file source/blender/freestyle/intern/python/StrokeShader/BPy_fstreamShader.h
+#ifndef __FREESTYLE_SCENE_HASH_H__
+#define __FREESTYLE_SCENE_HASH_H__
+
+/** \file blender/freestyle/intern/scene_graph/SceneHash.h
* \ingroup freestyle
*/
-#ifndef __FREESTYLE_PYTHON_FSTREAMSHADER_H__
-#define __FREESTYLE_PYTHON_FSTREAMSHADER_H__
-
-#include "../BPy_StrokeShader.h"
+#include "IndexedFaceSet.h"
+#include "SceneVisitor.h"
-#ifdef __cplusplus
-extern "C" {
+#ifdef WITH_CXX_GUARDEDALLOC
+#include "MEM_guardedalloc.h"
#endif
-///////////////////////////////////////////////////////////////////////////////////////////
+namespace Freestyle {
+
+class SceneHash : public SceneVisitor
+{
+public:
+ inline SceneHash() : SceneVisitor()
+ {
+ _hashcode = 0.0;
+ }
-extern PyTypeObject fstreamShader_Type;
+ virtual ~SceneHash() {}
-#define BPy_fstreamShader_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&fstreamShader_Type))
+ VISIT_DECL(IndexedFaceSet)
-/*---------------------------Python BPy_fstreamShader structure definition----------*/
-typedef struct {
- BPy_StrokeShader py_ss;
-} BPy_fstreamShader;
+ inline real getValue() {
+ return _hashcode;
+ }
+ inline void reset() {
+ _hashcode = 0.0;
+ }
-///////////////////////////////////////////////////////////////////////////////////////////
+private:
+ real _hashcode;
-#ifdef __cplusplus
-}
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:SceneHash")
#endif
+};
+} /* namespace Freestyle */
-#endif /* __FREESTYLE_PYTHON_FSTREAMSHADER_H__ */
+#endif // __FREESTYLE_SCENE_HASH_H__
diff --git a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp
index 274e36a4c9b..e37631e5bd6 100644
--- a/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp
+++ b/source/blender/freestyle/intern/stroke/AdvancedStrokeShaders.cpp
@@ -81,20 +81,6 @@ int CalligraphicShader::shade(Stroke &ioStroke) const
return 0;
}
-#if 0
-void TipRemoverShader::shade(Stroke &ioStroke) const
-{
- StrokeInternal::StrokeVertexIterator v, vend;
- for (v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd(); v != vend; ++v) {
- if (((*v)->curvilinearAbscissa() < _tipLength) ||
- (((*v)->strokeLength() - (*v)->curvilinearAbscissa()) < _tipLength)) {
- (*v)->attribute().setThickness(0.0, 0.0);
- (*v)->attribute().setColor(1, 1, 1);
- }
- }
-}
-#endif
-
/////////////////////////////////////////
//
// SPATIAL NOISE SHADER
@@ -347,63 +333,4 @@ void Smoother::copyVertices()
_stroke->UpdateLength();
}
-#if 0 // FIXME
-
-/////////////////////////////////////////
-//
-// OMISSION SHADER
-//
-/////////////////////////////////////////
-
-OmissionShader::OmissionShader(real sizeWindow, real thrVari, real thrFlat, real lFlat)
-{
- _sizeWindow = sizeWindow;
- _thresholdVariation = thrVari;
- _thresholdFlat = thrFlat;
- _lengthFlat = lFlat;
-}
-
-int OmissionShader::shade(Stroke &ioStroke) const
-{
- Omitter omi(ioStroke);
- omi.omit(_sizeWindow, _thresholdVariation, _thresholdFlat, _lengthFlat);
-
- return 0;
-}
-
-
-// OMITTER
-///////////////////////////
-
-Omitter::Omitter(Stroke &ioStroke) : Smoother(ioStroke)
-{
- StrokeInternal::StrokeVertexIterator v, vend;
- int i = 0;
- for (v = ioStroke.strokeVerticesBegin(), vend = ioStroke.strokeVerticesEnd(); v != vend; ++v, ++i) {
- _u[i] = (v)->curvilinearAbscissa();
- }
-}
-
-void Omitter::omit(real sizeWindow, real thrVari, real thrFlat, real lFlat)
-{
- _sizeWindow=sizeWindow;
- _thresholdVariation=thrVari;
- _thresholdFlat=thrFlat;
- _lengthFlat=lFlat;
-
- for (int i = 1; i < _nbVertices-1; ++i) {
- if (_u[i] < _lengthFlat)
- continue;
- // is the previous segment flat?
- int j = i - 1;
- while ((j >= 0) && (_u[i] - _u[j] < _lengthFlat)) {
- if ((_normal[j] * _normal[i]) < _thresholdFlat)
- ; // FIXME
- --j;
- }
- }
-}
-
-#endif
-
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
index e92913d097e..11b7df7ecec 100644
--- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
+++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.cpp
@@ -43,9 +43,6 @@
#include "BKE_global.h"
-//soc #include <qimage.h>
-//soc #include <QString>
-
extern "C" {
# include "IMB_imbuf.h"
# include "IMB_imbuf_types.h"
@@ -53,32 +50,6 @@ extern "C" {
namespace Freestyle {
-// Internal function
-
-#if 0 // soc
-void convert(const QImage& iImage, float **oArray, unsigned &oSize)
-{
- oSize = iImage.width();
- *oArray = new float[oSize];
- for (unsigned int i = 0; i < oSize; ++i) {
- QRgb rgb = iImage.pixel(i,0);
- (*oArray)[i] = ((float)qBlue(rgb)) / 255.0f;
- }
-}
-#endif
-
-static void convert(ImBuf *imBuf, float **oArray, unsigned &oSize)
-{
- oSize = imBuf->x;
- *oArray = new float[oSize];
-
- char *pix;
- for (unsigned int i = 0; i < oSize; ++i) {
- pix = (char *) imBuf->rect + i * 4;
- (*oArray)[i] = ((float) pix[2]) / 255.0f;
- }
-}
-
namespace StrokeShaders {
//
@@ -191,76 +162,6 @@ int LengthDependingThicknessShader::shade(Stroke& stroke) const
return 0;
}
-
-ThicknessVariationPatternShader::ThicknessVariationPatternShader(const string pattern_name, float iMinThickness,
- float iMaxThickness, bool stretch)
-: StrokeShader()
-{
- _stretch = stretch;
- _minThickness = iMinThickness;
- _maxThickness = iMaxThickness;
- ImBuf *image = NULL;
- vector<string> pathnames;
- StringUtils::getPathName(TextureManager::Options::getPatternsPath(), pattern_name, pathnames);
- for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); ++j) {
- ifstream ifs(j->c_str());
- if (ifs.is_open()) {
- /* OCIO_TODO: support different input color space */
- image = IMB_loadiffname(j->c_str(), 0, NULL);
- break;
- }
- }
- if (image == NULL)
- cerr << "Error: cannot find pattern \"" << pattern_name << "\" - check the path in the Options" << endl;
- else
- convert(image, &_aThickness, _size);
- IMB_freeImBuf(image);
-}
-
-
-int ThicknessVariationPatternShader::shade(Stroke& stroke) const
-{
- StrokeInternal::StrokeVertexIterator v, vend;
- float *array = NULL;
- /* int size; */ /* UNUSED */
- array = _aThickness;
- /* size = _size; */ /* UNUSED */
- int vert_size = stroke.strokeVerticesSize();
- int sig = 0;
- unsigned index;
- const float *originalThickness;
- for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
- originalThickness = v->attribute().getThickness();
- if (_stretch) {
- float tmp = v->u() * (_size - 1);
- index = (unsigned)floor(tmp);
- if ((tmp - index) > (index + 1 - tmp))
- ++index;
- }
- else {
- index = (unsigned)floor(v->curvilinearAbscissa());
- }
- index %= _size;
- float thicknessR = array[index] * originalThickness[0];
- float thicknessL = array[index] * originalThickness[1];
- if (thicknessR + thicknessL < _minThickness) {
- thicknessL = _minThickness / 2.0f;
- thicknessR = _minThickness / 2.0f;
- }
- if (thicknessR + thicknessL > _maxThickness) {
- thicknessL = _maxThickness / 2.0f;
- thicknessR = _maxThickness / 2.0f;
- }
- if ((sig == 0) || (sig == vert_size - 1))
- v->attribute().setThickness(1, 1);
- else
- v->attribute().setThickness(thicknessR, thicknessL);
- ++sig;
- }
- return 0;
-}
-
-
static const unsigned NB_VALUE_NOISE = 512;
ThicknessNoiseShader::ThicknessNoiseShader() : StrokeShader()
@@ -328,51 +229,6 @@ int IncreasingColorShader::shade(Stroke& stroke) const
return 0;
}
-ColorVariationPatternShader::ColorVariationPatternShader(const string pattern_name, bool stretch) : StrokeShader()
-{
- _stretch = stretch;
- ImBuf *image = NULL;
- vector<string> pathnames;
- StringUtils::getPathName(TextureManager::Options::getPatternsPath(), pattern_name, pathnames);
- for (vector<string>::const_iterator j = pathnames.begin(); j != pathnames.end(); ++j) {
- ifstream ifs(j->c_str());
- if (ifs.is_open()) {
- /* OCIO_TODO: support different input color space */
- image = IMB_loadiffname(j->c_str(), 0, NULL); //soc
- break;
- }
- }
- if (image == NULL)
- cerr << "Error: cannot find pattern \"" << pattern_name << "\" - check the path in the Options" << endl;
- else
- convert(image, &_aVariation, _size);
- IMB_freeImBuf(image);
-}
-
-int ColorVariationPatternShader::shade(Stroke& stroke) const
-{
- StrokeInternal::StrokeVertexIterator v, vend;
- unsigned index;
- for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd(); v != vend; ++v) {
- const float *originalColor = v->attribute().getColor();
- if (_stretch) {
- float tmp = v->u() * (_size - 1);
- index = (unsigned)floor(tmp);
- if ((tmp - index) > (index + 1 - tmp))
- ++index;
- }
- else {
- index = (unsigned)floor(v->curvilinearAbscissa());
- }
- index %= _size;
- float r = _aVariation[index] * originalColor[0];
- float g = _aVariation[index] * originalColor[1];
- float b = _aVariation[index] * originalColor[2];
- v->attribute().setColor(r, g, b);
- }
- return 0;
-}
-
int MaterialColorShader::shade(Stroke& stroke) const
{
Interface0DIterator v, vend;
@@ -389,29 +245,6 @@ int MaterialColorShader::shade(Stroke& stroke) const
return 0;
}
-
-int CalligraphicColorShader::shade(Stroke& stroke) const
-{
- Interface0DIterator v;
- Functions0D::VertexOrientation2DF0D fun;
- StrokeVertex *sv;
- for (v = stroke.verticesBegin(); !v.isEnd(); ++v) {
- if (fun(v) < 0)
- return -1;
- Vec2f vertexOri(fun.result);
- Vec2d ori2d(-vertexOri[1], vertexOri[0]);
- ori2d.normalizeSafe();
- real scal = ori2d * _orientation;
- sv = dynamic_cast<StrokeVertex*>(&(*v));
- if ((scal < 0))
- sv->attribute().setColor(0, 0, 0);
- else
- sv->attribute().setColor(1, 1, 1);
- }
- return 0;
-}
-
-
ColorNoiseShader::ColorNoiseShader() : StrokeShader()
{
_amplitude = 1.0f;
@@ -439,11 +272,9 @@ int ColorNoiseShader::shade(Stroke& stroke) const
float b = bruit * _amplitude + originalColor[2];
v->attribute().setColor(r, g, b);
}
-
return 0;
}
-
//
// Texture Shaders
//
@@ -451,7 +282,13 @@ int ColorNoiseShader::shade(Stroke& stroke) const
int BlenderTextureShader::shade(Stroke& stroke) const
{
- return stroke.setMTex(_mtex);
+ if (_mtex)
+ return stroke.setMTex(_mtex);
+ if (_nodeTree) {
+ stroke.setNodeTree(_nodeTree);
+ return 0;
+ }
+ return -1;
}
int StrokeTextureStepShader::shade(Stroke& stroke) const
@@ -460,19 +297,6 @@ int StrokeTextureStepShader::shade(Stroke& stroke) const
return 0;
}
-// Legacy shaders from freestyle standalone texture system
-int TextureAssignerShader::shade(Stroke& stroke) const
-{
- cout << "TextureAssignerShader is not supported in blender, please use the BlenderTextureShader" << endl;
- return 0;
-}
-
-int StrokeTextureShader::shade(Stroke& stroke) const
-{
- cout << "StrokeTextureShader is not supported in blender, please use the BlenderTextureShader" << endl;
- return 0;
-}
-
//
// Geometry Shaders
//
@@ -535,119 +359,6 @@ int ExternalContourStretcherShader::shade(Stroke& stroke) const
return 0;
}
-int BSplineShader::shade(Stroke& stroke) const
-{
- if (stroke.strokeVerticesSize() < 4)
- return 0;
-
- // Find the new vertices
- vector<Vec2d> newVertices;
- double t = 0.0;
- float _sampling = 5.0f;
-
- StrokeInternal::StrokeVertexIterator p0, p1, p2, p3, end;
- p0 = stroke.strokeVerticesBegin();
- p1 = p0;
- p2 = p1;
- p3 = p2;
- end = stroke.strokeVerticesEnd();
- double a[4], b[4];
- int n = 0;
- while (p1 != end) {
-#if 0
- if (p1 == end)
- p1 = p0;
-#endif
- if (p2 == end)
- p2 = p1;
- if (p3 == end)
- p3 = p2;
- // compute new matrix
- a[0] = (-(p0)->x() + 3 * (p1)->x() - 3 * (p2)->x() + (p3)->x()) / 6.0;
- a[1] = (3 * (p0)->x() - 6 * (p1)->x() + 3 * (p2)->x()) / 6.0;
- a[2] = (-3 * (p0)->x() + 3 * (p2)->x()) / 6.0;
- a[3] = ((p0)->x() + 4 * (p1)->x() + (p2)->x()) / 6.0;
-
- b[0] = (-(p0)->y() + 3 * (p1)->y() - 3 * (p2)->y() + (p3)->y()) / 6.0;
- b[1] = (3 * (p0)->y() - 6 * (p1)->y() + 3 * (p2)->y()) / 6.0;
- b[2] = (-3 * (p0)->y() + 3 * (p2)->y()) / 6.0;
- b[3] = ((p0)->y() + 4 * (p1)->y() + (p2)->y()) / 6.0;
-
- // draw the spline depending on resolution:
- Vec2d p1p2((p2)->x() - (p1)->x(), (p2)->y() - (p1)->y());
- double norm = p1p2.norm();
- //t = _sampling / norm;
- t = 0;
- while (t < 1) {
- newVertices.push_back(Vec2d((a[3] + t * (a[2] + t * (a[1] + t * a[0]))),
- (b[3] + t * (b[2] + t * (b[1] + t * b[0])))));
- t = t + _sampling / norm;
- }
- if (n > 2) {
- ++p0;
- ++p1;
- ++p2;
- ++p3;
- }
- else {
- if (n == 0)
- ++p3;
- if (n == 1) {
- ++p2;
- ++p3;
- }
- if (n == 2) {
- ++p1;
- ++p2;
- ++p3;
- }
- ++n;
- }
- }
- //last point:
- newVertices.push_back(Vec2d((p0)->x(), (p0)->y()));
-
- int originalSize = newVertices.size();
- _sampling = stroke.ComputeSampling(originalSize);
-
- // Resample and set x,y coordinates
- stroke.Resample(_sampling);
- int newsize = stroke.strokeVerticesSize();
-
- int nExtraVertex = 0;
- if (newsize < originalSize) {
- cerr << "Warning: unsufficient resampling" << endl;
- }
- else {
- nExtraVertex = newsize - originalSize;
- }
-
- // assigns the new coordinates:
- vector<Vec2d>::iterator p = newVertices.begin(), pend = newVertices.end();
- vector<Vec2d>::iterator last = p;
- n = 0;
- StrokeInternal::StrokeVertexIterator it, itend;
- for (it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd();
- (it != itend) && (p != pend);
- ++it, ++p, ++n)
- {
- it->setX(p->x());
- it->setY(p->y());
- last = p;
- }
-
- // nExtraVertex should stay unassigned
- for (int i = 0; i < nExtraVertex; ++i, ++it, ++n) {
- it->setX(last->x());
- it->setY(last->y());
- if (it.isEnd()) {
- // XXX Shouldn't we break in this case???
- cerr << "Warning: Problem encountered while creating B-spline" << endl;
- }
- }
- stroke.UpdateLength();
- return 0;
-}
//!! Bezier curve stroke shader
int BezierCurveShader::shade(Stroke& stroke) const
@@ -667,15 +378,6 @@ int BezierCurveShader::shade(Stroke& stroke) const
previous = v;
}
-#if 0
- Vec2d tmp;
- bool equal = false;
- if (data.front() == data.back()) {
- tmp = data.back();
- data.pop_back();
- equal = true;
- }
-#endif
// here we build the bezier curve
BezierCurve bcurve(data, _error);
@@ -696,25 +398,6 @@ int BezierCurveShader::shade(Stroke& stroke) const
}
}
-#if 0
- if (equal) {
- if (data.back() == data.front()) {
- vector<Vec2d>::iterator d = data.begin(), dend;
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "ending point = starting point" << endl;
- cout << "---------------DATA----------" << endl;
- for (dend = data.end(); d != dend; ++d) {
- cout << d->x() << "-" << d->y() << endl;
- }
- cout << "--------------BEZIER RESULT----------" << endl;
- for (d = CurveVertices.begin(), dend = CurveVertices.end(); d != dend; ++d) {
- cout << d->x() << "-" << d->y() << endl;
- }
- }
- }
- }
-#endif
-
// Resample the Stroke depending on the number of vertices of the bezier curve:
int originalSize = CurveVertices.size();
#if 0
@@ -728,11 +411,6 @@ int BezierCurveShader::shade(Stroke& stroke) const
cerr << "Warning: unsufficient resampling" << endl;
}
else {
-#if 0
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "Oversampling" << endl;
- }
-#endif
nExtraVertex = newsize - originalSize;
if (nExtraVertex != 0) {
if (G.debug & G_DEBUG_FREESTYLE) {
@@ -746,22 +424,12 @@ int BezierCurveShader::shade(Stroke& stroke) const
vector<Vec2d>::iterator last = p;
int n;
StrokeInternal::StrokeVertexIterator it, itend;
-#if 0
- for (; p != pend; ++n, ++p);
-#endif
for (n = 0, it = stroke.strokeVerticesBegin(), itend = stroke.strokeVerticesEnd(), pend = CurveVertices.end();
(it != itend) && (p != pend);
++it, ++p, ++n)
{
it->setX(p->x());
it->setY(p->y());
-#if 0
- double x = p->x();
- double y = p->y();
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "x = " << x << "-" << "y = " << y << endl;
- }
-#endif
last = p;
}
stroke.UpdateLength();
@@ -802,54 +470,15 @@ int BezierCurveShader::shade(Stroke& stroke) const
++it)
{
(it)->setAttribute(*a);
- if ((index <= index1) || (index > index2))
+ if ((index <= index1) || (index > index2)) {
++a;
- ++index;
- }
- return 0;
-}
-
-int InflateShader::shade(Stroke& stroke) const
-{
- // we're computing the curvature variance of the stroke. (Combo 5)
- // If it's too high, forget about it
- Functions1D::Curvature2DAngleF1D fun;
- if (fun(stroke) < 0)
- return -1;
- if (fun.result > _curvatureThreshold)
- return 0;
-
- Functions0D::VertexOrientation2DF0D ori_fun;
- Functions0D::Curvature2DAngleF0D curv_fun;
- Functions1D::Normal2DF1D norm_fun;
- Interface0DIterator it;
- StrokeVertex *sv;
- for (it = stroke.verticesBegin(); !it.isEnd(); ++it) {
- if (ori_fun(it) < 0)
- return -1;
- Vec2f ntmp(ori_fun.result);
- Vec2f n(ntmp.y(), -ntmp.x());
- if (norm_fun(stroke) < 0)
- return -1;
- Vec2f strokeN(norm_fun.result);
- if (n * strokeN < 0) {
- n[0] = -n[0];
- n[1] = -n[1];
}
- sv = dynamic_cast<StrokeVertex*>(&(*it));
- float u = sv->u();
- float t = 4.0f * (0.25f - (u - 0.5) * (u - 0.5));
- if (curv_fun(it) < 0)
- return -1;
- float curvature_coeff = (M_PI - curv_fun.result) / M_PI;
- Vec2d newPoint(sv->x() + curvature_coeff * t * _amount * n.x(),
- sv->y() + curvature_coeff * t * _amount * n.y());
- sv->setPoint(newPoint[0], newPoint[1]);
+ ++index;
}
- stroke.UpdateLength();
return 0;
}
+
class CurvePiece
{
public:
@@ -1033,40 +662,16 @@ int TipRemoverShader::shade(Stroke& stroke) const
// assign old attributes to new stroke vertices:
vector<StrokeAttribute>::iterator a = oldAttributes.begin(), aend = oldAttributes.end();
-#if 0
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "-----------------------------------------------" << endl;
- }
-#endif
for (v = stroke.strokeVerticesBegin(), vend = stroke.strokeVerticesEnd();
(v != vend) && (a != aend);
++v, ++a)
{
v->setAttribute(*a);
-#if 0
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "thickness = " << (*a).getThickness()[0] << "-" << (*a).getThickness()[1] << endl;
- }
-#endif
}
// we're done!
return 0;
}
-int streamShader::shade(Stroke& stroke) const
-{
- if (G.debug & G_DEBUG_FREESTYLE) {
- cout << stroke << endl;
- }
- return 0;
-}
-
-int fstreamShader::shade(Stroke& stroke) const
-{
- _stream << stroke << endl;
- return 0;
-}
-
} // end of namespace StrokeShaders
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
index 9186d164e9b..e3842f45eb0 100644
--- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
+++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h
@@ -36,7 +36,10 @@
#include "../geometry/Bezier.h"
#include "../geometry/Geom.h"
+extern "C" {
struct MTex;
+struct bNodeTree;
+}
using namespace std;
@@ -215,51 +218,6 @@ public:
virtual int shade(Stroke& stroke) const;
};
-/*! [ Thickness Shader ].
-* Applys a pattern (texture) to vary thickness.
-* The new thicknesses are the result of the multiplication
-* of the pattern and the original thickness
-*/
-class ThicknessVariationPatternShader : public StrokeShader
-{
-public:
- /*! Builds the shader.
- * \param pattern_name
- * The texture file name.
- * \param iMinThickness
- * The minimum thickness we don't want to exceed.
- * \param iMaxThickness
- * The maximum thickness we don't want to exceed.
- * \param stretch
- * Tells whether the pattern texture must be stretched or repeted to fit the stroke.
- */
- ThicknessVariationPatternShader(const string pattern_name, float iMinThickness = 1.0f, float iMaxThickness = 5.0f,
- bool stretch = true);
-
- /*! Destructor.*/
- virtual ~ThicknessVariationPatternShader()
- {
- if (0 != _aThickness) {
- delete[] _aThickness;
- _aThickness = 0;
- }
- }
-
- virtual string getName() const
- {
- return "ThicknessVariationPatternShader";
- }
-
- /*! The shading method. */
- virtual int shade(Stroke& stroke) const;
-
-private:
- float *_aThickness; // array of thickness values, in % of the max (i.e comprised between 0 and 1)
- unsigned _size;
- float _minThickness;
- float _maxThickness;
- bool _stretch;
-};
/*! [ Thickness Shader ].
* Adds some noise to the stroke thickness.
@@ -386,44 +344,6 @@ public:
virtual int shade(Stroke& stroke) const;
};
-/*! [ Color Shader ].
- * Applys a pattern to vary original color.
- * The new color is the result of the multiplication of the pattern and the original color
- */
-class ColorVariationPatternShader : public StrokeShader
-{
-public:
- /*! Builds the shader from the pattern texture file name.
- * \param pattern_name
- * The file name of the texture file to use as pattern
- * \param stretch
- * Tells whether the texture must be strecthed or repeted to fit the stroke.
- */
- ColorVariationPatternShader(const string pattern_name, bool stretch = true);
-
- /*! Destructor */
- virtual ~ColorVariationPatternShader()
- {
- if (0 != _aVariation) {
- delete[] _aVariation;
- _aVariation = 0;
- }
- }
-
- virtual string getName() const
- {
- return "ColorVariationPatternShader";
- }
-
- /*! The shading method. */
- virtual int shade(Stroke& stroke) const;
-
-private:
- float *_aVariation; // array of coef values, in % of the max (i.e comprised between 0 and 1)
- unsigned _size;
- bool _stretch;
-};
-
/* [ Color Shader ].
* Assigns a color to the stroke depending on the material of the shape to which ot belongs to. (Disney shader)
*/
@@ -446,28 +366,6 @@ public:
virtual int shade(Stroke& stroke) const;
};
-class CalligraphicColorShader : public StrokeShader
-{
-private:
- /* UNUSED */
- // int _textureId;
- Vec2d _orientation;
-
-public:
- CalligraphicColorShader(const Vec2d &iOrientation) : StrokeShader()
- {
- _orientation = iOrientation;
- _orientation.normalize();
- }
-
- virtual string getName() const
- {
- return "CalligraphicColorShader";
- }
-
- virtual int shade(Stroke& stroke) const;
-};
-
/*! [ Color Shader ].
* Shader to add noise to the stroke colors.
*/
@@ -498,105 +396,6 @@ public:
};
//
-// Texture Shaders
-//
-///////////////////////////////////////////////////////////////////////////////
-/*! [ Texture Shader ].
-* Assigns a texture to the stroke in order to simulate
-* its marks system. This shader takes as input an integer value
-* telling which texture and blending mode to use among a set of
-* predefined textures.
-* Here are the different presets:
-* 0) -> /brushes/charcoalAlpha.bmp, HUMID_MEDIUM
-* 1) -> /brushes/washbrushAlpha.bmp, HUMID_MEDIUM
-* 2) -> /brushes/oil.bmp, HUMID_MEDIUM
-* 3) -> /brushes/oilnoblend.bmp, HUMID_MEDIUM
-* 4) -> /brushes/charcoalAlpha.bmp, DRY_MEDIUM
-* 5) -> /brushes/washbrushAlpha.bmp, DRY_MEDIUM
-* 6) -> /brushes/opaqueDryBrushAlpha.bmp, OPAQUE_MEDIUM
-* 7) -> /brushes/opaqueBrushAlpha.bmp, Stroke::OPAQUE_MEDIUM
-* Any other value will lead to the following preset:
-* default) -> /brushes/smoothAlpha.bmp, OPAQUE_MEDIUM.
-*/
-class TextureAssignerShader : public StrokeShader // FIXME
-{
-private:
- int _textureId;
-
-public:
- /*! Builds the shader.
- * \param id
- * The number of the preset to use.
- */
- TextureAssignerShader(int id) : StrokeShader()
- {
- _textureId = id;
- }
-
- virtual string getName() const
- {
- return "TextureAssignerShader";
- }
-
- /*! The shading method */
- virtual int shade(Stroke& stroke) const;
-};
-
-/*! [ Texture Shader ].
-* Assigns a texture and a blending mode to the stroke
-* in order to simulate its marks system.
-*/
-class StrokeTextureShader : public StrokeShader
-{
-private:
- string _texturePath;
- Stroke::MediumType _mediumType;
- bool _tips; // 0 or 1
-
-public:
- /*! Builds the shader from the texture file name and the blending mode to use.
- * \param textureFile
- * The the texture file name.
- * \attention The textures must be placed in the $FREESTYLE_DIR/data/textures/brushes directory.
- * \param mediumType
- * The medium type and therefore, the blending mode that must be used for the rendering of this stroke.
- * \param iTips
- * Tells whether the texture includes tips or not.
- * If it is the case, the texture image must respect the following format:
- * \verbatim
- * __________
- * | |
- * | A |
- * |__________|
- * | | |
- * | B | C |
- * |_____|____|
- *
- * \endverbatim
- * - A : The stroke's corpus texture
- * - B : The stroke's left extremity texture
- * - C : The stroke's right extremity texture
- */
- StrokeTextureShader(const string textureFile, Stroke::MediumType mediumType = Stroke::OPAQUE_MEDIUM,
- bool iTips = false)
- : StrokeShader()
- {
- _texturePath = textureFile;
- _mediumType = mediumType;
- _tips = iTips;
- }
-
- virtual string getName() const
- {
- return "StrokeTextureShader";
- }
-
- /*! The shading method */
- virtual int shade(Stroke& stroke) const;
-};
-
-
-//
// Geometry Shaders
//
///////////////////////////////////////////////////////////////////////////////
@@ -675,20 +474,6 @@ public:
virtual int shade(Stroke& stroke) const;
};
-// B-Spline stroke shader
-class BSplineShader: public StrokeShader
-{
-public:
- BSplineShader() : StrokeShader() {}
-
- virtual string getName() const
- {
- return "BSplineShader";
- }
-
- virtual int shade(Stroke& stroke) const;
-};
-
// Bezier curve stroke shader
/*! [ Geometry Shader ].
@@ -721,37 +506,6 @@ public:
virtual int shade(Stroke& stroke) const;
};
-/* Shader to inflate the curves. It keeps the extreme points positions and moves the other ones along the 2D normal.
- * The displacement value is proportional to the 2d curvature at the considered point (the higher the curvature,
- * the smaller the displacement) and to a value specified by the user.
- */
-class InflateShader : public StrokeShader
-{
-private:
- float _amount;
- float _curvatureThreshold;
-
-public:
- /*! Builds an inflate shader
- * \param iAmount
- * A multiplicative coefficient that acts on the amount and direction of displacement
- * \param iThreshold
- * The curves having a 2d curvature > iThreshold at one of their points is not inflated
- */
- InflateShader(float iAmount, float iThreshold) : StrokeShader()
- {
- _amount = iAmount;
- _curvatureThreshold = iThreshold;
- }
-
- virtual string getName() const
- {
- return "InflateShader";
- }
-
- /*! The shading method */
- virtual int shade(Stroke& stroke) const;
-};
/*! [ Geometry Shader ].
* Shader to modify the Stroke geometry so that it looks more "polygonal".
@@ -843,59 +597,6 @@ protected:
real _tipLength;
};
-/*! [ output Shader ].
- * streams the Stroke
- */
-class streamShader : public StrokeShader
-{
-public:
- /*! Destructor. */
- virtual ~streamShader() {}
-
- /*! Returns the string "streamShader".*/
- virtual string getName() const
- {
- return "streamShader";
- }
-
- /*! The shading method. */
- virtual int shade(Stroke& stroke) const;
-};
-
-/*! [ output Shader ].
- * streams the Stroke in a file
- */
-class fstreamShader : public StrokeShader
-{
-protected:
- mutable ofstream _stream;
-
-public:
- /*! Builds the shader from the output file name */
- fstreamShader(const char *iFileName) : StrokeShader()
- {
- _stream.open(iFileName);
- if (!_stream.is_open()) {
- cerr << "couldn't open file " << iFileName << endl;
- }
- }
-
- /*! Destructor. */
- virtual ~fstreamShader()
- {
- _stream.close();
- }
-
- /*! Returns the string "fstreamShader".*/
- virtual string getName() const
- {
- return "fstreamShader";
- }
-
- /*! The shading method. */
- virtual int shade(Stroke& stroke) const;
-};
-
/*! [ Texture Shader ].
* Shader to assign texture to the Stroke material.
*/
@@ -904,6 +605,7 @@ class BlenderTextureShader : public StrokeShader
{
private:
MTex *_mtex;
+ bNodeTree *_nodeTree;
public:
/*! Builds the shader.
@@ -913,6 +615,17 @@ public:
BlenderTextureShader(MTex *mtex) : StrokeShader()
{
_mtex = mtex;
+ _nodeTree = NULL;
+ }
+
+ /*! Builds the shader.
+ * \param nodetree
+ * A node tree (of new shading nodes) to define textures.
+ */
+ BlenderTextureShader(bNodeTree *nodetree) : StrokeShader()
+ {
+ _nodeTree = nodetree;
+ _mtex = NULL;
}
virtual string getName() const
diff --git a/source/blender/freestyle/intern/stroke/Chain.cpp b/source/blender/freestyle/intern/stroke/Chain.cpp
index 7fd756472b0..0e8c2c9ae6f 100644
--- a/source/blender/freestyle/intern/stroke/Chain.cpp
+++ b/source/blender/freestyle/intern/stroke/Chain.cpp
@@ -59,6 +59,7 @@ void Chain::push_viewedge_back(ViewEdge *iViewEdge, bool orientation)
CurvePoint *cp = _Vertices.back(); // assumed to be instantiated as new CurvePoint(iSVertex, 0, 0.f);
SVertex *sv_first = (*vfirst);
FEdge *fe = _fedgeB->duplicate();
+ fe->setTemporary(true);
fe->setVertexB(sv_first);
fe->vertexA()->shape()->AddEdge(fe);
fe->vertexA()->AddFEdge(fe);
@@ -119,6 +120,7 @@ void Chain::push_viewedge_front(ViewEdge *iViewEdge, bool orientation)
SVertex *sv_curr = (*v);
FEdge *fe = (orientation) ? iViewEdge->fedgeA() : iViewEdge->fedgeB();
FEdge *fe2 = fe->duplicate();
+ fe2->setTemporary(true);
fe2->setVertexA(sv_curr);
fe2->setVertexB(sv_last);
sv_last->AddFEdge(fe2);
diff --git a/source/blender/freestyle/intern/stroke/Chain.h b/source/blender/freestyle/intern/stroke/Chain.h
index 95e825e270b..6cf3a7199bf 100644
--- a/source/blender/freestyle/intern/stroke/Chain.h
+++ b/source/blender/freestyle/intern/stroke/Chain.h
@@ -106,6 +106,10 @@ public:
{
return _splittingId;
}
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Chain")
+#endif
};
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/stroke/Curve.h b/source/blender/freestyle/intern/stroke/Curve.h
index 17b9a5c0a1f..726b238c74b 100644
--- a/source/blender/freestyle/intern/stroke/Curve.h
+++ b/source/blender/freestyle/intern/stroke/Curve.h
@@ -95,7 +95,7 @@ public: // Implementation of Interface0D
}
/*! Returns the 3D point. */
- virtual Vec3f getPoint3D() const
+ virtual Vec3r getPoint3D() const
{
return _Point3d;
}
@@ -119,9 +119,9 @@ public: // Implementation of Interface0D
}
/*! Returns the 2D point. */
- virtual Vec2f getPoint2D() const
+ virtual Vec2r getPoint2D() const
{
- return Vec2f((float)_Point2d.x(), (float)_Point2d.y());
+ return Vec2r(_Point2d.x(), _Point2d.y());
}
virtual FEdge *getFEdge(Interface0D& inter);
@@ -341,6 +341,10 @@ public:
real curvatureFredo() const;
Vec2d directionFredo() const;
#endif
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:CurvePoint")
+#endif
};
@@ -586,6 +590,10 @@ public:
* At each iteration a virtual temporary CurvePoint is created.
*/
virtual Interface0DIterator pointsEnd(float t = 0.0f);
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Curve")
+#endif
};
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp
index 2e68aa0c1fa..87ba34e8f42 100644
--- a/source/blender/freestyle/intern/stroke/Operators.cpp
+++ b/source/blender/freestyle/intern/stroke/Operators.cpp
@@ -32,6 +32,7 @@
#include "Operators.h"
#include "Canvas.h"
#include "Stroke.h"
+#include "StrokeIterators.h"
#include "CurveIterators.h"
#include "BKE_global.h"
@@ -1092,20 +1093,20 @@ static Stroke *createStroke(Interface1D& inter)
if (hasSingularity) {
// Try to address singular points such that the distance between two subsequent vertices
// are smaller than epsilon.
- Interface0DIterator v = stroke->verticesBegin();
- Interface0DIterator vnext = v;
+ StrokeInternal::StrokeVertexIterator v = stroke->strokeVerticesBegin();
+ StrokeInternal::StrokeVertexIterator vnext = v;
++vnext;
- Vec2r next((*v).getPoint2D());
+ Vec2r next((*v).getPoint());
while (!vnext.isEnd()) {
current = next;
- next = (*vnext).getPoint2D();
+ next = (*vnext).getPoint();
if ((next - current).norm() < 1.0e-6) {
- Interface0DIterator vprevious = v;
+ StrokeInternal::StrokeVertexIterator vprevious = v;
if (!vprevious.isBegin())
--vprevious;
// collect a set of overlapping vertices
- std::vector<Interface0D *> overlapping_vertices;
+ std::vector<StrokeVertex *> overlapping_vertices;
overlapping_vertices.push_back(&(*v));
do {
overlapping_vertices.push_back(&(*vnext));
@@ -1114,17 +1115,17 @@ static Stroke *createStroke(Interface1D& inter)
++vnext;
if (vnext.isEnd())
break;
- next = (*vnext).getPoint2D();
+ next = (*vnext).getPoint();
} while ((next - current).norm() < 1.0e-6);
Vec2r target;
bool reverse;
if (!vnext.isEnd()) {
- target = (*vnext).getPoint2D();
+ target = (*vnext).getPoint();
reverse = false;
}
else if (!vprevious.isBegin()) {
- target = (*vprevious).getPoint2D();
+ target = (*vprevious).getPoint();
reverse = true;
}
else {
@@ -1132,7 +1133,7 @@ static Stroke *createStroke(Interface1D& inter)
delete stroke;
return NULL;
}
- current = overlapping_vertices.front()->getPoint2D();
+ current = overlapping_vertices.front()->getPoint();
Vec2r dir(target - current);
real dist = dir.norm();
real len = 1.0e-3; // default offset length
@@ -1144,19 +1145,18 @@ static Stroke *createStroke(Interface1D& inter)
Vec2r offset(dir * len);
// add the offset to the overlapping vertices
StrokeVertex *sv;
- std::vector<Interface0D *>::iterator it = overlapping_vertices.begin();
+ std::vector<StrokeVertex *>::iterator it = overlapping_vertices.begin();
if (!reverse) {
- for (int n = 1; n < nvert; n++) {
- sv = dynamic_cast<StrokeVertex*>(*it);
- sv->setPoint(sv->getPoint() + offset * n);
+ for (int n = 0; n < nvert; n++) {
+ sv = (*it);
+ sv->setPoint(sv->getPoint() + offset * (n + 1));
++it;
}
}
else {
- int last = nvert - 1;
- for (int n = 0; n < last; n++) {
- sv = dynamic_cast<StrokeVertex*>(*it);
- sv->setPoint(sv->getPoint() + offset * (last - n));
+ for (int n = 0; n < nvert; n++) {
+ sv = (*it);
+ sv->setPoint(sv->getPoint() + offset * (nvert - n));
++it;
}
}
@@ -1242,7 +1242,7 @@ error:
return -1;
}
-void Operators::reset()
+void Operators::reset(bool removeStrokes)
{
ViewMap *vm = ViewMap::getInstance();
if (!vm) {
@@ -1253,11 +1253,7 @@ void Operators::reset()
for (I1DContainer::iterator it = _current_chains_set.begin(); it != _current_chains_set.end(); ++it)
delete *it;
_current_chains_set.clear();
-#if 0
- _current_view_edges_set.insert(_current_view_edges_set.begin(),
- vm->ViewEdges().begin(),
- vm->ViewEdges().end());
-#else
+
ViewMap::viewedges_container& vedges = vm->ViewEdges();
ViewMap::viewedges_container::iterator ve = vedges.begin(), veend = vedges.end();
for (; ve != veend; ++ve) {
@@ -1265,9 +1261,9 @@ void Operators::reset()
continue;
_current_view_edges_set.push_back(*ve);
}
-#endif
_current_set = &_current_view_edges_set;
- _current_strokes_set.clear();
+ if (removeStrokes)
+ _current_strokes_set.clear();
}
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/stroke/Operators.h b/source/blender/freestyle/intern/stroke/Operators.h
index 59ebec57246..c7b0e3f8b81 100644
--- a/source/blender/freestyle/intern/stroke/Operators.h
+++ b/source/blender/freestyle/intern/stroke/Operators.h
@@ -259,7 +259,7 @@ public:
return &_current_strokes_set;
}
- static void reset();
+ static void reset(bool removeStrokes=true);
private:
Operators() {}
diff --git a/source/blender/freestyle/intern/stroke/Stroke.cpp b/source/blender/freestyle/intern/stroke/Stroke.cpp
index 6629de0fa04..863da069259 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.cpp
+++ b/source/blender/freestyle/intern/stroke/Stroke.cpp
@@ -31,6 +31,7 @@
#include "StrokeRenderer.h"
#include "BKE_global.h"
+#include "BKE_node.h"
namespace Freestyle {
@@ -397,8 +398,8 @@ Stroke::Stroke()
for (int a = 0; a < MAX_MTEX; a++) {
_mtex[a] = NULL;
}
+ _nodeTree = NULL;
_tips = false;
- _rep = NULL;
}
Stroke::Stroke(const Stroke& iBrother)
@@ -424,11 +425,8 @@ Stroke::Stroke(const Stroke& iBrother)
_mtex[a] = NULL;
}
}
+ _nodeTree = iBrother._nodeTree;
_tips = iBrother._tips;
- if (iBrother._rep)
- _rep = new StrokeRep(*(iBrother._rep));
- else
- _rep = NULL;
}
Stroke::~Stroke()
@@ -441,10 +439,6 @@ Stroke::~Stroke()
}
_ViewEdges.clear();
- if (_rep) {
- delete _rep;
- _rep = NULL;
- }
}
Stroke& Stroke::operator=(const Stroke& iBrother)
@@ -462,10 +456,6 @@ Stroke& Stroke::operator=(const Stroke& iBrother)
_id = iBrother._id;
_ViewEdges = iBrother._ViewEdges;
_sampling = iBrother._sampling;
- if (_rep)
- delete _rep;
- if (iBrother._rep)
- _rep = new StrokeRep(*(iBrother._rep));
return *this;
}
@@ -508,11 +498,11 @@ public:
}
};
-void Stroke::Resample(int iNPoints)
+int Stroke::Resample(int iNPoints)
{
- int vertsize = strokeVerticesSize();
- if (iNPoints <= vertsize)
- return;
+ int NPointsToAdd = iNPoints - strokeVerticesSize();
+ if (NPointsToAdd <= 0)
+ return 0;
StrokeInternal::StrokeVertexIterator it = strokeVerticesBegin();
StrokeInternal::StrokeVertexIterator next = it;
@@ -531,7 +521,7 @@ void Stroke::Resample(int iNPoints)
Vec2r b((next)->getPoint());
Vec2r vec_tmp(b - a);
real norm_var = vec_tmp.norm();
- int numberOfPointsToAdd = (int)floor((iNPoints - strokeVerticesSize()) * norm_var / _Length);
+ int numberOfPointsToAdd = (int)floor(NPointsToAdd * norm_var / _Length);
float csampling = norm_var / (float)(numberOfPointsToAdd + 1);
strokeSegments.push_back(StrokeSegment(it, next, norm_var, numberOfPointsToAdd, csampling));
N += numberOfPointsToAdd;
@@ -543,9 +533,10 @@ void Stroke::Resample(int iNPoints)
meanlength /= (float)nsegments;
// if we don't have enough points let's resample finer some segments
- int NPointsToAdd = iNPoints - vertsize;
bool checkEveryone = false;
+ bool resampled;
while (N < NPointsToAdd) {
+ resampled = false;
for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
if (s->_sampling == 0.0f)
continue;
@@ -556,14 +547,20 @@ void Stroke::Resample(int iNPoints)
//resample
s->_n = s->_n + 1;
s->_sampling = s->_length / (float)(s->_n + 1);
- s->_resampled = true;
+ s->_resampled = resampled = true;
N++;
if (N == NPointsToAdd)
break;
}
}
+ if (checkEveryone && !resampled)
+ break;
checkEveryone = true;
}
+ if (N < NPointsToAdd) {
+ // fatal error, likely because _Length is inconsistent with the stroke length computed with the vertices
+ return -1;
+ }
//actually resample:
for (vector<StrokeSegment>::iterator s = strokeSegments.begin(), send = strokeSegments.end(); s != send; ++s) {
newVertices.push_back(&(*(s->_begin)));
@@ -594,19 +591,16 @@ void Stroke::Resample(int iNPoints)
_Vertices = newVertices;
newVertices.clear();
- if (_rep) {
- delete _rep;
- _rep = new StrokeRep(this);
- }
+ return 0;
}
-void Stroke::Resample(float iSampling)
+int Stroke::Resample(float iSampling)
{
//cerr << "old size :" << strokeVerticesSize() << endl;
if (iSampling == 0)
- return;
+ return 0;
if (iSampling >= _sampling)
- return;
+ return 0;
_sampling = iSampling;
// Resample...
@@ -651,10 +645,7 @@ void Stroke::Resample(float iSampling)
_Vertices = newVertices;
newVertices.clear();
- if (_rep) {
- delete _rep;
- _rep = new StrokeRep(this);
- }
+ return 0;
}
void Stroke::RemoveAllVertices()
@@ -766,16 +757,14 @@ void Stroke::ScaleThickness(float iFactor)
void Stroke::Render(const StrokeRenderer *iRenderer)
{
- if (!_rep)
- _rep = new StrokeRep(this);
- iRenderer->RenderStrokeRep(_rep);
+ StrokeRep rep(this);
+ iRenderer->RenderStrokeRep(&rep);
}
void Stroke::RenderBasic(const StrokeRenderer *iRenderer)
{
- if (!_rep)
- _rep = new StrokeRep(this);
- iRenderer->RenderStrokeRepBasic(_rep);
+ StrokeRep rep(this);
+ iRenderer->RenderStrokeRepBasic(&rep);
}
Stroke::vertex_iterator Stroke::vertices_begin(float sampling)
diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h
index f6451d8e487..8ff801ed144 100644
--- a/source/blender/freestyle/intern/stroke/Stroke.h
+++ b/source/blender/freestyle/intern/stroke/Stroke.h
@@ -45,6 +45,8 @@
extern "C" {
#include "DNA_material_types.h"
+
+struct bNodeTree;
}
#ifndef MAX_MTEX
@@ -375,14 +377,14 @@ public:
return _Point2d[1];
}
- /*! Returns the 2D point coordinates as a Vec2d */
- Vec2f getPoint ()
+ /*! Returns the 2D point coordinates as a Vec2r */
+ inline Vec2r getPoint() const
{
- return Vec2f((float)point2d()[0], (float)point2d()[1]);
+ return getPoint2D();
}
/*! Returns the ith 2D point coordinate (i=0 or 1)*/
- inline real operator[](const int i) const
+ inline real operator[](const int i) const
{
return _Point2d[i];
}
@@ -438,7 +440,7 @@ public:
}
/*! sets the 2D x and y values */
- inline void setPoint(const Vec2f& p)
+ inline void setPoint(const Vec2r& p)
{
_Point2d[0] = p[0];
_Point2d[1] = p[1];
@@ -472,6 +474,10 @@ public:
/* interface definition */
/* inherited */
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:StrokeVertex")
+#endif
};
@@ -541,9 +547,9 @@ private:
MediumType _mediumType;
unsigned int _textureId;
MTex *_mtex[MAX_MTEX];
+ bNodeTree *_nodeTree;
bool _tips;
Vec2r _extremityOrientations[2]; // the orientations of the first and last extermity
- StrokeRep *_rep;
public:
/*! default constructor */
@@ -588,7 +594,7 @@ public:
* \param iNPoints
* The number of vertices we eventually want in our stroke.
*/
- void Resample(int iNPoints);
+ int Resample(int iNPoints);
/*! Resampling method.
* Resamples the curve with a given sampling.
@@ -596,7 +602,7 @@ public:
* \param iSampling
* The new sampling value.
*/
- void Resample(float iSampling);
+ int Resample(float iSampling);
/*! Removes all vertices from the Stroke.
*/
@@ -653,10 +659,16 @@ public:
return _mtex[idx];
}
+ /*! Return the shader node tree to define textures. */
+ inline bNodeTree *getNodeTree()
+ {
+ return _nodeTree;
+ }
+
/*! Returns true if this Stroke has textures assigned, false otherwise. */
inline bool hasTex() const
{
- return _mtex[0] != NULL;
+ return (_mtex[0] != NULL) || _nodeTree;
}
/*! Returns true if this Stroke uses a texture with tips, false otherwise. */
@@ -767,6 +779,12 @@ public:
return -1; /* no free slots */
}
+ /*! assigns a node tree (of new shading nodes) to define textures. */
+ inline void setNodeTree(bNodeTree *iNodeTree)
+ {
+ _nodeTree = iNodeTree;
+ }
+
/*! sets the flag telling whether this stroke is using a texture with tips or not. */
inline void setTips(bool iTips)
{
@@ -848,6 +866,10 @@ public:
virtual Interface0DIterator pointsBegin(float t = 0.0f);
virtual Interface0DIterator pointsEnd(float t = 0.0f);
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:Stroke")
+#endif
};
diff --git a/source/blender/freestyle/intern/stroke/StrokeIterators.h b/source/blender/freestyle/intern/stroke/StrokeIterators.h
index a8ec529fbfa..1df9aa2794a 100644
--- a/source/blender/freestyle/intern/stroke/StrokeIterators.h
+++ b/source/blender/freestyle/intern/stroke/StrokeIterators.h
@@ -171,6 +171,18 @@ public:
return _it == _begin;
}
+ /*! Returns true if the pointed StrokeVertex is the final valid StrokeVertex of the Stroke. */
+ bool atLast()
+ {
+ if (_it == _end)
+ return false;
+
+ ++_it;
+ bool result = (_it == _end);
+ --_it;
+ return result;
+ }
+
/*! Returns true if the pointed StrokeVertex is after the last StrokeVertex of the Stroke. */
bool isEnd() const
{
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.cpp b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
index 8e84228f37f..f7857107006 100644
--- a/source/blender/freestyle/intern/stroke/StrokeRep.cpp
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
@@ -523,7 +523,7 @@ void Strip::computeTexCoord (const vector<StrokeVertex *>& iStrokeVertices, floa
sv = (*v);
_vertices[i]->setTexCoord(Vec2r((real)(sv->curvilinearAbscissa() / (_averageThickness * texStep)), 0));
i++;
- _vertices[i]->setTexCoord(Vec2r((real)(sv->curvilinearAbscissa() / (_averageThickness * texStep)), 1));
+ _vertices[i]->setTexCoord(Vec2r((real)(sv->curvilinearAbscissa() / (_averageThickness * texStep)), -1));
i++;
}
}
@@ -561,12 +561,12 @@ void Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertice
if (u > 0.25)
break;
- svRep->setTexCoord(Vec2r((real)u, 0.5), true);
+ svRep->setTexCoord(Vec2r((real)u, -0.5), true);
i++;
++currentSV;
svRep = *currentSV;
- svRep->setTexCoord(Vec2r((real)u, 1), true);
+ svRep->setTexCoord(Vec2r((real)u, -1), true);
i++;
++currentSV;
uPrev = u;
@@ -581,8 +581,8 @@ void Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertice
for (int k = 0; k < 2; k++) {
tvRep[k] = new StrokeVertexRep((1 - t) * _vertices[i - 2]->point2d() + t * _vertices[i]->point2d());
tvRep[k]->setTexCoord((1 - t) * _vertices[i - 2]->texCoord() + t * _vertices[i]->texCoord());
- // v coord is 0.5 for tvRep[0], 1.0 for tvRep[1]
- tvRep[k]->setTexCoord(Vec2r(0.25, 0.5 * (k + 1)), true);
+ // v coord is -0.5 for tvRep[0], -1.0 for tvRep[1]
+ tvRep[k]->setTexCoord(Vec2r(0.25, -0.5 * (k + 1)), true);
tvRep[k]->setColor((1 - t) * _vertices[i - 2]->color() + t * Vec3r(sv->attribute().getColorRGB()));
tvRep[k]->setAlpha((1 - t) * _vertices[i - 2]->alpha() + t * sv->attribute().getAlpha());
i++;
@@ -595,8 +595,8 @@ void Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertice
// copy the vertices with different texture coordinates
for (int k = 0; k < 2; k++) {
tvRep[k] = new StrokeVertexRep(*(_vertices[i - 2]));
- // v coord is 0.0 for tvRep[0], 0.5 for tvRep[1]
- tvRep[k]->setTexCoord(Vec2r(0.0, 0.5 * k), true); // FIXED u coord
+ // v coord is 0.0 for tvRep[0], -0.5 for tvRep[1]
+ tvRep[k]->setTexCoord(Vec2r(0.0, -0.5 * k), true);
i++;
}
for (int k = 0; k < 2; k++) {
@@ -620,7 +620,7 @@ void Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertice
++currentSV;
svRep = *currentSV;
- svRep->setTexCoord(Vec2r((real)u, 0.5), true);
+ svRep->setTexCoord(Vec2r((real)u, -0.5), true);
i++;
++currentSV;
@@ -637,8 +637,8 @@ void Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertice
for (int k = 0; k < 2; k++) {
tvRep[k] = new StrokeVertexRep((1 - t) * _vertices[i - 2]->point2d() + t * _vertices[i]->point2d());
tvRep[k]->setTexCoord((1 - t) * _vertices[i - 2]->texCoord() + t * _vertices[i]->texCoord());
- // v coord is 0.0 for tvRep[0], 0.5 for tvRep[1]
- tvRep[k]->setTexCoord(Vec2r((real)tiles, 0.5 * k), true); // FIXED u coord
+ // v coord is 0.0 for tvRep[0], -0.5 for tvRep[1]
+ tvRep[k]->setTexCoord(Vec2r((real)tiles, -0.5 * k), true);
tvRep[k]->setColor((1 - t) * _vertices[i - 2]->color() + t * Vec3r(sv->attribute().getColorRGB()));
tvRep[k]->setAlpha((1 - t) * _vertices[i - 2]->alpha() + t * sv->attribute().getAlpha());
i++;
@@ -651,8 +651,8 @@ void Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertice
// copy the vertices with different texture coordinates
for (int k = 0; k < 2; k++) {
tvRep[k] = new StrokeVertexRep(*(_vertices[i - 2]));
- // v coord is 0.5 for tvRep[0], 1.0 for tvRep[1]
- tvRep[k]->setTexCoord(Vec2r(0.75, 0.5 * (k + 1)), true);
+ // v coord is -0.5 for tvRep[0], -1.0 for tvRep[1]
+ tvRep[k]->setTexCoord(Vec2r(0.75, -0.5 * (k + 1)), true);
i++;
}
for (int k = 0; k < 2; k++) {
@@ -667,12 +667,12 @@ void Strip::computeTexCoordWithTips (const vector<StrokeVertex*>& iStrokeVertice
svRep = *currentSV;
u = 0.75 + sv->curvilinearAbscissa() / spacedThickness * fact - float(tiles) - 0.25;
- svRep->setTexCoord(Vec2r((real)u, 0.5), true);
+ svRep->setTexCoord(Vec2r((real)u, -0.5), true);
i++;
++currentSV;
svRep = *currentSV;
- svRep->setTexCoord(Vec2r((real)u, 1), true);
+ svRep->setTexCoord(Vec2r((real)u, -1), true);
i++;
++currentSV;
}
@@ -704,6 +704,8 @@ StrokeRep::StrokeRep()
{
_stroke = 0;
_strokeType = Stroke::OPAQUE_MEDIUM;
+ _nodeTree = NULL;
+ _hasTex = false;
_textureStep = 1.0;
for (int a = 0; a < MAX_MTEX; a++) {
_mtex[a] = NULL;
@@ -724,6 +726,8 @@ StrokeRep::StrokeRep(Stroke *iStroke)
{
_stroke = iStroke;
_strokeType = iStroke->getMediumType();
+ _nodeTree = iStroke->getNodeTree();
+ _hasTex = iStroke->hasTex();
_textureId = iStroke->getTextureId();
_textureStep = iStroke->getTextureStep();
for (int a = 0; a < MAX_MTEX; a++) {
@@ -757,6 +761,8 @@ StrokeRep::StrokeRep(const StrokeRep& iBrother)
_strokeType = iBrother._strokeType;
_textureId = iBrother._textureId;
_textureStep = iBrother._textureStep;
+ _nodeTree = iBrother._nodeTree;
+ _hasTex = iBrother._hasTex;
for (int a = 0; a < MAX_MTEX; a++) {
if (iBrother._mtex[a]) {
_mtex[a] = iBrother._mtex[a];
@@ -808,7 +814,7 @@ void StrokeRep::create()
end = true;
}
if ((!strip.empty()) && (strip.size() > 1)) {
- _strips.push_back(new Strip(strip, _stroke->hasTex(), first, end, _textureStep));
+ _strips.push_back(new Strip(strip, _hasTex, first, end, _textureStep));
strip.clear();
}
first = false;
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.h b/source/blender/freestyle/intern/stroke/StrokeRep.h
index 61a456cdf42..ba042eb496d 100644
--- a/source/blender/freestyle/intern/stroke/StrokeRep.h
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.h
@@ -37,7 +37,8 @@
#endif
extern "C" {
-#include "DNA_material_types.h"
+#include "DNA_material_types.h" // for MAX_MTEX
+struct bNodeTree;
}
namespace Freestyle {
@@ -185,7 +186,9 @@ protected:
unsigned int _textureId;
float _textureStep;
MTex *_mtex[MAX_MTEX];
+ bNodeTree *_nodeTree;
Material *_material;
+ bool _hasTex;
// float _averageTextureAlpha;
@@ -222,6 +225,16 @@ public:
return _material;
}
+ inline bNodeTree *getNodeTree() const
+ {
+ return _nodeTree;
+ }
+
+ inline bool hasTex() const
+ {
+ return _hasTex;
+ }
+
inline vector<Strip*>& getStrips()
{
return _strips;
diff --git a/source/blender/freestyle/intern/system/PointerSequence.h b/source/blender/freestyle/intern/system/PointerSequence.h
index 32c7898f840..791df90ba9d 100644
--- a/source/blender/freestyle/intern/system/PointerSequence.h
+++ b/source/blender/freestyle/intern/system/PointerSequence.h
@@ -30,7 +30,7 @@
* PointerSequence
*
* Produces a wrapped version of a sequence type (std::vector, std::deque, std::list) that will take ownership of
- * pointers tht it stores. Those pointers will be deleted in its destructor.
+ * pointers that it stores. Those pointers will be deleted in its destructor.
*
* Because the contained pointers are wholly owned by the sequence, you cannot make a copy of the sequence.
* Making a copy would result in a double free.
diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
index 9c9cd88f188..a5e526fc490 100644
--- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
+++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp
@@ -63,14 +63,14 @@ void FEdgeXDetector::processShapes(WingedEdge& we)
WXFace *wxf = dynamic_cast<WXFace*>(*wf);
wxf->Clear();
}
- _computeViewIndependant = true;
+ _computeViewIndependent = true;
}
- else if (!(wxs)->getComputeViewIndependantFlag()) {
+ else if (!(wxs)->getComputeViewIndependentFlag()) {
wxs->Reset();
- _computeViewIndependant = false;
+ _computeViewIndependent = false;
}
else {
- _computeViewIndependant = true;
+ _computeViewIndependent = true;
}
preProcessShape(wxs);
if (progressBarDisplay)
@@ -97,8 +97,8 @@ void FEdgeXDetector::processShapes(WingedEdge& we)
if (progressBarDisplay)
_pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
- wxs->setComputeViewIndependantFlag(false);
- _computeViewIndependant = false;
+ wxs->setComputeViewIndependentFlag(false);
+ _computeViewIndependent = false;
_changes = false;
// reset user data
@@ -187,8 +187,8 @@ void FEdgeXDetector::computeCurvatures(WXVertex *vertex)
CurvatureInfo *C;
float radius = _sphereRadius * _meanEdgeSize;
- // view independant stuff
- if (_computeViewIndependant) {
+ // view independent stuff
+ if (_computeViewIndependent) {
C = new CurvatureInfo();
vertex->setCurvatures(C);
OGF::NormalCycle ncycle;
@@ -333,7 +333,7 @@ void FEdgeXDetector::ProcessSilhouetteEdge(WXEdge *iEdge)
/////////
void FEdgeXDetector::processBorderShape(WXShape *iWShape)
{
- if (!_computeViewIndependant)
+ if (!_computeViewIndependent)
return;
// Make a pass on the edges to detect the BORDER
vector<WEdge*>::iterator we, weend;
@@ -358,7 +358,7 @@ void FEdgeXDetector::ProcessBorderEdge(WXEdge *iEdge)
/////////
void FEdgeXDetector::processCreaseShape(WXShape *iWShape)
{
- if (!_computeViewIndependant)
+ if (!_computeViewIndependent)
return;
// Make a pass on the edges to detect the CREASE
@@ -390,7 +390,7 @@ void FEdgeXDetector::processRidgesAndValleysShape(WXShape *iWShape)
// Don't forget to add the built layer to the face at the end of the ProcessFace:
//iFace->AddSmoothLayer(faceLayer);
- if (!_computeViewIndependant)
+ if (!_computeViewIndependent)
return;
// Here the curvatures must already have been computed
@@ -684,7 +684,7 @@ void FEdgeXDetector::postProcessSuggestiveContourFace(WXFace *iFace)
////////////////////
void FEdgeXDetector::processMaterialBoundaryShape(WXShape *iWShape)
{
- if (!_computeViewIndependant)
+ if (!_computeViewIndependent)
return;
// Make a pass on the edges to detect material boundaries
vector<WEdge*>::iterator we, weend;
diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.h b/source/blender/freestyle/intern/view_map/FEdgeXDetector.h
index 8adf685a6eb..8170fc5baab 100644
--- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.h
+++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.h
@@ -57,7 +57,7 @@ public:
{
_pProgressBar = NULL;
_pRenderMonitor = NULL;
- _computeViewIndependant = true;
+ _computeViewIndependent = true;
_bbox_diagonal = 1.0;
_meanEdgeSize = 0;
_computeRidgesAndValleys = true;
@@ -213,7 +213,7 @@ protected:
Vec3r _Viewpoint;
real _bbox_diagonal; // diagonal of the current processed shape bbox
//oldtmp values
- bool _computeViewIndependant;
+ bool _computeViewIndependent;
real _meanK1;
real _meanKr;
real _minK1;
diff --git a/source/blender/freestyle/intern/view_map/Functions0D.h b/source/blender/freestyle/intern/view_map/Functions0D.h
index 045ad317db2..647a3a530c6 100644
--- a/source/blender/freestyle/intern/view_map/Functions0D.h
+++ b/source/blender/freestyle/intern/view_map/Functions0D.h
@@ -65,13 +65,17 @@ using namespace Geometry;
* \attention In the scripting language, there exists several prototypes depending on the returned value type.
* For example, you would inherit from a UnaryFunction0DDouble if you wish to define a function that returns a double.
* The different existing prototypes are:
- * - UnaryFunction0DVoid
- * - UnaryFunction0DUnsigned
- * - UnaryFunction0DReal
- * - UnaryFunction0DFloat
* - UnaryFunction0DDouble
+ * - UnaryFunction0DEdgeNature
+ * - UnaryFunction0DFloat
+ * - UnaryFunction0DId
+ * - UnaryFunction0DMaterial
+ * - UnaryFunction0DUnsigned
* - UnaryFunction0DVec2f
* - UnaryFunction0DVec3f
+ * - UnaryFunction0DVectorViewShape
+ * - UnaryFunction0DViewShape
+ * - UnaryFunction0DVoid
*/
template <class T>
class UnaryFunction0D
diff --git a/source/blender/freestyle/intern/view_map/Functions1D.cpp b/source/blender/freestyle/intern/view_map/Functions1D.cpp
index f29da6680bf..11e0cc37d4d 100644
--- a/source/blender/freestyle/intern/view_map/Functions1D.cpp
+++ b/source/blender/freestyle/intern/view_map/Functions1D.cpp
@@ -198,7 +198,9 @@ int GetOccludeeF1D::operator()(Interface1D& inter)
ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter);
if (ve) {
ViewShape *aShape = ve->aShape();
- shapesVector.push_back(aShape);
+ if (aShape) {
+ shapesVector.push_back(aShape);
+ }
}
else {
Interface0DIterator it = inter.verticesBegin(), itend = inter.verticesEnd();
diff --git a/source/blender/freestyle/intern/view_map/Functions1D.h b/source/blender/freestyle/intern/view_map/Functions1D.h
index 0821475ca9c..d2a5870f27a 100644
--- a/source/blender/freestyle/intern/view_map/Functions1D.h
+++ b/source/blender/freestyle/intern/view_map/Functions1D.h
@@ -55,13 +55,14 @@ namespace Freestyle {
* \attention In the scripting language, there exists several prototypes depending on the returned value type.
* For example, you would inherit from a UnaryFunction1DDouble if you wish to define a function that returns a double.
* The different existing prototypes are:
- * - UnaryFunction1DVoid
- * - UnaryFunction1DUnsigned
- * - UnaryFunction1DReal
- * - UnaryFunction1DFloat
* - UnaryFunction1DDouble
+ * - UnaryFunction1DEdgeNature
+ * - UnaryFunction1DFloat
+ * - UnaryFunction1DUnsigned
* - UnaryFunction1DVec2f
* - UnaryFunction1DVec3f
+ * - UnaryFunction1DVectorViewShape
+ * - UnaryFunction1DVoid
*/
template <class T>
class UnaryFunction1D
diff --git a/source/blender/freestyle/intern/view_map/Interface0D.cpp b/source/blender/freestyle/intern/view_map/Interface0D.cpp
index 135a935d2fe..1d8515700d3 100644
--- a/source/blender/freestyle/intern/view_map/Interface0D.cpp
+++ b/source/blender/freestyle/intern/view_map/Interface0D.cpp
@@ -48,7 +48,7 @@ real Interface0D::getZ() const
return 0;
}
-Geometry::Vec3f Interface0D::getPoint3D() const
+Geometry::Vec3r Interface0D::getPoint3D() const
{
PyErr_SetString(PyExc_TypeError, "method getPoint3D() not properly overridden");
return 0;
@@ -72,7 +72,7 @@ real Interface0D::getProjectedZ() const
return 0;
}
-Geometry::Vec2f Interface0D::getPoint2D() const
+Geometry::Vec2r Interface0D::getPoint2D() const
{
PyErr_SetString(PyExc_TypeError, "method getPoint2D() not properly overridden");
return 0;
diff --git a/source/blender/freestyle/intern/view_map/Interface0D.h b/source/blender/freestyle/intern/view_map/Interface0D.h
index e59ed4c96c8..da71d7ad949 100644
--- a/source/blender/freestyle/intern/view_map/Interface0D.h
+++ b/source/blender/freestyle/intern/view_map/Interface0D.h
@@ -86,7 +86,7 @@ public:
virtual real getZ() const;
/*! Returns the 3D point. */
- virtual Geometry::Vec3f getPoint3D() const;
+ virtual Geometry::Vec3r getPoint3D() const;
/*! Returns the 2D x coordinate of the point. */
virtual real getProjectedX() const;
@@ -98,7 +98,7 @@ public:
virtual real getProjectedZ() const;
/*! Returns the 2D point. */
- virtual Geometry::Vec2f getPoint2D() const;
+ virtual Geometry::Vec2r getPoint2D() const;
/*! Returns the FEdge that lies between this Interface0D and the Interface0D given as argument. */
virtual FEdge *getFEdge(Interface0D&);
@@ -302,6 +302,18 @@ public:
return _iterator->isEnd();
}
+ /*! Returns true when the iterator is pointing to the final valid element. */
+ virtual bool atLast() const
+ {
+ if (_iterator->isEnd())
+ return false;
+
+ _iterator->increment();
+ bool result = _iterator->isEnd();
+ _iterator->decrement();
+ return result;
+ }
+
/*! operator == . */
bool operator==(const Interface0DIterator& it) const
{
diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h
index e747f9c3e68..94b00157ccd 100644
--- a/source/blender/freestyle/intern/view_map/Silhouette.h
+++ b/source/blender/freestyle/intern/view_map/Silhouette.h
@@ -103,7 +103,7 @@ public: // Implementation of Interface0D
}
/*! Returns the 3D point. */
- virtual Vec3f getPoint3D() const
+ virtual Vec3r getPoint3D() const
{
return _Point3D;
}
@@ -127,9 +127,9 @@ public: // Implementation of Interface0D
}
/*! Returns the 2D point. */
- virtual Vec2f getPoint2D() const
+ virtual Vec2r getPoint2D() const
{
- return Vec2f((float)_Point2D.x(), (float)_Point2D.y());
+ return Vec2r(_Point2D.x(), _Point2D.y());
}
/*! Returns the FEdge that lies between this Svertex and the Interface0D given as argument. */
@@ -378,6 +378,17 @@ public:
_FEdges.push_back(iFEdge);
}
+ /*! Remove an FEdge from the list of edges emanating from this SVertex. */
+ inline void RemoveFEdge(FEdge *iFEdge)
+ {
+ for (vector<FEdge *>::iterator fe = _FEdges.begin(), fend = _FEdges.end(); fe != fend; fe++) {
+ if (iFEdge == (*fe)) {
+ _FEdges.erase(fe);
+ break;
+ }
+ }
+ }
+
/* replaces edge 1 by edge 2 in the list of edges */
inline void Replace(FEdge *e1, FEdge *e2)
{
@@ -441,6 +452,10 @@ public:
/*! angle in radians */
inline real curvature2d_as_angle() const;
#endif
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:SVertex")
+#endif
};
/**********************************/
@@ -518,6 +533,8 @@ protected:
bool _isInImage;
+ bool _isTemporary;
+
public:
/*! A field that can be used by the user to store any data.
* This field must be reseted afterwards using ResetUserData().
@@ -538,6 +555,7 @@ public:
_occludeeEmpty = true;
_isSmooth = false;
_isInImage = true;
+ _isTemporary = false;
}
/*! Builds an FEdge going from vA to vB. */
@@ -554,6 +572,7 @@ public:
_occludeeEmpty = true;
_isSmooth = false;
_isInImage = true;
+ _isTemporary = false;
}
/*! Copy constructor */
@@ -573,6 +592,7 @@ public:
_occludeeEmpty = iBrother._occludeeEmpty;
_isSmooth = iBrother._isSmooth;
_isInImage = iBrother._isInImage;
+ _isTemporary = iBrother._isTemporary;
iBrother.userdata = this;
userdata = 0;
}
@@ -708,6 +728,11 @@ public:
return _isInImage;
}
+ inline bool isTemporary() const
+ {
+ return _isTemporary;
+ }
+
/* modifiers */
/*! Sets the first SVertex. */
inline void setVertexA(SVertex *vA)
@@ -803,6 +828,11 @@ public:
_isInImage = iFlag;
}
+ inline void setTemporary(bool iFlag)
+ {
+ _isTemporary = iFlag;
+ }
+
/* checks whether two FEdge have a common vertex.
* Returns a pointer on the common vertex if it exists, NULL otherwise.
*/
@@ -931,6 +961,10 @@ public:
* The sampling with which we want to iterate over points of this FEdge.
*/
virtual inline Interface0DIterator pointsEnd(float t = 0.0f);
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FEdge")
+#endif
};
//
@@ -1241,6 +1275,10 @@ public:
{
_bFaceMark = iFaceMark;
}
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FEdgeSharp")
+#endif
};
/*! Class defining a smooth edge. This kind of edge typically runs across a face of the input mesh. It can be
@@ -1353,6 +1391,10 @@ public:
{
_FrsMaterialIndex = i;
}
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:FEdgeSmooth")
+#endif
};
diff --git a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp
index ee885f29211..3bfa4e5e3c1 100644
--- a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp
+++ b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp
@@ -130,53 +130,20 @@ void SilhouetteGeomEngine::retrieveViewport(int viewport[4])
memcpy(viewport, _viewport, 4 * sizeof(int));
}
-//#define HUGE 1.0e9
-
void SilhouetteGeomEngine::ProjectSilhouette(vector<SVertex*>& ioVertices)
{
Vec3r newPoint;
-#if 0
- real min = HUGE;
- real max = -HUGE;
-#endif
vector<SVertex*>::iterator sv, svend;
- const real depth = _zfar - _znear;
- const real fac = (depth < 1.0e-6) ? 1.0 : 1.0 / depth;
-
for (sv = ioVertices.begin(), svend = ioVertices.end(); sv != svend; sv++) {
GeomUtils::fromWorldToImage((*sv)->point3D(), newPoint, _modelViewMatrix, _projectionMatrix, _viewport);
- newPoint[2] = (-newPoint[2] - _znear) * fac; // normalize Z between 0 and 1
(*sv)->setPoint2D(newPoint);
-#if 0
- cerr << (*sv)->point2d().z() << " ";
- real d = (*sv)->point2d()[2];
- if (d > max)
- max =d;
- if (d < min)
- min =d;
-#endif
- }
-#if 0
- for (sv = ioVertices.begin(), svend = ioVertices.end(); sv != svend; sv++) {
- Vec3r P((*sv)->point2d());
- (*sv)->setPoint2D(Vec3r(P[0], P[1], 1.0 - (P[2] - min) / (max - min)));
- //cerr << (*sv)->point2d()[2] << " ";
}
-#endif
}
void SilhouetteGeomEngine::ProjectSilhouette(SVertex *ioVertex)
{
Vec3r newPoint;
-#if 0
- real min = HUGE;
- real max = -HUGE;
- vector<SVertex*>::iterator sv, svend;
-#endif
- const real depth = _zfar - _znear;
- const real fac = (depth < 1.0e-6) ? 1.0 : 1.0 / depth;
GeomUtils::fromWorldToImage(ioVertex->point3D(), newPoint, _modelViewMatrix, _projectionMatrix, _viewport);
- newPoint[2] = (-newPoint[2] - _znear) * fac; // normalize Z between 0 and 1
ioVertex->setPoint2D(newPoint);
}
@@ -311,11 +278,16 @@ iter:
Vec3r SilhouetteGeomEngine::WorldToImage(const Vec3r& M)
{
- const real depth = _zfar - _znear;
- const real fac = (depth < 1.0e-6) ? 1.0 : 1.0 / depth;
Vec3r newPoint;
GeomUtils::fromWorldToImage(M, newPoint, _transform, _viewport);
- newPoint[2] = (-newPoint[2] - _znear) * fac; // normalize Z between 0 and 1
+ return newPoint;
+}
+
+Vec3r SilhouetteGeomEngine::CameraToImage(const Vec3r& M)
+{
+ Vec3r newPoint, p;
+ GeomUtils::fromCameraToRetina(M, p, _projectionMatrix);
+ GeomUtils::fromRetinaToImage(p, newPoint, _viewport);
return newPoint;
}
diff --git a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h
index 1234c028ca1..e4bf1517512 100644
--- a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h
+++ b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h
@@ -131,6 +131,9 @@ public:
/*! From world to image */
static Vec3r WorldToImage(const Vec3r& M);
+ /*! From camera to image */
+ static Vec3r CameraToImage(const Vec3r& M);
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:SilhouetteGeomEngine")
#endif
diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.h b/source/blender/freestyle/intern/view_map/SteerableViewMap.h
index 0cd5d222621..3a660627776 100644
--- a/source/blender/freestyle/intern/view_map/SteerableViewMap.h
+++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.h
@@ -54,7 +54,7 @@ class GrayImage;
class SteerableViewMap
{
protected:
- // for each vector the list of nbOrientations weigths corresponding to its contributions
+ // for each vector the list of nbOrientations weights corresponding to its contributions
// to the nbOrientations directional maps
map<unsigned int, double*> _mapping;
unsigned _nbOrientations;
@@ -73,7 +73,7 @@ public:
virtual void Reset();
/*! Adds a FEdge to steerable VM.
- * Returns the nbOrientations weigths corresponding to the FEdge contributions to the nbOrientations
+ * Returns the nbOrientations weights corresponding to the FEdge contributions to the nbOrientations
* directional maps.
*/
double *AddFEdge(FEdge *iFEdge);
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp
index fd5ebb99f72..6bb0082e379 100644
--- a/source/blender/freestyle/intern/view_map/ViewMap.cpp
+++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp
@@ -63,6 +63,30 @@ ViewMap::~ViewMap()
_VEdges.clear();
}
+void ViewMap::Clean()
+{
+ vector<FEdge*> tmpEdges;
+
+ for (vector<ViewShape*>::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) {
+ vector<FEdge*>& edges = (*vs)->sshape()->getEdgeList();
+ for (vector<FEdge*>::iterator it = edges.begin(), itend = edges.end(); it != itend; it++) {
+ if ((*it)->isTemporary()) {
+ (*it)->setTemporary(false); // avoid being counted multiple times
+ tmpEdges.push_back(*it);
+ }
+ }
+ }
+
+ for (vector<FEdge*>::iterator it = tmpEdges.begin(), itend = tmpEdges.end(); it != itend; it++) {
+ for (vector<ViewShape*>::iterator vs = _VShapes.begin(), vsend = _VShapes.end(); vs != vsend; vs++) {
+ (*vs)->sshape()->RemoveEdge(*it);
+ }
+ (*it)->vertexA()->RemoveFEdge(*it);
+ (*it)->vertexB()->RemoveFEdge(*it);
+ delete (*it);
+ }
+}
+
ViewShape *ViewMap::viewShape(unsigned id)
{
int index = _shapeIdToIndex[id];
diff --git a/source/blender/freestyle/intern/view_map/ViewMap.h b/source/blender/freestyle/intern/view_map/ViewMap.h
index eeaeada5dc6..0ee1864e086 100644
--- a/source/blender/freestyle/intern/view_map/ViewMap.h
+++ b/source/blender/freestyle/intern/view_map/ViewMap.h
@@ -236,6 +236,9 @@ public:
/* connects a FEdge to the graph trough a SVertex */
//FEdge *Connect(FEdge *ioEdge, SVertex *ioVertex);
+ /* Clean temporary FEdges created by chaining */
+ virtual void Clean();
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ViewMap")
#endif
@@ -369,7 +372,6 @@ public:
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ViewVertex")
#endif
-
};
/**********************************/
@@ -419,7 +421,7 @@ public: // Implementation of Interface0D
}
/*! Returns the 3D point. */
- virtual Vec3f getPoint3D() const
+ virtual Vec3r getPoint3D() const
{
cerr << "Warning: getPoint3D() undefined for this point" << endl;
return _FrontSVertex->getPoint3D();
@@ -443,7 +445,7 @@ public: // Implementation of Interface0D
}
/*! Returns the 2D point. */
- virtual Vec2f getPoint2D() const
+ virtual Vec2r getPoint2D() const
{
return _FrontSVertex->getPoint2D();
}
@@ -642,7 +644,6 @@ public:
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:TVertex")
#endif
-
};
@@ -692,7 +693,7 @@ public: // Implementation of Interface0D
}
/*! Returns the 3D point. */
- virtual Vec3f getPoint3D() const
+ virtual Vec3r getPoint3D() const
{
return _SVertex->getPoint3D();
}
@@ -716,7 +717,7 @@ public: // Implementation of Interface0D
}
/*! Returns the 2D point. */
- virtual Vec2f getPoint2D() const
+ virtual Vec2r getPoint2D() const
{
return _SVertex->getPoint2D();
}
@@ -859,7 +860,6 @@ public:
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:NonTVertex")
#endif
-
};
/**********************************/
@@ -1379,7 +1379,6 @@ public:
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:ViewEdge")
#endif
-
};
diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
index 4a910099bff..38941b23357 100644
--- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp
+++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp
@@ -539,7 +539,7 @@ inline static real angle(WOEdge *h)
{
const Vec3r& n1 = h->GetbFace()->GetNormal();
const Vec3r& n2 = h->GetaFace()->GetNormal();
- const Vec3r v = h->getVec3r();
+ const Vec3r v = h->GetVec();
real sine = (n1 ^ n2) * v / v.norm();
if (sine >= 1.0) {
return M_PI / 2.0;
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.cpp b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
index 97248669822..de166531d8b 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.cpp
@@ -211,11 +211,6 @@ WOEdge *WOEdge::duplicate()
return clone;
}
-Vec3r WOEdge::getVec3r ()
-{
- return Vec3r(_pbVertex->GetVertex() - _paVertex->GetVertex());
-}
-
WOEdge *WOEdge::twin ()
{
return GetOwner()->GetOtherOEdge(this);
@@ -302,34 +297,28 @@ WOEdge *WFace::MakeEdge(WVertex *v1, WVertex *v2)
WEdge *we = (*it1);
WOEdge *woea = we->GetaOEdge();
- //if ((*it1)->GetbVertex() == v2) {
if ((woea->GetaVertex() == v1) && (woea->GetbVertex() == v2)) {
// The oriented edge already exists
cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId() << " appears twice, correcting" << endl;
// Adds the edge to the face
- //AddEdge((*it1)->GetaOEdge());
AddEdge(woea);
(*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges() + 1);
//sets these vertices as border:
v1->setBorder(true);
v2->setBorder(true);
- //return (*it1)->GetaOEdge();
return woea;
}
WOEdge *woeb = we->GetbOEdge();
- //if ((*it1)->GetbVertex() == v2)
if (woeb && (woeb->GetaVertex() == v1) && (woeb->GetbVertex() == v2)) {
// The oriented edge already exists
cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId() << " appears twice, correcting" << endl;
// Adds the edge to the face
- //AddEdge((*it1)->GetaOEdge());
AddEdge(woeb);
(*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges() + 1);
//sets these vertices as border:
v1->setBorder(true);
v2->setBorder(true);
- //return (*it1)->GetaOEdge();
return woeb;
}
}
diff --git a/source/blender/freestyle/intern/winged_edge/WEdge.h b/source/blender/freestyle/intern/winged_edge/WEdge.h
index 5dda41ad279..41525e03d8e 100644
--- a/source/blender/freestyle/intern/winged_edge/WEdge.h
+++ b/source/blender/freestyle/intern/winged_edge/WEdge.h
@@ -525,8 +525,6 @@ public:
/*! Retrieves the list of edges in CW order */
inline void RetrieveCWOrderedEdges(vector<WEdge*>& oEdges);
- /*! returns the vector between the two vertices */
- Vec3r getVec3r ();
WOEdge *twin ();
WOEdge *getPrevOnFace();
@@ -1297,7 +1295,9 @@ protected:
class WingedEdge
{
public:
- WingedEdge() {}
+ WingedEdge() {
+ _numFaces = 0;
+ }
~WingedEdge()
{
@@ -1309,11 +1309,13 @@ public:
for (vector<WShape *>::iterator it = _wshapes.begin(); it != _wshapes.end(); it++)
delete *it;
_wshapes.clear();
+ _numFaces = 0;
}
void addWShape(WShape *wshape)
{
_wshapes.push_back(wshape);
+ _numFaces += wshape->GetFaceList().size();
}
vector<WShape *>& getWShapes()
@@ -1321,8 +1323,14 @@ public:
return _wshapes;
}
+ unsigned getNumFaces()
+ {
+ return _numFaces;
+ }
+
private:
vector<WShape *> _wshapes;
+ unsigned _numFaces;
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:WingedEdge")
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdge.h b/source/blender/freestyle/intern/winged_edge/WXEdge.h
index ce9749369fc..3c9ec7a7e3d 100644
--- a/source/blender/freestyle/intern/winged_edge/WXEdge.h
+++ b/source/blender/freestyle/intern/winged_edge/WXEdge.h
@@ -718,18 +718,18 @@ public:
typedef WXShape type_name;
protected:
- bool _computeViewIndependant; // flag to indicate whether the view independant stuff must be computed or not
+ bool _computeViewIndependent; // flag to indicate whether the view independent stuff must be computed or not
public:
inline WXShape() : WShape()
{
- _computeViewIndependant = true;
+ _computeViewIndependent = true;
}
/*! copy constructor */
inline WXShape(WXShape& iBrother) : WShape(iBrother)
{
- _computeViewIndependant = iBrother._computeViewIndependant;
+ _computeViewIndependent = iBrother._computeViewIndependent;
}
virtual WShape *duplicate()
@@ -740,14 +740,14 @@ public:
virtual ~WXShape() {}
- inline bool getComputeViewIndependantFlag() const
+ inline bool getComputeViewIndependentFlag() const
{
- return _computeViewIndependant;
+ return _computeViewIndependent;
}
- inline void setComputeViewIndependantFlag(bool iFlag)
+ inline void setComputeViewIndependentFlag(bool iFlag)
{
- _computeViewIndependant = iFlag;
+ _computeViewIndependent = iFlag;
}
/*! designed to build a specialized WFace for use in MakeFace */
diff --git a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
index eab638840e5..590e03255f5 100644
--- a/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WXEdgeBuilder.cpp
@@ -36,7 +36,10 @@ void WXEdgeBuilder::visitIndexedFaceSet(IndexedFaceSet& ifs)
if (_pRenderMonitor && _pRenderMonitor->testBreak())
return;
WXShape *shape = new WXShape;
- buildWShape(*shape, ifs);
+ if (!buildWShape(*shape, ifs)) {
+ delete shape;
+ return;
+ }
shape->setId(ifs.getId().getFirst());
shape->setName(ifs.getName());
//ifs.setId(shape->GetId());
diff --git a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
index c83abe85318..c9f2f3badab 100644
--- a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
+++ b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.cpp
@@ -43,7 +43,10 @@ void WingedEdgeBuilder::visitIndexedFaceSet(IndexedFaceSet& ifs)
if (_pRenderMonitor && _pRenderMonitor->testBreak())
return;
WShape *shape = new WShape;
- buildWShape(*shape, ifs);
+ if (!buildWShape(*shape, ifs)) {
+ delete shape;
+ return;
+ }
shape->setId(ifs.getId().getFirst());
//ifs.setId(shape->GetId());
}
@@ -80,7 +83,7 @@ void WingedEdgeBuilder::visitNodeTransformAfter(NodeTransform&)
_matrices_stack.pop_back();
}
-void WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs)
+bool WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs)
{
unsigned int vsize = ifs.vsize();
unsigned int nsize = ifs.nsize();
@@ -171,6 +174,9 @@ void WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs)
delete[] new_vertices;
delete[] new_normals;
+ if (shape.GetFaceList().size() == 0) // this may happen due to degenerate triangles
+ return false;
+
// compute bbox
shape.ComputeBBox();
// compute mean edge size:
@@ -198,8 +204,11 @@ void WingedEdgeBuilder::buildWShape(WShape& shape, IndexedFaceSet& ifs)
(*wv)->setSmooth(false);
}
}
+
// Adds the new WShape to the WingedEdge structure
_winged_edge->addWShape(&shape);
+
+ return true;
}
void WingedEdgeBuilder::buildWVertices(WShape& shape, const real *vertices, unsigned vsize)
diff --git a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h
index 7fd5cd8443a..36f090f4ae9 100644
--- a/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h
+++ b/source/blender/freestyle/intern/winged_edge/WingedEdgeBuilder.h
@@ -117,7 +117,7 @@ public:
}
protected:
- virtual void buildWShape(WShape& shape, IndexedFaceSet& ifs);
+ virtual bool buildWShape(WShape& shape, IndexedFaceSet& ifs);
virtual void buildWVertices(WShape& shape, const real *vertices, unsigned vsize);
RenderMonitor *_pRenderMonitor;
diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt
index 739deffa519..63eea9486ed 100644
--- a/source/blender/gpu/CMakeLists.txt
+++ b/source/blender/gpu/CMakeLists.txt
@@ -36,6 +36,7 @@ set(INC
../nodes
../nodes/intern
+ ../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/smoke/extern
)
@@ -49,15 +50,21 @@ set(SRC
intern/gpu_codegen.c
intern/gpu_draw.c
intern/gpu_extensions.c
+ intern/gpu_init_exit.c
intern/gpu_material.c
intern/gpu_simple_shader.c
+ intern/gpu_select.c
GPU_buffers.h
GPU_draw.h
GPU_extensions.h
+ GPU_glew.h
+ GPU_init_exit.h
GPU_material.h
GPU_simple_shader.h
+ GPU_select.h
intern/gpu_codegen.h
+ intern/gpu_extensions_private.h
)
data_to_c_simple(shaders/gpu_shader_material.glsl SRC)
@@ -77,7 +84,7 @@ if(WITH_MOD_SMOKE)
add_definitions(-DWITH_SMOKE)
endif()
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h
index 096b2080b2b..ba461d5f8a2 100644
--- a/source/blender/gpu/GPU_buffers.h
+++ b/source/blender/gpu/GPU_buffers.h
@@ -32,11 +32,11 @@
#ifndef __GPU_BUFFERS_H__
#define __GPU_BUFFERS_H__
-#ifdef _DEBUG
-/*#define DEBUG_VBO(X) printf(X)*/
-#define DEBUG_VBO(X)
+#ifdef DEBUG
+/* #define DEBUG_VBO(X) printf(X)*/
+# define DEBUG_VBO(X)
#else
-#define DEBUG_VBO(X)
+# define DEBUG_VBO(X)
#endif
struct BMesh;
@@ -139,6 +139,7 @@ void GPU_drawobject_free(struct DerivedMesh *dm);
void GPU_vertex_setup(struct DerivedMesh *dm);
void GPU_normal_setup(struct DerivedMesh *dm);
void GPU_uv_setup(struct DerivedMesh *dm);
+void GPU_texpaint_uv_setup(struct DerivedMesh *dm);
/* colType is the cddata MCol type to use! */
void GPU_color_setup(struct DerivedMesh *dm, int colType);
void GPU_edge_setup(struct DerivedMesh *dm); /* does not mix with other data */
diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h
index ee1eabc2a15..3ddec157c49 100644
--- a/source/blender/gpu/GPU_draw.h
+++ b/source/blender/gpu/GPU_draw.h
@@ -87,7 +87,7 @@ int GPU_get_material_alpha_blend(void);
* - passing NULL clears the state again */
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 */
@@ -134,6 +134,7 @@ bool GPU_upload_dxt_texture(struct ImBuf *ibuf);
void GPU_free_image(struct Image *ima);
void GPU_free_images(void);
void GPU_free_images_anim(void);
+void GPU_free_images_old(void);
/* smoke drawing functions */
void GPU_free_smoke(struct SmokeModifierData *smd);
diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h
index e97cc57055f..3daf8585539 100644
--- a/source/blender/gpu/GPU_extensions.h
+++ b/source/blender/gpu/GPU_extensions.h
@@ -55,8 +55,6 @@ typedef struct GPUShader GPUShader;
/* GPU extensions support */
void GPU_extensions_disable(void);
-void GPU_extensions_init(void); /* call this before running any of the functions below */
-void GPU_extensions_exit(void);
int GPU_print_error(const char *str);
int GPU_glsl_support(void);
@@ -117,6 +115,9 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, 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);
+void GPU_invalid_tex_init(void);
+void GPU_invalid_tex_bind(int mode);
+void GPU_invalid_tex_free(void);
void GPU_texture_free(GPUTexture *tex);
diff --git a/source/blender/gpu/GPU_glew.h b/source/blender/gpu/GPU_glew.h
new file mode 100644
index 00000000000..94217863fd6
--- /dev/null
+++ b/source/blender/gpu/GPU_glew.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) 2012 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Jason Wilkins.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file source/blender/gpu/GPU_glew.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_GLEW_H__
+#define __GPU_GLEW_H__
+
+#include "glew-mx.h"
+
+#endif /* __GPU_GLEW_H__ */
diff --git a/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.h b/source/blender/gpu/GPU_init_exit.h
index 047ff4b58b5..e89c970b7d9 100644
--- a/source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.h
+++ b/source/blender/gpu/GPU_init_exit.h
@@ -15,39 +15,32 @@
* 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): Jason Wilkins.
+ *
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file source/blender/freestyle/intern/python/StrokeShader/BPy_streamShader.h
- * \ingroup freestyle
+/** \file blender/gpu/GPU_init_exit.h
+ * \ingroup gpu
*/
-#ifndef __FREESTYLE_PYTHON_STREAMSHADER_H__
-#define __FREESTYLE_PYTHON_STREAMSHADER_H__
-
-#include "../BPy_StrokeShader.h"
+#ifndef __GPU_INIT_EXIT_H__
+#define __GPU_INIT_EXIT_H__
#ifdef __cplusplus
extern "C" {
#endif
-///////////////////////////////////////////////////////////////////////////////////////////
-
-extern PyTypeObject streamShader_Type;
-
-#define BPy_streamShader_Check(v) (PyObject_IsInstance((PyObject *)v, (PyObject *)&streamShader_Type))
-
-/*---------------------------Python BPy_streamShader structure definition----------*/
-typedef struct {
- BPy_StrokeShader py_ss;
-} BPy_streamShader;
-
-
-///////////////////////////////////////////////////////////////////////////////////////////
+void GPU_init(void);
+void GPU_exit(void);
#ifdef __cplusplus
}
#endif
-
-#endif /* __FREESTYLE_PYTHON_STREAMSHADER_H__ */
+#endif /* __GPU_INIT_EXIT_H__ */
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 1011ac80901..a111401343e 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -34,6 +34,8 @@
#include "DNA_listBase.h"
+#include "BLI_sys_types.h" /* for bool */
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -137,7 +139,7 @@ void GPU_material_free(struct Material *ma);
void GPU_materials_free(void);
bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma);
-void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4]);
+void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][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);
@@ -147,6 +149,7 @@ void GPU_material_vertex_attributes(GPUMaterial *material,
struct GPUVertexAttribs *attrib);
bool GPU_material_do_color_management(GPUMaterial *mat);
+bool GPU_material_use_new_shading_nodes(GPUMaterial *mat);
/* Exported shading */
diff --git a/source/blender/gpu/GPU_select.h b/source/blender/gpu/GPU_select.h
new file mode 100644
index 00000000000..1a274e0ad9d
--- /dev/null
+++ b/source/blender/gpu/GPU_select.h
@@ -0,0 +1,61 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Antony Riakiotakis.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file GPU_select.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_SELECT__
+#define __GPU_SELECT__
+
+#include "DNA_vec_types.h" /* rcft */
+#include "BLI_sys_types.h"
+
+/* flags for mode of operation */
+enum {
+ GPU_SELECT_ALL = 1,
+ GPU_SELECT_NEAREST_FIRST_PASS = 2,
+ GPU_SELECT_NEAREST_SECOND_PASS = 3,
+};
+
+/* initialize and provide buffer for results */
+void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits);
+
+/* loads a new selection id and ends previous query, if any. In second pass of selection it also returns
+ * if id has been hit on the first pass already. Thus we can skip drawing un-hit objects IMPORTANT: We rely on the order of object rendering on passes to be
+ * the same for this to work */
+bool GPU_select_load_id(unsigned int id);
+
+/* cleanup and flush selection results to buffer. Return number of hits and hits in buffer.
+ * if dopass is true, we will do a second pass with occlusion queries to get the closest hit */
+unsigned int GPU_select_end(void);
+
+/* does the GPU support occlusion queries? */
+bool GPU_select_query_check_support(void);
+
+/* is occlusion query supported and user activated? */
+bool GPU_select_query_check_active(void);
+
+#endif
diff --git a/source/blender/gpu/SConscript b/source/blender/gpu/SConscript
index e9320f08eff..f11ecafc986 100644
--- a/source/blender/gpu/SConscript
+++ b/source/blender/gpu/SConscript
@@ -30,13 +30,14 @@ Import ('env')
sources = env.Glob('intern/*.c')
sources += env.Glob('shaders/*.c')
-defs = [ 'GLEW_STATIC' ]
+defs = env['BF_GL_DEFINITIONS']
incs = [
'.',
+ '#/intern/glew-mx',
'#/intern/guardedalloc',
+ env['BF_GLEW_INC'],
'#/intern/smoke/extern',
- '#/extern/glew/include',
'../blenkernel',
'../blenlib',
'../bmesh',
@@ -46,7 +47,6 @@ incs = [
'../makesrna',
'../nodes',
'../nodes/intern',
- env['BF_OPENGL_INC'],
]
if env['WITH_BF_GAMEENGINE']:
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index f5256f18897..b5a576b509c 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -36,7 +36,7 @@
#include <stddef.h>
#include <string.h>
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
@@ -46,11 +46,13 @@
#include "BLI_ghash.h"
#include "BLI_threads.h"
+#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "BKE_ccg.h"
#include "BKE_DerivedMesh.h"
#include "BKE_paint.h"
+#include "BKE_material.h"
#include "BKE_pbvh.h"
#include "DNA_userdef_types.h"
@@ -61,15 +63,18 @@
#include "bmesh.h"
typedef enum {
- GPU_BUFFER_VERTEX_STATE = 1,
- GPU_BUFFER_NORMAL_STATE = 2,
- GPU_BUFFER_TEXCOORD_STATE = 4,
- GPU_BUFFER_COLOR_STATE = 8,
- GPU_BUFFER_ELEMENT_STATE = 16,
+ GPU_BUFFER_VERTEX_STATE = (1 << 0),
+ GPU_BUFFER_NORMAL_STATE = (1 << 1),
+ GPU_BUFFER_TEXCOORD_UNIT_0_STATE = (1 << 2),
+ GPU_BUFFER_TEXCOORD_UNIT_2_STATE = (1 << 3),
+ GPU_BUFFER_COLOR_STATE = (1 << 4),
+ GPU_BUFFER_ELEMENT_STATE = (1 << 5),
} GPUBufferState;
#define MAX_GPU_ATTRIB_DATA 32
+#define BUFFER_OFFSET(n) ((GLubyte *)NULL + (n))
+
/* -1 - undefined, 0 - vertex arrays, 1 - VBOs */
static int useVBOs = -1;
static GPUBufferState GLStates = 0;
@@ -611,7 +616,7 @@ static GPUBuffer *gpu_buffer_setup(DerivedMesh *dm, GPUDrawObject *object,
}
mat_orig_to_new = MEM_mallocN(sizeof(*mat_orig_to_new) * dm->totmat,
- "GPU_buffer_setup.mat_orig_to_new");
+ "GPU_buffer_setup.mat_orig_to_new");
cur_index_per_mat = MEM_mallocN(sizeof(int) * object->totmaterial,
"GPU_buffer_setup.cur_index_per_mat");
for (i = 0; i < object->totmaterial; i++) {
@@ -836,6 +841,61 @@ static void GPU_buffer_copy_uv(DerivedMesh *dm, float *varray, int *index, int *
}
}
+
+static void GPU_buffer_copy_uv_texpaint(DerivedMesh *dm, float *varray, int *index, int *mat_orig_to_new, void *UNUSED(user))
+{
+ int start;
+ int i, totface;
+
+ int totmaterial = dm->totmat;
+ MTFace **mtface_base;
+ MTFace *stencil_base;
+ int stencil;
+ MFace *mf;
+
+ /* should have been checked for before, reassert */
+ BLI_assert(DM_get_tessface_data_layer(dm, CD_MTFACE));
+ mf = dm->getTessFaceArray(dm);
+ mtface_base = MEM_mallocN(totmaterial * sizeof(*mtface_base), "texslots");
+
+ for (i = 0; i < totmaterial; i++) {
+ mtface_base[i] = DM_paint_uvlayer_active_get(dm, i);
+ }
+
+ stencil = CustomData_get_stencil_layer(&dm->faceData, CD_MTFACE);
+ stencil_base = CustomData_get_layer_n(&dm->faceData, CD_MTFACE, stencil);
+
+ totface = dm->getNumTessFaces(dm);
+
+ for (i = 0; i < totface; i++, mf++) {
+ int mat_i = mf->mat_nr;
+ start = index[mat_orig_to_new[mat_i]];
+
+ /* v1 v2 v3 */
+ copy_v2_v2(&varray[start], mtface_base[mat_i][i].uv[0]);
+ copy_v2_v2(&varray[start + 2], stencil_base[i].uv[0]);
+ copy_v2_v2(&varray[start + 4], mtface_base[mat_i][i].uv[1]);
+ copy_v2_v2(&varray[start + 6], stencil_base[i].uv[1]);
+ copy_v2_v2(&varray[start + 8], mtface_base[mat_i][i].uv[2]);
+ copy_v2_v2(&varray[start + 10], stencil_base[i].uv[2]);
+ index[mat_orig_to_new[mat_i]] += 12;
+
+ if (mf->v4) {
+ /* v3 v4 v1 */
+ copy_v2_v2(&varray[start + 12], mtface_base[mat_i][i].uv[2]);
+ copy_v2_v2(&varray[start + 14], stencil_base[i].uv[2]);
+ copy_v2_v2(&varray[start + 16], mtface_base[mat_i][i].uv[3]);
+ copy_v2_v2(&varray[start + 18], stencil_base[i].uv[3]);
+ copy_v2_v2(&varray[start + 20], mtface_base[mat_i][i].uv[0]);
+ copy_v2_v2(&varray[start + 22], stencil_base[i].uv[0]);
+ index[mat_orig_to_new[mat_i]] += 12;
+ }
+ }
+
+ MEM_freeN(mtface_base);
+}
+
+
static void copy_mcol_uc3(unsigned char *v, unsigned char *col)
{
v[0] = col[3];
@@ -925,6 +985,7 @@ typedef enum {
GPU_BUFFER_NORMAL,
GPU_BUFFER_COLOR,
GPU_BUFFER_UV,
+ GPU_BUFFER_UV_TEXPAINT,
GPU_BUFFER_EDGE,
GPU_BUFFER_UVEDGE,
} GPUBufferType;
@@ -940,6 +1001,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_edge, GL_ELEMENT_ARRAY_BUFFER_ARB, 2},
{GPU_buffer_copy_uvedge, GL_ELEMENT_ARRAY_BUFFER_ARB, 4}
};
@@ -956,6 +1018,8 @@ static GPUBuffer **gpu_drawobject_buffer_from_type(GPUDrawObject *gdo, GPUBuffer
return &gdo->colors;
case GPU_BUFFER_UV:
return &gdo->uv;
+ case GPU_BUFFER_UV_TEXPAINT:
+ return &gdo->uv;
case GPU_BUFFER_EDGE:
return &gdo->edges;
case GPU_BUFFER_UVEDGE:
@@ -977,6 +1041,8 @@ static int gpu_buffer_size_from_type(DerivedMesh *dm, GPUBufferType type)
return sizeof(char) * 3 * dm->drawObject->tot_triangle_point;
case GPU_BUFFER_UV:
return sizeof(float) * 2 * dm->drawObject->tot_triangle_point;
+ case GPU_BUFFER_UV_TEXPAINT:
+ return sizeof(float) * 4 * dm->drawObject->tot_triangle_point;
case GPU_BUFFER_EDGE:
return sizeof(int) * 2 * dm->drawObject->totedge;
case GPU_BUFFER_UVEDGE:
@@ -1005,7 +1071,7 @@ static GPUBuffer *gpu_buffer_setup_type(DerivedMesh *dm, GPUBufferType type)
if (!(user_data = DM_get_tessface_data_layer(dm, dm->drawObject->colType)))
return NULL;
}
- else if (type == GPU_BUFFER_UV) {
+ else if (ELEM(type, GPU_BUFFER_UV, GPU_BUFFER_UV_TEXPAINT)) {
if (!DM_get_tessface_data_layer(dm, CD_MTFACE))
return NULL;
}
@@ -1081,9 +1147,35 @@ void GPU_uv_setup(DerivedMesh *dm)
glTexCoordPointer(2, GL_FLOAT, 0, dm->drawObject->uv->pointer);
}
- GLStates |= GPU_BUFFER_TEXCOORD_STATE;
+ GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE;
+}
+
+void GPU_texpaint_uv_setup(DerivedMesh *dm)
+{
+ if (!gpu_buffer_setup_common(dm, GPU_BUFFER_UV_TEXPAINT))
+ return;
+
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ if (useVBOs) {
+ glBindBufferARB(GL_ARRAY_BUFFER_ARB, dm->drawObject->uv->id);
+ glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), 0);
+ glClientActiveTexture(GL_TEXTURE2);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), BUFFER_OFFSET(2 * sizeof(float)));
+ glClientActiveTexture(GL_TEXTURE0);
+ }
+ else {
+ glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), dm->drawObject->uv->pointer);
+ glClientActiveTexture(GL_TEXTURE2);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glTexCoordPointer(2, GL_FLOAT, 4 * sizeof(float), (char *)dm->drawObject->uv->pointer + 2 * sizeof(float));
+ glClientActiveTexture(GL_TEXTURE0);
+ }
+
+ GLStates |= GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE;
}
+
void GPU_color_setup(DerivedMesh *dm, int colType)
{
if (!dm->drawObject) {
@@ -1241,8 +1333,13 @@ void GPU_buffer_unbind(void)
glDisableClientState(GL_VERTEX_ARRAY);
if (GLStates & GPU_BUFFER_NORMAL_STATE)
glDisableClientState(GL_NORMAL_ARRAY);
- if (GLStates & GPU_BUFFER_TEXCOORD_STATE)
+ if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_0_STATE)
+ glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ if (GLStates & GPU_BUFFER_TEXCOORD_UNIT_2_STATE) {
+ glClientActiveTexture(GL_TEXTURE2);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+ glClientActiveTexture(GL_TEXTURE0);
+ }
if (GLStates & GPU_BUFFER_COLOR_STATE)
glDisableClientState(GL_COLOR_ARRAY);
if (GLStates & GPU_BUFFER_ELEMENT_STATE) {
@@ -1251,8 +1348,8 @@ void GPU_buffer_unbind(void)
}
}
GLStates &= ~(GPU_BUFFER_VERTEX_STATE | GPU_BUFFER_NORMAL_STATE |
- GPU_BUFFER_TEXCOORD_STATE | GPU_BUFFER_COLOR_STATE |
- GPU_BUFFER_ELEMENT_STATE);
+ GPU_BUFFER_TEXCOORD_UNIT_0_STATE | GPU_BUFFER_TEXCOORD_UNIT_2_STATE |
+ GPU_BUFFER_COLOR_STATE | GPU_BUFFER_ELEMENT_STATE);
for (i = 0; i < MAX_GPU_ATTRIB_DATA; i++) {
if (attribData[i].index != -1) {
@@ -2577,11 +2674,17 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces,
}
else if (buffers->use_bmesh) {
/* due to dynamc nature of dyntopo, only get first material */
- GSetIterator gs_iter;
- BMFace *f;
- BLI_gsetIterator_init(&gs_iter, bm_faces);
- f = BLI_gsetIterator_getKey(&gs_iter);
- GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color);
+ if (BLI_gset_size(bm_faces) > 0) {
+ GSetIterator gs_iter;
+ BMFace *f;
+
+ BLI_gsetIterator_init(&gs_iter, bm_faces);
+ f = BLI_gsetIterator_getKey(&gs_iter);
+ GPU_material_diffuse_get(f->mat_nr + 1, diffuse_color);
+ }
+ else {
+ return false;
+ }
}
else {
const DMFlagMat *flags = &buffers->grid_flag_mats[buffers->grid_indices[0]];
@@ -2589,9 +2692,7 @@ bool GPU_pbvh_buffers_diffuse_changed(GPU_PBVH_Buffers *buffers, GSet *bm_faces,
GPU_material_diffuse_get(flags->mat_nr + 1, diffuse_color);
}
- return diffuse_color[0] != buffers->diffuse_color[0] ||
- diffuse_color[1] != buffers->diffuse_color[1] ||
- diffuse_color[2] != buffers->diffuse_color[2];
+ return !equals_v3v3(diffuse_color, buffers->diffuse_color);
}
/* release a GPU_PBVH_Buffers id;
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index b3155f0ad50..4182f51561b 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -31,7 +31,7 @@
* Convert material node-trees to GLSL.
*/
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
@@ -97,7 +97,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
/* skip a variable/function name */
while (*str) {
- if (ELEM7(*str, ' ', '(', ')', ',', '\t', '\n', '\r'))
+ if (ELEM(*str, ' ', '(', ')', ',', '\t', '\n', '\r'))
break;
else {
if (token && len < max-1) {
@@ -115,7 +115,7 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
/* skip the next special characters:
* note the missing ')' */
while (*str) {
- if (ELEM6(*str, ' ', '(', ',', '\t', '\n', '\r'))
+ if (ELEM(*str, ' ', '(', ',', '\t', '\n', '\r'))
str++;
else
break;
@@ -242,12 +242,12 @@ GPUFunction *GPU_lookup_function(const char *name)
return (GPUFunction*)BLI_ghash_lookup(FUNCTION_HASH, (void *)name);
}
-void GPU_codegen_init(void)
+void gpu_codegen_init(void)
{
GPU_code_generate_glsl_lib();
}
-void GPU_codegen_exit(void)
+void gpu_codegen_exit(void)
{
extern Material defmaterial; // render module abuse...
@@ -665,7 +665,7 @@ static char *code_generate_vertex(ListBase *nodes)
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_ModelViewMatrix * vec4(att%d.xyz, 0)).xyz);\n", input->attribid, input->attribid);
+ BLI_dynstr_appendf(ds, "\tvar%d.xyz = normalize(gl_NormalMatrix * att%d.xyz);\n", input->attribid, input->attribid);
BLI_dynstr_appendf(ds, "\tvar%d.w = att%d.w;\n", input->attribid, input->attribid);
}
else
@@ -1410,6 +1410,10 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri
/* failed? */
if (!shader) {
+ if (fragmentcode)
+ MEM_freeN(fragmentcode);
+ if (vertexcode)
+ MEM_freeN(vertexcode);
memset(attribs, 0, sizeof(*attribs));
memset(builtins, 0, sizeof(*builtins));
GPU_nodes_free(nodes);
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index b6db923e5c2..69213925931 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -35,7 +35,7 @@
#include "DNA_listBase.h"
#include "GPU_material.h"
-#include "GL/glew.h"
+#include "GPU_glew.h"
struct ListBase;
struct GPUShader;
@@ -106,7 +106,7 @@ struct GPUNodeLink {
int type;
int users;
- GPUTexture *dynamictex;
+ struct GPUTexture *dynamictex;
GPUBuiltin builtin;
GPUOpenGLBuiltin oglbuiltin;
@@ -146,7 +146,7 @@ typedef struct GPUInput {
float *dynamicvec; /* vector data in case it is dynamic */
int dynamictype; /* origin of the dynamic uniform (GPUDynamicType) */
void *dynamicdata; /* data source of the dynamic uniform */
- GPUTexture *tex; /* input texture, only set at runtime */
+ struct GPUTexture *tex; /* input texture, only set at runtime */
int shaderloc; /* id from opengl */
char shadername[32]; /* name in shader */
@@ -185,8 +185,8 @@ void GPU_pass_unbind(GPUPass *pass);
void GPU_pass_free(GPUPass *pass);
-void GPU_codegen_init(void);
-void GPU_codegen_exit(void);
+void gpu_codegen_init(void);
+void gpu_codegen_exit(void);
/* Material calls */
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 1845de16780..622e7b5ce9e 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -38,7 +38,7 @@
#include <string.h>
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "BLI_blenlib.h"
#include "BLI_linklist.h"
@@ -76,6 +76,8 @@
#include "GPU_extensions.h"
#include "GPU_material.h"
+#include "PIL_time.h"
+
#include "smoke_API.h"
extern Material defmaterial; /* from material.c */
@@ -368,9 +370,9 @@ static void gpu_make_repbind(Image *ima)
BKE_image_release_ibuf(ima, ibuf, NULL);
}
-static void gpu_clear_tpage(void)
+void GPU_clear_tpage(bool force)
{
- if (GTS.lasttface==NULL)
+ if (GTS.lasttface==NULL && !force)
return;
GTS.lasttface= NULL;
@@ -528,12 +530,16 @@ int GPU_verify_image(Image *ima, ImageUser *iuser, int tftile, bool compare, boo
* a high precision format only if it is available */
use_high_bit_depth = true;
}
+ /* we may skip this in high precision, but if not, we need to have a valid buffer here */
+ else if (ibuf->userflags & IB_RECT_INVALID) {
+ IMB_rect_from_float(ibuf);
+ }
/* TODO unneeded when float images are correctly treated as linear always */
if (!is_data)
do_color_management = true;
- if (ibuf->rect==NULL)
+ if (ibuf->rect == NULL)
IMB_rect_from_float(ibuf);
}
@@ -864,7 +870,7 @@ int GPU_set_tpage(MTFace *tface, int mipmap, int alphablend)
/* check if we need to clear the state */
if (tface==NULL) {
- gpu_clear_tpage();
+ GPU_clear_tpage(false);
return 0;
}
@@ -1033,21 +1039,14 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h)
* which is much quicker for painting */
GLint row_length, skip_pixels, skip_rows;
- glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
- glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
- glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows);
-
/* if color correction is needed, we must update the part that needs updating. */
if (ibuf->rect_float) {
- float *buffer = MEM_mallocN(w*h*sizeof(float)*4, "temp_texpaint_float_buf");
+ float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf");
bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0;
IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
-
+
if (GPU_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
MEM_freeN(buffer);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
- glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
- glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
@@ -1072,15 +1071,16 @@ void GPU_paint_update_image(Image *ima, int x, int y, int w, int h)
}
if (GPU_check_scaled_image(ibuf, ima, NULL, x, y, w, h)) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
- glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
- glPixelStorei(GL_UNPACK_SKIP_ROWS, skip_rows);
BKE_image_release_ibuf(ima, ibuf, NULL);
return;
}
glBindTexture(GL_TEXTURE_2D, ima->bindcode);
+ glGetIntegerv(GL_UNPACK_ROW_LENGTH, &row_length);
+ glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
+ glGetIntegerv(GL_UNPACK_SKIP_ROWS, &skip_rows);
+
glPixelStorei(GL_UNPACK_ROW_LENGTH, ibuf->x);
glPixelStorei(GL_UNPACK_SKIP_PIXELS, x);
glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
@@ -1311,6 +1311,45 @@ void GPU_free_images_anim(void)
GPU_free_image(ima);
}
+
+void GPU_free_images_old(void)
+{
+ Image *ima;
+ static int lasttime = 0;
+ int ctime = (int)PIL_check_seconds_timer();
+
+ /*
+ * Run garbage collector once for every collecting period of time
+ * if textimeout is 0, that's the option to NOT run the collector
+ */
+ if (U.textimeout == 0 || ctime % U.texcollectrate || ctime == lasttime)
+ return;
+
+ /* of course not! */
+ if (G.is_rendering)
+ return;
+
+ lasttime = ctime;
+
+ ima = G.main->image.first;
+ while (ima) {
+ if ((ima->flag & IMA_NOCOLLECT) == 0 && ctime - ima->lastused > U.textimeout) {
+ /* If it's in GL memory, deallocate and set time tag to current time
+ * This gives textures a "second chance" to be used before dying. */
+ if (ima->bindcode || ima->repbind) {
+ GPU_free_image(ima);
+ ima->lastused = ctime;
+ }
+ /* Otherwise, just kill the buffers */
+ else {
+ BKE_image_free_buffers(ima);
+ }
+ }
+ ima = ima->id.next;
+ }
+}
+
+
/* OpenGL Materials */
#define FIXEDMAT 8
@@ -1334,6 +1373,7 @@ static struct GPUMaterialState {
Object *gob;
Scene *gscene;
int glay;
+ bool gscenelock;
float (*gviewmat)[4];
float (*gviewinv)[4];
@@ -1422,6 +1462,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
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.gscenelock = (v3d->scenelock != 0);
GMS.gviewmat= rv3d->viewmat;
GMS.gviewinv= rv3d->viewinv;
@@ -1505,7 +1546,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
/* setting 'do_alpha_after = true' indicates this object needs to be
* drawn in a second alpha pass for improved blending */
if (do_alpha_after && !GMS.is_alpha_pass)
- if (ELEM3(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT))
+ if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ADD, GPU_BLEND_ALPHA_SORT))
*do_alpha_after = true;
GMS.alphablend[a]= alphablend;
@@ -1582,7 +1623,7 @@ int GPU_enable_material(int nr, void *attribs)
gpumat = GPU_material_from_blender(GMS.gscene, mat);
GPU_material_vertex_attributes(gpumat, gattribs);
- GPU_material_bind(gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), GMS.gviewmat, GMS.gviewinv);
+ GPU_material_bind(gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), GMS.gviewmat, GMS.gviewinv, GMS.gscenelock);
auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gob->col, auto_bump_scale);
@@ -1837,6 +1878,37 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][
return count;
}
+static void gpu_multisample(bool enable)
+{
+ if (GLEW_VERSION_1_3 || GLEW_ARB_multisample) {
+#ifdef __linux__
+ /* changing multisample from the default (enabled) causes problems on some
+ * systems (NVIDIA/Linux) when the pixel format doesn't have a multisample buffer */
+ bool toggle_ok = true;
+
+ if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
+ int samples = 0;
+ glGetIntegerv(GL_SAMPLES, &samples);
+
+ if (samples == 0)
+ toggle_ok = false;
+ }
+
+ if (toggle_ok) {
+ if (enable)
+ glEnable(GL_MULTISAMPLE);
+ else
+ glDisable(GL_MULTISAMPLE);
+ }
+#else
+ if (enable)
+ glEnable(GL_MULTISAMPLE);
+ else
+ glDisable(GL_MULTISAMPLE);
+#endif
+ }
+}
+
/* Default OpenGL State */
void GPU_state_init(void)
@@ -1909,9 +1981,7 @@ void GPU_state_init(void)
glCullFace(GL_BACK);
glDisable(GL_CULL_FACE);
- /* calling this makes drawing very slow when AA is not set up in ghost
- * on Linux/NVIDIA. */
- // glDisable(GL_MULTISAMPLE);
+ gpu_multisample(false);
}
#ifdef DEBUG
diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c
index cd256a570d0..04f8e68431a 100644
--- a/source/blender/gpu/intern/gpu_extensions.c
+++ b/source/blender/gpu/intern/gpu_extensions.c
@@ -33,7 +33,7 @@
*/
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "DNA_image_types.h"
@@ -48,7 +48,9 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_simple_shader.h"
-#include "gpu_codegen.h"
+
+#include "intern/gpu_codegen.h"
+#include "intern/gpu_extensions_private.h"
#include <stdlib.h>
#include <stdio.h>
@@ -58,6 +60,8 @@
# include "BLI_winstuff.h"
#endif
+#define MAX_DEFINE_LENGTH 72
+
/* Extensions support */
/* extensions used:
@@ -94,6 +98,9 @@ static struct GPUGlobal {
GPUOSType os;
GPUDriverType driver;
GPUShaders shaders;
+ GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */
+ GPUTexture *invalid_tex_2D;
+ GPUTexture *invalid_tex_3D;
} GG = {1, 0};
/* GPU Types */
@@ -105,8 +112,6 @@ int GPU_type_matches(GPUDeviceType device, GPUOSType os, GPUDriverType driver)
/* GPU Extensions */
-static int gpu_extensions_init = 0;
-
void GPU_extensions_disable(void)
{
GG.extdisabled = 1;
@@ -117,18 +122,11 @@ int GPU_max_texture_size(void)
return GG.maxtexsize;
}
-void GPU_extensions_init(void)
+void gpu_extensions_init(void)
{
GLint r, g, b;
const char *vendor, *renderer;
- /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */
- if (gpu_extensions_init) return;
- gpu_extensions_init= 1;
-
- glewInit();
- GPU_codegen_init();
-
/* glewIsSupported("GL_VERSION_2_0") */
if (GLEW_ARB_multitexture)
@@ -223,14 +221,15 @@ void GPU_extensions_init(void)
GG.os = GPU_OS_UNIX;
#endif
+
+ GPU_invalid_tex_init();
GPU_simple_shaders_init();
}
-void GPU_extensions_exit(void)
+void gpu_extensions_exit(void)
{
- gpu_extensions_init = 0;
- GPU_codegen_exit();
GPU_simple_shaders_exit();
+ GPU_invalid_tex_free();
}
int GPU_glsl_support(void)
@@ -572,11 +571,6 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data,
return ima->gputexture;
}
- if (!bindcode) {
- glBindTexture(GL_TEXTURE_2D, lastbindcode);
- return NULL;
- }
-
tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->bindcode = bindcode;
tex->number = -1;
@@ -587,7 +581,7 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, bool is_data,
ima->gputexture= tex;
if (!glIsTexture(tex->bindcode)) {
- GPU_print_error("Blender Texture");
+ GPU_print_error("Blender Texture Not Loaded");
}
else {
glBindTexture(GL_TEXTURE_2D, tex->bindcode);
@@ -625,12 +619,6 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
return tex;
}
- /* error binding anything */
- if (!bindcode) {
- glBindTexture(GL_TEXTURE_2D, lastbindcode);
- return NULL;
- }
-
tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture");
tex->bindcode = bindcode;
tex->number = -1;
@@ -640,7 +628,7 @@ GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap)
prv->gputexture[0]= tex;
if (!glIsTexture(tex->bindcode)) {
- GPU_print_error("Blender Texture");
+ GPU_print_error("Blender Texture Not Loaded");
}
else {
glBindTexture(GL_TEXTURE_2D, tex->bindcode);
@@ -706,6 +694,40 @@ GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256])
return tex;
}
+void GPU_invalid_tex_init(void)
+{
+ float color[4] = {1.0f, 0.0f, 1.0f, 1.0};
+ GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL);
+ GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, NULL);
+ GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color);
+}
+
+void GPU_invalid_tex_bind(int mode)
+{
+ switch (mode) {
+ case GL_TEXTURE_1D:
+ glBindTexture(GL_TEXTURE_1D, GG.invalid_tex_1D->bindcode);
+ break;
+ case GL_TEXTURE_2D:
+ glBindTexture(GL_TEXTURE_2D, GG.invalid_tex_2D->bindcode);
+ break;
+ case GL_TEXTURE_3D:
+ glBindTexture(GL_TEXTURE_3D, GG.invalid_tex_3D->bindcode);
+ break;
+ }
+}
+
+void GPU_invalid_tex_free(void)
+{
+ if (GG.invalid_tex_1D)
+ GPU_texture_free(GG.invalid_tex_1D);
+ if (GG.invalid_tex_2D)
+ GPU_texture_free(GG.invalid_tex_2D);
+ if (GG.invalid_tex_3D)
+ GPU_texture_free(GG.invalid_tex_3D);
+}
+
+
void GPU_texture_bind(GPUTexture *tex, int number)
{
GLenum arbnumber;
@@ -722,7 +744,11 @@ void GPU_texture_bind(GPUTexture *tex, int number)
arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + number);
if (number != 0) glActiveTextureARB(arbnumber);
- glBindTexture(tex->target, tex->bindcode);
+ if (tex->bindcode != 0) {
+ glBindTexture(tex->target, tex->bindcode);
+ }
+ else
+ GPU_invalid_tex_bind(tex->target);
glEnable(tex->target);
if (number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
@@ -845,6 +871,9 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, char err
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
GG.currentfb = fb->object;
+ /* Clean glError buffer. */
+ while (glGetError() != GL_NO_ERROR) {}
+
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment,
tex->target, tex->bindcode, 0);
@@ -1135,51 +1164,72 @@ struct GPUShader {
int totattrib; /* total number of attributes */
};
-static void shader_print_errors(const char *task, char *log, const char *code)
+static void shader_print_errors(const char *task, char *log, const char **code, int totcode)
{
- const char *c, *pos, *end = code + strlen(code);
- int line = 1;
+ int i;
fprintf(stderr, "GPUShader: %s error:\n", task);
- if (G.debug & G_DEBUG) {
- c = code;
- while ((c < end) && (pos = strchr(c, '\n'))) {
- fprintf(stderr, "%2d ", line);
- fwrite(c, (pos+1)-c, 1, stderr);
- c = pos+1;
- line++;
+ 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);
+
+ c = code[i];
+ while ((c < end) && (pos = strchr(c, '\n'))) {
+ fprintf(stderr, "%2d ", line);
+ fwrite(c, (pos+1)-c, 1, stderr);
+ c = pos+1;
+ line++;
+ }
+
+ fprintf(stderr, "%s", c);
}
+ }
+
+ fprintf(stderr, "%s\n", log);
+}
- fprintf(stderr, "%s", c);
+static const char *gpu_shader_version(void)
+{
+ /* turn on glsl 1.30 for bicubic bump mapping and ATI clipping support */
+ if (GLEW_VERSION_3_0 &&
+ (GPU_bicubic_bump_support() || GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)))
+ {
+ return "#version 130\n";
}
- fprintf(stderr, "%s\n", log);
+ return "";
}
+
static const char *gpu_shader_standard_extensions(void)
{
/* need this extensions for high quality bump mapping */
- if (GPU_bicubic_bump_support()) {
- return "#version 130\n"
- "#extension GL_ARB_texture_query_lod: enable\n"
- "#define BUMP_BICUBIC\n";
- }
+ if (GPU_bicubic_bump_support())
+ return "#extension GL_ARB_texture_query_lod: enable\n";
return "";
}
-static const char *gpu_shader_standard_defines(void)
+static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH])
{
/* some useful defines to detect GPU type */
- if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY))
- return "#define GPU_ATI\n";
+ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+ strcat(defines, "#define GPU_ATI\n");
+ if (GLEW_VERSION_3_0)
+ strcat(defines, "#define CLIP_WORKAROUND\n");
+ }
else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY))
- return "#define GPU_NVIDIA\n";
+ strcat(defines, "#define GPU_NVIDIA\n");
else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY))
- return "#define GPU_INTEL\n";
-
- return "";
+ strcat(defines, "#define GPU_INTEL\n");
+
+ if (GPU_bicubic_bump_support())
+ strcat(defines, "#define BUMP_BICUBIC\n");
+ return;
}
GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const char *libcode, const char *defines)
@@ -1188,6 +1238,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
GLcharARB log[5000];
GLsizei length = 0;
GPUShader *shader;
+ char standard_defines[MAX_DEFINE_LENGTH] = "";
if (!GLEW_ARB_vertex_shader || !GLEW_ARB_fragment_shader)
return NULL;
@@ -1209,12 +1260,16 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
return NULL;
}
+ gpu_shader_standard_defines(standard_defines);
+
if (vertexcode) {
- const char *source[4];
+ const char *source[5];
+ /* custom limit, may be too small, beware */
int num_source = 0;
+ source[num_source++] = gpu_shader_version();
source[num_source++] = gpu_shader_standard_extensions();
- source[num_source++] = gpu_shader_standard_defines();
+ source[num_source++] = standard_defines;
if (defines) source[num_source++] = defines;
if (vertexcode) source[num_source++] = vertexcode;
@@ -1227,7 +1282,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
if (!status) {
glGetInfoLogARB(shader->vertex, sizeof(log), &length, log);
- shader_print_errors("compile", log, vertexcode);
+ shader_print_errors("compile", log, source, num_source);
GPU_shader_free(shader);
return NULL;
@@ -1235,11 +1290,12 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
}
if (fragcode) {
- const char *source[5];
+ const char *source[6];
int num_source = 0;
+ source[num_source++] = gpu_shader_version();
source[num_source++] = gpu_shader_standard_extensions();
- source[num_source++] = gpu_shader_standard_defines();
+ source[num_source++] = standard_defines;
if (defines) source[num_source++] = defines;
if (libcode) source[num_source++] = libcode;
@@ -1253,7 +1309,7 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
if (!status) {
glGetInfoLogARB(shader->fragment, sizeof(log), &length, log);
- shader_print_errors("compile", log, fragcode);
+ shader_print_errors("compile", log, source, num_source);
GPU_shader_free(shader);
return NULL;
@@ -1269,9 +1325,9 @@ GPUShader *GPU_shader_create(const char *vertexcode, const char *fragcode, const
glGetObjectParameterivARB(shader->object, GL_OBJECT_LINK_STATUS_ARB, &status);
if (!status) {
glGetInfoLogARB(shader->object, sizeof(log), &length, log);
- if (fragcode) shader_print_errors("linking", log, fragcode);
- else if (vertexcode) shader_print_errors("linking", log, vertexcode);
- else if (libcode) shader_print_errors("linking", log, libcode);
+ 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);
GPU_shader_free(shader);
return NULL;
@@ -1397,7 +1453,10 @@ void GPU_shader_uniform_texture(GPUShader *UNUSED(shader), int location, GPUText
arbnumber = (GLenum)((GLuint)GL_TEXTURE0_ARB + tex->number);
if (tex->number != 0) glActiveTextureARB(arbnumber);
- glBindTexture(tex->target, tex->bindcode);
+ if (tex->bindcode != 0)
+ glBindTexture(tex->target, tex->bindcode);
+ else
+ GPU_invalid_tex_bind(tex->target);
glUniform1iARB(location, tex->number);
glEnable(tex->target);
if (tex->number != 0) glActiveTextureARB(GL_TEXTURE0_ARB);
diff --git a/source/blender/gpu/intern/gpu_extensions_private.h b/source/blender/gpu/intern/gpu_extensions_private.h
new file mode 100644
index 00000000000..a4124b8fa3d
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_extensions_private.h
@@ -0,0 +1,32 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file gpu_extensions_private.h
+ * \ingroup gpu
+ */
+
+#ifndef __GPU_EXTENSIONS_PRIVATE_H__
+#define __GPU_EXTENSIONS_PRIVATE_H__
+
+/* call this before running any of the functions below */
+void gpu_extensions_init(void);
+void gpu_extensions_exit(void);
+
+#endif /* __GPU_EXTENSIONS_PRIVATE_H__ */
diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c
new file mode 100644
index 00000000000..912774cd345
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_init_exit.c
@@ -0,0 +1,68 @@
+/*
+ * ***** 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): Jason Wilkins
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file source/blender/gpu/intern/gpu_init_exit.c
+ * \ingroup gpu
+ */
+
+#include "BLI_sys_types.h"
+#include "GPU_init_exit.h" /* interface */
+#include "GPU_extensions.h" /* library */
+
+#include "intern/gpu_codegen.h"
+#include "intern/gpu_extensions_private.h"
+
+/**
+ * although the order of initialization and shutdown should not matter
+ * (except for the extensions), I chose alphabetical and reverse alphabetical order
+ */
+
+static bool initialized = false;
+
+void GPU_init(void)
+{
+ /* can't avoid calling this multiple times, see wm_window_add_ghostwindow */
+ if (initialized)
+ return;
+
+ initialized = true;
+
+ gpu_extensions_init(); /* must come first */
+
+ gpu_codegen_init();
+}
+
+
+
+void GPU_exit(void)
+{
+ gpu_codegen_exit();
+
+ gpu_extensions_exit(); /* must come last */
+
+ initialized = false;
+}
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 4b070a4568a..32d7e04aeea 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -35,8 +35,6 @@
#include <math.h>
#include <string.h>
-#include "GL/glew.h"
-
#include "MEM_guardedalloc.h"
#include "DNA_lamp_types.h"
@@ -270,13 +268,13 @@ bool GPU_lamp_override_visible(GPULamp *lamp, SceneRenderLayer *srl, Material *m
return true;
}
-void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4])
+void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], bool scenelock)
{
if (material->pass) {
LinkData *nlink;
GPULamp *lamp;
GPUShader *shader = GPU_pass_shader(material->pass);
- SceneRenderLayer *srl = BLI_findlink(&material->scene->r.layers, material->scene->r.actlay);
+ SceneRenderLayer *srl = scenelock ? BLI_findlink(&material->scene->r.layers, material->scene->r.actlay) : NULL;
if (srl)
viewlay &= srl->lay;
@@ -417,6 +415,11 @@ bool GPU_material_do_color_management(GPUMaterial *mat)
return !((mat->scene->gm.flag & GAME_GLSL_NO_COLOR_MANAGEMENT));
}
+bool GPU_material_use_new_shading_nodes(GPUMaterial *mat)
+{
+ return BKE_scene_use_new_shading_nodes(mat->scene);
+}
+
static GPUNodeLink *lamp_get_visibility(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **lv, GPUNodeLink **dist)
{
GPUNodeLink *visifac, *inpr;
@@ -734,8 +737,9 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
i = is;
GPU_link(mat, "shade_visifac", i, visifac, shi->refl, &i);
- GPU_link(mat, "set_value", GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), &lcol);
+ GPU_link(mat, "set_rgb", GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob), &lcol);
shade_light_textures(mat, lamp, &lcol);
+ GPU_link(mat, "shade_mul_value_v3", GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), lcol, &lcol);
#if 0
if (ma->mode & MA_TANGENT_VN)
@@ -765,20 +769,18 @@ static void shade_one_light(GPUShadeInput *shi, GPUShadeResult *shr, GPULamp *la
}
if (lamp->mode & LA_ONLYSHADOW) {
- GPUNodeLink *rgb;
+ GPUNodeLink *shadrgb;
GPU_link(mat, "shade_only_shadow", i, shadfac,
- GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob), &shadfac);
-
- GPU_link(mat, "shade_mul", shi->rgb, GPU_uniform(lamp->shadow_color), &rgb);
- GPU_link(mat, "mtex_rgb_invert", rgb, &rgb);
+ GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, lamp->ob),
+ GPU_uniform(lamp->shadow_color), &shadrgb);
if (!(lamp->mode & LA_NO_DIFF)) {
- GPU_link(mat, "shade_only_shadow_diffuse", shadfac, rgb,
+ GPU_link(mat, "shade_only_shadow_diffuse", shadrgb, shi->rgb,
shr->diff, &shr->diff);
}
if (!(lamp->mode & LA_NO_SPEC))
- GPU_link(mat, "shade_only_shadow_specular", shadfac, shi->specrgb,
+ GPU_link(mat, "shade_only_shadow_specular", shadrgb, shi->specrgb,
shr->spec, &shr->spec);
add_user_list(&mat->lamps, lamp);
@@ -890,6 +892,10 @@ static void material_lights(GPUShadeInput *shi, GPUShadeResult *shr)
free_object_duplilist(lb);
}
}
+
+ /* prevent only shadow lamps from producing negative colors.*/
+ GPU_link(shi->gpumat, "shade_clamp_positive", shr->spec, &shr->spec);
+ GPU_link(shi->gpumat, "shade_clamp_positive", shr->diff, &shr->diff);
}
static void texture_rgb_blend(GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *out, GPUNodeLink *fact, GPUNodeLink *facg, int blendtype, GPUNodeLink **in)
@@ -937,6 +943,12 @@ static void texture_rgb_blend(GPUMaterial *mat, GPUNodeLink *tex, GPUNodeLink *o
case MTEX_BLEND_COLOR:
GPU_link(mat, "mtex_rgb_color", out, tex, fact, facg, in);
break;
+ case MTEX_SOFT_LIGHT:
+ GPU_link(mat, "mtex_rgb_soft", out, tex, fact, facg, in);
+ break;
+ case MTEX_LIN_LIGHT:
+ GPU_link(mat, "mtex_rgb_linear", out, tex, fact, facg, in);
+ break;
default:
GPU_link(mat, "set_rgb_zero", &in);
break;
@@ -1157,7 +1169,7 @@ static void do_material_tex(GPUShadeInput *shi)
}
else if (mtex->normapspace == MTEX_NSPACE_OBJECT) {
/* transform normal by object then view matrix */
- GPU_link(mat, "mtex_nspace_object", GPU_builtin(GPU_VIEW_MATRIX), GPU_builtin(GPU_OBJECT_MATRIX), tnor, &newnor);
+ GPU_link(mat, "mtex_nspace_object", tnor, &newnor);
}
else if (mtex->normapspace == MTEX_NSPACE_WORLD) {
/* transform normal by view matrix */
@@ -1665,6 +1677,23 @@ void GPU_materials_free(void)
/* Lamps and shadow buffers */
+static void gpu_lamp_calc_winmat(GPULamp *lamp)
+{
+ float temp, angle, pixsize, wsize;
+
+ if (lamp->type == LA_SUN) {
+ wsize = lamp->la->shadow_frustum_size;
+ orthographic_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
+ }
+ else {
+ angle= saacos(lamp->spotsi);
+ temp= 0.5f*lamp->size*cosf(angle)/sinf(angle);
+ pixsize= (lamp->d)/temp;
+ wsize= pixsize*0.5f*lamp->size;
+ perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
+ }
+}
+
void GPU_lamp_update(GPULamp *lamp, int lay, int hide, float obmat[4][4])
{
float mat[4][4];
@@ -1686,9 +1715,9 @@ void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float ener
lamp->energy = energy;
if (lamp->mode & LA_NEG) lamp->energy= -lamp->energy;
- lamp->col[0]= r* lamp->energy;
- lamp->col[1]= g* lamp->energy;
- lamp->col[2]= b* lamp->energy;
+ 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)
@@ -1702,12 +1731,12 @@ void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend)
{
lamp->spotsi = cosf(spotsize * 0.5f);
lamp->spotbl = (1.0f - lamp->spotsi) * spotblend;
+
+ gpu_lamp_calc_winmat(lamp);
}
static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *la, GPULamp *lamp)
{
- float temp, angle, pixsize, wsize;
-
lamp->scene = scene;
lamp->ob = ob;
lamp->par = par;
@@ -1720,9 +1749,9 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
lamp->energy = la->energy;
if (lamp->mode & LA_NEG) lamp->energy= -lamp->energy;
- lamp->col[0]= la->r*lamp->energy;
- lamp->col[1]= la->g*lamp->energy;
- lamp->col[2]= la->b*lamp->energy;
+ 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);
@@ -1750,17 +1779,7 @@ static void gpu_lamp_from_blender(Scene *scene, Object *ob, Object *par, Lamp *l
lamp->bias *= 0.25f;
/* makeshadowbuf */
- if (lamp->type == LA_SUN) {
- wsize = la->shadow_frustum_size;
- orthographic_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
- }
- else {
- angle= saacos(lamp->spotsi);
- temp= 0.5f*lamp->size*cosf(angle)/sinf(angle);
- pixsize= (lamp->d)/temp;
- wsize= pixsize*0.5f*lamp->size;
- perspective_m4(lamp->winmat, -wsize, wsize, -wsize, wsize, lamp->d, lamp->clipend);
- }
+ gpu_lamp_calc_winmat(lamp);
}
static void gpu_lamp_shadow_free(GPULamp *lamp)
@@ -1995,6 +2014,7 @@ GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **co
*col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob);
visifac = lamp_get_visibility(mat, lamp, lv, dist);
+ /* looks like it's not used? psy-fi */
shade_light_textures(mat, lamp, col);
if (GPU_lamp_has_shadow_buffer(lamp)) {
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
new file mode 100644
index 00000000000..afd6af9efae
--- /dev/null
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -0,0 +1,245 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Antony Riakiotakis.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/gpu/intern/gpu_select.c
+ * \ingroup gpu
+ *
+ * Interface for accessing gpu-related methods for selection. The semantics will be
+ * similar to glRenderMode(GL_SELECT) since the goal is to maintain compatibility.
+ */
+#include "GPU_select.h"
+#include "GPU_extensions.h"
+#include "GPU_glew.h"
+
+#include "BLI_utildefines.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_userdef_types.h"
+
+/* Ad hoc number of queries to allocate to skip doing many glGenQueries */
+#define ALLOC_QUERIES 200
+
+typedef struct GPUQueryState {
+ /* To ignore selection id calls when not initialized */
+ bool select_is_active;
+ /* Tracks whether a query has been issued so that gpu_load_id can end the previous one */
+ bool query_issued;
+ /* array holding the OpenGL query identifiers */
+ unsigned int *queries;
+ /* array holding the id corresponding to each query */
+ unsigned int *id;
+ /* number of queries in *queries and *id */
+ unsigned int num_of_queries;
+ /* index to the next query to start */
+ unsigned int active_query;
+ /* flag to cache user preference for occlusion based selection */
+ bool use_gpu_select;
+ /* cache on initialization */
+ unsigned int *buffer;
+ unsigned int bufsize;
+ /* mode of operation */
+ char mode;
+ unsigned int index;
+ int oldhits;
+} GPUQueryState;
+
+static GPUQueryState g_query_state = {0};
+
+void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, char mode, int oldhits)
+{
+ g_query_state.select_is_active = true;
+ g_query_state.query_issued = false;
+ g_query_state.active_query = 0;
+ g_query_state.use_gpu_select = GPU_select_query_check_active();
+ g_query_state.num_of_queries = 0;
+ g_query_state.bufsize = bufsize;
+ g_query_state.buffer = buffer;
+ g_query_state.mode = mode;
+ g_query_state.index = 0;
+ g_query_state.oldhits = oldhits;
+
+ if (!g_query_state.use_gpu_select) {
+ glSelectBuffer( bufsize, (GLuint *)buffer);
+ glRenderMode(GL_SELECT);
+ glInitNames();
+ glPushName(-1);
+ }
+ else {
+ float viewport[4];
+
+ g_query_state.num_of_queries = ALLOC_QUERIES;
+
+ g_query_state.queries = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.queries) , "gpu selection queries");
+ g_query_state.id = MEM_mallocN(g_query_state.num_of_queries * sizeof(*g_query_state.id) , "gpu selection ids");
+ glGenQueriesARB(g_query_state.num_of_queries, g_query_state.queries);
+
+ glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_VIEWPORT_BIT);
+ /* disable writing to the framebuffer */
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+
+ /* In order to save some fill rate we minimize the viewport using rect.
+ * We need to get the region of the scissor so that our geometry doesn't
+ * get rejected before the depth test. Should probably cull rect against
+ * scissor for viewport but this is a rare case I think */
+ glGetFloatv(GL_SCISSOR_BOX, viewport);
+ if (!input || input->xmin == input->xmax) {
+ glViewport(viewport[0], viewport[1], 24, 24);
+ }
+ else {
+ glViewport(viewport[0], viewport[1], (int)(input->xmax - input->xmin), (int)(input->ymax - input->ymin));
+ }
+
+ /* occlusion queries operates on fragments that pass tests and since we are interested on all
+ * objects in the view frustum independently of their order, we need to disable the depth test */
+ if (mode == GPU_SELECT_ALL) {
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ }
+ else if (mode == GPU_SELECT_NEAREST_FIRST_PASS) {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_TRUE);
+ glDepthFunc(GL_LEQUAL);
+ }
+ else if (mode == GPU_SELECT_NEAREST_SECOND_PASS) {
+ glEnable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_EQUAL);
+ }
+ }
+}
+
+bool GPU_select_load_id(unsigned int id)
+{
+ /* if no selection mode active, ignore */
+ if(!g_query_state.select_is_active)
+ return true;
+
+ if (!g_query_state.use_gpu_select) {
+ glLoadName(id);
+ }
+ else {
+ if (g_query_state.query_issued) {
+ glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+ }
+ /* if required, allocate extra queries */
+ if (g_query_state.active_query == g_query_state.num_of_queries) {
+ g_query_state.num_of_queries += ALLOC_QUERIES;
+ g_query_state.queries = MEM_reallocN(g_query_state.queries, g_query_state.num_of_queries * sizeof(*g_query_state.queries));
+ g_query_state.id = MEM_reallocN(g_query_state.id, g_query_state.num_of_queries * sizeof(*g_query_state.id));
+ glGenQueriesARB(ALLOC_QUERIES, &g_query_state.queries[g_query_state.active_query]);
+ }
+
+ glBeginQueryARB(GL_SAMPLES_PASSED_ARB, g_query_state.queries[g_query_state.active_query]);
+ g_query_state.id[g_query_state.active_query] = id;
+ g_query_state.active_query++;
+ g_query_state.query_issued = true;
+
+ if (g_query_state.mode == GPU_SELECT_NEAREST_SECOND_PASS) {
+ if (g_query_state.buffer[g_query_state.index * 4 + 3] == id) {
+ g_query_state.index++;
+ return true;
+ }
+ else {
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+unsigned int GPU_select_end(void)
+{
+ unsigned int hits = 0;
+ if (!g_query_state.use_gpu_select) {
+ glPopName();
+ hits = glRenderMode(GL_RENDER);
+ }
+ else {
+ int i;
+
+ if (g_query_state.query_issued) {
+ glEndQueryARB(GL_SAMPLES_PASSED_ARB);
+ }
+
+ for (i = 0; i < g_query_state.active_query; i++) {
+ unsigned int result;
+ glGetQueryObjectuivARB(g_query_state.queries[i], GL_QUERY_RESULT_ARB, &result);
+ if (result > 0) {
+ if (g_query_state.mode != GPU_SELECT_NEAREST_SECOND_PASS) {
+ if(hits < g_query_state.bufsize) {
+ g_query_state.buffer[hits * 4] = 1;
+ g_query_state.buffer[hits * 4 + 1] = 0xFFFF;
+ g_query_state.buffer[hits * 4 + 2] = 0xFFFF;
+ g_query_state.buffer[hits * 4 + 3] = g_query_state.id[i];
+
+ hits++;
+ }
+ else {
+ hits = -1;
+ break;
+ }
+ }
+ else {
+ int j;
+ /* search in buffer and make selected object first */
+ for (j = 0; j < g_query_state.oldhits; j++) {
+ if (g_query_state.buffer[j * 4 + 3] == g_query_state.id[i]) {
+ g_query_state.buffer[j * 4 + 1] = 0;
+ g_query_state.buffer[j * 4 + 2] = 0;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ glDeleteQueriesARB(g_query_state.num_of_queries, g_query_state.queries);
+ MEM_freeN(g_query_state.queries);
+ MEM_freeN(g_query_state.id);
+ glPopAttrib();
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ }
+
+ g_query_state.select_is_active = false;
+
+ return hits;
+}
+
+
+bool GPU_select_query_check_support(void)
+{
+ return GLEW_ARB_occlusion_query;
+}
+
+
+bool GPU_select_query_check_active(void)
+{
+ return GLEW_ARB_occlusion_query &&
+ ((U.gpu_select_method == USER_SELECT_USE_OCCLUSION_QUERY) ||
+ ((U.gpu_select_method == USER_SELECT_AUTO) && GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)));
+}
diff --git a/source/blender/gpu/intern/gpu_simple_shader.c b/source/blender/gpu/intern/gpu_simple_shader.c
index 0cb712d220f..c0d7ebd4abb 100644
--- a/source/blender/gpu/intern/gpu_simple_shader.c
+++ b/source/blender/gpu/intern/gpu_simple_shader.c
@@ -42,7 +42,7 @@
* - Optimize for case where no texture matrix is used.
*/
-#include "GL/glew.h"
+#include "GPU_glew.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index a224f8e979a..5a0812cb367 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -752,6 +752,18 @@ void combine_rgb(float r, float g, float b, out vec4 col)
col = vec4(r, g, b, 1.0);
}
+void separate_xyz(vec3 vec, out float x, out float y, out float z)
+{
+ x = vec.r;
+ y = vec.g;
+ z = vec.b;
+}
+
+void combine_xyz(float x, float y, float z, out vec3 vec)
+{
+ vec = vec3(x, y, z);
+}
+
void separate_hsv(vec4 col, out float h, out float s, out float v)
{
vec4 hsv;
@@ -1000,6 +1012,38 @@ void mtex_rgb_color(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 i
incol.rgb = col.rgb;
}
+void mtex_rgb_soft(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
+{
+ float facm;
+
+ fact *= facg;
+ facm = 1.0-fact;
+
+ vec3 one = vec3(1.0);
+ vec3 scr = one - (one - texcol)*(one - outcol);
+ incol = facm*outcol + fact*((one - texcol)*outcol*texcol + outcol*scr);
+}
+
+void mtex_rgb_linear(vec3 outcol, vec3 texcol, float fact, float facg, out vec3 incol)
+{
+ fact *= facg;
+
+ if(texcol.r > 0.5)
+ incol.r = outcol.r + fact*(2.0*(texcol.r - 0.5));
+ else
+ incol.r = outcol.r + fact*(2.0*(texcol.r) - 1.0);
+
+ if(texcol.g > 0.5)
+ incol.g = outcol.g + fact*(2.0*(texcol.g - 0.5));
+ else
+ incol.g = outcol.g + fact*(2.0*(texcol.g) - 1.0);
+
+ if(texcol.b > 0.5)
+ incol.b = outcol.b + fact*(2.0*(texcol.b - 0.5));
+ else
+ incol.b = outcol.b + fact*(2.0*(texcol.b) - 1.0);
+}
+
void mtex_value_vars(inout float fact, float facg, out float facm)
{
fact *= abs(facg);
@@ -1167,7 +1211,12 @@ void mtex_mapping_size(vec3 texco, vec3 size, out vec3 outtexco)
void mtex_2d_mapping(vec3 vec, out vec3 outvec)
{
- outvec = vec3(vec.xy*0.5 + vec2(0.5, 0.5), vec.z);
+ outvec = vec3(vec.xy*0.5 + vec2(0.5), vec.z);
+}
+
+vec3 mtex_2d_mapping(vec3 vec)
+{
+ return vec3(vec.xy*0.5 + vec2(0.5), vec.z);
}
void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color)
@@ -1458,9 +1507,9 @@ void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal)
outnormal = normalize((viewmat*vec4(texnormal, 0.0)).xyz);
}
-void mtex_nspace_object(mat4 viewmat, mat4 obmat, vec3 texnormal, out vec3 outnormal)
+void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
{
- outnormal = normalize((viewmat*(obmat*vec4(texnormal, 0.0))).xyz);
+ outnormal = normalize(gl_NormalMatrix * texnormal);
}
void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal)
@@ -1911,6 +1960,11 @@ void shade_mul_value(float fac, vec4 col, out vec4 outcol)
outcol = col*fac;
}
+void shade_mul_value_v3(float fac, vec3 col, out vec3 outcol)
+{
+ outcol = col*fac;
+}
+
void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
{
outcol = vec4(col.rgb*obcol.rgb, col.a);
@@ -1921,19 +1975,24 @@ void ramp_rgbtobw(vec3 color, out float outval)
outval = color.r*0.3 + color.g*0.58 + color.b*0.12;
}
-void shade_only_shadow(float i, float shadfac, float energy, out float outshadfac)
+void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb)
{
- outshadfac = i*energy*(1.0 - shadfac);
+ outshadrgb = i*energy*(1.0 - shadfac)*(vec3(1.0)-shadcol);
}
-void shade_only_shadow_diffuse(float shadfac, vec3 rgb, vec4 diff, out vec4 outdiff)
+void shade_only_shadow_diffuse(vec3 shadrgb, vec3 rgb, vec4 diff, out vec4 outdiff)
{
- outdiff = diff - vec4(rgb*shadfac, 0.0);
+ outdiff = diff - vec4(rgb*shadrgb, 0.0);
}
-void shade_only_shadow_specular(float shadfac, vec3 specrgb, vec4 spec, out vec4 outspec)
+void shade_only_shadow_specular(vec3 shadrgb, vec3 specrgb, vec4 spec, out vec4 outspec)
{
- outspec = spec - vec4(specrgb*shadfac, 0.0);
+ outspec = spec - vec4(specrgb*shadrgb, 0.0);
+}
+
+void shade_clamp_positive(vec4 col, out vec4 outcol)
+{
+ outcol = max(col, vec4(0.0));
}
void test_shadowbuf(vec3 rco, sampler2DShadow shadowmap, mat4 shadowpersmat, float shadowbias, float inp, out float result)
@@ -2164,7 +2223,7 @@ void node_subsurface_scattering(vec4 color, float scale, vec3 radius, float shar
node_bsdf_diffuse(color, 0.0, N, result);
}
-void node_bsdf_hair(vec4 color, float roughnessu, float roughnessv, out vec4 result)
+void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, out vec4 result)
{
result = color;
}
@@ -2192,8 +2251,11 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
void node_fresnel(float ior, vec3 N, vec3 I, out float result)
{
+ /* handle perspective/orthographic */
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
+
float eta = max(ior, 0.00001);
- result = fresnel_dielectric(normalize(I), N, (gl_FrontFacing)? eta: 1.0/eta);
+ result = fresnel_dielectric(I_view, N, (gl_FrontFacing)? eta: 1.0/eta);
}
/* layer_weight */
@@ -2237,16 +2299,25 @@ void node_attribute(vec3 attr_uv, out vec4 outcol, out vec3 outvec, out float ou
outf = (attr_uv.x + attr_uv.y + attr_uv.z)/3.0;
}
+void node_uvmap(vec3 attr_uv, out vec3 outvec)
+{
+ outvec = attr_uv;
+}
+
void node_geometry(vec3 I, vec3 N, mat4 toworld,
out vec3 position, out vec3 normal, out vec3 tangent,
out vec3 true_normal, out vec3 incoming, out vec3 parametric,
out float backfacing)
{
position = (toworld*vec4(I, 1.0)).xyz;
- normal = N;
+ normal = (toworld*vec4(N, 0.0)).xyz;
tangent = vec3(0.0);
- true_normal = N;
- incoming = I;
+ true_normal = normal;
+
+ /* handle perspective/orthographic */
+ vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0)? normalize(I): vec3(0.0, 0.0, -1.0);
+ incoming = -(toworld*vec4(I_view, 0.0)).xyz;
+
parametric = vec3(0.0);
backfacing = (gl_FrontFacing)? 0.0: 1.0;
}
@@ -2256,14 +2327,18 @@ void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat,
out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
out vec3 camera, out vec3 window, out vec3 reflection)
{
- generated = attr_orco;
+ generated = mtex_2d_mapping(attr_orco);
normal = normalize((obinvmat*(viewinvmat*vec4(N, 0.0))).xyz);
uv = attr_uv;
object = (obinvmat*(viewinvmat*vec4(I, 1.0))).xyz;
camera = I;
- window = gl_FragCoord.xyz;
- reflection = reflect(N, I);
+ vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0);
+ window = mtex_2d_mapping(projvec.xyz/projvec.w);
+ vec3 shade_I;
+ shade_view(I, shade_I);
+ vec3 view_reflection = reflect(shade_I, normalize(N));
+ reflection = (viewinvmat*vec4(view_reflection, 0.0)).xyz;
}
/* textures */
diff --git a/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl b/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl
index 9491eaa672d..8ccd0feb5e2 100644
--- a/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_simple_vert.glsl
@@ -15,6 +15,10 @@ varying vec4 varying_vertex_color;
varying vec2 varying_texture_coord;
#endif
+#ifdef CLIP_WORKAROUND
+varying float gl_ClipDistance[6];
+#endif
+
void main()
{
vec4 co = gl_ModelViewMatrix * gl_Vertex;
@@ -29,10 +33,14 @@ void main()
gl_Position = gl_ProjectionMatrix * co;
-#ifdef GPU_NVIDIA
+#ifdef CLIP_WORKAROUND
+ int i;
+ for(i = 0; i < 6; i++)
+ gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
+#elif !defined(GPU_ATI)
// Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
// graphic cards, while on ATI it can cause a software fallback.
- gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
+ gl_ClipVertex = co;
#endif
#ifdef USE_COLOR
diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
index 8741a13ea9b..b5d8dcc0f35 100644
--- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl
@@ -2,6 +2,10 @@
varying vec3 varposition;
varying vec3 varnormal;
+#ifdef CLIP_WORKAROUND
+varying float gl_ClipDistance[6];
+#endif
+
void main()
{
vec4 co = gl_ModelViewMatrix * gl_Vertex;
@@ -10,9 +14,13 @@ void main()
varnormal = normalize(gl_NormalMatrix * gl_Normal);
gl_Position = gl_ProjectionMatrix * co;
-#ifdef GPU_NVIDIA
+#ifdef CLIP_WORKAROUND
+ int i;
+ for(i = 0; i < 6; i++)
+ gl_ClipDistance[i] = dot(co, gl_ClipPlane[i]);
+#elif !defined(GPU_ATI)
// Setting gl_ClipVertex is necessary to get glClipPlane working on NVIDIA
// graphic cards, while on ATI it can cause a software fallback.
- gl_ClipVertex = gl_ModelViewMatrix * gl_Vertex;
+ gl_ClipVertex = co;
#endif
diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c
index 80c508267f3..cd09b56b262 100644
--- a/source/blender/ikplugin/intern/iksolver_plugin.c
+++ b/source/blender/ikplugin/intern/iksolver_plugin.c
@@ -215,7 +215,7 @@ static void where_is_ik_bone(bPoseChannel *pchan, float ik_mat[3][3]) // nr =
copy_m4_m3(ikmat, ik_mat);
if (pchan->parent)
- mul_serie_m4(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(pchan->pose_mat, pchan->parent->pose_mat, pchan->chan_mat, ikmat);
else
mul_m4_m4m4(pchan->pose_mat, pchan->chan_mat, ikmat);
@@ -420,7 +420,7 @@ static void execute_posetree(struct Scene *scene, Object *ob, PoseTree *tree)
/* end effector in world space */
copy_m4_m4(end_pose, pchan->pose_mat);
copy_v3_v3(end_pose[3], pchan->pose_tail);
- mul_serie_m4(world_pose, goalinv, ob->obmat, end_pose, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(world_pose, goalinv, ob->obmat, end_pose);
/* blend position */
goalpos[0] = fac * goalpos[0] + mfac * world_pose[3][0];
diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp
index dbc4100e287..afff97a8409 100644
--- a/source/blender/ikplugin/intern/itasc_plugin.cpp
+++ b/source/blender/ikplugin/intern/itasc_plugin.cpp
@@ -68,7 +68,7 @@ extern "C" {
#include "itasc_plugin.h"
// default parameters
-bItasc DefIKParam;
+static bItasc DefIKParam;
// in case of animation mode, feedback and timestep is fixed
// #define ANIM_TIMESTEP 1.0
@@ -566,7 +566,7 @@ static bool target_callback(const iTaSC::Timestamp& timestamp, const iTaSC::Fram
float chanmat[4][4];
copy_m4_m4(chanmat, pchan->pose_mat);
copy_v3_v3(chanmat[3], pchan->pose_tail);
- mul_serie_m4(restmat, target->owner->obmat, chanmat, target->eeRest, NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(restmat, target->owner->obmat, chanmat, target->eeRest);
}
else {
mul_m4_m4m4(restmat, target->owner->obmat, target->eeRest);
diff --git a/source/blender/imbuf/CMakeLists.txt b/source/blender/imbuf/CMakeLists.txt
index 4025a41b6a7..e8977913948 100644
--- a/source/blender/imbuf/CMakeLists.txt
+++ b/source/blender/imbuf/CMakeLists.txt
@@ -36,7 +36,7 @@ set(INC
set(INC_SYS
${JPEG_INCLUDE_DIR}
- ${PNG_INCLUDE_DIR}
+ ${PNG_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
)
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index 090e7a66d41..ce6a7eb1c47 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -163,6 +163,22 @@ typedef enum IMB_BlendMode {
IMB_BLEND_DARKEN = 5,
IMB_BLEND_ERASE_ALPHA = 6,
IMB_BLEND_ADD_ALPHA = 7,
+ IMB_BLEND_OVERLAY = 8,
+ IMB_BLEND_HARDLIGHT = 9,
+ IMB_BLEND_COLORBURN = 10,
+ IMB_BLEND_LINEARBURN = 11,
+ IMB_BLEND_COLORDODGE = 12,
+ IMB_BLEND_SCREEN = 13,
+ IMB_BLEND_SOFTLIGHT = 14,
+ IMB_BLEND_PINLIGHT = 15,
+ IMB_BLEND_VIVIDLIGHT = 16,
+ IMB_BLEND_LINEARLIGHT = 17,
+ IMB_BLEND_DIFFERENCE = 18,
+ IMB_BLEND_EXCLUSION = 19,
+ IMB_BLEND_HUE = 20,
+ IMB_BLEND_SATURATION = 21,
+ IMB_BLEND_LUMINOSITY = 22,
+ IMB_BLEND_COLOR = 23,
IMB_BLEND_COPY = 1000,
IMB_BLEND_COPY_RGB = 1001,
@@ -179,9 +195,9 @@ void IMB_rectclip(struct ImBuf *dbuf, struct ImBuf *sbuf, int *destx,
void IMB_rectcpy(struct ImBuf *drect, struct ImBuf *srect, int destx,
int desty, int srcx, int srcy, int width, int height);
void IMB_rectblend(struct ImBuf *dbuf, struct ImBuf *obuf, struct ImBuf *sbuf,
- unsigned short *dmask, unsigned short *smask, unsigned short mask_max,
+ unsigned short *dmask, unsigned short *curvemask, unsigned short *mmask, float mask_max,
int destx, int desty, int origx, int origy, int srcx, int srcy,
- int width, int height, IMB_BlendMode mode);
+ int width, int height, IMB_BlendMode mode, bool accumulate);
/**
*
diff --git a/source/blender/imbuf/intern/cache.c b/source/blender/imbuf/intern/cache.c
index 0c17dd21434..677c3dbe700 100644
--- a/source/blender/imbuf/intern/cache.c
+++ b/source/blender/imbuf/intern/cache.c
@@ -101,14 +101,14 @@ static unsigned int imb_global_tile_hash(const void *gtile_p)
return ((unsigned int)(intptr_t)gtile->ibuf) * 769 + gtile->tx * 53 + gtile->ty * 97;
}
-static int imb_global_tile_cmp(const void *a_p, const void *b_p)
+static bool imb_global_tile_cmp(const void *a_p, const void *b_p)
{
const ImGlobalTile *a = a_p;
const ImGlobalTile *b = b_p;
- if (a->ibuf == b->ibuf && a->tx == b->tx && a->ty == b->ty) return 0;
- else if (a->ibuf < b->ibuf || a->tx < b->tx || a->ty < b->ty) return -1;
- else return 1;
+ return ((a->ibuf != b->ibuf) ||
+ (a->tx != b->tx) ||
+ (a->ty != b->ty));
}
static unsigned int imb_thread_tile_hash(const void *ttile_p)
@@ -118,14 +118,14 @@ static unsigned int imb_thread_tile_hash(const void *ttile_p)
return ((unsigned int)(intptr_t)ttile->ibuf) * 769 + ttile->tx * 53 + ttile->ty * 97;
}
-static int imb_thread_tile_cmp(const void *a_p, const void *b_p)
+static bool imb_thread_tile_cmp(const void *a_p, const void *b_p)
{
const ImThreadTile *a = a_p;
const ImThreadTile *b = b_p;
- if (a->ibuf == b->ibuf && a->tx == b->tx && a->ty == b->ty) return 0;
- else if (a->ibuf < b->ibuf || a->tx < b->tx || a->ty < b->ty) return -1;
- else return 1;
+ return ((a->ibuf != b->ibuf) ||
+ (a->tx != b->tx) ||
+ (a->ty != b->ty));
}
/******************************** Load/Unload ********************************/
diff --git a/source/blender/imbuf/intern/cineon/cineonlib.c b/source/blender/imbuf/intern/cineon/cineonlib.c
index e8cb550fc05..880df0ce5c3 100644
--- a/source/blender/imbuf/intern/cineon/cineonlib.c
+++ b/source/blender/imbuf/intern/cineon/cineonlib.c
@@ -39,10 +39,6 @@
#include "BLI_fileops.h"
#include "BLI_utildefines.h"
-#if defined(_MSC_VER) && (_MSC_VER <= 1500)
-#include "BLI_math_base.h"
-#endif
-
#include "MEM_guardedalloc.h"
/*
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index 84f80faeacc..626d05b05c5 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -39,10 +39,6 @@
#include "BLI_fileops.h"
#include "BLI_utildefines.h"
-#if defined(_MSC_VER) && (_MSC_VER <= 1500)
-#include "BLI_math_base.h"
-#endif
-
#include "MEM_guardedalloc.h"
/*
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 590b21259c3..5dd6b366a93 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -252,22 +252,13 @@ static unsigned int colormanage_hashhash(const void *key_v)
return rval;
}
-static int colormanage_hashcmp(const void *av, const void *bv)
+static bool colormanage_hashcmp(const void *av, const void *bv)
{
const ColormanageCacheKey *a = (ColormanageCacheKey *) av;
const ColormanageCacheKey *b = (ColormanageCacheKey *) bv;
- if (a->view < b->view)
- return -1;
- else if (a->view > b->view)
- return 1;
-
- if (a->display < b->display)
- return -1;
- else if (a->display > b->display)
- return 1;
-
- return 0;
+ return ((a->view != b->view) ||
+ (a->display != b->display));
}
static struct MovieCache *colormanage_moviecache_ensure(ImBuf *ibuf)
@@ -626,8 +617,12 @@ void colormanagement_init(void)
ocio_env = getenv("OCIO");
- if (ocio_env && ocio_env[0] != '\0')
+ if (ocio_env && ocio_env[0] != '\0') {
config = OCIO_configCreateFromEnv();
+ if (config != NULL) {
+ printf("Color management: Using %s as a configuration file\n", ocio_env);
+ }
+ }
if (config == NULL) {
configdir = BLI_get_folder(BLENDER_DATAFILES, "colormanagement");
@@ -1891,7 +1886,7 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, boo
* so much useful to just ignore alpha -- it leads to bad
* artifacts especially when saving byte images.
*
- * What we do here is we're overing our image on top of
+ * What we do here is we're overlaying our image on top of
* background color (which is currently black).
*
* This is quite much the same as what Gimp does and it
@@ -2805,7 +2800,7 @@ void IMB_partial_display_buffer_update(ImBuf *ibuf, const float *linear_buffer,
int y;
for (y = ymin; y < ymax; y++) {
int index = y * buffer_width * 4;
- memcpy(ibuf->rect + index, display_buffer + index, (xmax - xmin) * 4);
+ memcpy((unsigned char *)ibuf->rect + index, display_buffer + index, (xmax - xmin) * 4);
}
}
}
@@ -3040,7 +3035,7 @@ static void update_glsl_display_processor(const ColorManagedViewSettings *view_s
global_glsl_state.exposure = view_settings->exposure;
global_glsl_state.gamma = view_settings->gamma;
- /* We're using curve mapping's address as a acache ID,
+ /* We're using curve mapping's address as a cache ID,
* so we need to make sure re-allocation gives new address here.
* We do this by allocating new curve mapping before freeing ol one.
*/
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 9975c58bdd2..03cd5ecd646 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -720,6 +720,7 @@ void IMB_partial_rect_from_float(ImBuf *ibuf, float *buffer, int x, int y, int w
ibuf->channels, IB_PROFILE_SRGB, profile_from, true,
w, h, w, ibuf->x);
+ IMB_buffer_float_unpremultiply(buffer, w, h);
/* XXX: need to convert to image buffer's rect space */
IMB_buffer_byte_from_float(rect_byte, buffer,
4, ibuf->dither, IB_PROFILE_SRGB, IB_PROFILE_SRGB, 0,
diff --git a/source/blender/imbuf/intern/imageprocess.c b/source/blender/imbuf/intern/imageprocess.c
index cf875bb247b..8234b01992b 100644
--- a/source/blender/imbuf/intern/imageprocess.c
+++ b/source/blender/imbuf/intern/imageprocess.c
@@ -166,6 +166,10 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4],
if (x2 >= in->x) x2 = x2 - in->x;
if (y2 >= in->y) y2 = y2 - in->y;
+ a = u - floorf(u);
+ b = v - floorf(v);
+ a_b = a * b; ma_b = (1.0f - a) * b; a_mb = a * (1.0f - b); ma_mb = (1.0f - a) * (1.0f - b);
+
if (outF) {
/* sample including outside of edges of image */
row1 = in->rect_float + in->x * y1 * 4 + 4 * x1;
@@ -173,14 +177,16 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4],
row3 = in->rect_float + in->x * y1 * 4 + 4 * x2;
row4 = in->rect_float + in->x * y2 * 4 + 4 * x2;
- a = u - floorf(u);
- b = v - floorf(v);
- a_b = a * b; ma_b = (1.0f - a) * b; a_mb = a * (1.0f - b); ma_mb = (1.0f - a) * (1.0f - b);
-
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];
outF[2] = ma_mb * row1[2] + a_mb * row3[2] + ma_b * row2[2] + a_b * row4[2];
outF[3] = ma_mb * row1[3] + a_mb * row3[3] + ma_b * row2[3] + a_b * row4[3];
+
+ /* clamp here or else we can easily get off-range */
+ CLAMP(outF[0], 0.0f, 1.0f);
+ CLAMP(outF[1], 0.0f, 1.0f);
+ CLAMP(outF[2], 0.0f, 1.0f);
+ CLAMP(outF[3], 0.0f, 1.0f);
}
if (outI) {
/* sample including outside of edges of image */
@@ -188,10 +194,6 @@ void bilinear_interpolation_color_wrap(struct ImBuf *in, unsigned char outI[4],
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;
-
- a = u - floorf(u);
- b = v - floorf(v);
- a_b = a * b; ma_b = (1.0f - a) * b; a_mb = a * (1.0f - b); ma_mb = (1.0f - a) * (1.0f - b);
/* 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 */
diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c
index 2b4367528dd..797d34d118b 100644
--- a/source/blender/imbuf/intern/metadata.c
+++ b/source/blender/imbuf/intern/metadata.c
@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <string.h>
+#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "MEM_guardedalloc.h"
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index ea75673e5f0..1641bd3089b 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -104,7 +104,7 @@ static unsigned int moviecache_hashhash(const void *keyv)
return key->cache_owner->hashfp(key->userkey);
}
-static int moviecache_hashcmp(const void *av, const void *bv)
+static bool moviecache_hashcmp(const void *av, const void *bv)
{
const MovieCacheKey *a = (MovieCacheKey *)av;
const MovieCacheKey *b = (MovieCacheKey *)bv;
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index 401070cd799..ba1bda640a6 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -48,7 +48,7 @@ extern "C"
{
// The following prevents a linking error in debug mode for MSVC using the libs in CVS
-#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__)
_CRTIMP void __cdecl _invalid_parameter_noinfo(void)
{
}
@@ -270,6 +270,10 @@ typedef struct _RGBAZ RGBAZ;
extern "C"
{
+/**
+ * Test presence of OpenEXR file.
+ * \param mem pointer to loaded OpenEXR bitstream
+ */
int imb_is_a_openexr(unsigned char *mem)
{
return Imf::isImfMagic((const char *)mem);
@@ -892,7 +896,7 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
echan->chan_id = name[0];
layname[0] = '\0';
- if (ELEM4(name[0], 'R', 'G', 'B', 'A'))
+ if (ELEM(name[0], 'R', 'G', 'B', 'A'))
strcpy(passname, "Combined");
else if (name[0] == 'Z')
strcpy(passname, "Depth");
@@ -923,9 +927,9 @@ static int imb_exr_split_channel_name(ExrChannel *echan, char *layname, char *pa
*
* Here we do some magic to distinguish such cases.
*/
- if (ELEM3(token[1], 'X', 'Y', 'Z') ||
- ELEM3(token[1], 'R', 'G', 'B') ||
- ELEM3(token[1], 'U', 'V', 'A'))
+ if (ELEM(token[1], 'X', 'Y', 'Z') ||
+ ELEM(token[1], 'R', 'G', 'B') ||
+ ELEM(token[1], 'U', 'V', 'A'))
{
echan->chan_id = token[1];
ok = true;
@@ -1120,6 +1124,27 @@ static const char *exr_rgba_channelname(InputFile *file, const char *chan)
return chan;
}
+static bool exr_has_rgb(InputFile *file)
+{
+ return file->header().channels().findChannel("R") != NULL &&
+ file->header().channels().findChannel("G") != NULL &&
+ file->header().channels().findChannel("B") != NULL;
+}
+
+static bool exr_has_luma(InputFile *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;
+}
+
+static bool exr_has_chroma(InputFile *file)
+{
+ return file->header().channels().findChannel("BY") != NULL &&
+ file->header().channels().findChannel("RY") != NULL;
+}
+
static int exr_has_zbuffer(InputFile *file)
{
return !(file->header().channels().findChannel("Z") == NULL);
@@ -1215,6 +1240,8 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
}
}
else {
+ 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;
@@ -1227,12 +1254,22 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
/* but, since we read y-flipped (negative y stride) we move to last scanline */
first += 4 * (height - 1) * width;
- frameBuffer.insert(exr_rgba_channelname(file, "R"),
- Slice(Imf::FLOAT, (char *) first, xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "G"),
- Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride));
- frameBuffer.insert(exr_rgba_channelname(file, "B"),
- Slice(Imf::FLOAT, (char *) (first + 2), xstride, ystride));
+ if (has_rgb) {
+ frameBuffer.insert(exr_rgba_channelname(file, "R"),
+ Slice(Imf::FLOAT, (char *) first, xstride, ystride));
+ frameBuffer.insert(exr_rgba_channelname(file, "G"),
+ Slice(Imf::FLOAT, (char *) (first + 1), xstride, ystride));
+ 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"),
+ Slice(Imf::FLOAT, (char *) first, xstride, ystride));
+ 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"),
+ 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"),
@@ -1260,6 +1297,24 @@ struct ImBuf *imb_load_openexr(unsigned char *mem, size_t size, int flags, char
// if (flag & IM_rect)
// IMB_rect_from_float(ibuf);
+ if (!has_rgb && has_luma) {
+ size_t a;
+ 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,
+ &color[0], &color[1], &color[2],
+ BLI_YCC_ITU_BT709);
+ }
+ }
+ else {
+ for (a = 0; a < (size_t) ibuf->x * ibuf->y; ++a) {
+ float *color = ibuf->rect_float + a * 4;
+ color[1] = color[2] = color[0];
+ }
+ }
+ }
+
/* file is no longer needed */
delete file;
}
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.h b/source/blender/imbuf/intern/openexr/openexr_api.h
index 3135795fb3f..bc21d8cea7b 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.h
+++ b/source/blender/imbuf/intern/openexr/openexr_api.h
@@ -36,13 +36,8 @@
#ifdef __cplusplus
extern "C" {
#endif
-
+
#include <stdio.h>
-
-/**
- * Test presence of OpenEXR file.
- * \param mem pointer to loaded OpenEXR bitstream
- */
void imb_initopenexr (void);
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index b620dbd9b10..d00a836667e 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -35,8 +35,10 @@
#include "BLI_utildefines.h"
#include "BLI_fileops.h"
-
#include "BLI_math.h"
+
+#include "BKE_global.h"
+
#include "MEM_guardedalloc.h"
#include "imbuf.h"
@@ -484,6 +486,23 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
return(1);
}
+static void imb_png_warning(png_structp UNUSED(png_ptr), png_const_charp message)
+{
+ /* We suppress iCCP warnings. That's how Blender always used to behave,
+ * and with new libpng it became too much picky, giving a warning on
+ * the splash screen even.
+ */
+ if ((G.debug & G_DEBUG) == 0 && !strncmp(message, "iCCP", 4)) {
+ return;
+ }
+ fprintf(stderr, "libpng warning: %s\n", message);
+}
+
+static void imb_png_error(png_structp UNUSED(png_ptr), png_const_charp message)
+{
+ fprintf(stderr, "libpng error: %s\n", message);
+}
+
ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE])
{
struct ImBuf *ibuf = NULL;
@@ -513,6 +532,8 @@ ImBuf *imb_loadpng(unsigned char *mem, size_t size, int flags, char colorspace[I
return NULL;
}
+ png_set_error_fn(png_ptr, NULL, imb_png_error, imb_png_warning);
+
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_read_struct(&png_ptr, (png_infopp)NULL,
diff --git a/source/blender/imbuf/intern/readimage.c b/source/blender/imbuf/intern/readimage.c
index f0bcfcea62d..bb09c57d1e5 100644
--- a/source/blender/imbuf/intern/readimage.c
+++ b/source/blender/imbuf/intern/readimage.c
@@ -58,7 +58,7 @@ static void imb_handle_alpha(ImBuf *ibuf, int flags, char colorspace[IM_MAX_SPAC
int alpha_flags;
if (colorspace) {
- if (ibuf->rect) {
+ if (ibuf->rect != NULL && ibuf->rect_float == NULL) {
/* byte buffer is never internally converted to some standard space,
* store pointer to it's color space descriptor instead
*/
diff --git a/source/blender/imbuf/intern/rectop.c b/source/blender/imbuf/intern/rectop.c
index 6df7587ee5c..dd2406e234e 100644
--- a/source/blender/imbuf/intern/rectop.c
+++ b/source/blender/imbuf/intern/rectop.c
@@ -65,6 +65,39 @@ void IMB_blend_color_byte(unsigned char dst[4], unsigned char src1[4], unsigned
blend_color_erase_alpha_byte(dst, src1, src2); break;
case IMB_BLEND_ADD_ALPHA:
blend_color_add_alpha_byte(dst, src1, src2); break;
+ case IMB_BLEND_OVERLAY:
+ blend_color_overlay_byte(dst, src1, src2); break;
+ case IMB_BLEND_HARDLIGHT:
+ blend_color_hardlight_byte(dst, src1, src2); break;
+ case IMB_BLEND_COLORBURN:
+ blend_color_burn_byte(dst, src1, src2); break;
+ case IMB_BLEND_LINEARBURN:
+ blend_color_linearburn_byte(dst, src1, src2); break;
+ case IMB_BLEND_COLORDODGE:
+ blend_color_dodge_byte(dst, src1, src2); break;
+ case IMB_BLEND_SCREEN:
+ blend_color_screen_byte(dst, src1, src2); break;
+ case IMB_BLEND_SOFTLIGHT:
+ blend_color_softlight_byte(dst, src1, src2); break;
+ case IMB_BLEND_PINLIGHT:
+ blend_color_pinlight_byte(dst, src1, src2); break;
+ case IMB_BLEND_LINEARLIGHT:
+ blend_color_linearlight_byte(dst, src1, src2); break;
+ case IMB_BLEND_VIVIDLIGHT:
+ blend_color_vividlight_byte(dst, src1, src2); break;
+ case IMB_BLEND_DIFFERENCE:
+ blend_color_difference_byte(dst, src1, src2); break;
+ case IMB_BLEND_EXCLUSION:
+ blend_color_exclusion_byte(dst, src1, src2); break;
+ case IMB_BLEND_COLOR:
+ blend_color_color_byte(dst, src1, src2); break;
+ case IMB_BLEND_HUE:
+ blend_color_hue_byte(dst, src1, src2); break;
+ case IMB_BLEND_SATURATION:
+ blend_color_saturation_byte(dst, src1, src2); break;
+ case IMB_BLEND_LUMINOSITY:
+ blend_color_luminosity_byte(dst, src1, src2); break;
+
default:
dst[0] = src1[0];
dst[1] = src1[1];
@@ -93,6 +126,38 @@ void IMB_blend_color_float(float dst[4], float src1[4], float src2[4], IMB_Blend
blend_color_erase_alpha_float(dst, src1, src2); break;
case IMB_BLEND_ADD_ALPHA:
blend_color_add_alpha_float(dst, src1, src2); break;
+ case IMB_BLEND_OVERLAY:
+ blend_color_overlay_float(dst, src1, src2); break;
+ case IMB_BLEND_HARDLIGHT:
+ blend_color_hardlight_float(dst, src1, src2); break;
+ case IMB_BLEND_COLORBURN:
+ blend_color_burn_float(dst, src1, src2); break;
+ case IMB_BLEND_LINEARBURN:
+ blend_color_linearburn_float(dst, src1, src2); break;
+ case IMB_BLEND_COLORDODGE:
+ blend_color_dodge_float(dst, src1, src2); break;
+ case IMB_BLEND_SCREEN:
+ blend_color_screen_float(dst, src1, src2); break;
+ case IMB_BLEND_SOFTLIGHT:
+ blend_color_softlight_float(dst, src1, src2); break;
+ case IMB_BLEND_PINLIGHT:
+ blend_color_pinlight_float(dst, src1, src2); break;
+ case IMB_BLEND_LINEARLIGHT:
+ blend_color_linearlight_float(dst, src1, src2); break;
+ case IMB_BLEND_VIVIDLIGHT:
+ blend_color_vividlight_float(dst, src1, src2); break;
+ case IMB_BLEND_DIFFERENCE:
+ blend_color_difference_float(dst, src1, src2); break;
+ case IMB_BLEND_EXCLUSION:
+ blend_color_exclusion_float(dst, src1, src2); break;
+ case IMB_BLEND_COLOR:
+ blend_color_color_float(dst, src1, src2); break;
+ case IMB_BLEND_HUE:
+ blend_color_hue_float(dst, src1, src2); break;
+ case IMB_BLEND_SATURATION:
+ blend_color_saturation_float(dst, src1, src2); break;
+ case IMB_BLEND_LUMINOSITY:
+ blend_color_luminosity_float(dst, src1, src2); break;
default:
dst[0] = src1[0];
dst[1] = src1[1];
@@ -226,22 +291,23 @@ static void imb_rectclip3(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, int *destx,
void IMB_rectcpy(ImBuf *dbuf, ImBuf *sbuf, int destx,
int desty, int srcx, int srcy, int width, int height)
{
- IMB_rectblend(dbuf, dbuf, sbuf, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY);
+ IMB_rectblend(dbuf, dbuf, sbuf, NULL, NULL, NULL, 0, destx, desty, destx, desty, srcx, srcy, width, height, IMB_BLEND_COPY, false);
}
typedef void (*IMB_blend_func)(unsigned char *dst, const unsigned char *src1, const unsigned char *src2);
typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2);
-void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
- unsigned short *smask, unsigned short mask_max,
+void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask, unsigned short *curvemask,
+ unsigned short *texmask, float mask_max,
int destx, int desty, int origx, int origy, int srcx, int srcy, int width, int height,
- IMB_BlendMode mode)
+ IMB_BlendMode mode, bool accumulate)
{
unsigned int *drect = NULL, *orect, *srect = NULL, *dr, *or, *sr;
float *drectf = NULL, *orectf, *srectf = NULL, *drf, *orf, *srf;
- unsigned short *smaskrect = smask, *smr;
+ unsigned short *cmaskrect = curvemask, *cmr;
unsigned short *dmaskrect = dmask, *dmr;
+ unsigned short *texmaskrect = texmask, *tmr;
int do_float, do_char, srcskip, destskip, origskip, x;
IMB_blend_func func = NULL;
IMB_blend_func_float func_float = NULL;
@@ -277,8 +343,11 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
if (do_float) srectf = sbuf->rect_float + (srcy * sbuf->x + srcx) * 4;
srcskip = sbuf->x;
- if (smaskrect)
- smaskrect += srcy * sbuf->x + srcx;
+ if (cmaskrect)
+ cmaskrect += srcy * sbuf->x + srcx;
+
+ if (texmaskrect)
+ texmaskrect += srcy * sbuf->x + srcx;
}
else {
srect = drect;
@@ -388,6 +457,70 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
func = blend_color_add_alpha_byte;
func_float = blend_color_add_alpha_float;
break;
+ case IMB_BLEND_OVERLAY:
+ func = blend_color_overlay_byte;
+ func_float = blend_color_overlay_float;
+ break;
+ case IMB_BLEND_HARDLIGHT:
+ func = blend_color_hardlight_byte;
+ func_float = blend_color_hardlight_float;
+ break;
+ case IMB_BLEND_COLORBURN:
+ func = blend_color_burn_byte;
+ func_float = blend_color_burn_float;
+ break;
+ case IMB_BLEND_LINEARBURN:
+ func = blend_color_linearburn_byte;
+ func_float = blend_color_linearburn_float;
+ break;
+ case IMB_BLEND_COLORDODGE:
+ func = blend_color_dodge_byte;
+ func_float = blend_color_dodge_float;
+ break;
+ case IMB_BLEND_SCREEN:
+ func = blend_color_screen_byte;
+ func_float = blend_color_screen_float;
+ break;
+ case IMB_BLEND_SOFTLIGHT:
+ func = blend_color_softlight_byte;
+ func_float = blend_color_softlight_float;
+ break;
+ case IMB_BLEND_PINLIGHT:
+ func = blend_color_pinlight_byte;
+ func_float = blend_color_pinlight_float;
+ break;
+ case IMB_BLEND_LINEARLIGHT:
+ func = blend_color_linearlight_byte;
+ func_float = blend_color_linearlight_float;
+ break;
+ case IMB_BLEND_VIVIDLIGHT:
+ func = blend_color_vividlight_byte;
+ func_float = blend_color_vividlight_float;
+ break;
+ case IMB_BLEND_DIFFERENCE:
+ func = blend_color_difference_byte;
+ func_float = blend_color_difference_float;
+ break;
+ case IMB_BLEND_EXCLUSION:
+ func = blend_color_exclusion_byte;
+ func_float = blend_color_exclusion_float;
+ break;
+ case IMB_BLEND_COLOR:
+ func = blend_color_color_byte;
+ func_float = blend_color_color_float;
+ break;
+ case IMB_BLEND_HUE:
+ func = blend_color_hue_byte;
+ func_float = blend_color_hue_float;
+ break;
+ case IMB_BLEND_SATURATION:
+ func = blend_color_saturation_byte;
+ func_float = blend_color_saturation_float;
+ break;
+ case IMB_BLEND_LUMINOSITY:
+ func = blend_color_luminosity_byte;
+ func_float = blend_color_luminosity_float;
+ break;
default:
break;
}
@@ -399,21 +532,60 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
or = orect;
sr = srect;
- if (dmaskrect && smaskrect) {
+ if (cmaskrect) {
/* mask accumulation for painting */
- dmr = dmaskrect;
- smr = smaskrect;
+ cmr = cmaskrect;
+ tmr = texmaskrect;
- for (x = width; x > 0; x--, dr++, or++, sr++, dmr++, smr++) {
- unsigned char *src = (unsigned char *)sr;
+ /* destination mask present, do max alpha masking */
+ if (dmaskrect) {
+ dmr = dmaskrect;
+ for (x = width; x > 0; x--, dr++, or++, sr++, dmr++, cmr++) {
+ unsigned char *src = (unsigned char *)sr;
+ float mask_lim = mask_max * (*cmr);
- if (src[3] && *smr) {
- unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535);
+ if (texmaskrect)
+ mask_lim *= ((*tmr++) / 65535.0f);
- if (mask > *dmr) {
- unsigned char mask_src[4];
+ if (src[3] && mask_lim) {
+ float mask;
+
+ if (accumulate)
+ mask = *dmr + mask_lim;
+ else
+ mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f));
+
+ mask = min_ff(mask, 65535.0);
+
+ if (mask > *dmr) {
+ unsigned char mask_src[4];
+
+ *dmr = mask;
- *dmr = mask;
+ mask_src[0] = src[0];
+ mask_src[1] = src[1];
+ mask_src[2] = src[2];
+ mask_src[3] = divide_round_i(src[3] * mask, 65535);
+
+ func((unsigned char *)dr, (unsigned char *)or, mask_src);
+ }
+ }
+ }
+ dmaskrect += origskip;
+ }
+ /* no destination mask buffer, do regular blend with masktexture if present */
+ else {
+ for (x = width; x > 0; x--, dr++, or++, sr++, cmr++) {
+ unsigned char *src = (unsigned char *)sr;
+ float mask = (float)mask_max * ((float)(*cmr));
+
+ if (texmaskrect)
+ mask *= ((float)(*tmr++) / 65535.0f);
+
+ mask = min_ff(mask, 65535.0);
+
+ if (src[3] && (mask > 0.0f)) {
+ unsigned char mask_src[4];
mask_src[0] = src[0];
mask_src[1] = src[1];
@@ -425,8 +597,9 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
}
}
- dmaskrect += origskip;
- smaskrect += srcskip;
+ cmaskrect += srcskip;
+ if (texmaskrect)
+ texmaskrect += srcskip;
}
else {
/* regular blending */
@@ -446,28 +619,65 @@ void IMB_rectblend(ImBuf *dbuf, ImBuf *obuf, ImBuf *sbuf, unsigned short *dmask,
orf = orectf;
srf = srectf;
- if (dmaskrect && smaskrect) {
+ if (cmaskrect) {
/* mask accumulation for painting */
- dmr = dmaskrect;
- smr = smaskrect;
+ cmr = cmaskrect;
+ tmr = texmaskrect;
+
+ /* destination mask present, do max alpha masking */
+ if (dmaskrect) {
+ dmr = dmaskrect;
+ for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, cmr++) {
+ float mask_lim = mask_max * (*cmr);
+
+ if (texmaskrect)
+ mask_lim *= ((*tmr++) / 65535.0f);
+
+ if (srf[3] && mask_lim) {
+ float mask;
+
+ if (accumulate)
+ mask = min_ff(*dmr + mask_lim, 65535.0);
+ else
+ mask = *dmr + mask_lim - (*dmr * (*cmr / 65535.0f));
+
+ mask = min_ff(mask, 65535.0);
+
+ if (mask > *dmr) {
+ float mask_srf[4];
+
+ *dmr = mask;
+ mul_v4_v4fl(mask_srf, srf, mask / 65535.0f);
+
+ func_float(drf, orf, mask_srf);
+ }
+ }
+ }
+ dmaskrect += origskip;
+ }
+ /* no destination mask buffer, do regular blend with masktexture if present */
+ else {
+ for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, cmr++) {
+ float mask = (float)mask_max * ((float)(*cmr));
+
+ if (texmaskrect)
+ mask *= ((float)(*tmr++) / 65535.0f);
- for (x = width; x > 0; x--, drf += 4, orf += 4, srf += 4, dmr++, smr++) {
- if (srf[3] != 0 && *smr) {
- unsigned short mask = *dmr + (((mask_max - *dmr) * (*smr)) / 65535);
+ mask = min_ff(mask, 65535.0);
- if (mask > *dmr) {
+ if (srf[3] && (mask > 0.0f)) {
float mask_srf[4];
- *dmr = mask;
- mul_v4_v4fl(mask_srf, srf, mask * (1.0f / 65535.0f));
+ mul_v4_v4fl(mask_srf, srf, mask / 65535.0f);
func_float(drf, orf, mask_srf);
}
}
}
- dmaskrect += origskip;
- smaskrect += srcskip;
+ cmaskrect += srcskip;
+ if (texmaskrect)
+ texmaskrect += srcskip;
}
else {
/* regular blending */
diff --git a/source/blender/imbuf/intern/scaling.c b/source/blender/imbuf/intern/scaling.c
index c98b39c826b..e480f06da2b 100644
--- a/source/blender/imbuf/intern/scaling.c
+++ b/source/blender/imbuf/intern/scaling.c
@@ -33,6 +33,7 @@
#include "BLI_utildefines.h"
+#include "BLI_math_base.h"
#include "BLI_math_color.h"
#include "BLI_math_interp.h"
#include "MEM_guardedalloc.h"
@@ -51,26 +52,17 @@
/************************************************************************/
-struct ImBuf *IMB_half_x(struct ImBuf *ibuf1)
+static void imb_half_x_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1)
{
- struct ImBuf *ibuf2;
uchar *p1, *_p1, *dest;
short a, r, g, b;
int x, y;
float af, rf, gf, bf, *p1f, *_p1f, *destf;
bool do_rect, do_float;
- if (ibuf1 == NULL) return (NULL);
- if (ibuf1->rect == NULL && ibuf1->rect_float == NULL) return (NULL);
-
do_rect = (ibuf1->rect != NULL);
- do_float = (ibuf1->rect_float != NULL);
-
- if (ibuf1->x <= 1) return(IMB_dupImBuf(ibuf1));
+ do_float = (ibuf1->rect_float != NULL && ibuf2->rect_float != NULL);
- ibuf2 = IMB_allocImBuf((ibuf1->x) / 2, ibuf1->y, ibuf1->planes, ibuf1->flags);
- if (ibuf2 == NULL) return (NULL);
-
_p1 = (uchar *) ibuf1->rect;
dest = (uchar *) ibuf2->rect;
@@ -113,9 +105,24 @@ struct ImBuf *IMB_half_x(struct ImBuf *ibuf1)
if (do_rect) _p1 += (ibuf1->x << 2);
if (do_float) _p1f += (ibuf1->x << 2);
}
- return (ibuf2);
}
+struct ImBuf *IMB_half_x(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+
+ if (ibuf1 == NULL) return (NULL);
+ if (ibuf1->rect == NULL && ibuf1->rect_float == NULL) return (NULL);
+
+ if (ibuf1->x <= 1) return(IMB_dupImBuf(ibuf1));
+
+ ibuf2 = IMB_allocImBuf((ibuf1->x) / 2, ibuf1->y, ibuf1->planes, ibuf1->flags);
+ if (ibuf2 == NULL) return (NULL);
+
+ imb_half_x_no_alloc(ibuf2, ibuf1);
+
+ return (ibuf2);
+}
struct ImBuf *IMB_double_fast_x(struct ImBuf *ibuf1)
{
@@ -170,9 +177,8 @@ struct ImBuf *IMB_double_x(struct ImBuf *ibuf1)
}
-struct ImBuf *IMB_half_y(struct ImBuf *ibuf1)
+static void imb_half_y_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1)
{
- struct ImBuf *ibuf2;
uchar *p1, *p2, *_p1, *dest;
short a, r, g, b;
int x, y;
@@ -181,15 +187,9 @@ struct ImBuf *IMB_half_y(struct ImBuf *ibuf1)
p1 = p2 = NULL;
p1f = p2f = NULL;
- if (ibuf1 == NULL) return (NULL);
- if (ibuf1->rect == NULL && ibuf1->rect_float == NULL) return (NULL);
- if (ibuf1->y <= 1) return(IMB_dupImBuf(ibuf1));
do_rect = (ibuf1->rect != NULL);
- do_float = (ibuf1->rect_float != NULL);
-
- ibuf2 = IMB_allocImBuf(ibuf1->x, (ibuf1->y) / 2, ibuf1->planes, ibuf1->flags);
- if (ibuf2 == NULL) return (NULL);
+ do_float = (ibuf1->rect_float != NULL && ibuf2->rect_float != NULL);
_p1 = (uchar *) ibuf1->rect;
dest = (uchar *) ibuf2->rect;
@@ -238,6 +238,23 @@ struct ImBuf *IMB_half_y(struct ImBuf *ibuf1)
if (do_rect) _p1 += (ibuf1->x << 3);
if (do_float) _p1f += (ibuf1->x << 3);
}
+}
+
+
+struct ImBuf *IMB_half_y(struct ImBuf *ibuf1)
+{
+ struct ImBuf *ibuf2;
+
+ if (ibuf1 == NULL) return (NULL);
+ if (ibuf1->rect == NULL && ibuf1->rect_float == NULL) return (NULL);
+
+ if (ibuf1->y <= 1) return(IMB_dupImBuf(ibuf1));
+
+ ibuf2 = IMB_allocImBuf(ibuf1->x, (ibuf1->y) / 2, ibuf1->planes, ibuf1->flags);
+ if (ibuf2 == NULL) return (NULL);
+
+ imb_half_y_no_alloc(ibuf2, ibuf1);
+
return (ibuf2);
}
@@ -303,24 +320,24 @@ MINLINE void straight_uchar_to_premul_ushort(unsigned short result[4], const uns
result[0] = color[0] * alpha;
result[1] = color[1] * alpha;
result[2] = color[2] * alpha;
- result[3] = alpha * 255;
+ result[3] = alpha * 256;
}
MINLINE void premul_ushort_to_straight_uchar(unsigned char *result, const unsigned short color[4])
{
if (color[3] <= 255) {
- result[0] = color[0] / 255;
- result[1] = color[1] / 255;
- result[2] = color[2] / 255;
- result[3] = color[3] / 255;
+ result[0] = USHORTTOUCHAR(color[0]);
+ result[1] = USHORTTOUCHAR(color[1]);
+ result[2] = USHORTTOUCHAR(color[2]);
+ result[3] = USHORTTOUCHAR(color[3]);
}
else {
- unsigned short alpha = color[3] / 255;
+ unsigned short alpha = color[3] / 256;
- result[0] = color[0] / alpha;
- result[1] = color[1] / alpha;
- result[2] = color[2] / alpha;
- result[3] = alpha;
+ result[0] = USHORTTOUCHAR(color[0] / alpha * 256);
+ result[1] = USHORTTOUCHAR(color[1] / alpha * 256);
+ result[2] = USHORTTOUCHAR(color[2] / alpha * 256);
+ result[3] = USHORTTOUCHAR(color[3]);
}
}
@@ -335,28 +352,38 @@ void imb_onehalf_no_alloc(struct ImBuf *ibuf2, struct ImBuf *ibuf1)
imb_addrectImBuf(ibuf2);
}
+ if (ibuf1->x <= 1) {
+ imb_half_y_no_alloc(ibuf2, ibuf1);
+ return;
+ }
+ if (ibuf1->y <= 1) {
+ imb_half_x_no_alloc(ibuf2, ibuf1);
+ return;
+ }
+
if (do_rect) {
unsigned char *cp1, *cp2, *dest;
cp1 = (unsigned char *) ibuf1->rect;
dest = (unsigned char *) ibuf2->rect;
+
for (y = ibuf2->y; y > 0; y--) {
cp2 = cp1 + (ibuf1->x << 2);
for (x = ibuf2->x; x > 0; x--) {
unsigned short p1i[8], p2i[8], desti[4];
-
+
straight_uchar_to_premul_ushort(p1i, cp1);
straight_uchar_to_premul_ushort(p2i, cp2);
straight_uchar_to_premul_ushort(p1i + 4, cp1 + 4);
straight_uchar_to_premul_ushort(p2i + 4, cp2 + 4);
-
+
desti[0] = ((unsigned int) p1i[0] + p2i[0] + p1i[4] + p2i[4]) >> 2;
desti[1] = ((unsigned int) p1i[1] + p2i[1] + p1i[5] + p2i[5]) >> 2;
desti[2] = ((unsigned int) p1i[2] + p2i[2] + p1i[6] + p2i[6]) >> 2;
desti[3] = ((unsigned int) p1i[3] + p2i[3] + p1i[7] + p2i[7]) >> 2;
-
+
premul_ushort_to_straight_uchar(dest, desti);
-
+
cp1 += 8;
cp2 += 8;
dest += 4;
@@ -1353,7 +1380,7 @@ static ImBuf *scaleupy(struct ImBuf *ibuf, int newy)
val_g += 0.5f;
val_r = rect[3];
- nval_r = rect[skipx + 4];
+ nval_r = rect[skipx + 3];
diff_r = nval_r - val_r;
val_r += 0.5f;
diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c
index b4c97a2aea1..9a97a142198 100644
--- a/source/blender/imbuf/intern/thumbs.c
+++ b/source/blender/imbuf/intern/thumbs.c
@@ -197,19 +197,6 @@ static void escape_uri_string(const char *string, char *escaped_string, int esca
*q = '\0';
}
-static void to_hex_char(char *hexbytes, const unsigned char *bytes, int len)
-{
- const unsigned char *p;
- char *q;
-
- for (q = hexbytes, p = bytes; len; p++) {
- const unsigned char c = (unsigned char) *p;
- len--;
- *q++ = hex[c >> 4];
- *q++ = hex[c & 15];
- }
-}
-
/** ----- end of adapted code from glib --- */
static int uri_from_filename(const char *path, char *uri)
@@ -258,9 +245,7 @@ static void thumbname_from_uri(const char *uri, char *thumb, const int thumb_len
md5_buffer(uri, strlen(uri), digest);
hexdigest[0] = '\0';
- to_hex_char(hexdigest, digest, 16);
- hexdigest[32] = '\0';
- BLI_snprintf(thumb, thumb_len, "%s.png", hexdigest);
+ BLI_snprintf(thumb, thumb_len, "%s.png", md5_to_hexdigest(digest, hexdigest));
// printf("%s: '%s' --> '%s'\n", __func__, uri, thumb);
}
@@ -305,7 +290,7 @@ ImBuf *IMB_thumb_create(const char *path, ThumbSize size, ThumbSource source, Im
short tsize = 128;
short ex, ey;
float scaledx, scaledy;
- struct stat info;
+ BLI_stat_t info;
switch (size) {
case THB_NORMAL:
@@ -472,7 +457,7 @@ ImBuf *IMB_thumb_manage(const char *path, ThumbSize size, ThumbSource source)
{
char thumb[FILE_MAX];
char uri[URI_MAX];
- struct stat st;
+ BLI_stat_t st;
ImBuf *img = NULL;
if (BLI_stat(path, &st)) {
diff --git a/source/blender/imbuf/intern/util.c b/source/blender/imbuf/intern/util.c
index fbb28849ce6..32100aa2288 100644
--- a/source/blender/imbuf/intern/util.c
+++ b/source/blender/imbuf/intern/util.c
@@ -187,7 +187,7 @@ int IMB_ispic_type(const char *name)
unsigned char buf[HEADER_SIZE];
ImFileType *type;
- struct stat st;
+ BLI_stat_t st;
int fp;
if (UTIL_DEBUG) printf("IMB_ispic_name: loading %s\n", name);
@@ -254,10 +254,6 @@ static int isqtime(const char *name)
#ifdef WITH_FFMPEG
-#if defined(_MSC_VER) && _MSC_VER < 1800
-#define va_copy(dst, src) ((dst) = (src))
-#endif
-
/* BLI_vsnprintf in ffmpeg_log_callback() causes invalid warning */
#ifdef __GNUC__
# pragma GCC diagnostic push
@@ -391,7 +387,7 @@ static int isredcode(const char *filename)
int imb_get_anim_type(const char *name)
{
int type;
- struct stat st;
+ BLI_stat_t st;
if (UTIL_DEBUG) printf("in getanimtype: %s\n", name);
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index f429360e1cf..33d1445fb93 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -168,14 +168,10 @@ typedef struct PreviewImage {
#ifdef __BIG_ENDIAN__
/* big endian */
-# define MAKE_ID2(c, d) ( (c)<<8 | (d) )
-# define MOST_SIG_BYTE 0
-# define BBIG_ENDIAN
+# define MAKE_ID2(c, d) ((c) << 8 | (d))
#else
/* little endian */
-# define MAKE_ID2(c, d) ( (d)<<8 | (c) )
-# define MOST_SIG_BYTE 1
-# define BLITTLE_ENDIAN
+# define MAKE_ID2(c, d) ((d) << 8 | (c))
#endif
/* ID from database */
@@ -186,7 +182,7 @@ typedef struct PreviewImage {
#define ID_CU MAKE_ID2('C', 'U') /* Curve */
#define ID_MB MAKE_ID2('M', 'B') /* MetaBall */
#define ID_MA MAKE_ID2('M', 'A') /* Material */
-#define ID_TE MAKE_ID2('T', 'E') /* Texture */
+#define ID_TE MAKE_ID2('T', 'E') /* Tex (Texture) */
#define ID_IM MAKE_ID2('I', 'M') /* Image */
#define ID_LT MAKE_ID2('L', 'T') /* Lattice */
#define ID_LA MAKE_ID2('L', 'A') /* Lamp */
@@ -196,23 +192,25 @@ typedef struct PreviewImage {
#define ID_WO MAKE_ID2('W', 'O') /* World */
#define ID_SCR MAKE_ID2('S', 'R') /* Screen */
#define ID_SCRN MAKE_ID2('S', 'N') /* (depreciated?) */
-#define ID_VF MAKE_ID2('V', 'F') /* VectorFont */
+#define ID_VF MAKE_ID2('V', 'F') /* VFont (Vector Font) */
#define ID_TXT MAKE_ID2('T', 'X') /* Text */
#define ID_SPK MAKE_ID2('S', 'K') /* Speaker */
#define ID_SO MAKE_ID2('S', 'O') /* Sound */
#define ID_GR MAKE_ID2('G', 'R') /* Group */
#define ID_ID MAKE_ID2('I', 'D') /* (internal use only) */
-#define ID_AR MAKE_ID2('A', 'R') /* Armature */
-#define ID_AC MAKE_ID2('A', 'C') /* Action */
+#define ID_AR MAKE_ID2('A', 'R') /* bArmature */
+#define ID_AC MAKE_ID2('A', 'C') /* bAction */
#define ID_SCRIPT MAKE_ID2('P', 'Y') /* Script (depreciated) */
-#define ID_NT MAKE_ID2('N', 'T') /* NodeTree */
+#define ID_NT MAKE_ID2('N', 'T') /* bNodeTree */
#define ID_BR MAKE_ID2('B', 'R') /* Brush */
#define ID_PA MAKE_ID2('P', 'A') /* ParticleSettings */
-#define ID_GD MAKE_ID2('G', 'D') /* GreasePencil */
+#define ID_GD MAKE_ID2('G', 'D') /* bGPdata, (Grease Pencil) */
#define ID_WM MAKE_ID2('W', 'M') /* WindowManager */
#define ID_MC MAKE_ID2('M', 'C') /* MovieClip */
#define ID_MSK MAKE_ID2('M', 'S') /* Mask */
#define ID_LS MAKE_ID2('L', 'S') /* FreestyleLineStyle */
+#define ID_PAL MAKE_ID2('P', 'L') /* Palette */
+#define ID_PC MAKE_ID2('P', 'C') /* PaintCurve */
/* NOTE! Fake IDs, needed for g.sipo->blocktype or outliner */
#define ID_SEQ MAKE_ID2('S', 'Q')
@@ -235,7 +233,7 @@ typedef struct PreviewImage {
# undef GS
#endif
// #define GS(a) (*((short *)(a)))
-#define GS(a) (CHECK_TYPE_INLINE(a, const char *), (*((short *)(a))))
+#define GS(a) (CHECK_TYPE_INLINE(a, char *), (*((short *)(a))))
#define ID_NEW(a) if ( (a) && (a)->id.newid ) (a) = (void *)(a)->id.newid
#define ID_NEW_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; }
diff --git a/source/blender/makesdna/DNA_actuator_types.h b/source/blender/makesdna/DNA_actuator_types.h
index 99f0c999a29..dcde9007cd8 100644
--- a/source/blender/makesdna/DNA_actuator_types.h
+++ b/source/blender/makesdna/DNA_actuator_types.h
@@ -97,6 +97,8 @@ typedef struct bEditObjectActuator {
float mass;
short localflag; /* flag for the lin & ang. vel: apply locally */
short dyn_operation;
+ short upflag, trackflag; /* flag for up axis and track axis */
+ int pad;
} bEditObjectActuator;
typedef struct bSceneActuator {
@@ -245,6 +247,18 @@ typedef struct bSteeringActuator {
struct Object *navmesh;
} bSteeringActuator;
+typedef struct bMouseActuator {
+ short type; /* 0=Visibility, 1=Look */
+ short flag;
+
+ int object_axis[2];
+ float threshold[2];
+ float sensitivity[2];
+ float limit_x[2];
+ float limit_y[2];
+} bMouseActuator;
+
+
typedef struct bActuator {
struct bActuator *next, *prev, *mynew;
short type;
@@ -314,6 +328,7 @@ typedef struct bActuator {
#define ACT_STATE 22
#define ACT_ARMATURE 23
#define ACT_STEERING 24
+#define ACT_MOUSE 25
/* actuator flag */
#define ACT_SHOW 1
@@ -382,6 +397,7 @@ typedef struct bActuator {
#define ACT_PROP_ADD 1
#define ACT_PROP_COPY 2
#define ACT_PROP_TOGGLE 3
+#define ACT_PROP_LEVEL 4
/* constraint flag */
#define ACT_CONST_NONE 0
@@ -426,6 +442,19 @@ typedef struct bActuator {
/* editObjectActuator->flag */
#define ACT_TRACK_3D 1
+/* editObjectActuator->upflag */
+#define ACT_TRACK_UP_X 0
+#define ACT_TRACK_UP_Y 1
+#define ACT_TRACK_UP_Z 2
+
+/* editObjectActuator->trackflag */
+#define ACT_TRACK_TRAXIS_X 0
+#define ACT_TRACK_TRAXIS_Y 1
+#define ACT_TRACK_TRAXIS_Z 2
+#define ACT_TRACK_TRAXIS_NEGX 3
+#define ACT_TRACK_TRAXIS_NEGY 4
+#define ACT_TRACK_TRAXIS_NEGZ 5
+
/* editObjectActuator->flag for replace mesh actuator */
#define ACT_EDOB_REPLACE_MESH_NOGFX 2 /* use for replace mesh actuator */
#define ACT_EDOB_REPLACE_MESH_PHYS 4
@@ -542,4 +571,22 @@ typedef struct bActuator {
#define ACT_STEERING_AUTOMATICFACING 4
#define ACT_STEERING_NORMALUP 8
+/* mouseactuator->type */
+#define ACT_MOUSE_VISIBILITY 0
+#define ACT_MOUSE_LOOK 1
+
+/* mouseactuator->flag */
+#define ACT_MOUSE_VISIBLE (1 << 0)
+#define ACT_MOUSE_USE_AXIS_X (1 << 1)
+#define ACT_MOUSE_USE_AXIS_Y (1 << 2)
+#define ACT_MOUSE_RESET_X (1 << 3)
+#define ACT_MOUSE_RESET_Y (1 << 4)
+#define ACT_MOUSE_LOCAL_X (1 << 5)
+#define ACT_MOUSE_LOCAL_Y (1 << 6)
+
+/* mouseactuator->object_axis */
+#define ACT_MOUSE_OBJECT_AXIS_X 0
+#define ACT_MOUSE_OBJECT_AXIS_Y 1
+#define ACT_MOUSE_OBJECT_AXIS_Z 2
+
#endif /* __DNA_ACTUATOR_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 390233a433d..3d0d6b820d7 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -793,6 +793,9 @@ typedef enum eInsertKeyFlags {
INSERTKEY_REPLACE = (1<<4), /* only replace an existing keyframe (this overrides INSERTKEY_NEEDED) */
INSERTKEY_XYZ2RGB = (1<<5), /* transform F-Curves should have XYZ->RGB color mode */
INSERTKEY_NO_USERPREF = (1 << 6), /* ignore user-prefs (needed for predictable API use) */
+ /* Allow to make a full copy of new key into existing one, if any, instead of 'reusing' existing handles.
+ * Used by copy/paste code. */
+ INSERTKEY_OVERWRITE_FULL = (1<<7),
} eInsertKeyFlags;
/* ************************************************ */
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index 86fa7058f97..b14861fcf47 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -35,6 +35,7 @@
#include "DNA_ID.h"
#include "DNA_texture_types.h" /* for MTex */
+#include "DNA_curve_types.h"
//#ifndef MAX_MTEX // XXX Not used?
//#define MAX_MTEX 18
@@ -62,6 +63,9 @@ typedef struct Brush {
struct ImBuf *icon_imbuf;
PreviewImage *preview;
+ struct ColorBand *gradient; /* color gradient */
+ struct PaintCurve *paint_curve;
+
char icon_filepath[1024]; /* 1024 = FILE_MAX */
float normal_weight;
@@ -71,6 +75,7 @@ typedef struct Brush {
float weight; /* brush weight */
int size; /* brush diameter */
int flag; /* general purpose flag */
+ int mask_pressure; /* pressure influence for mask */
float jitter; /* jitter the position of the brush */
int jitter_absolute; /* absolute jitter in pixels */
int overlay_flags;
@@ -82,10 +87,17 @@ typedef struct Brush {
float rgb[3]; /* color */
float alpha; /* opacity */
+ float secondary_rgb[3]; /* background color */
+
int sculpt_plane; /* the direction of movement for sculpt vertices */
float plane_offset; /* offset for plane brushes (clay, flatten, fill, scrape) */
+ float pad;
+ int gradient_spacing;
+ int gradient_stroke_mode; /* source for stroke color gradient application */
+ int gradient_fill_mode; /* source for fill tool color gradient application */
+
char sculpt_tool; /* active sculpt tool */
char vertexpaint_tool; /* active vertex/weight paint blend mode (poorly named) */
char imagepaint_tool; /* active image paint tool */
@@ -100,12 +112,21 @@ typedef struct Brush {
float texture_sample_bias;
+ /* overlay */
int texture_overlay_alpha;
int mask_overlay_alpha;
int cursor_overlay_alpha;
float unprojected_radius;
+ /* soften/sharpen */
+ float sharp_threshold;
+ int blur_kernel_radius;
+ int blur_mode;
+
+ /* fill tool */
+ float fill_threshold;
+
float add_col[3];
float sub_col[3];
@@ -116,6 +137,52 @@ typedef struct Brush {
float mask_stencil_dimension[2];
} Brush;
+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
+{
+ ID id;
+
+ /* pointer to individual colours */
+ ListBase colors;
+ ListBase deleted;
+
+ int active_color;
+ int pad;
+} Palette;
+
+typedef struct PaintCurvePoint
+{
+ BezTriple bez; /* bezier handle */
+ float pressure; /* pressure on that point */
+} PaintCurvePoint;
+
+typedef struct PaintCurve
+{
+ ID id;
+ PaintCurvePoint *points; /* points of curve */
+ int tot_points;
+ int add_index; /* index where next point will be added */
+} PaintCurve;
+
+/* Brush.gradient_source */
+typedef enum BrushGradientSourceStroke {
+ BRUSH_GRADIENT_PRESSURE = 0, /* gradient from pressure */
+ BRUSH_GRADIENT_SPACING_REPEAT = 1, /* gradient from spacing */
+ BRUSH_GRADIENT_SPACING_CLAMP = 2 /* gradient from spacing */
+} BrushGradientSourceStroke;
+
+typedef enum BrushGradientSourceFill {
+ BRUSH_GRADIENT_LINEAR = 0, /* gradient from pressure */
+ BRUSH_GRADIENT_RADIAL = 1 /* gradient from spacing */
+} BrushGradientSourceFill;
+
/* Brush.flag */
typedef enum BrushFlags {
BRUSH_AIRBRUSH = (1 << 0),
@@ -124,7 +191,7 @@ typedef enum BrushFlags {
BRUSH_SIZE_PRESSURE = (1 << 3),
BRUSH_JITTER_PRESSURE = (1 << 4),
BRUSH_SPACING_PRESSURE = (1 << 5),
- // BRUSH_FIXED_TEX = (1 << 6), /* obsolete, use mtex->brush_map_mode = MTEX_MAP_MODE_TILED instead */
+ BRUSH_UNUSED = (1 << 6),
BRUSH_RAKE = (1 << 7),
BRUSH_ANCHORED = (1 << 8),
BRUSH_DIR_IN = (1 << 9),
@@ -138,7 +205,7 @@ typedef enum BrushFlags {
BRUSH_SPACE_ATTEN = (1 << 18),
BRUSH_ADAPTIVE_SPACE = (1 << 19),
BRUSH_LOCK_SIZE = (1 << 20),
-// BRUSH_TEXTURE_OVERLAY = (1 << 21), /* obsolete, use overlay_flags |= BRUSH_OVERLAY_PRIMARY instead */
+ BRUSH_USE_GRADIENT = (1 << 21),
BRUSH_EDGE_TO_EDGE = (1 << 22),
BRUSH_DRAG_DOT = (1 << 23),
BRUSH_INVERSE_SMOOTH_PRESSURE = (1 << 24),
@@ -146,13 +213,16 @@ typedef enum BrushFlags {
BRUSH_PLANE_TRIM = (1 << 26),
BRUSH_FRONTFACE = (1 << 27),
BRUSH_CUSTOM_ICON = (1 << 28),
-
- /* temporary flag which sets up automatically for correct brush
- * drawing when inverted modal operator is running */
- BRUSH_INVERTED = (1 << 29),
- BRUSH_ABSOLUTE_JITTER = (1 << 30)
+ BRUSH_LINE = (1 << 29),
+ BRUSH_ABSOLUTE_JITTER = (1 << 30),
+ BRUSH_CURVE = (1 << 31)
} BrushFlags;
+typedef enum {
+ BRUSH_MASK_PRESSURE_RAMP = (1 << 1),
+ BRUSH_MASK_PRESSURE_CUTOFF = (1 << 2)
+} BrushMaskPressureFlags;
+
/* Brush.overlay_flags */
typedef enum OverlayFlags {
BRUSH_OVERLAY_CURSOR = (1),
@@ -195,7 +265,9 @@ typedef enum BrushImagePaintTool {
PAINT_TOOL_DRAW = 0,
PAINT_TOOL_SOFTEN = 1,
PAINT_TOOL_SMEAR = 2,
- PAINT_TOOL_CLONE = 3
+ PAINT_TOOL_CLONE = 3,
+ PAINT_TOOL_FILL = 4,
+ PAINT_TOOL_MASK = 5
} BrushImagePaintTool;
/* direction that the brush displaces along */
@@ -222,6 +294,12 @@ typedef enum {
BRUSH_MASK_SMOOTH = 1
} BrushMaskTool;
+/* blur kernel types, Brush.blur_mode */
+typedef enum BlurKernelType {
+ KERNEL_GAUSSIAN,
+ KERNEL_BOX
+} BlurKernelType;
+
#define MAX_BRUSH_PIXEL_RADIUS 200
#endif
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index e35e4673684..fb33879e2c1 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -284,10 +284,14 @@ typedef struct bFollowPathConstraint {
/* Stretch to constraint */
typedef struct bStretchToConstraint {
struct Object *tar;
+ int flag;
int volmode;
- int plane;
+ int plane;
float orglength;
float bulge;
+ float bulge_min;
+ float bulge_max;
+ float bulge_smooth;
char subtarget[64]; /* MAX_ID_NAME-2 */
} bStretchToConstraint;
@@ -796,7 +800,8 @@ typedef enum ePivotConstraint_Flag {
typedef enum eFollowTrack_Flags {
FOLLOWTRACK_ACTIVECLIP = (1<<0),
- FOLLOWTRACK_USE_3D_POSITION = (1<<1)
+ FOLLOWTRACK_USE_3D_POSITION = (1<<1),
+ FOLLOWTRACK_USE_UNDISTORTION = (1<<2)
} eFollowTrack_Flags;
typedef enum eFollowTrack_FrameMethod {
@@ -819,6 +824,12 @@ typedef enum eObjectSolver_Flags {
#define CONSTRAINT_DRAW_PIVOT 0x40
#define CONSTRAINT_DISABLE_LINKED_COLLISION 0x80
+/* ObjectSolver Constraint -> flag */
+typedef enum eStretchTo_Flags {
+ STRETCHTOCON_USE_BULGE_MIN = (1 << 0),
+ STRETCHTOCON_USE_BULGE_MAX = (1 << 1),
+} eStretchTo_Flags;
+
/* important: these defines need to match up with PHY_DynamicTypes headerfile */
#define CONSTRAINT_RB_BALL 1
#define CONSTRAINT_RB_HINGE 2
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 0321c1cad12..87496fb491f 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -71,22 +71,27 @@ typedef struct Path {
/* These two Lines with # tell makesdna this struct can be excluded. */
#
#
+typedef struct BevPoint {
+ float vec[3], alfa, radius, weight, offset;
+ float sina, cosa; /* 2D Only */
+ float dir[3], tan[3], quat[4]; /* 3D Only */
+ short split_tag, dupe_tag;
+} BevPoint;
+
+/* These two Lines with # tell makesdna this struct can be excluded. */
+#
+#
typedef struct BevList {
struct BevList *next, *prev;
int nr, dupe_nr;
int poly, hole;
int charidx;
-} BevList;
+ int *segbevcount;
+ float *seglen;
-/* These two Lines with # tell makesdna this struct can be excluded. */
-#
-#
-typedef struct BevPoint {
- float vec[3], alfa, radius, weight;
- float sina, cosa; /* 2D Only */
- float dir[3], tan[3], quat[4]; /* 3D Only */
- short split_tag, dupe_tag;
-} BevPoint;
+ /* over-alloc */
+ BevPoint bevpoints[0];
+} BevList;
/**
* Keyframes on F-Curves (allows code reuse of Bezier eval code) and
@@ -288,7 +293,7 @@ typedef struct Curve {
#define CU_PATH_RADIUS 4096 /* make use of the path radius if this is enabled (default for new curves) */
#define CU_DEFORM_FILL 8192 /* fill 2d curve after deformation */
#define CU_FILL_CAPS 16384 /* fill bevel caps */
-#define CU_MAP_TAPER 32768 /* map taper object to bevelled area */
+#define CU_MAP_TAPER 32768 /* map taper object to beveled area */
/* twist mode */
#define CU_TWIST_Z_UP 0
diff --git a/source/blender/makesdna/DNA_freestyle_types.h b/source/blender/makesdna/DNA_freestyle_types.h
index 195c7eb4841..d099511a088 100644
--- a/source/blender/makesdna/DNA_freestyle_types.h
+++ b/source/blender/makesdna/DNA_freestyle_types.h
@@ -50,6 +50,7 @@ struct Text;
#define FREESTYLE_FACE_SMOOTHNESS_FLAG (1 << 3)
#define FREESTYLE_ADVANCED_OPTIONS_FLAG (1 << 4)
#define FREESTYLE_CULLING (1 << 5)
+#define FREESTYLE_VIEW_MAP_CACHE (1 << 6)
/* FreestyleConfig::mode */
#define FREESTYLE_CONTROL_SCRIPT_MODE 1
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index 0b9dddd0ea5..fcb894c9ebf 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -64,6 +64,10 @@ typedef struct ImageUser {
} ImageUser;
+typedef struct RenderSlot {
+ char name[64]; /* 64 = MAX_NAME */
+} RenderSlot;
+
/* iuser->flag */
#define IMA_ANIM_ALWAYS 1
#define IMA_ANIM_REFRESHED 2
@@ -109,6 +113,7 @@ typedef struct Image {
int gen_x, gen_y;
char gen_type, gen_flag;
short gen_depth;
+ float gen_color[4];
/* display aspect - for UV editing images resized for faster openGL display */
float aspx, aspy;
@@ -118,6 +123,7 @@ typedef struct Image {
char alpha_mode;
char pad[7];
+ RenderSlot render_slots[8]; /* 8 = IMA_MAX_RENDER_SLOT */
} Image;
diff --git a/source/blender/makesdna/DNA_lamp_types.h b/source/blender/makesdna/DNA_lamp_types.h
index b7aae005e3b..a920182d5a3 100644
--- a/source/blender/makesdna/DNA_lamp_types.h
+++ b/source/blender/makesdna/DNA_lamp_types.h
@@ -131,26 +131,26 @@ typedef struct Lamp {
#define LA_YF_PHOTON 5
/* mode */
-#define LA_SHAD_BUF 1
-#define LA_HALO 2
-#define LA_LAYER 4
-#define LA_QUAD 8 /* no longer used */
-#define LA_NEG 16
-#define LA_ONLYSHADOW 32
-#define LA_SPHERE 64
-#define LA_SQUARE 128
-#define LA_TEXTURE 256
-#define LA_OSATEX 512
-/* #define LA_DEEP_SHADOW 1024 */ /* not used anywhere */
-#define LA_NO_DIFF 2048
-#define LA_NO_SPEC 4096
-#define LA_SHAD_RAY 8192
+#define LA_SHAD_BUF (1 << 0)
+#define LA_HALO (1 << 1)
+#define LA_LAYER (1 << 2)
+#define LA_QUAD (1 << 3) /* no longer used */
+#define LA_NEG (1 << 4)
+#define LA_ONLYSHADOW (1 << 5)
+#define LA_SPHERE (1 << 6)
+#define LA_SQUARE (1 << 7)
+#define LA_TEXTURE (1 << 8)
+#define LA_OSATEX (1 << 9)
+/* #define LA_DEEP_SHADOW (1 << 10) */ /* not used anywhere */
+#define LA_NO_DIFF (1 << 11)
+#define LA_NO_SPEC (1 << 12)
+#define LA_SHAD_RAY (1 << 13)
/* yafray: lamp shadowbuffer flag, softlight */
/* Since it is used with LOCAL lamp, can't use LA_SHAD */
-/* #define LA_YF_SOFT 16384 */ /* no longer used */
-#define LA_LAYER_SHADOW 32768
-#define LA_SHAD_TEX (1<<16)
-#define LA_SHOW_CONE (1<<17)
+/* #define LA_YF_SOFT (1 << 14) */ /* no longer used */
+#define LA_LAYER_SHADOW (1 << 15)
+#define LA_SHAD_TEX (1 << 16)
+#define LA_SHOW_CONE (1 << 17)
/* layer_shadow */
#define LA_LAYER_SHADOW_BOTH 0
diff --git a/source/blender/makesdna/DNA_linestyle_types.h b/source/blender/makesdna/DNA_linestyle_types.h
index f7ba53c1f79..ac848600c2d 100644
--- a/source/blender/makesdna/DNA_linestyle_types.h
+++ b/source/blender/makesdna/DNA_linestyle_types.h
@@ -42,9 +42,12 @@
/* texco (also in DNA_material_types.h) */
#define TEXCO_STROKE 16 /* actually it's UV */
+struct AnimData;
struct ColorBand;
struct CurveMapping;
struct MTex;
+struct Object;
+struct bNodeTree;
typedef struct LineStyleModifier {
struct LineStyleModifier *next, *prev;
@@ -196,6 +199,11 @@ typedef struct LineStyleThicknessModifier_DistanceFromObject {
#define LS_MODIFIER_MATERIAL_SPEC_B 8
#define LS_MODIFIER_MATERIAL_SPEC_HARD 9
#define LS_MODIFIER_MATERIAL_ALPHA 10
+#define LS_MODIFIER_MATERIAL_LINE 11
+#define LS_MODIFIER_MATERIAL_LINE_R 12
+#define LS_MODIFIER_MATERIAL_LINE_G 13
+#define LS_MODIFIER_MATERIAL_LINE_B 14
+#define LS_MODIFIER_MATERIAL_LINE_A 15
typedef struct LineStyleColorModifier_Material {
struct LineStyleModifier modifier;
@@ -380,6 +388,7 @@ typedef struct LineStyleThicknessModifier_Calligraphy {
#define LS_NO_SORTING (1 << 11)
#define LS_REVERSE_ORDER (1 << 12) /* for sorting */
#define LS_TEXTURE (1 << 13)
+#define LS_CHAIN_COUNT (1 << 14)
/* FreestyleLineStyle::chaining */
#define LS_CHAINING_PLAIN 1
@@ -399,6 +408,8 @@ typedef struct LineStyleThicknessModifier_Calligraphy {
/* FreestyleLineStyle::sort_key */
#define LS_SORT_KEY_DISTANCE_FROM_CAMERA 1
#define LS_SORT_KEY_2D_LENGTH 2
+#define LS_SORT_KEY_PROJECTED_X 3
+#define LS_SORT_KEY_PROJECTED_Y 4
/* FreestyleLineStyle::integration_type */
#define LS_INTEGRATION_MEAN 1
@@ -421,13 +432,14 @@ typedef struct FreestyleLineStyle {
float split_length;
float min_angle, max_angle; /* in radians, for splitting */
float min_length, max_length;
+ unsigned int chain_count;
unsigned short split_dash1, split_gap1;
unsigned short split_dash2, split_gap2;
unsigned short split_dash3, split_gap3;
int sort_key, integration_type;
- float texstep;
+ float texstep;
short texact, pr_texture;
- short use_nodes, pad;
+ short use_nodes, pad[3];
unsigned short dash1, gap1, dash2, gap2, dash3, gap3;
int panel; /* for UI */
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 6bcbabc226d..3f94a9cfebb 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -41,6 +41,7 @@
#endif
struct MTex;
+struct Image;
struct ColorBand;
struct Group;
struct bNodeTree;
@@ -82,6 +83,13 @@ typedef struct GameSettings {
int pad1;
} GameSettings;
+typedef struct TexPaintSlot {
+ struct Image *ima; /* image to be painted on */
+ char *uvname; /* customdata index for uv layer, MAX_NAME*/
+ int index; /* index for mtex slot in material for blender internal */
+ int pad;
+} TexPaintSlot;
+
typedef struct Material {
ID id;
struct AnimData *adt; /* animation data (must be immediately after id for utilities to use it) */
@@ -178,9 +186,19 @@ typedef struct Material {
short shadowonly_flag; /* "shadowsonly" type */
short index; /* custom index for render passes */
+ /* Freestyle line settings */
+ float line_col[4];
+ short line_priority;
short vcol_alpha;
+
+ /* texture painting */
+ short paint_active_slot;
+ short paint_clone_slot;
+ short tot_slots;
short pad4[3];
+ struct TexPaintSlot *texpaintslot; /* cached slot for painting. Make sure to recalculate before use
+ * with refresh_texpaint_image_cache */
ListBase gpumaterial; /* runtime */
} Material;
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 7c5846e5819..47782bb3ae1 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -308,6 +308,9 @@ typedef struct BevelModifierData {
short val_flags; /* used to interpret the bevel value */
short lim_flags; /* flags to tell the tool how to limit the bevel */
short e_flags; /* flags to direct how edge weights are applied to verts */
+ short mat; /* material index if >= 0, else material inherited from surrounding faces */
+ short pad;
+ int pad2;
float profile; /* controls profile shape (0->1, .5 is round) */
/* if the MOD_BEVEL_ANGLE is set, this will be how "sharp" an edge must be before it gets beveled */
float bevel_angle;
@@ -837,6 +840,7 @@ enum {
MOD_SOLIDIFY_VGROUP_INV = (1 << 3),
MOD_SOLIDIFY_RIM_MATERIAL = (1 << 4), /* deprecated, used in do_versions */
MOD_SOLIDIFY_FLIP = (1 << 5),
+ MOD_SOLIDIFY_NOSHELL = (1 << 6),
};
#if (DNA_DEPRECATED_GCC_POISON == 1)
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index e13d53934cb..e0d25e763d4 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -852,6 +852,12 @@ typedef struct NodeShaderUVMap {
char uv_map[64];
} NodeShaderUVMap;
+typedef struct NodeSunBeams {
+ float source[2];
+
+ float ray_length;
+} NodeSunBeams;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -874,9 +880,10 @@ typedef struct NodeShaderUVMap {
#define CMP_NODE_CHANNEL_MATTE_CS_YCC 4
/* glossy distributions */
-#define SHD_GLOSSY_BECKMANN 0
-#define SHD_GLOSSY_SHARP 1
-#define SHD_GLOSSY_GGX 2
+#define SHD_GLOSSY_BECKMANN 0
+#define SHD_GLOSSY_SHARP 1
+#define SHD_GLOSSY_GGX 2
+#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3
/* vector transform */
#define SHD_VECT_TRANSFORM_TYPE_VECTOR 0
diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h
index 811c33befca..0bcc6bfd70e 100644
--- a/source/blender/makesdna/DNA_object_types.h
+++ b/source/blender/makesdna/DNA_object_types.h
@@ -127,7 +127,7 @@ typedef struct Object {
struct Object *proxy, *proxy_group, *proxy_from;
struct Ipo *ipo DNA_DEPRECATED; /* old animation system, deprecated for 2.5 */
/* struct Path *path; */
- struct BoundBox *bb;
+ struct BoundBox *bb; /* axis aligned boundbox (in localspace) */
struct bAction *action DNA_DEPRECATED; // XXX deprecated... old animation system
struct bAction *poselib;
struct bPose *pose; /* pose data, armature objects only */
@@ -188,6 +188,7 @@ typedef struct Object {
char scavisflag; /* more display settings for game logic */
char depsflag;
+ /* dupli-frame settings */
int dupon, dupoff, dupsta, dupend;
int pad;
@@ -315,7 +316,6 @@ typedef struct ObHook {
typedef struct DupliObject {
struct DupliObject *next, *prev;
struct Object *ob;
- unsigned int origlay, pad;
float mat[4][4];
float orco[3], uv[2];
@@ -362,13 +362,13 @@ enum {
#define OB_TYPE_SUPPORT_VGROUP(_type) \
(ELEM(_type, OB_MESH, OB_LATTICE))
#define OB_TYPE_SUPPORT_EDITMODE(_type) \
- (ELEM7(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE))
+ (ELEM(_type, OB_MESH, OB_FONT, OB_CURVE, OB_SURF, OB_MBALL, OB_LATTICE, OB_ARMATURE))
#define OB_TYPE_SUPPORT_PARVERT(_type) \
- (ELEM4(_type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE))
+ (ELEM(_type, OB_MESH, OB_SURF, OB_CURVE, OB_LATTICE))
/* is this ID type used as object data */
#define OB_DATA_SUPPORT_ID(_id_type) \
- (ELEM8(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_CA, ID_LT, ID_AR))
+ (ELEM(_id_type, ID_ME, ID_CU, ID_MB, ID_LA, ID_SPK, ID_CA, ID_LT, ID_AR))
#define OB_DATA_SUPPORT_ID_CASE \
ID_ME: case ID_CU: case ID_MB: case ID_LA: case ID_SPK: case ID_CA: case ID_LT: case ID_AR
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index ceb938c3af2..f8f962107f6 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -242,6 +242,7 @@ typedef enum ScenePassType {
SCE_PASS_SUBSURFACE_DIRECT = (1 << 28),
SCE_PASS_SUBSURFACE_INDIRECT = (1 << 29),
SCE_PASS_SUBSURFACE_COLOR = (1 << 30),
+ SCE_PASS_DEBUG = (1 << 31), /* This is a virtual pass. */
} ScenePassType;
/* note, srl->passflag is treestore element 'nr' in outliner, short still... */
@@ -604,6 +605,9 @@ typedef struct RenderData {
/* Cycles baking */
struct BakeData bake;
+
+ int preview_start_resolution;
+ int pad;
} RenderData;
/* *************************************************************** */
@@ -808,7 +812,8 @@ typedef struct TimeMarker {
/* Paint Tool Base */
typedef struct Paint {
struct Brush *brush;
-
+ struct Palette *palette;
+
/* WM Paint cursor */
void *paint_cursor;
unsigned char paint_cursor_col[4];
@@ -831,15 +836,20 @@ typedef struct Paint {
typedef struct ImagePaintSettings {
Paint paint;
- short flag, pad;
+ short flag, missing_data;
/* for projection painting only */
short seam_bleed, normal_angle;
short screen_grab_size[2]; /* capture size for re-projection */
- int pad1;
+ int mode; /* mode used for texture painting */
- void *paintcursor; /* wm handle */
+ void *paintcursor; /* wm handle */
+ struct Image *stencil; /* workaround until we support true layer masks */
+ struct Image *clone; /* clone layer for image mode for projective texture painting */
+ struct Image *canvas; /* canvas when the explicit system is used for painting */
+ float stencil_col[3];
+ float pad1;
} ImagePaintSettings;
/* ------------------------------------------- */
@@ -963,6 +973,11 @@ typedef struct UnifiedPaintSettings {
/* unified brush weight, [0, 1] */
float weight;
+ /* unified brush color */
+ float rgb[3];
+ /* unified brush secondary color */
+ float secondary_rgb[3];
+
/* user preferences for sculpt and paint */
int flag;
@@ -970,7 +985,6 @@ typedef struct UnifiedPaintSettings {
/* record movement of mouse so that rake can start at an intuitive angle */
float last_rake[2];
- int pad;
float brush_rotation;
@@ -978,7 +992,14 @@ typedef struct UnifiedPaintSettings {
* all data below are used to communicate with cursor drawing and tex sampling *
*********************************************************************************/
int draw_anchored;
- int anchored_size;
+ int anchored_size;
+
+ char draw_inverted;
+ char pad3[7];
+
+ float overlap_factor; /* normalization factor due to accumulated value of curve along spacing.
+ * Calculated when brush spacing changes to dampen strength of stroke
+ * if space attenuation is used*/
float anchored_initial_mouse[2];
/* check is there an ongoing stroke right now */
@@ -998,15 +1019,16 @@ typedef struct UnifiedPaintSettings {
struct ColorSpace *colorspace;
/* radius of brush, premultiplied with pressure.
- * In case of anchored brushes contains that radius */
+ * In case of anchored brushes contains the anchored radius */
float pixel_radius;
- int pad2;
+ int pad4;
} UnifiedPaintSettings;
typedef enum {
UNIFIED_PAINT_SIZE = (1 << 0),
UNIFIED_PAINT_ALPHA = (1 << 1),
UNIFIED_PAINT_WEIGHT = (1 << 5),
+ UNIFIED_PAINT_COLOR = (1 << 6),
/* only used if unified size is enabled, mirrors the brush flags
* BRUSH_LOCK_SIZE and BRUSH_SIZE_PRESSURE */
@@ -1377,6 +1399,7 @@ typedef struct Scene {
/* #define R_RECURS_PROTECTION 0x20000 */
#define R_TEXNODE_PREVIEW 0x40000
#define R_VIEWPORT_PREVIEW 0x80000
+#define R_EXR_CACHE_FILE 0x100000
/* r->stamp */
#define R_STAMP_TIME 0x0001
@@ -1442,8 +1465,9 @@ enum {
#define R_BAKE_LORES_MESH 32
#define R_BAKE_VCOL 64
#define R_BAKE_USERSCALE 128
-#define R_BAKE_SPLIT_MAT 256
-#define R_BAKE_AUTO_NAME 512
+#define R_BAKE_CAGE 256
+#define R_BAKE_SPLIT_MAT 512
+#define R_BAKE_AUTO_NAME 1024
/* bake_normal_space */
#define R_BAKE_SPACE_CAMERA 0
@@ -1615,8 +1639,8 @@ typedef enum eVGroupSelect {
#define SCE_FRAME_DROP (1<<3)
- /* return flag BKE_scene_base_iter_next function */
-#define F_ERROR -1
+ /* return flag BKE_scene_base_iter_next functions */
+/* #define F_ERROR -1 */ /* UNUSED */
#define F_START 0
#define F_SCENE 1
#define F_DUPLI 3
@@ -1642,7 +1666,7 @@ enum {
typedef enum {
PAINT_SHOW_BRUSH = (1 << 0),
PAINT_FAST_NAVIGATE = (1 << 1),
- PAINT_SHOW_BRUSH_ON_SURFACE = (1 << 2),
+ PAINT_SHOW_BRUSH_ON_SURFACE = (1 << 2)
} PaintFlags;
/* Paint.symmetry_flags
@@ -1687,6 +1711,11 @@ typedef enum SculptFlags {
SCULPT_DYNTOPO_DETAIL_CONSTANT = (1 << 13)
} SculptFlags;
+typedef enum ImagePaintMode {
+ IMAGEPAINT_MODE_MATERIAL, /* detect texture paint slots from the material */
+ IMAGEPAINT_MODE_IMAGE, /* select texture paint image directly */
+} ImagePaintMode;
+
#if (DNA_DEPRECATED_GCC_POISON == 1)
#pragma GCC poison SCULPT_SYMM_X SCULPT_SYMM_Y SCULPT_SYMM_Z SCULPT_SYMMETRY_FEATHER
#endif
@@ -1705,6 +1734,11 @@ typedef enum SculptFlags {
#define IMAGEPAINT_PROJECT_LAYER_STENCIL 256
#define IMAGEPAINT_PROJECT_LAYER_STENCIL_INV 512
+#define IMAGEPAINT_MISSING_UVS (1 << 0)
+#define IMAGEPAINT_MISSING_MATERIAL (1 << 1)
+#define IMAGEPAINT_MISSING_TEX (1 << 2)
+#define IMAGEPAINT_MISSING_STENCIL (1 << 3)
+
/* toolsettings->uvcalc_flag */
#define UVCALC_FILLHOLES 1
#define UVCALC_NO_ASPECT_CORRECT 2 /* would call this UVCALC_ASPECT_CORRECT, except it should be default with old file */
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 41d26e34f03..47a08c62f95 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -60,7 +60,7 @@ typedef struct bScreen {
int redraws_flag; /* user-setting for which editors get redrawn during anim playback (used to be time->redraws) */
int pad1;
- short full; /* temp screen for image render display or fileselect */
+ short state; /* temp screen for image render display or fileselect */
short temp; /* temp screen in a temp window, don't save (like user prefs) */
short winid; /* winid from WM, starts with 1 */
short do_draw; /* notifier for drawing edges */
@@ -247,7 +247,8 @@ typedef struct ARegion {
short do_draw_overlay; /* private, cached notifier events */
short swap; /* private, indicator to survive swap-exchange */
short overlap; /* private, set for indicate drawing overlapped */
- short pad[2];
+ short flagfullscreen; /* temporary copy of flag settings for clean fullscreen */
+ short pad;
struct ARegionType *type; /* callbacks for this region type */
@@ -271,12 +272,12 @@ typedef struct ARegion {
// #define WIN_EQUAL 3 // UNUSED
/* area->flag */
-#define HEADER_NO_PULLDOWN 1
-#define AREA_FLAG_DRAWJOINTO 2
-#define AREA_FLAG_DRAWJOINFROM 4
-#define AREA_TEMP_INFO 8
-#define AREA_FLAG_DRAWSPLIT_H 16
-#define AREA_FLAG_DRAWSPLIT_V 32
+#define HEADER_NO_PULLDOWN (1 << 0)
+#define AREA_FLAG_DRAWJOINTO (1 << 1)
+#define AREA_FLAG_DRAWJOINFROM (1 << 2)
+#define AREA_TEMP_INFO (1 << 3)
+#define AREA_FLAG_DRAWSPLIT_H (1 << 4)
+#define AREA_FLAG_DRAWSPLIT_V (1 << 5)
#define EDGEWIDTH 1
#define AREAGRID 4
@@ -287,9 +288,12 @@ typedef struct ARegion {
#define HEADERDOWN 1
#define HEADERTOP 2
-/* screen->full */
-#define SCREENNORMAL 0
-#define SCREENFULL 1
+/* screen->state */
+enum {
+ SCREENNORMAL = 0,
+ SCREENMAXIMIZED = 1, /* one editor taking over the screen */
+ SCREENFULL = 2, /* one editor taking over the screen with no bare-minimum UI elements */
+};
/* Panel->flag */
enum {
@@ -315,6 +319,9 @@ enum {
#define PNL_DEFAULT_CLOSED 1
#define PNL_NO_HEADER 2
+/* Fallback panel category (only for old scripts which need updating) */
+#define PNL_CATEGORY_FALLBACK "Misc"
+
/* uiList layout_type */
enum {
UILST_LAYOUT_DEFAULT = 0,
@@ -383,6 +390,6 @@ enum {
#define RGN_DRAW 1
#define RGN_DRAW_PARTIAL 2
#define RGN_DRAWING 4
-
+#define RGN_DRAW_REFRESH_UI 8 /* re-create uiBlock's where possible */
#endif
diff --git a/source/blender/makesdna/DNA_sensor_types.h b/source/blender/makesdna/DNA_sensor_types.h
index fcdbbe31541..8d59a13768b 100644
--- a/source/blender/makesdna/DNA_sensor_types.h
+++ b/source/blender/makesdna/DNA_sensor_types.h
@@ -57,7 +57,9 @@ typedef struct bMouseSensor {
short type;
short flag;
short pad1;
- short pad2;
+ short mode; /* flag to choose material or property */
+ char propname[64];
+ char matname[64];
} bMouseSensor;
/* DEPRECATED */
@@ -202,6 +204,8 @@ typedef struct bJoystickSensor {
#define SENS_PROP_INTERVAL 2
#define SENS_PROP_CHANGED 3
#define SENS_PROP_EXPRESSION 4
+#define SENS_PROP_LESSTHAN 5
+#define SENS_PROP_GREATERTHAN 6
/* raysensor->axisflag */
/* flip x and y to make y default!!! */
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 69d4693ab05..af33ae80ed9 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -193,6 +193,8 @@ typedef struct MetaStack {
struct MetaStack *next, *prev;
ListBase *oldbasep;
Sequence *parseq;
+ /* the startdisp/enddisp when entering the meta */
+ int disp_range[2];
} MetaStack;
typedef struct Editing {
@@ -249,6 +251,11 @@ typedef struct SpeedControlVars {
int lastValidFrame;
} SpeedControlVars;
+typedef struct GaussianBlurVars {
+ float size_x;
+ float size_y;
+} GaussianBlurVars;
+
/* ***************** Sequence modifiers ****************** */
typedef struct SequenceModifierData {
@@ -421,7 +428,8 @@ enum {
SEQ_TYPE_SPEED = 29,
SEQ_TYPE_MULTICAM = 30,
SEQ_TYPE_ADJUSTMENT = 31,
- SEQ_TYPE_EFFECT_MAX = 31
+ SEQ_TYPE_GAUSSIAN_BLUR = 40,
+ SEQ_TYPE_EFFECT_MAX = 40
};
#define SEQ_MOVIECLIP_RENDER_UNDISTORTED (1 << 0)
@@ -434,7 +442,7 @@ enum {
*/
-#define SEQ_HAS_PATH(_seq) (ELEM4((_seq)->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD))
+#define SEQ_HAS_PATH(_seq) (ELEM((_seq)->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD))
/* modifiers */
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index c7a6d4809a5..a267217abf6 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -57,7 +57,6 @@ struct Scopes;
struct Histogram;
struct SpaceIpo;
struct BlendHandle;
-struct RenderInfo;
struct bNodeTree;
struct uiBlock;
struct FileList;
@@ -809,6 +808,8 @@ typedef enum eSpaceImage_Flag {
SI_DRAW_OTHER = (1 << 23),
SI_COLOR_CORRECTION = (1 << 24),
+
+ SI_NO_DRAW_TEXPAINT = (1 << 25)
} eSpaceImage_Flag;
/* Text Editor ============================================ */
@@ -989,6 +990,7 @@ typedef enum eSpaceNode_TexFrom {
typedef enum eSpaceNode_ShaderFrom {
SNODE_SHADER_OBJECT = 0,
SNODE_SHADER_WORLD = 1,
+ SNODE_SHADER_LINESTYLE = 2,
} eSpaceNode_ShaderFrom;
/* Game Logic Editor ===================================== */
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index 1906f71a230..d256cfb2e85 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -111,9 +111,12 @@ typedef struct CBData {
/* 32 = MAXCOLORBAND */
/* note that this has to remain a single struct, for UserDef */
typedef struct ColorBand {
- short flag, tot, cur, ipotype;
+ short tot, cur;
+ char ipotype, ipotype_hue;
+ char color_mode;
+ char pad[1];
+
CBData data[32];
-
} ColorBand;
typedef struct EnvMap {
@@ -498,7 +501,6 @@ typedef struct ColorMapping {
#define MTEX_BLEND_SAT 11
#define MTEX_BLEND_VAL 12
#define MTEX_BLEND_COLOR 13
-/* free for use */
#define MTEX_SOFT_LIGHT 15
#define MTEX_LIN_LIGHT 16
@@ -510,6 +512,32 @@ typedef struct ColorMapping {
#define MTEX_MAP_MODE_RANDOM 4
#define MTEX_MAP_MODE_STENCIL 5
+/* **************** ColorBand ********************* */
+
+/* colormode */
+enum {
+ COLBAND_BLEND_RGB = 0,
+ COLBAND_BLEND_HSV = 1,
+ COLBAND_BLEND_HSL = 2,
+};
+
+/* interpolation */
+enum {
+ COLBAND_INTERP_LINEAR = 0,
+ COLBAND_INTERP_EASE = 1,
+ COLBAND_INTERP_B_SPLINE = 2,
+ COLBAND_INTERP_CARDINAL = 3,
+ COLBAND_INTERP_CONSTANT = 4,
+};
+
+/* color interpolation */
+enum {
+ COLBAND_HUE_NEAR = 0,
+ COLBAND_HUE_FAR = 1,
+ COLBAND_HUE_CW = 2,
+ COLBAND_HUE_CCW = 3,
+};
+
/* **************** EnvMap ********************* */
/* type */
@@ -585,7 +613,7 @@ typedef struct ColorMapping {
#define TEX_VD_IMAGE_SEQUENCE 3
#define TEX_VD_SMOKE 4
/* for voxels which use VoxelData->source_path */
-#define TEX_VD_IS_SOURCE_PATH(_format) (ELEM3(_format, TEX_VD_BLENDERVOXEL, TEX_VD_RAW_8BIT, TEX_VD_RAW_16BIT))
+#define TEX_VD_IS_SOURCE_PATH(_format) (ELEM(_format, TEX_VD_BLENDERVOXEL, TEX_VD_RAW_8BIT, TEX_VD_RAW_16BIT))
/* smoke data types */
#define TEX_VD_SMOKEDENSITY 0
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 4f5670d16c1..769e2573aa4 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -154,7 +154,6 @@ typedef struct uiGradientColors {
char high_gradient[4];
int show_grad;
int pad2;
-
} uiGradientColors;
typedef struct ThemeUI {
@@ -163,7 +162,7 @@ typedef struct ThemeUI {
uiWidgetColors wcol_radio, wcol_option, wcol_toggle;
uiWidgetColors wcol_num, wcol_numslider;
uiWidgetColors wcol_menu, wcol_pulldown, wcol_menu_back, wcol_menu_item, wcol_tooltip;
- uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item;
+ uiWidgetColors wcol_box, wcol_scroll, wcol_progress, wcol_list_item, wcol_pie_menu;
uiWidgetStateColors wcol_state;
@@ -246,6 +245,7 @@ typedef struct ThemeSpace {
char extra_edge_len[4], extra_edge_angle[4], extra_face_angle[4], extra_face_area[4];
char normal[4];
char vertex_normal[4];
+ char loop_normal[4];
char bone_solid[4], bone_pose[4], bone_pose_active[4];
char strip[4], strip_select[4];
char cframe[4];
@@ -263,7 +263,7 @@ typedef struct ThemeSpace {
char keyborder[4], keyborder_select[4];
char console_output[4], console_input[4], console_info[4], console_error[4];
- char console_cursor[4], console_select[4], pad1[4];
+ char console_cursor[4], console_select[4];
char vertex_size, outline_width, facedot_size;
char noodle_curving;
@@ -328,6 +328,9 @@ typedef struct ThemeSpace {
char info_warning[4], info_warning_text[4];
char info_info[4], info_info_text[4];
char info_debug[4], info_debug_text[4];
+
+ char paint_curve_pivot[4];
+ char paint_curve_handle[4];
} ThemeSpace;
@@ -422,6 +425,8 @@ typedef struct UserDef {
char tempdir[768]; /* FILE_MAXDIR length */
char fontdir[768];
char renderdir[1024]; /* FILE_MAX length */
+ /* EXR cache path */
+ char render_cachedir[768]; /* 768 = FILE_MAXDIR */
char textudir[768];
char pythondir[768];
char sounddir[768];
@@ -487,7 +492,8 @@ typedef struct UserDef {
short color_picker_type;
char ipo_new; /* interpolation mode for newly added F-Curves */
char keyhandles_new; /* handle types for newly added keyframes */
- char pad1[2];
+ char gpu_select_method;
+ char pad1;
short scrcastfps; /* frame rate for screencast to be played back */
short scrcastwait; /* milliseconds between screencast snapshots */
@@ -521,11 +527,23 @@ typedef struct UserDef {
char author[80]; /* author name for file formats supporting it */
+ char font_path_ui[1024];
+
int compute_device_type;
int compute_device_id;
float fcu_inactive_alpha; /* opacity of inactive F-Curves in F-Curve Editor */
float pixelsize; /* private, set by GHOST, to multiply DPI with */
+ int virtual_pixel; /* virtual pixelsize mode */
+
+ short pie_interaction_type; /* if keeping a pie menu spawn button pressed after this time, it turns into
+ * a drag/release pie menu */
+ short pie_initial_timeout; /* direction in the pie menu will always be calculated from the initial position
+ * within this time limit */
+ short pie_animation_timeout;
+ short pie_menu_confirm;
+ short pie_menu_radius; /* pie menu radius */
+ short pie_menu_threshold; /* pie menu distance from center before a direction is set */
struct WalkNavigation walk_navigation;
} UserDef;
@@ -712,6 +730,13 @@ typedef enum eOpenGL_RenderingOptions {
/* USER_DISABLE_AA = (1 << 4), */ /* DEPRECATED */
} eOpenGL_RenderingOptions;
+/* selection method for opengl gpu_select_method */
+typedef enum eOpenGL_SelectOptions {
+ USER_SELECT_AUTO = 0,
+ USER_SELECT_USE_OCCLUSION_QUERY = 1,
+ USER_SELECT_USE_SELECT_RENDERMODE = 2
+} eOpenGL_SelectOptions;
+
/* wm draw method */
typedef enum eWM_DrawMethod {
USER_DRAW_TRIPLE = 0,
@@ -830,6 +855,11 @@ typedef enum eImageDrawMethod {
IMAGE_DRAW_METHOD_DRAWPIXELS = 3,
} eImageDrawMethod;
+typedef enum eUserpref_VirtualPixel {
+ VIRTUAL_PIXEL_NATIVE = 0,
+ VIRTUAL_PIXEL_DOUBLE = 1,
+} eUserpref_VirtualPixel;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesdna/DNA_vfont_types.h b/source/blender/makesdna/DNA_vfont_types.h
index 416c5f594a3..7025a5767c4 100644
--- a/source/blender/makesdna/DNA_vfont_types.h
+++ b/source/blender/makesdna/DNA_vfont_types.h
@@ -65,6 +65,9 @@ typedef struct VFont {
#define FO_PAGEDOWN 9
#define FO_SELCHANGE 10
+/* BKE_vfont_to_curve will move the cursor in these cases */
+#define FO_CURS_IS_MOTION(mode) (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN))
+
#define FO_BUILTIN_NAME "<builtin>"
#endif /* __DNA_VFONT_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 98c12e9cc11..3efba488299 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -41,7 +41,6 @@ struct Base;
struct BoundBox;
struct MovieClip;
struct MovieClipUser;
-struct RenderInfo;
struct RenderEngine;
struct bGPdata;
struct SmoothView3DStore;
@@ -102,7 +101,6 @@ typedef struct RegionView3D {
struct BoundBox *clipbb;
struct RegionView3D *localvd; /* allocated backup of its self while in localview */
- struct RenderInfo *ri;
struct RenderEngine *render_engine;
struct ViewDepths *depths;
void *gpuoffscreen;
diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h
index a17e416b5bd..4cf6bfe9a8f 100644
--- a/source/blender/makesdna/DNA_windowmanager_types.h
+++ b/source/blender/makesdna/DNA_windowmanager_types.h
@@ -171,11 +171,6 @@ typedef struct wmWindow {
void *ghostwin; /* don't want to include ghost.h stuff */
- int winid; /* winid also in screens, is for retrieving this window after read */
-
- short grabcursor; /* cursor grab mode */
- short pad;
-
struct bScreen *screen; /* active screen */
struct bScreen *newscreen; /* temporary when switching */
char screenname[64]; /* MAX_ID_NAME for matching window with active screen after file read */
@@ -187,8 +182,14 @@ typedef struct wmWindow {
short cursor; /* current mouse cursor type */
short lastcursor; /* previous cursor when setting modal one */
short modalcursor; /* the current modal cursor */
+ short grabcursor; /* cursor grab mode */
short addmousemove; /* internal: tag this for extra mousemove event, makes cursors/buttons active on UI switching */
- short pad2;
+
+ int winid; /* winid also in screens, is for retrieving this window after read */
+
+ short lock_pie_event; /* internal, lock pie creation from this event until released */
+ short last_pie_event; /* exception to the above rule for nested pies, store last pie event for operators
+ * that spawn a new pie right after destruction of last pie */
struct wmEvent *eventstate; /* storage for event system */
diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c
index bc1ee28d582..f60562f1ac9 100644
--- a/source/blender/makesdna/intern/dna_genfile.c
+++ b/source/blender/makesdna/intern/dna_genfile.c
@@ -1304,8 +1304,9 @@ bool DNA_struct_elem_find(SDNA *sdna, const char *stype, const char *vartype, co
const short * const spo = sdna->structs[SDNAnr];
const char * const cp = find_elem(sdna, vartype, name, spo, NULL, NULL);
- if (cp) return true;
- return (int)((intptr_t)cp);
+ if (cp) {
+ return true;
+ }
}
return false;
}
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index add59bafc3f..f0582b39819 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -262,6 +262,7 @@ extern StructRNA RNA_GameProperty;
extern StructRNA RNA_GameSoftBodySettings;
extern StructRNA RNA_GameStringProperty;
extern StructRNA RNA_GameTimerProperty;
+extern StructRNA RNA_GaussianBlurSequence;
extern StructRNA RNA_GlowSequence;
extern StructRNA RNA_GreasePencil;
extern StructRNA RNA_Group;
@@ -277,6 +278,7 @@ extern StructRNA RNA_ImagePaint;
extern StructRNA RNA_ImageSequence;
extern StructRNA RNA_ImageTexture;
extern StructRNA RNA_ImageUser;
+extern StructRNA RNA_ImapaintToolCapabilities;
extern StructRNA RNA_InflowFluidSettings;
extern StructRNA RNA_IntProperty;
extern StructRNA RNA_Itasc;
@@ -427,6 +429,9 @@ extern StructRNA RNA_OrController;
extern StructRNA RNA_OutflowFluidSettings;
extern StructRNA RNA_PackedFile;
extern StructRNA RNA_Paint;
+extern StructRNA RNA_PaintCurve;
+extern StructRNA RNA_Palette;
+extern StructRNA RNA_PaletteColor;
extern StructRNA RNA_Panel;
extern StructRNA RNA_Particle;
extern StructRNA RNA_ParticleBrush;
@@ -630,6 +635,7 @@ extern StructRNA RNA_TransformConstraint;
extern StructRNA RNA_TransformSequence;
extern StructRNA RNA_UILayout;
extern StructRNA RNA_UIList;
+extern StructRNA RNA_UIPieMenu;
extern StructRNA RNA_UIPopupMenu;
extern StructRNA RNA_UVWarpModifier;
extern StructRNA RNA_UVProjectModifier;
@@ -791,6 +797,8 @@ void RNA_property_enum_items(struct bContext *C, PointerRNA *ptr, PropertyRNA *p
EnumPropertyItem **item, int *r_totitem, bool *r_free);
void RNA_property_enum_items_gettexted(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop,
EnumPropertyItem **r_item, int *r_totitem, bool *r_free);
+void RNA_property_enum_items_gettexted_all(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop,
+ EnumPropertyItem **r_item, int *r_totitem, bool *r_free);
bool RNA_property_enum_value(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value);
bool RNA_property_enum_identifier(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **identifier);
bool RNA_property_enum_name(struct bContext *C, PointerRNA *ptr, PropertyRNA *prop, const int value, const char **name);
@@ -924,9 +932,22 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path,
bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path,
PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index);
+typedef struct PropertyElemRNA PropertyElemRNA;
+struct PropertyElemRNA {
+ PropertyElemRNA *next, *prev;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+ int index;
+};
+bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, struct ListBase *r_elements);
+
char *RNA_path_from_ID_to_struct(PointerRNA *ptr);
char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop);
+char *RNA_path_resolve_from_type_to_property(
+ struct PointerRNA *ptr, struct PropertyRNA *prop,
+ const struct StructRNA *type);
+
char *RNA_path_full_ID_py(struct ID *id);
char *RNA_path_full_struct_py(struct PointerRNA *ptr);
char *RNA_path_full_property_py(struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
@@ -1019,12 +1040,12 @@ void RNA_collection_clear(PointerRNA *ptr, const char *name);
CollectionPropertyIterator rna_macro_iter; \
for (RNA_property_collection_begin( \
sptr, \
- RNA_struct_iterator_property(sptr->type), \
+ RNA_struct_iterator_property((sptr)->type), \
&rna_macro_iter); \
rna_macro_iter.valid; \
RNA_property_collection_next(&rna_macro_iter)) \
{ \
- PropertyRNA *prop = rna_macro_iter.ptr.data;
+ PropertyRNA *prop = (PropertyRNA *)rna_macro_iter.ptr.data;
#define RNA_STRUCT_END \
} \
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index 7abda8790c3..4e7a564e9d4 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -38,7 +38,8 @@ incs = [
'#/intern/guardedalloc',
'#/intern/atomic',
'#/intern/memutil',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/audaspace/intern',
'#/intern/cycles/blender',
'#/intern/smoke/extern',
@@ -57,7 +58,7 @@ incs = [
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_SMOKE']:
defs.append('WITH_SMOKE')
@@ -117,6 +118,9 @@ if env['WITH_BF_OCEANSIM']:
if env['WITH_BF_CYCLES']:
defs.append('WITH_CYCLES')
+ if env['WITH_BF_CYCLES_DEBUG']:
+ defs.append('WITH_CYCLES_DEBUG')
+
if env['WITH_BF_SDL']:
defs.append('WITH_SDL')
@@ -126,6 +130,10 @@ if env['WITH_BF_OPENAL']:
if env['WITH_BF_JACK']:
defs.append('WITH_JACK')
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+ incs += ' ../freestyle'
+
if env['OURPLATFORM'] == 'linux':
cflags='-pthread'
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 6a0208a49e9..5d736f9c011 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -155,6 +155,9 @@ set(INC_SYS
if(WITH_CYCLES)
add_definitions(-DWITH_CYCLES)
+ if(WITH_CYCLES_DEBUG)
+ add_definitions(-DWITH_CYCLES_DEBUG)
+ endif()
endif()
if(WITH_PYTHON)
@@ -264,6 +267,13 @@ if(WITH_BULLET)
add_definitions(-DWITH_BULLET)
endif()
+if(WITH_FREESTYLE)
+ list(APPEND INC
+ ../../freestyle
+ )
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
# Build makesrna executable
blender_include_dirs(
.
@@ -283,13 +293,14 @@ blender_include_dirs(
../../../../intern/audaspace/intern
../../../../intern/cycles/blender
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
../../../../intern/atomic
../../../../intern/memutil
../../../../intern/smoke/extern
)
blender_include_dirs_sys(
- ${GLEW_INCLUDE_PATH}
+ "${GLEW_INCLUDE_PATH}"
)
add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC})
@@ -318,4 +329,6 @@ set(SRC
rna_mesh_utils.h
)
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(bf_rna "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
index 1acc1e85aef..415f5497a7e 100644
--- a/source/blender/makesrna/intern/SConscript
+++ b/source/blender/makesrna/intern/SConscript
@@ -53,11 +53,12 @@ makesrna_tool = env.Clone()
rna = env.Clone()
makesrna_tool.Append(CCFLAGS = '-DBASE_HEADER="\\"source/blender/makesrna/\\"" ')
-defs = []
+defs = env['BF_GL_DEFINITIONS']
incs = [
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/audaspace/intern',
'#/intern/cycles/blender',
'#/intern/smoke/extern',
@@ -67,6 +68,7 @@ incs = [
'../../blenlib',
'../../bmesh',
'../../editors/include',
+ '../../gpu',
'../../ikplugin',
'../../imbuf',
'../../makesdna',
@@ -144,6 +146,12 @@ if env['WITH_BF_COLLADA']:
if env['WITH_BF_CYCLES']:
defs.append('WITH_CYCLES')
+ if env['WITH_BF_CYCLES_DEBUG']:
+ defs.append('WITH_CYCLES_DEBUG')
+
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+ incs += ' ../../freestyle'
if env['OURPLATFORM'] == 'linux':
cflags='-pthread'
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 7f1f04cdb6a..9023f25e3d5 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -745,6 +745,24 @@ static void rna_clamp_value_range(FILE *f, PropertyRNA *prop)
}
}
+#ifdef USE_RNA_RANGE_CHECK
+static void rna_clamp_value_range_check(
+ FILE *f, PropertyRNA *prop,
+ const char *dnaname_prefix, const char *dnaname)
+{
+ if (prop->type == PROP_INT) {
+ IntPropertyRNA *iprop = (IntPropertyRNA *)prop;
+ fprintf(f,
+ " { BLI_STATIC_ASSERT("
+ "(TYPEOF_MAX(%s%s) >= %d) && "
+ "(TYPEOF_MIN(%s%s) <= %d), "
+ "\"invalid limits\"); }\n",
+ dnaname_prefix, dnaname, iprop->hardmax,
+ dnaname_prefix, dnaname, iprop->hardmin);
+ }
+}
+#endif /* USE_RNA_RANGE_CHECK */
+
static void rna_clamp_value(FILE *f, PropertyRNA *prop, int array)
{
if (prop->type == PROP_INT) {
@@ -944,6 +962,18 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr
}
fprintf(f, " }\n");
}
+
+#ifdef USE_RNA_RANGE_CHECK
+ if (dp->dnaname && manualfunc == NULL) {
+ if (dp->dnaarraylength == 1) {
+ rna_clamp_value_range_check(f, prop, "data->", dp->dnaname);
+ }
+ else {
+ rna_clamp_value_range_check(f, prop, "*data->", dp->dnaname);
+ }
+ }
+#endif
+
fprintf(f, "}\n\n");
}
else {
@@ -975,6 +1005,13 @@ static char *rna_def_property_set_func(FILE *f, StructRNA *srna, PropertyRNA *pr
rna_clamp_value(f, prop, 0);
}
}
+
+#ifdef USE_RNA_RANGE_CHECK
+ if (dp->dnaname && manualfunc == NULL) {
+ rna_clamp_value_range_check(f, prop, "data->", dp->dnaname);
+ }
+#endif
+
fprintf(f, "}\n\n");
}
break;
diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c
index 7959e60da33..51d81295f8c 100644
--- a/source/blender/makesrna/intern/rna_ID.c
+++ b/source/blender/makesrna/intern/rna_ID.c
@@ -60,11 +60,14 @@ EnumPropertyItem id_type_items[] = {
{ID_LI, "LIBRARY", ICON_LIBRARY_DATA_DIRECT, "Library", ""},
{ID_LS, "LINESTYLE", ICON_LINE_DATA, "Line Style", ""},
{ID_LT, "LATTICE", ICON_LATTICE_DATA, "Lattice", ""},
+ {ID_MSK, "MASK", ICON_MOD_MASK, "Mask", ""},
{ID_MA, "MATERIAL", ICON_MATERIAL_DATA, "Material", ""},
{ID_MB, "META", ICON_META_DATA, "MetaBall", ""},
{ID_ME, "MESH", ICON_MESH_DATA, "Mesh", ""},
{ID_NT, "NODETREE", ICON_NODETREE, "NodeTree", ""},
{ID_OB, "OBJECT", ICON_OBJECT_DATA, "Object", ""},
+ {ID_PC, "PAINTCURVE", ICON_CURVE_BEZCURVE, "Paint Curve", ""},
+ {ID_PAL, "PALETTE", ICON_COLOR, "Palette", ""},
{ID_PA, "PARTICLE", ICON_PARTICLE_DATA, "Particle", ""},
{ID_SCE, "SCENE", ICON_SCENE_DATA, "Scene", ""},
{ID_SCR, "SCREEN", ICON_SPLITSCREEN, "Screen", ""},
@@ -153,6 +156,8 @@ short RNA_type_to_ID_code(StructRNA *type)
if (RNA_struct_is_a(type, &RNA_WindowManager)) return ID_WM;
if (RNA_struct_is_a(type, &RNA_MovieClip)) return ID_MC;
if (RNA_struct_is_a(type, &RNA_Mask)) return ID_MSK;
+ if (RNA_struct_is_a(type, &RNA_Palette)) return ID_PAL;
+ if (RNA_struct_is_a(type, &RNA_PaintCurve)) return ID_PC;
return 0;
}
@@ -190,6 +195,9 @@ StructRNA *ID_code_to_RNA_type(short idcode)
case ID_WM: return &RNA_WindowManager;
case ID_MC: return &RNA_MovieClip;
case ID_MSK: return &RNA_Mask;
+ case ID_PAL: return &RNA_Palette;
+ case ID_PC: return &RNA_PaintCurve;
+
default: return &RNA_ID;
}
}
@@ -620,6 +628,10 @@ static void rna_def_library(BlenderRNA *brna)
prop = RNA_def_property(srna, "parent", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Library");
RNA_def_property_ui_text(prop, "Parent", "");
+
+ 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", "");
}
void RNA_def_ID(BlenderRNA *brna)
{
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index ded0278b44d..806b9d0d5ad 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -55,6 +55,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
@@ -359,12 +360,12 @@ static bool rna_idproperty_verify_valid(PointerRNA *ptr, PropertyRNA *prop, IDPr
if (idprop->subtype == IDP_FLOAT && prop->type != PROP_FLOAT)
return false;
- if (idprop->subtype == IDP_INT && !ELEM3(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM))
+ if (idprop->subtype == IDP_INT && !ELEM(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM))
return false;
break;
case IDP_INT:
- if (!ELEM3(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM))
+ if (!ELEM(prop->type, PROP_BOOLEAN, PROP_INT, PROP_ENUM))
return false;
break;
case IDP_FLOAT:
@@ -872,8 +873,8 @@ char RNA_property_array_item_char(PropertyRNA *prop, int index)
if ((index < 4) && ELEM(subtype, PROP_QUATERNION, PROP_AXISANGLE)) {
return quatitem[index];
}
- else if ((index < 4) && ELEM8(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_XYZ_LENGTH,
- PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION, PROP_COORDS))
+ else if ((index < 4) && ELEM(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_XYZ_LENGTH,
+ PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION, PROP_COORDS))
{
return vectoritem[index];
}
@@ -902,7 +903,7 @@ int RNA_property_array_item_index(PropertyRNA *prop, char name)
return 3;
}
}
- else if (ELEM6(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ,
+ else if (ELEM(subtype, PROP_TRANSLATION, PROP_DIRECTION, PROP_XYZ, PROP_XYZ_LENGTH,
PROP_EULER, PROP_VELOCITY, PROP_ACCELERATION))
{
switch (name) {
@@ -1249,12 +1250,9 @@ void RNA_property_enum_items(bContext *C, PointerRNA *ptr, PropertyRNA *prop, En
}
}
-void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop,
- EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
-{
- RNA_property_enum_items(C, ptr, prop, r_item, r_totitem, r_free);
-
#ifdef WITH_INTERNATIONAL
+static void property_enum_translate(PropertyRNA *prop, EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
+{
if (!(prop->flag & PROP_ENUM_NO_TRANSLATE)) {
int i;
@@ -1300,9 +1298,71 @@ void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA
*r_item = nitem;
}
+}
+#endif
+
+void RNA_property_enum_items_gettexted(bContext *C, PointerRNA *ptr, PropertyRNA *prop,
+ EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
+{
+ RNA_property_enum_items(C, ptr, prop, r_item, r_totitem, r_free);
+
+#ifdef WITH_INTERNATIONAL
+ property_enum_translate(prop, r_item, r_totitem, r_free);
#endif
}
+void RNA_property_enum_items_gettexted_all(bContext *C, PointerRNA *ptr, PropertyRNA *prop,
+ EnumPropertyItem **r_item, int *r_totitem, bool *r_free)
+{
+ EnumPropertyRNA *eprop = (EnumPropertyRNA *)rna_ensure_property(prop);
+ int mem_size = sizeof(EnumPropertyItem) * (eprop->totitem + 1);
+ /* first return all items */
+ *r_free = true;
+ *r_item = MEM_mallocN(mem_size, "enum_gettext_all");
+ memcpy(*r_item, eprop->item, mem_size);
+
+ if (r_totitem)
+ *r_totitem = eprop->totitem;
+
+ if (eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) {
+ EnumPropertyItem *item;
+ int i;
+ bool free = false;
+
+ if (prop->flag & PROP_ENUM_NO_CONTEXT)
+ item = eprop->itemf(NULL, ptr, prop, &free);
+ else
+ item = eprop->itemf(C, ptr, prop, &free);
+
+ /* any callbacks returning NULL should be fixed */
+ BLI_assert(item != NULL);
+
+ for (i = 0; i < eprop->totitem; i++) {
+ bool exists = false;
+ int i_fixed;
+
+ /* items that do not exist on list are returned, but have their names/identifiers NULLed out */
+ for (i_fixed = 0; item[i_fixed].identifier; i_fixed++) {
+ if (STREQ(item[i_fixed].identifier, (*r_item)[i].identifier)) {
+ exists = true;
+ break;
+ }
+ }
+
+ if (!exists) {
+ (*r_item)[i].name = NULL;
+ (*r_item)[i].identifier = "";
+ }
+ }
+
+ if (free)
+ MEM_freeN(item);
+ }
+
+#ifdef WITH_INTERNATIONAL
+ property_enum_translate(prop, r_item, r_totitem, r_free);
+#endif
+}
bool RNA_property_enum_value(bContext *C, PointerRNA *ptr, PropertyRNA *prop, const char *identifier, int *r_value)
{
@@ -3329,7 +3389,7 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro
/* check type */
itemtype = RNA_property_type(itemprop);
- if (!ELEM3(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
BKE_report(reports, RPT_ERROR, "Only boolean, int and float properties supported");
return 0;
}
@@ -3409,7 +3469,7 @@ static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *pro
break;
}
- if (!ELEM3(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
+ if (!ELEM(itemtype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) {
BKE_report(reports, RPT_ERROR, "Only boolean, int and float properties supported");
err = 1;
break;
@@ -4015,11 +4075,14 @@ static bool rna_path_parse_array_index(const char **path, PointerRNA *ptr, Prope
}
static bool rna_path_parse(PointerRNA *ptr, const char *path,
- PointerRNA *r_ptr, PropertyRNA **r_prop, int *index,
+ PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index,
+ ListBase *r_elements,
const bool eval_pointer)
{
PropertyRNA *prop;
PointerRNA curptr;
+ PropertyElemRNA *prop_elem = NULL;
+ int index = -1;
char fixedbuf[256];
int type;
@@ -4061,6 +4124,14 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
if (!prop)
return false;
+ if (r_elements) {
+ prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__);
+ prop_elem->ptr = curptr;
+ prop_elem->prop = prop;
+ prop_elem->index = -1; /* index will be added later, if needed. */
+ BLI_addtail(r_elements, prop_elem);
+ }
+
type = RNA_property_type(prop);
/* now look up the value of this property if it is a pointer or
@@ -4076,7 +4147,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
curptr = nextptr;
prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
- if (index) *index = -1;
+ index = -1;
}
break;
}
@@ -4093,21 +4164,38 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
curptr = nextptr;
prop = NULL; /* now we have a PointerRNA, the prop is our parent so forget it */
- if (index) *index = -1;
+ index = -1;
}
break;
}
default:
- if (index) {
- if (!rna_path_parse_array_index(&path, &curptr, prop, index))
+ if (r_index || prop_elem) {
+ if (!rna_path_parse_array_index(&path, &curptr, prop, &index)) {
return false;
+ }
+
+ if (prop_elem) {
+ prop_elem->index = index;
+ }
}
break;
}
}
- *r_ptr = curptr;
- *r_prop = prop;
+ if (r_ptr)
+ *r_ptr = curptr;
+ if (r_prop)
+ *r_prop = prop;
+ if (r_index)
+ *r_index = index;
+
+ if (prop_elem && (prop_elem->ptr.data != curptr.data || prop_elem->prop != prop || prop_elem->index != index)) {
+ PropertyElemRNA *prop_elem = MEM_mallocN(sizeof(PropertyElemRNA), __func__);
+ prop_elem->ptr = curptr;
+ prop_elem->prop = prop;
+ prop_elem->index = index;
+ BLI_addtail(r_elements, prop_elem);
+ }
return true;
}
@@ -4120,7 +4208,7 @@ static bool rna_path_parse(PointerRNA *ptr, const char *path,
*/
bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, true))
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, true))
return false;
return r_ptr->data != NULL;
@@ -4134,7 +4222,7 @@ bool RNA_path_resolve(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, Prop
*/
bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, true))
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, true))
return false;
return r_ptr->data != NULL;
@@ -4149,7 +4237,7 @@ bool RNA_path_resolve_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr,
*/
bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, false))
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, NULL, NULL, false))
return false;
return r_ptr->data != NULL && *r_prop != NULL;
@@ -4165,12 +4253,25 @@ bool RNA_path_resolve_property(PointerRNA *ptr, const char *path, PointerRNA *r_
*/
bool RNA_path_resolve_property_full(PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop, int *r_index)
{
- if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, false))
+ if (!rna_path_parse(ptr, path, r_ptr, r_prop, r_index, NULL, false))
return false;
return r_ptr->data != NULL && *r_prop != NULL;
}
+/**
+ * Resolve the given RNA Path into a linked list of PropertyElemRNA's.
+ *
+ * To be used when complex operations over path are needed, like e.g. get relative paths, to avoid too much
+ * string operations.
+ *
+ * \return True if there was no error while resolving the path
+ * \note Assumes all pointers provided are valid
+ */
+bool RNA_path_resolve_elements(PointerRNA *ptr, const char *path, ListBase *r_elements)
+{
+ return rna_path_parse(ptr, path, NULL, NULL, NULL, r_elements, false);
+}
char *RNA_path_append(const char *path, PointerRNA *UNUSED(ptr), PropertyRNA *prop, int intkey, const char *strkey)
{
@@ -4498,6 +4599,47 @@ char *RNA_path_from_ID_to_property(PointerRNA *ptr, PropertyRNA *prop)
}
/**
+ * \return the path to given ptr/prop from the closest ancestor of given type, if any (else return NULL).
+ */
+char *RNA_path_resolve_from_type_to_property(
+ PointerRNA *ptr, PropertyRNA *prop,
+ const StructRNA *type)
+{
+ /* Try to recursively find an "type"'d ancestor,
+ * to handle situations where path from ID is not enough. */
+ PointerRNA idptr;
+ ListBase path_elems = {NULL};
+ char *path = NULL;
+ char *full_path = RNA_path_from_ID_to_property(ptr, prop);
+
+ if (full_path == NULL) {
+ return NULL;
+ }
+
+ RNA_id_pointer_create(ptr->id.data, &idptr);
+
+ if (RNA_path_resolve_elements(&idptr, full_path, &path_elems)) {
+ PropertyElemRNA *prop_elem;
+
+ for (prop_elem = path_elems.last; prop_elem; prop_elem = prop_elem->prev) {
+ if (RNA_struct_is_a(prop_elem->ptr.type, type)) {
+ char *ref_path = RNA_path_from_ID_to_struct(&prop_elem->ptr);
+ if (ref_path) {
+ path = BLI_strdup(full_path + strlen(ref_path) + 1); /* +1 for the linking '.' */
+ MEM_freeN(ref_path);
+ }
+ break;
+ }
+ }
+
+ BLI_freelistN(&path_elems);
+ }
+
+ MEM_freeN(full_path);
+ return path;
+}
+
+/**
* Get the ID as a python representation, eg:
* bpy.data.foo["bar"]
*/
@@ -6323,18 +6465,29 @@ bool RNA_property_reset(PointerRNA *ptr, PropertyRNA *prop, int index)
return false;
}
}
-
+
bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop, int index)
{
int len, fromlen;
+ PropertyRNA *fromprop = prop;
+
+ if (prop->magic != RNA_MAGIC) {
+ /* 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);
+ /* 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);
+ }
+ }
/* get the length of the array to work with */
len = RNA_property_array_length(ptr, prop);
- fromlen = RNA_property_array_length(fromptr, prop);
+ fromlen = RNA_property_array_length(fromptr, fromprop);
if (len != fromlen)
return false;
-
+
/* get and set the default values as appropriate for the various types */
switch (RNA_property_type(prop)) {
case PROP_BOOLEAN:
@@ -6342,18 +6495,18 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop,
if (index == -1) {
int *tmparray = MEM_callocN(sizeof(int) * len, "copy - boolean");
- RNA_property_boolean_get_array(fromptr, prop, tmparray);
+ RNA_property_boolean_get_array(fromptr, fromprop, tmparray);
RNA_property_boolean_set_array(ptr, prop, tmparray);
MEM_freeN(tmparray);
}
else {
- int value = RNA_property_boolean_get_index(fromptr, prop, index);
+ int value = RNA_property_boolean_get_index(fromptr, fromprop, index);
RNA_property_boolean_set_index(ptr, prop, index, value);
}
}
else {
- int value = RNA_property_boolean_get(fromptr, prop);
+ int value = RNA_property_boolean_get(fromptr, fromprop);
RNA_property_boolean_set(ptr, prop, value);
}
return true;
@@ -6362,18 +6515,18 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop,
if (index == -1) {
int *tmparray = MEM_callocN(sizeof(int) * len, "copy - int");
- RNA_property_int_get_array(fromptr, prop, tmparray);
+ RNA_property_int_get_array(fromptr, fromprop, tmparray);
RNA_property_int_set_array(ptr, prop, tmparray);
MEM_freeN(tmparray);
}
else {
- int value = RNA_property_int_get_index(fromptr, prop, index);
+ int value = RNA_property_int_get_index(fromptr, fromprop, index);
RNA_property_int_set_index(ptr, prop, index, value);
}
}
else {
- int value = RNA_property_int_get(fromptr, prop);
+ int value = RNA_property_int_get(fromptr, fromprop);
RNA_property_int_set(ptr, prop, value);
}
return true;
@@ -6382,36 +6535,36 @@ bool RNA_property_copy(PointerRNA *ptr, PointerRNA *fromptr, PropertyRNA *prop,
if (index == -1) {
float *tmparray = MEM_callocN(sizeof(float) * len, "copy - float");
- RNA_property_float_get_array(fromptr, prop, tmparray);
+ RNA_property_float_get_array(fromptr, fromprop, tmparray);
RNA_property_float_set_array(ptr, prop, tmparray);
MEM_freeN(tmparray);
}
else {
- float value = RNA_property_float_get_index(fromptr, prop, index);
+ float value = RNA_property_float_get_index(fromptr, fromprop, index);
RNA_property_float_set_index(ptr, prop, index, value);
}
}
else {
- float value = RNA_property_float_get(fromptr, prop);
+ float value = RNA_property_float_get(fromptr, fromprop);
RNA_property_float_set(ptr, prop, value);
}
return true;
case PROP_ENUM:
{
- int value = RNA_property_enum_get(fromptr, prop);
+ int value = RNA_property_enum_get(fromptr, fromprop);
RNA_property_enum_set(ptr, prop, value);
return true;
}
case PROP_POINTER:
{
- PointerRNA value = RNA_property_pointer_get(fromptr, prop);
+ PointerRNA value = RNA_property_pointer_get(fromptr, fromprop);
RNA_property_pointer_set(ptr, prop, value);
return true;
}
case PROP_STRING:
{
- char *value = RNA_property_string_get_alloc(fromptr, prop, NULL, 0, NULL);
+ char *value = RNA_property_string_get_alloc(fromptr, fromprop, NULL, 0, NULL);
RNA_property_string_set(ptr, prop, value);
MEM_freeN(value);
return true;
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index ecfa1286a78..750c98a536d 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -281,7 +281,7 @@ static void rna_def_dopesheet(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", ADS_FLAG_SHOW_DBFILTERS);
RNA_def_property_ui_text(prop, "Show Datablock Filters",
"Show options for whether channels related to certain types of data are included");
- RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, -1);
+ RNA_def_property_ui_icon(prop, ICON_DISCLOSURE_TRI_RIGHT, 1);
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN, NULL);
/* General Filtering Settings */
diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c
index fd04fb46cf1..0114ffa35c0 100644
--- a/source/blender/makesrna/intern/rna_actuator.c
+++ b/source/blender/makesrna/intern/rna_actuator.c
@@ -55,6 +55,7 @@ static EnumPropertyItem actuator_type_items[] = {
{ACT_2DFILTER, "FILTER_2D", 0, "Filter 2D", ""},
{ACT_GAME, "GAME", 0, "Game", ""},
{ACT_MESSAGE, "MESSAGE", 0, "Message", ""},
+ {ACT_MOUSE, "MOUSE", 0, "Mouse", ""},
{ACT_OBJECT, "MOTION", 0, "Motion", ""},
{ACT_PARENT, "PARENT", 0, "Parent", ""},
{ACT_PROPERTY, "PROPERTY", 0, "Property", ""},
@@ -110,6 +111,8 @@ static StructRNA *rna_Actuator_refine(struct PointerRNA *ptr)
return &RNA_ArmatureActuator;
case ACT_STEERING:
return &RNA_SteeringActuator;
+ case ACT_MOUSE:
+ return &RNA_MouseActuator;
default:
return &RNA_Actuator;
}
@@ -147,7 +150,7 @@ static void rna_ConstraintActuator_type_set(struct PointerRNA *ptr, int value)
switch (ca->type) {
case ACT_CONST_TYPE_ORI:
/* negative axis not supported in the orientation mode */
- if (ELEM3(ca->mode, ACT_CONST_DIRNX, ACT_CONST_DIRNY, ACT_CONST_DIRNZ))
+ if (ELEM(ca->mode, ACT_CONST_DIRNX, ACT_CONST_DIRNY, ACT_CONST_DIRNZ))
ca->mode = ACT_CONST_NONE;
break;
@@ -459,6 +462,7 @@ EnumPropertyItem *rna_Actuator_type_itemf(bContext *C, PointerRNA *ptr, Property
RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_2DFILTER);
RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_GAME);
RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_MESSAGE);
+ RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_MOUSE);
RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_OBJECT);
RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_PARENT);
RNA_enum_items_add_value(&item, &totitem, actuator_type_items, ACT_PROPERTY);
@@ -1086,6 +1090,7 @@ static void rna_def_property_actuator(BlenderRNA *brna)
{ACT_PROP_ADD, "ADD", 0, "Add", ""},
{ACT_PROP_COPY, "COPY", 0, "Copy", ""},
{ACT_PROP_TOGGLE, "TOGGLE", 0, "Toggle", "For bool/int/float/timer properties only"},
+ {ACT_PROP_LEVEL, "LEVEL", 0, "Level", "For bool/int/float/timer properties only"},
{0, NULL, 0, NULL, NULL}
};
@@ -1365,6 +1370,23 @@ static void rna_def_edit_object_actuator(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_track_axis_items[] = {
+ {ACT_TRACK_TRAXIS_X, "TRACKAXISX", 0, "X axis", ""},
+ {ACT_TRACK_TRAXIS_Y, "TRACKAXISY", 0, "Y axis", ""},
+ {ACT_TRACK_TRAXIS_Z, "TRACKAXISZ", 0, "Z axis", ""},
+ {ACT_TRACK_TRAXIS_NEGX, "TRACKAXISNEGX", 0, "-X axis", ""},
+ {ACT_TRACK_TRAXIS_NEGY, "TRACKAXISNEGY", 0, "-Y axis", ""},
+ {ACT_TRACK_TRAXIS_NEGZ, "TRACKAXISNEGZ", 0, "-Z axis", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_up_axis_items[] = {
+ {ACT_TRACK_UP_X, "UPAXISX", 0, "X axis", ""},
+ {ACT_TRACK_UP_Y, "UPAXISY", 0, "Y axis", ""},
+ {ACT_TRACK_UP_Z, "UPAXISZ", 0, "Z axis", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "EditObjectActuator", "Actuator");
RNA_def_struct_ui_text(srna, "Edit Object Actuator", "Actuator used to edit objects");
RNA_def_struct_sdna_from(srna, "bEditObjectActuator", "data");
@@ -1381,6 +1403,18 @@ static void rna_def_edit_object_actuator(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Dynamic Operation", "");
RNA_def_property_update(prop, NC_LOGIC, NULL);
+ prop = RNA_def_property(srna, "up_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "upflag");
+ RNA_def_property_enum_items(prop, prop_up_axis_items);
+ RNA_def_property_ui_text(prop, "Up Axis", "The axis that points upward");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "track_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "trackflag");
+ RNA_def_property_enum_items(prop, prop_track_axis_items);
+ RNA_def_property_ui_text(prop, "Track Axis", "The axis that points to the target object");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_pointer_sdna(prop, NULL, "ob");
@@ -2038,6 +2072,134 @@ static void rna_def_steering_actuator(BlenderRNA *brna)
RNA_def_property_update(prop, NC_LOGIC, NULL);
}
+static void rna_def_mouse_actuator(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_type_items[] = {
+ {ACT_MOUSE_VISIBILITY, "VISIBILITY", 0, "Visibility", ""},
+ {ACT_MOUSE_LOOK, "LOOK", 0, "Look", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_object_axis_items[] = {
+ {ACT_MOUSE_OBJECT_AXIS_X, "OBJECT_AXIS_X", 0, "X Axis", ""},
+ {ACT_MOUSE_OBJECT_AXIS_Y, "OBJECT_AXIS_Y", 0, "Y Axis", ""},
+ {ACT_MOUSE_OBJECT_AXIS_Z, "OBJECT_AXIS_Z", 0, "Z Axis", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "MouseActuator", "Actuator");
+ RNA_def_struct_ui_text(srna, "Mouse Actuator", "");
+ RNA_def_struct_sdna_from(srna, "bMouseActuator", "data");
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "type");
+ RNA_def_property_enum_items(prop, prop_type_items);
+ RNA_def_property_ui_text(prop, "Mode", "");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ /* Visibility */
+ prop = RNA_def_property(srna, "visible", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_VISIBLE);
+ RNA_def_property_ui_text(prop, "Visible", "Make mouse cursor visible");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ /* Mouse Look */
+ prop = RNA_def_property(srna, "use_axis_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_USE_AXIS_X);
+ RNA_def_property_ui_text(prop, "Use X Axis", "Calculate mouse movement on the X axis");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "use_axis_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_USE_AXIS_Y);
+ RNA_def_property_ui_text(prop, "Use Y Axis", "Calculate mouse movement on the Y axis");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "reset_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_RESET_X);
+ RNA_def_property_ui_text(prop, "Reset",
+ "Reset the cursor's X position to the center of the screen space after calculating");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "reset_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_RESET_Y);
+ RNA_def_property_ui_text(prop, "Reset",
+ "Reset the cursor's Y position to the center of the screen space after calculating");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "local_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_LOCAL_X);
+ RNA_def_property_ui_text(prop, "Local", "Apply rotation locally");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "local_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", ACT_MOUSE_LOCAL_Y);
+ RNA_def_property_ui_text(prop, "Local", "Apply rotation locally");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "threshold_x", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "threshold[0]");
+ RNA_def_property_ui_range(prop, 0, 0.5, 1, 3);
+ RNA_def_property_ui_text(prop, "Threshold", "Amount of X motion before mouse movement will register");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "threshold_y", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "threshold[1]");
+ RNA_def_property_ui_range(prop, 0, 0.5, 1, 3);
+ RNA_def_property_ui_text(prop, "Threshold", "Amount of Y motion before mouse movement will register");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "object_axis_x", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "object_axis[0]");
+ RNA_def_property_enum_items(prop, prop_object_axis_items);
+ RNA_def_property_ui_text(prop, "Object Axis", "Local object axis mouse movement in the X direction will apply to");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "object_axis_y", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "object_axis[1]");
+ RNA_def_property_enum_items(prop, prop_object_axis_items);
+ RNA_def_property_ui_text(prop, "Object Axis", "Local object axis mouse movement in the Y direction will apply to");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "sensitivity_x", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "sensitivity[0]");
+ RNA_def_property_ui_range(prop, -100.0, 100.0, 0.2, 3);
+ RNA_def_property_ui_text(prop, "Sensitivity", "Sensitivity of the X axis");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "sensitivity_y", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "sensitivity[1]");
+ RNA_def_property_ui_range(prop, -100.0, 100.0, 0.2, 3);
+ RNA_def_property_ui_text(prop, "Sensitivity", "Sensitivity of the Y axis");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "min_x", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "limit_x[0]");
+ RNA_def_property_ui_range(prop, DEG2RADF(-3600.0f), 0.0, 9, 3);
+ RNA_def_property_ui_text(prop, "Min", "Maximum negative rotation allowed by X mouse movement (0 for infinite)");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "max_x", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "limit_x[1]");
+ RNA_def_property_ui_range(prop, 0.0, DEG2RADF(3600.0f), 9, 3);
+ RNA_def_property_ui_text(prop, "Max", "Maximum positive rotation allowed by X mouse movement (0 for infinite)");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "min_y", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "limit_y[0]");
+ RNA_def_property_ui_range(prop, DEG2RADF(-3600.0f), 0.0, 9, 3);
+ RNA_def_property_ui_text(prop, "Min", "Maximum negative rotation allowed by Y mouse movement (0 for infinite)");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "max_y", PROP_FLOAT, PROP_ANGLE);
+ RNA_def_property_float_sdna(prop, NULL, "limit_y[1]");
+ RNA_def_property_ui_range(prop, 0.0, DEG2RADF(3600.0f), 9, 3);
+ RNA_def_property_ui_text(prop, "Max", "Maximum positive rotation allowed by Y mouse movement (0 for infinite)");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+}
+
void RNA_def_actuator(BlenderRNA *brna)
{
rna_def_actuator(brna);
@@ -2059,6 +2221,7 @@ void RNA_def_actuator(BlenderRNA *brna)
rna_def_state_actuator(brna);
rna_def_armature_actuator(brna);
rna_def_steering_actuator(brna);
+ rna_def_mouse_actuator(brna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 1bccceab5ab..421d7b28dda 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -475,7 +475,7 @@ static int rna_Armature_is_editmode_get(PointerRNA *ptr)
return (arm->edbo != NULL);
}
-void rna_Armature_transform(struct bArmature *arm, float *mat)
+static void rna_Armature_transform(struct bArmature *arm, float *mat)
{
ED_armature_transform(arm, (float (*)[4])mat);
}
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 9c81d5893bf..bbc2e0572fa 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -54,7 +54,10 @@ static EnumPropertyItem sculpt_stroke_method_items[] = {
{BRUSH_DRAG_DOT, "DRAG_DOT", 0, "Drag Dot", "Allows a single dot to be carefully positioned"},
{BRUSH_SPACE, "SPACE", 0, "Space", "Limit brush application to the distance specified by spacing"},
{BRUSH_AIRBRUSH, "AIRBRUSH", 0, "Airbrush", "Keep applying paint effect while holding mouse (spray)"},
- {BRUSH_ANCHORED, "ANCHORED", 0, "Anchored", "Keep the brush anchored to the initial location"},
+ {BRUSH_ANCHORED, "ANCHORED", 0, "Anchored", "Keep the brush anchored to the initial location"},
+ {BRUSH_LINE, "LINE", 0, "Line", "Draw a line with dabs separated according to spacing"},
+ {BRUSH_CURVE, "CURVE", 0, "Curve",
+ "Define the stroke curve with a bezier curve (dabs are separated according to spacing)"},
{0, NULL, 0, NULL, NULL}
};
@@ -99,6 +102,8 @@ EnumPropertyItem brush_image_tool_items[] = {
{PAINT_TOOL_SOFTEN, "SOFTEN", ICON_BRUSH_SOFTEN, "Soften", ""},
{PAINT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SMEAR, "Smear", ""},
{PAINT_TOOL_CLONE, "CLONE", ICON_BRUSH_CLONE, "Clone", ""},
+ {PAINT_TOOL_FILL, "FILL", ICON_BRUSH_TEXFILL, "Fill", ""},
+ {PAINT_TOOL_MASK, "MASK", ICON_BRUSH_TEXMASK, "Mask", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -120,9 +125,9 @@ EnumPropertyItem brush_image_tool_items[] = {
static int rna_SculptToolCapabilities_has_accumulate_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM6(br->sculpt_tool,
- SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CREASE,
- SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_LAYER);
+ return ELEM(br->sculpt_tool,
+ SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CREASE,
+ SCULPT_TOOL_DRAW, SCULPT_TOOL_INFLATE, SCULPT_TOOL_LAYER);
}
static int rna_SculptToolCapabilities_has_auto_smooth_get(PointerRNA *ptr)
@@ -142,9 +147,9 @@ static int rna_SculptToolCapabilities_has_jitter_get(PointerRNA *ptr)
Brush *br = (Brush *)ptr->data;
return (!(br->flag & BRUSH_ANCHORED) &&
!(br->flag & BRUSH_DRAG_DOT) &&
- !ELEM4(br->sculpt_tool,
- SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB));
+ !ELEM(br->sculpt_tool,
+ SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB));
}
static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr)
@@ -156,7 +161,7 @@ static int rna_SculptToolCapabilities_has_normal_weight_get(PointerRNA *ptr)
static int rna_BrushCapabilities_has_overlay_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM3(br->mtex.brush_map_mode,
+ return ELEM(br->mtex.brush_map_mode,
MTEX_MAP_MODE_VIEW,
MTEX_MAP_MODE_TILED,
MTEX_MAP_MODE_STENCIL);
@@ -177,22 +182,22 @@ static int rna_SculptToolCapabilities_has_pinch_factor_get(PointerRNA *ptr)
static int rna_SculptToolCapabilities_has_plane_offset_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM5(br->sculpt_tool, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS,
- SCULPT_TOOL_FILL, SCULPT_TOOL_FLATTEN, SCULPT_TOOL_SCRAPE);
+ return ELEM(br->sculpt_tool, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS,
+ SCULPT_TOOL_FILL, SCULPT_TOOL_FLATTEN, SCULPT_TOOL_SCRAPE);
}
static int rna_SculptToolCapabilities_has_random_texture_angle_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return (!ELEM4(br->sculpt_tool,
- SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
- SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB));
+ return (!ELEM(br->sculpt_tool,
+ SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
+ SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB));
}
static int rna_BrushCapabilities_has_random_texture_angle_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return (ELEM3(br->mtex.brush_map_mode,
+ return (ELEM(br->mtex.brush_map_mode,
MTEX_MAP_MODE_VIEW,
MTEX_MAP_MODE_AREA,
MTEX_MAP_MODE_RANDOM) &&
@@ -202,19 +207,19 @@ static int rna_BrushCapabilities_has_random_texture_angle_get(PointerRNA *ptr)
static int rna_SculptToolCapabilities_has_sculpt_plane_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return !ELEM4(br->sculpt_tool, SCULPT_TOOL_INFLATE,
- SCULPT_TOOL_MASK, SCULPT_TOOL_PINCH,
- SCULPT_TOOL_SMOOTH);
+ return !ELEM(br->sculpt_tool, SCULPT_TOOL_INFLATE,
+ SCULPT_TOOL_MASK, SCULPT_TOOL_PINCH,
+ SCULPT_TOOL_SMOOTH);
}
static int rna_SculptToolCapabilities_has_secondary_color_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM10(br->sculpt_tool,
- SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS,
- SCULPT_TOOL_CREASE, SCULPT_TOOL_DRAW, SCULPT_TOOL_FILL,
- SCULPT_TOOL_FLATTEN, SCULPT_TOOL_INFLATE, SCULPT_TOOL_PINCH,
- SCULPT_TOOL_SCRAPE);
+ return ELEM(br->sculpt_tool,
+ SCULPT_TOOL_BLOB, SCULPT_TOOL_CLAY, SCULPT_TOOL_CLAY_STRIPS,
+ SCULPT_TOOL_CREASE, SCULPT_TOOL_DRAW, SCULPT_TOOL_FILL,
+ SCULPT_TOOL_FLATTEN, SCULPT_TOOL_INFLATE, SCULPT_TOOL_PINCH,
+ SCULPT_TOOL_SCRAPE);
}
static int rna_SculptToolCapabilities_has_smooth_stroke_get(PointerRNA *ptr)
@@ -222,26 +227,44 @@ static int rna_SculptToolCapabilities_has_smooth_stroke_get(PointerRNA *ptr)
Brush *br = (Brush *)ptr->data;
return (!(br->flag & BRUSH_ANCHORED) &&
!(br->flag & BRUSH_DRAG_DOT) &&
- !ELEM4(br->sculpt_tool,
+ !(br->flag & BRUSH_LINE) &&
+ !(br->flag & BRUSH_CURVE) &&
+ !ELEM(br->sculpt_tool,
SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SNAKE_HOOK, SCULPT_TOOL_THUMB));
}
+static int rna_BrushCapabilities_has_smooth_stroke_get(PointerRNA *ptr)
+{
+ Brush *br = (Brush *)ptr->data;
+ return (!(br->flag & BRUSH_ANCHORED) &&
+ !(br->flag & BRUSH_DRAG_DOT) &&
+ !(br->flag & BRUSH_LINE) &&
+ !(br->flag & BRUSH_CURVE));
+}
+
static int rna_SculptToolCapabilities_has_space_attenuation_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ((br->flag & BRUSH_SPACE) &&
- !ELEM4(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
+ return ((br->flag & (BRUSH_SPACE | BRUSH_LINE | BRUSH_CURVE)) &&
+ !ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_ROTATE,
SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SNAKE_HOOK));
}
+static int rna_ImapaintToolCapabilities_has_space_attenuation_get(PointerRNA *ptr)
+{
+ Brush *br = (Brush *)ptr->data;
+ return (br->flag & (BRUSH_SPACE | BRUSH_LINE | BRUSH_CURVE)) &&
+ br->imagepaint_tool != PAINT_TOOL_FILL;
+}
+
static int rna_BrushCapabilities_has_spacing_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
return (!(br->flag & BRUSH_ANCHORED));
}
-static int rna_SculptToolCapabilities_has_strength_get(PointerRNA *ptr)
+static int rna_SculptToolCapabilities_has_strength_pressure_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
return !ELEM(br->sculpt_tool, SCULPT_TOOL_GRAB, SCULPT_TOOL_SNAKE_HOOK);
@@ -250,12 +273,12 @@ static int rna_SculptToolCapabilities_has_strength_get(PointerRNA *ptr)
static int rna_BrushCapabilities_has_texture_angle_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM5(br->mtex.brush_map_mode,
- MTEX_MAP_MODE_VIEW,
- MTEX_MAP_MODE_AREA,
- MTEX_MAP_MODE_TILED,
- MTEX_MAP_MODE_STENCIL,
- MTEX_MAP_MODE_RANDOM);
+ return ELEM(br->mtex.brush_map_mode,
+ MTEX_MAP_MODE_VIEW,
+ MTEX_MAP_MODE_AREA,
+ MTEX_MAP_MODE_TILED,
+ MTEX_MAP_MODE_STENCIL,
+ MTEX_MAP_MODE_RANDOM);
}
static int rna_SculptToolCapabilities_has_gravity_get(PointerRNA *ptr)
@@ -267,17 +290,46 @@ static int rna_SculptToolCapabilities_has_gravity_get(PointerRNA *ptr)
static int rna_BrushCapabilities_has_texture_angle_source_get(PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- return ELEM3(br->mtex.brush_map_mode,
+ return ELEM(br->mtex.brush_map_mode,
MTEX_MAP_MODE_VIEW,
MTEX_MAP_MODE_AREA,
MTEX_MAP_MODE_RANDOM);
}
-static PointerRNA rna_Sculpt_sculpt_tool_capabilities_get(PointerRNA *ptr)
+static int rna_ImapaintToolCapabilities_has_accumulate_get(PointerRNA *ptr)
+{
+ /* only support for draw tool */
+ Brush *br = (Brush *)ptr->data;
+
+ return ((br->flag & BRUSH_AIRBRUSH) ||
+ (br->flag & BRUSH_DRAG_DOT) ||
+ (br->flag & BRUSH_ANCHORED) ||
+ (br->imagepaint_tool == PAINT_TOOL_SOFTEN) ||
+ (br->imagepaint_tool == PAINT_TOOL_SMEAR) ||
+ (br->imagepaint_tool == PAINT_TOOL_FILL) ||
+ (br->mtex.tex && !ELEM(br->mtex.brush_map_mode, MTEX_MAP_MODE_TILED, MTEX_MAP_MODE_STENCIL, MTEX_MAP_MODE_3D))
+ ) ? false : true;
+}
+
+static int rna_ImapaintToolCapabilities_has_radius_get(PointerRNA *ptr)
+{
+ /* only support for draw tool */
+ Brush *br = (Brush *)ptr->data;
+
+ return (br->imagepaint_tool != PAINT_TOOL_FILL);
+}
+
+
+static PointerRNA rna_Sculpt_tool_capabilities_get(PointerRNA *ptr)
{
return rna_pointer_inherit_refine(ptr, &RNA_SculptToolCapabilities, ptr->id.data);
}
+static PointerRNA rna_Imapaint_tool_capabilities_get(PointerRNA *ptr)
+{
+ return rna_pointer_inherit_refine(ptr, &RNA_ImapaintToolCapabilities, ptr->id.data);
+}
+
static PointerRNA rna_Brush_capabilities_get(PointerRNA *ptr)
{
return rna_pointer_inherit_refine(ptr, &RNA_BrushCapabilities, ptr->id.data);
@@ -328,7 +380,6 @@ static void rna_Brush_size_update(Main *bmain, Scene *scene, PointerRNA *ptr)
static void rna_Brush_sculpt_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- BKE_paint_invalidate_overlay_all();
rna_Brush_reset_icon(br, "sculpt");
rna_Brush_update(bmain, scene, ptr);
}
@@ -336,7 +387,6 @@ static void rna_Brush_sculpt_tool_update(Main *bmain, Scene *scene, PointerRNA *
static void rna_Brush_vertex_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- BKE_paint_invalidate_overlay_all();
rna_Brush_reset_icon(br, "vertex_paint");
rna_Brush_update(bmain, scene, ptr);
}
@@ -344,11 +394,16 @@ static void rna_Brush_vertex_tool_update(Main *bmain, Scene *scene, PointerRNA *
static void rna_Brush_imagepaint_tool_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
- BKE_paint_invalidate_overlay_all();
rna_Brush_reset_icon(br, "image_paint");
rna_Brush_update(bmain, scene, ptr);
}
+static void rna_Brush_stroke_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ WM_main_add_notifier(NC_SCENE | ND_TOOLSETTINGS, scene);
+ rna_Brush_update(bmain, scene, ptr);
+}
+
static void rna_Brush_icon_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
Brush *br = (Brush *)ptr->data;
@@ -388,6 +443,17 @@ static void rna_Brush_set_size(PointerRNA *ptr, int value)
brush->size = value;
}
+static void rna_Brush_use_gradient_set(PointerRNA *ptr, int value)
+{
+ Brush *br = (Brush *)ptr->data;
+
+ if (value) br->flag |= BRUSH_USE_GRADIENT;
+ else br->flag &= ~BRUSH_USE_GRADIENT;
+
+ if ((br->flag & BRUSH_USE_GRADIENT) && br->gradient == NULL)
+ br->gradient = add_colorband(true);
+}
+
static void rna_Brush_set_unprojected_radius(PointerRNA *ptr, float value)
{
Brush *brush = ptr->data;
@@ -397,13 +463,16 @@ static void rna_Brush_set_unprojected_radius(PointerRNA *ptr, float value)
brush->unprojected_radius = value;
}
-static EnumPropertyItem *rna_Brush_direction_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+static EnumPropertyItem *rna_Brush_direction_itemf(bContext *C, PointerRNA *ptr,
PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
{
+ PaintMode mode = BKE_paintmode_get_active_from_context(C);
+
static EnumPropertyItem prop_default_items[] = {
{0, NULL, 0, NULL, NULL}
};
+ /* sculpt mode */
static EnumPropertyItem prop_flatten_contrast_items[] = {
{0, "FLATTEN", 0, "Flatten", "Add effect of brush"},
{BRUSH_DIR_IN, "CONTRAST", 0, "Contrast", "Subtract effect of brush"},
@@ -434,41 +503,66 @@ static EnumPropertyItem *rna_Brush_direction_itemf(bContext *UNUSED(C), PointerR
{0, NULL, 0, NULL, NULL}
};
+ /* texture paint mode */
+ static EnumPropertyItem prop_soften_sharpen_items[] = {
+ {0, "SOFTEN", 0, "Soften", "Blur effect of brush"},
+ {BRUSH_DIR_IN, "SHARPEN", 0, "Sharpen", "Sharpen effect of brush"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
Brush *me = (Brush *)(ptr->data);
- switch (me->sculpt_tool) {
- case SCULPT_TOOL_DRAW:
- case SCULPT_TOOL_CREASE:
- case SCULPT_TOOL_BLOB:
- case SCULPT_TOOL_LAYER:
- case SCULPT_TOOL_CLAY:
- case SCULPT_TOOL_CLAY_STRIPS:
- return prop_direction_items;
-
- case SCULPT_TOOL_MASK:
- switch ((BrushMaskTool)me->mask_tool) {
- case BRUSH_MASK_DRAW:
+ switch (mode) {
+ case PAINT_SCULPT:
+ switch (me->sculpt_tool) {
+ case SCULPT_TOOL_DRAW:
+ case SCULPT_TOOL_CREASE:
+ case SCULPT_TOOL_BLOB:
+ case SCULPT_TOOL_LAYER:
+ case SCULPT_TOOL_CLAY:
+ case SCULPT_TOOL_CLAY_STRIPS:
return prop_direction_items;
- break;
- case BRUSH_MASK_SMOOTH:
- return prop_default_items;
- break;
- }
- case SCULPT_TOOL_FLATTEN:
- return prop_flatten_contrast_items;
+ case SCULPT_TOOL_MASK:
+ switch ((BrushMaskTool)me->mask_tool) {
+ case BRUSH_MASK_DRAW:
+ return prop_direction_items;
+ break;
+ case BRUSH_MASK_SMOOTH:
+ return prop_default_items;
+ break;
+ }
- case SCULPT_TOOL_FILL:
- return prop_fill_deepen_items;
+ case SCULPT_TOOL_FLATTEN:
+ return prop_flatten_contrast_items;
- case SCULPT_TOOL_SCRAPE:
- return prop_scrape_peaks_items;
+ case SCULPT_TOOL_FILL:
+ return prop_fill_deepen_items;
- case SCULPT_TOOL_PINCH:
- return prop_pinch_magnify_items;
+ case SCULPT_TOOL_SCRAPE:
+ return prop_scrape_peaks_items;
- case SCULPT_TOOL_INFLATE:
- return prop_inflate_deflate_items;
+ case SCULPT_TOOL_PINCH:
+ return prop_pinch_magnify_items;
+
+ case SCULPT_TOOL_INFLATE:
+ return prop_inflate_deflate_items;
+
+ default:
+ return prop_default_items;
+ }
+ break;
+
+ case PAINT_TEXTURE_2D:
+ case PAINT_TEXTURE_PROJECTIVE:
+ switch (me->imagepaint_tool) {
+ case PAINT_TOOL_SOFTEN:
+ return prop_soften_sharpen_items;
+
+ default:
+ return prop_default_items;
+ }
+ break;
default:
return prop_default_items;
@@ -484,11 +578,15 @@ static EnumPropertyItem *rna_Brush_stroke_itemf(bContext *C, PointerRNA *UNUSED(
{0, "DOTS", 0, "Dots", "Apply paint on each mouse move step"},
{BRUSH_SPACE, "SPACE", 0, "Space", "Limit brush application to the distance specified by spacing"},
{BRUSH_AIRBRUSH, "AIRBRUSH", 0, "Airbrush", "Keep applying paint effect while holding mouse (spray)"},
+ {BRUSH_LINE, "LINE", 0, "Line", "Drag a line with dabs separated according to spacing"},
+ {BRUSH_CURVE, "CURVE", 0, "Curve", "Define the stroke curve with a bezier curve. Dabs are separated according to spacing"},
{0, NULL, 0, NULL, NULL}
};
switch (mode) {
case PAINT_SCULPT:
+ case PAINT_TEXTURE_2D:
+ case PAINT_TEXTURE_PROJECTIVE:
return sculpt_stroke_method_items;
default:
@@ -591,7 +689,7 @@ static void rna_def_sculpt_capabilities(BlenderRNA *brna)
SCULPT_TOOL_CAPABILITY(has_secondary_color, "Has Secondary Color");
SCULPT_TOOL_CAPABILITY(has_smooth_stroke, "Has Smooth Stroke");
SCULPT_TOOL_CAPABILITY(has_space_attenuation, "Has Space Attenuation");
- SCULPT_TOOL_CAPABILITY(has_strength, "Has Strength");
+ SCULPT_TOOL_CAPABILITY(has_strength_pressure, "Has Strength Pressure");
SCULPT_TOOL_CAPABILITY(has_gravity, "Has Gravity");
#undef SCULPT_CAPABILITY
@@ -622,10 +720,39 @@ static void rna_def_brush_capabilities(BlenderRNA *brna)
BRUSH_CAPABILITY(has_texture_angle, "Has Texture Angle");
BRUSH_CAPABILITY(has_texture_angle_source, "Has Texture Angle Source");
BRUSH_CAPABILITY(has_spacing, "Has Spacing");
+ BRUSH_CAPABILITY(has_smooth_stroke, "Has Smooth Stroke");
+
#undef BRUSH_CAPABILITY
}
+static void rna_def_image_paint_capabilities(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "ImapaintToolCapabilities", NULL);
+ RNA_def_struct_sdna(srna, "Brush");
+ RNA_def_struct_nested(brna, srna, "Brush");
+ RNA_def_struct_ui_text(srna, "Image Paint Capabilities",
+ "Read-only indications of which brush operations "
+ "are supported by the current image paint brush");
+
+#define IMAPAINT_TOOL_CAPABILITY(prop_name_, ui_name_) \
+ prop = RNA_def_property(srna, #prop_name_, \
+ PROP_BOOLEAN, PROP_NONE); \
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE); \
+ RNA_def_property_boolean_funcs(prop, "rna_ImapaintToolCapabilities_" \
+ #prop_name_ "_get", NULL); \
+ RNA_def_property_ui_text(prop, ui_name_, NULL)
+
+ IMAPAINT_TOOL_CAPABILITY(has_accumulate, "Has Accumulate");
+ IMAPAINT_TOOL_CAPABILITY(has_space_attenuation, "Has Space Attenuation");
+ IMAPAINT_TOOL_CAPABILITY(has_radius, "Has Radius");
+
+#undef IMAPAINT_TOOL_CAPABILITY
+}
+
static void rna_def_brush(BlenderRNA *brna)
{
StructRNA *srna;
@@ -640,6 +767,22 @@ static void rna_def_brush(BlenderRNA *brna)
{IMB_BLEND_DARKEN, "DARKEN", 0, "Darken", "Use darken blending mode while painting"},
{IMB_BLEND_ERASE_ALPHA, "ERASE_ALPHA", 0, "Erase Alpha", "Erase alpha while painting"},
{IMB_BLEND_ADD_ALPHA, "ADD_ALPHA", 0, "Add Alpha", "Add alpha while painting"},
+ {IMB_BLEND_OVERLAY, "OVERLAY", 0, "Overlay", "Use overlay blending mode while painting"},
+ {IMB_BLEND_HARDLIGHT, "HARDLIGHT", 0, "Hard light", "Use hard light blending mode while painting"},
+ {IMB_BLEND_COLORBURN, "COLORBURN", 0, "Color burn", "Use color burn blending mode while painting"},
+ {IMB_BLEND_LINEARBURN, "LINEARBURN", 0, "Linear burn", "Use linear burn blending mode while painting"},
+ {IMB_BLEND_COLORDODGE, "COLORDODGE", 0, "Color dodge", "Use color dodge blending mode while painting"},
+ {IMB_BLEND_SCREEN, "SCREEN", 0, "Screen", "Use screen blending mode while painting"},
+ {IMB_BLEND_SOFTLIGHT, "SOFTLIGHT", 0, "Soft light", "Use softlight blending mode while painting"},
+ {IMB_BLEND_PINLIGHT, "PINLIGHT", 0, "Pin light", "Use pinlight blending mode while painting"},
+ {IMB_BLEND_VIVIDLIGHT, "VIVIDLIGHT", 0, "Vivid light", "Use vividlight blending mode while painting"},
+ {IMB_BLEND_LINEARLIGHT, "LINEARLIGHT", 0, "Linear light", "Use linearlight blending mode while painting"},
+ {IMB_BLEND_DIFFERENCE, "DIFFERENCE", 0, "Difference", "Use difference blending mode while painting"},
+ {IMB_BLEND_EXCLUSION, "EXCLUSION", 0, "Exclusion", "Use exclusion blending mode while painting"},
+ {IMB_BLEND_HUE, "HUE", 0, "Hue", "Use hue blending mode while painting"},
+ {IMB_BLEND_SATURATION, "SATURATION", 0, "Saturation", "Use saturation blending mode while painting"},
+ {IMB_BLEND_LUMINOSITY, "LUMINOSITY", 0, "Luminosity", "Use luminosity blending mode while painting"},
+ {IMB_BLEND_COLOR, "COLOR", 0, "Color", "Use color blending mode while painting"},
{0, NULL, 0, NULL, NULL}
};
@@ -671,6 +814,32 @@ static void rna_def_brush(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem brush_blur_mode_items[] = {
+ {KERNEL_BOX, "BOX", 0, "Box", ""},
+ {KERNEL_GAUSSIAN, "GAUSSIAN", 0, "Gaussian", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem brush_gradient_items[] = {
+ {BRUSH_GRADIENT_PRESSURE, "PRESSURE", 0, "Pressure", ""},
+ {BRUSH_GRADIENT_SPACING_REPEAT, "SPACING_REPEAT", 0, "Repeat", ""},
+ {BRUSH_GRADIENT_SPACING_CLAMP, "SPACING_CLAMP", 0, "Clamp", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem brush_gradient_fill_items[] = {
+ {BRUSH_GRADIENT_LINEAR, "LINEAR", 0, "Linear", ""},
+ {BRUSH_GRADIENT_RADIAL, "RADIAL", 0, "Radial", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem brush_mask_pressure_items[] = {
+ {0, "NONE", 0, "Off", ""},
+ {BRUSH_MASK_PRESSURE_RAMP, "RAMP", ICON_STYLUS_PRESSURE, "Ramp", ""},
+ {BRUSH_MASK_PRESSURE_CUTOFF, "CUTOFF", ICON_STYLUS_PRESSURE, "Cutoff", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "Brush", "ID");
RNA_def_struct_ui_text(srna, "Brush", "Brush datablock for storing brush settings for painting and sculpting");
RNA_def_struct_ui_icon(srna, ICON_BRUSH_DATA);
@@ -710,7 +879,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_enum_items(prop, sculpt_stroke_method_items);
RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_Brush_stroke_itemf");
RNA_def_property_ui_text(prop, "Stroke Method", "");
- RNA_def_property_update(prop, 0, "rna_Brush_update");
+ RNA_def_property_update(prop, 0, "rna_Brush_stroke_update");
prop = RNA_def_property(srna, "texture_angle_source_random", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
@@ -769,6 +938,13 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Spacing", "Spacing between brush daubs as a percentage of brush diameter");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "grad_spacing", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "gradient_spacing");
+ RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_ui_range(prop, 1, 10000, 5, -1);
+ RNA_def_property_ui_text(prop, "Gradient Spacing", "Spacing before brush gradient goes full circle");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "smooth_stroke_radius", PROP_INT, PROP_NONE);
RNA_def_property_range(prop, 10, 200);
RNA_def_property_ui_text(prop, "Smooth Stroke Radius", "Minimum distance from last point before stroke continues");
@@ -791,7 +967,13 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "rgb");
RNA_def_property_ui_text(prop, "Color", "");
RNA_def_property_update(prop, 0, "rna_Brush_update");
-
+
+ prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "secondary_rgb");
+ RNA_def_property_ui_text(prop, "Secondary Color", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "weight", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_range(prop, 0.0f, 1.0f);
@@ -884,6 +1066,32 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mask Stencil Dimensions", "Dimensions of mask stencil in viewport");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "sharp_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3);
+ RNA_def_property_float_sdna(prop, NULL, "sharp_threshold");
+ RNA_def_property_ui_text(prop, "Sharp Threshold", "Threshold below which, no sharpening is done");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "fill_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 100.0);
+ RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3);
+ RNA_def_property_float_sdna(prop, NULL, "fill_threshold");
+ RNA_def_property_ui_text(prop, "Fill Threshold", "Threshold above which filling is not propagated");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "blur_kernel_radius", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "blur_kernel_radius");
+ RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_ui_range(prop, 1, 50, 1, -1);
+ RNA_def_property_ui_text(prop, "Kernel Radius", "Radius of kernel used for soften and sharpen in pixels");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "blur_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_blur_mode_items);
+ RNA_def_property_ui_text(prop, "Blur Mode", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* flag */
prop = RNA_def_property(srna, "use_airbrush", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_AIRBRUSH);
@@ -919,7 +1127,13 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
RNA_def_property_ui_text(prop, "Size Pressure", "Enable tablet pressure sensitivity for size");
RNA_def_property_update(prop, 0, "rna_Brush_update");
-
+
+ prop = RNA_def_property(srna, "use_gradient", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_USE_GRADIENT);
+ RNA_def_property_boolean_funcs(prop, NULL, "rna_Brush_use_gradient_set");
+ RNA_def_property_ui_text(prop, "Use Gradient", "Use Gradient by utilizing a sampling method");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_pressure_jitter", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_JITTER_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
@@ -932,6 +1146,12 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Spacing Pressure", "Enable tablet pressure sensitivity for spacing");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_pressure_masking", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mask_pressure");
+ RNA_def_property_enum_items(prop, brush_mask_pressure_items);
+ RNA_def_property_ui_text(prop, "Mask Pressure Mode", "Pen pressure makes texture influence smaller");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_inverse_smooth_pressure", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_INVERSE_SMOOTH_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
@@ -974,6 +1194,16 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Space", "Limit brush application to the distance specified by spacing");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_line", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_LINE);
+ RNA_def_property_ui_text(prop, "Line", "Draw a line with dabs separated according to spacing");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "use_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_CURVE);
+ RNA_def_property_ui_text(prop, "Curve", "Define the stroke curve with a bezier curve. Dabs are separated according to spacing");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_smooth_stroke", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_SMOOTH_STROKE);
RNA_def_property_ui_text(prop, "Smooth Stroke", "Brush lags behind mouse and follows a smoother path");
@@ -1015,7 +1245,7 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Edge-to-edge", "Drag anchor brush from edge-to-edge");
RNA_def_property_update(prop, 0, "rna_Brush_update");
- prop = RNA_def_property(srna, "use_drag_dot", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_restore_mesh", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_DRAG_DOT);
RNA_def_property_ui_text(prop, "Restore Mesh", "Allow a single dot to be carefully positioned");
RNA_def_property_update(prop, 0, "rna_Brush_update");
@@ -1031,6 +1261,28 @@ static void rna_def_brush(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Curve", "Editable falloff curve");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "paint_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Paint Curve", "Active Paint Curve");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "gradient", PROP_POINTER, PROP_NEVER_NULL);
+ RNA_def_property_pointer_sdna(prop, NULL, "gradient");
+ RNA_def_property_struct_type(prop, "ColorRamp");
+ RNA_def_property_ui_text(prop, "Gradient", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ /* gradient source */
+ prop = RNA_def_property(srna, "gradient_stroke_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_gradient_items);
+ RNA_def_property_ui_text(prop, "Gradient Stroke Mode", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
+ prop = RNA_def_property(srna, "gradient_fill_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, brush_gradient_fill_items);
+ RNA_def_property_ui_text(prop, "Gradient Fill Mode", "");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
/* overlay flags */
prop = RNA_def_property(srna, "use_primary_overlay", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "overlay_flags", BRUSH_OVERLAY_PRIMARY);
@@ -1173,8 +1425,14 @@ static void rna_def_brush(BlenderRNA *brna)
prop = RNA_def_property(srna, "sculpt_capabilities", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_struct_type(prop, "SculptToolCapabilities");
- RNA_def_property_pointer_funcs(prop, "rna_Sculpt_sculpt_tool_capabilities_get", NULL, NULL, NULL);
+ RNA_def_property_pointer_funcs(prop, "rna_Sculpt_tool_capabilities_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Sculpt Capabilities", "Brush's capabilities in sculpt mode");
+
+ prop = RNA_def_property(srna, "image_paint_capabilities", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "ImapaintToolCapabilities");
+ RNA_def_property_pointer_funcs(prop, "rna_Imapaint_tool_capabilities_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Image Painting Capabilities", "Brush's capabilities in image paint mode");
}
@@ -1211,6 +1469,11 @@ static void rna_def_operator_stroke_element(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Pressure", "Tablet pressure");
+ prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_IDPROPERTY);
+ RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_text(prop, "Brush Size", "Brush Size in screen space");
+
prop = RNA_def_property(srna, "pen_flip", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_flag(prop, PROP_IDPROPERTY);
RNA_def_property_ui_text(prop, "Flip", "");
@@ -1237,6 +1500,7 @@ void RNA_def_brush(BlenderRNA *brna)
rna_def_brush(brna);
rna_def_brush_capabilities(brna);
rna_def_sculpt_capabilities(brna);
+ rna_def_image_paint_capabilities(brna);
rna_def_brush_texture_slot(brna);
rna_def_operator_stroke_element(brna);
}
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index df9a08480cb..fa2a3258d1a 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -176,7 +176,7 @@ static char *rna_ColorRamp_path(PointerRNA *ptr)
char *node_path;
for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM3(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) {
+ if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) {
if (node->storage == ptr->data) {
/* all node color ramp properties called 'color_ramp'
* prepend path from ID to the node
@@ -193,7 +193,7 @@ static char *rna_ColorRamp_path(PointerRNA *ptr)
case ID_LS:
{
- char *path = BKE_path_from_ID_to_color_ramp((FreestyleLineStyle *)id, (ColorBand *)ptr->data);
+ char *path = BKE_linestyle_path_to_color_ramp((FreestyleLineStyle *)id, (ColorBand *)ptr->data);
if (path)
return path;
break;
@@ -265,7 +265,7 @@ static char *rna_ColorRampElement_path(PointerRNA *ptr)
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM3(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) {
+ if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) {
RNA_pointer_create(id, &RNA_ColorRamp, node->storage, &ramp_ptr);
COLRAMP_GETPATH;
}
@@ -277,7 +277,7 @@ static char *rna_ColorRampElement_path(PointerRNA *ptr)
ListBase listbase;
LinkData *link;
- BKE_list_modifier_color_ramps((FreestyleLineStyle *)id, &listbase);
+ BKE_linestyle_modifier_list_color_ramps((FreestyleLineStyle *)id, &listbase);
for (link = (LinkData *)listbase.first; link; link = link->next) {
RNA_pointer_create(id, &RNA_ColorRamp, link->data, &ramp_ptr);
COLRAMP_GETPATH;
@@ -324,7 +324,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
bNode *node;
for (node = ntree->nodes.first; node; node = node->next) {
- if (ELEM3(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) {
+ if (ELEM(node->type, SH_NODE_VALTORGB, CMP_NODE_VALTORGB, TEX_NODE_VALTORGB)) {
ED_node_tag_update_nodetree(bmain, ntree);
}
}
@@ -378,7 +378,7 @@ static void rna_ColorRampElement_remove(struct ColorBand *coba, ReportList *repo
RNA_POINTER_INVALIDATE(element_ptr);
}
-void rna_CurveMap_remove_point(CurveMap *cuma, ReportList *reports, PointerRNA *point_ptr)
+static void rna_CurveMap_remove_point(CurveMap *cuma, ReportList *reports, PointerRNA *point_ptr)
{
CurveMapPoint *point = point_ptr->data;
if (curvemap_remove_point(cuma, point) == false) {
@@ -816,13 +816,15 @@ static void rna_def_curvemapping(BlenderRNA *brna)
prop = RNA_def_property(srna, "black_level", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "black");
- RNA_def_property_range(prop, -1000.0f, 1000.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 1, 3);
RNA_def_property_ui_text(prop, "Black Level", "For RGB curves, the color that black is mapped to");
RNA_def_property_float_funcs(prop, NULL, "rna_CurveMapping_black_level_set", NULL);
prop = RNA_def_property(srna, "white_level", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "white");
- RNA_def_property_range(prop, -1000.0f, 1000.0f);
+ RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
+ RNA_def_property_ui_range(prop, -1000.0f, 1000.0f, 1, 3);
RNA_def_property_ui_text(prop, "White Level", "For RGB curves, the color that white is mapped to");
RNA_def_property_float_funcs(prop, NULL, "rna_CurveMapping_white_level_set", NULL);
@@ -848,7 +850,12 @@ static void rna_def_color_ramp_element(BlenderRNA *brna)
RNA_def_property_array(prop, 4);
RNA_def_property_ui_text(prop, "Color", "Set color of selected color stop");
RNA_def_property_update(prop, 0, "rna_ColorRamp_update");
-
+
+ prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "a");
+ RNA_def_property_ui_text(prop, "Alpha", "Set alpha of selected color stop");
+ RNA_def_property_update(prop, 0, "rna_ColorRamp_update");
+
prop = RNA_def_property(srna, "position", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "pos");
RNA_def_property_range(prop, 0, 1);
@@ -893,14 +900,29 @@ static void rna_def_color_ramp(BlenderRNA *brna)
FunctionRNA *func;
static EnumPropertyItem prop_interpolation_items[] = {
- {1, "EASE", 0, "Ease", ""},
- {3, "CARDINAL", 0, "Cardinal", ""},
- {0, "LINEAR", 0, "Linear", ""},
- {2, "B_SPLINE", 0, "B-Spline", ""},
- {4, "CONSTANT", 0, "Constant", ""},
+ {COLBAND_INTERP_EASE, "EASE", 0, "Ease", ""},
+ {COLBAND_INTERP_CARDINAL, "CARDINAL", 0, "Cardinal", ""},
+ {COLBAND_INTERP_LINEAR, "LINEAR", 0, "Linear", ""},
+ {COLBAND_INTERP_B_SPLINE, "B_SPLINE", 0, "B-Spline", ""},
+ {COLBAND_INTERP_CONSTANT, "CONSTANT", 0, "Constant", ""},
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem prop_mode_items[] = {
+ {COLBAND_BLEND_RGB, "RGB", 0, "RGB", ""},
+ {COLBAND_BLEND_HSV, "HSV", 0, "HSV", ""},
+ {COLBAND_BLEND_HSL, "HSL", 0, "HSL", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_hsv_items[] = {
+ {COLBAND_HUE_NEAR, "NEAR", 0, "Near", ""},
+ {COLBAND_HUE_FAR, "FAR", 0, "Far", ""},
+ {COLBAND_HUE_CW, "CW", 0, "Clockwise", ""},
+ {COLBAND_HUE_CCW, "CCW", 0, "Counter-Clockwise", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "ColorRamp", NULL);
RNA_def_struct_sdna(srna, "ColorBand");
RNA_def_struct_path_func(srna, "rna_ColorRamp_path");
@@ -919,6 +941,18 @@ static void rna_def_color_ramp(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Interpolation", "Set interpolation between color stops");
RNA_def_property_update(prop, 0, "rna_ColorRamp_update");
+ prop = RNA_def_property(srna, "hue_interpolation", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "ipotype_hue");
+ RNA_def_property_enum_items(prop, prop_hsv_items);
+ RNA_def_property_ui_text(prop, "Color Interpolation", "Set color interpolation");
+ RNA_def_property_update(prop, 0, "rna_ColorRamp_update");
+
+ prop = RNA_def_property(srna, "color_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "color_mode");
+ RNA_def_property_enum_items(prop, prop_mode_items);
+ RNA_def_property_ui_text(prop, "Color Mode", "Set color mode to use for interpolation");
+ RNA_def_property_update(prop, 0, "rna_ColorRamp_update");
+
#if 0 /* use len(elements) */
prop = RNA_def_property(srna, "total", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "tot");
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 5fbaae71482..77355dbad0e 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -351,7 +351,7 @@ static void rna_ActionConstraint_minmax_range(PointerRNA *ptr, float *min, float
bActionConstraint *acon = (bActionConstraint *)con->data;
/* 0, 1, 2 = magic numbers for rotX, rotY, rotZ */
- if (ELEM3(acon->type, 0, 1, 2)) {
+ if (ELEM(acon->type, 0, 1, 2)) {
*min = -180.0f;
*max = 180.0f;
}
@@ -662,6 +662,7 @@ static void rna_def_constraint_kinematic(BlenderRNA *brna)
prop = RNA_def_property(srna, "pole_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "poleangle");
RNA_def_property_range(prop, -M_PI, M_PI);
+ RNA_def_property_ui_range(prop, -M_PI, M_PI, 10, 4);
RNA_def_property_ui_text(prop, "Pole Angle", "Pole rotation offset");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
@@ -1364,6 +1365,31 @@ static void rna_def_constraint_stretch_to(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0, 100.f);
RNA_def_property_ui_text(prop, "Volume Variation", "Factor between volume variation and stretching");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_bulge_min", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", STRETCHTOCON_USE_BULGE_MIN);
+ RNA_def_property_ui_text(prop, "Use Volume Variation Minimum", "Use lower limit for volume variation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "use_bulge_max", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", STRETCHTOCON_USE_BULGE_MAX);
+ RNA_def_property_ui_text(prop, "Use Volume Variation Maximum", "Use upper limit for volume variation");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "bulge_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0f);
+ RNA_def_property_ui_text(prop, "Volume Variation Minimum", "Minimum volume stretching factor");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "bulge_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 1.0, 100.0f);
+ RNA_def_property_ui_text(prop, "Volume Variation Maximum", "Maximum volume stretching factor");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
+
+ prop = RNA_def_property(srna, "bulge_smooth", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_range(prop, 0.0, 1.0f);
+ RNA_def_property_ui_text(prop, "Volume Variation Smoothness", "");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constraint_rigid_body_joint(BlenderRNA *brna)
@@ -2451,6 +2477,12 @@ static void rna_def_constraint_follow_track(BlenderRNA *brna)
RNA_def_property_enum_items(prop, frame_method_items);
RNA_def_property_ui_text(prop, "Frame Method", "How the footage fits in the camera frame");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_dependency_update");
+
+ /* use undistortion */
+ prop = RNA_def_property(srna, "use_undistorted_position", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", FOLLOWTRACK_USE_UNDISTORTION);
+ RNA_def_property_ui_text(prop, "Undistort", "Parent to undistorted position of 2D track");
+ RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constraint_camera_solver(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 142b4ed6574..29f1dd5f29f 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -323,8 +323,15 @@ static int rna_Nurb_length(PointerRNA *ptr)
static void rna_Nurb_type_set(PointerRNA *ptr, int value)
{
+ Curve *cu = (Curve *)ptr->id.data;
Nurb *nu = (Nurb *)ptr->data;
- BKE_nurb_type_convert(nu, value, true);
+ const int pntsu_prev = nu->pntsu;
+
+ if (BKE_nurb_type_convert(nu, value, true)) {
+ if (nu->pntsu != pntsu_prev) {
+ cu->actvert = CU_ACT_NONE;
+ }
+ }
}
static void rna_BPoint_array_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
@@ -1021,7 +1028,7 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
prop = RNA_def_property(srna, "underline_height", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "ulheight");
- RNA_def_property_range(prop, -0.2f, 0.8f);
+ RNA_def_property_range(prop, 0.0f, 0.8f);
RNA_def_property_ui_text(prop, "Underline Thickness", "");
RNA_def_property_update(prop, 0, "rna_Curve_update_data");
diff --git a/source/blender/makesrna/intern/rna_curve_api.c b/source/blender/makesrna/intern/rna_curve_api.c
index b689242f68f..e85511f08e9 100644
--- a/source/blender/makesrna/intern/rna_curve_api.c
+++ b/source/blender/makesrna/intern/rna_curve_api.c
@@ -38,14 +38,16 @@
#include "BLI_utildefines.h"
-#include "ED_curve.h"
+#include "BKE_curve.h"
#include "rna_internal.h" /* own include */
#ifdef RNA_RUNTIME
-void rna_Curve_transform(Curve *cu, float *mat)
+static void rna_Curve_transform(Curve *cu, float *mat, int shape_keys)
{
- ED_curve_transform(cu, (float (*)[4])mat);
+ BKE_curve_transform(cu, (float (*)[4])mat, shape_keys);
+
+ DAG_id_tag_update(&cu->id, 0);
}
#else
@@ -58,6 +60,13 @@ void RNA_api_curve(StructRNA *srna)
RNA_def_function_ui_description(func, "Transform curve by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
+
+ func = RNA_def_function(srna, "validate_material_indices", "BKE_curve_material_index_validate");
+ RNA_def_function_ui_description(func, "Validate material indices of splines or letters, return True when the curve "
+ "has had invalid indices corrected (to default 0)");
+ parm = RNA_def_boolean(func, "result", 0, "Result", "");
+ RNA_def_function_return(func, parm);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 266bc1bf0a5..3b9078153f3 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -61,7 +61,7 @@ EnumPropertyItem fmodifier_type_items[] = {
{FMODIFIER_TYPE_NOISE, "NOISE", 0, "Noise",
"Add pseudo-random noise on top of F-Curves"},
/*{FMODIFIER_TYPE_FILTER, "FILTER", 0, "Filter", ""},*/ /* FIXME: not implemented yet! */
- /*{FMODIFIER_TYPE_PYTHON, "PYTHON", 0, "Python", ""}, *//* FIXME: not implemented yet! */
+ {FMODIFIER_TYPE_PYTHON, "PYTHON", 0, "Python", ""},
{FMODIFIER_TYPE_LIMITS, "LIMITS", 0, "Limits",
"Restrict maximum and minimum values of F-Curve"},
{FMODIFIER_TYPE_STEPPED, "STEPPED", 0, "Stepped Interpolation",
@@ -457,7 +457,7 @@ static void rna_FCurve_range(FCurve *fcu, float range[2])
static void rna_FCurve_update_data_ex(FCurve *fcu)
{
sort_time_fcurve(fcu);
- testhandles_fcurve(fcu, true);
+ calchandles_fcurve(fcu);
}
/* RNA update callback for F-Curves after curve shape changes */
@@ -820,7 +820,7 @@ static FCM_EnvelopeData *rna_FModifierEnvelope_points_add(FModifier *fmod, Repor
return (env->data + i);
}
-void rna_FModifierEnvelope_points_remove(FModifier *fmod, ReportList *reports, PointerRNA *point)
+static void rna_FModifierEnvelope_points_remove(FModifier *fmod, ReportList *reports, PointerRNA *point)
{
FCM_EnvelopeData *cp = point->data;
FMod_Envelope *env = (FMod_Envelope *)fmod->data;
diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c
index 8f4108c23d0..01feb3cb748 100644
--- a/source/blender/makesrna/intern/rna_fluidsim.c
+++ b/source/blender/makesrna/intern/rna_fluidsim.c
@@ -465,7 +465,8 @@ static void rna_def_fluidsim_volume(StructRNA *srna)
RNA_def_property_enum_bitflag_sdna(prop, NULL, "volumeInitType");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_enum_items(prop, volume_type_items);
- RNA_def_property_ui_text(prop, "Volume Initialization", "Volume initialization type");
+ RNA_def_property_ui_text(prop, "Volume Initialization", "Volume initialization type "
+ "(WARNING: complex volumes might require too much memory and break simulation)");
prop = RNA_def_property(srna, "use_animated_mesh", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "domainNovecgen", 0);
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index cdedb3576b0..c4677710676 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -101,6 +101,8 @@ static void rna_GPencil_active_layer_set(PointerRNA *ptr, PointerRNA value)
gl->flag &= ~GP_LAYER_ACTIVE;
}
}
+
+ WM_main_add_notifier(NC_GPENCIL | NA_EDITED, NULL);
}
}
@@ -586,7 +588,7 @@ static void rna_def_gpencil_layers_api(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
- RNA_def_property_struct_type(prop, "GreasePencil");
+ RNA_def_property_struct_type(prop, "GPencilLayer");
RNA_def_property_pointer_funcs(prop, "rna_GPencil_active_layer_get", "rna_GPencil_active_layer_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Active Layer", "Active grease pencil layer");
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index 0b129bab524..141de511a09 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -399,6 +399,43 @@ static int rna_Image_is_float_get(PointerRNA *ptr)
return is_float;
}
+static void rna_Image_render_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Image *image = (Image *)ptr->id.data;
+ rna_iterator_array_begin(iter, (void *)image->render_slots, sizeof(RenderSlot), IMA_MAX_RENDER_SLOT, 0, NULL);
+}
+
+static PointerRNA rna_render_slots_active_get(PointerRNA *ptr)
+{
+ Image *image = (Image *)ptr->id.data;
+ RenderSlot *render_slot = &image->render_slots[image->render_slot];
+
+ return rna_pointer_inherit_refine(ptr, &RNA_RenderSlot, render_slot);
+}
+
+static void rna_render_slots_active_set(PointerRNA *ptr, PointerRNA value)
+{
+ Image *image = (Image *)ptr->id.data;
+ if (value.id.data == image) {
+ RenderSlot *render_slot = (RenderSlot *)value.data;
+ int index = render_slot - image->render_slots;
+ image->render_slot = CLAMPIS(index, 0, IMA_MAX_RENDER_SLOT - 1);
+ }
+}
+
+static int rna_render_slots_active_index_get(PointerRNA *ptr)
+{
+ Image *image = (Image *)ptr->id.data;
+ return image->render_slot;
+}
+
+static void rna_render_slots_active_index_set(PointerRNA *ptr, int value)
+{
+ Image *image = (Image *)ptr->id.data;
+ image->render_slot = value;
+ CLAMP(image->render_slot, 0, IMA_MAX_RENDER_SLOT - 1);
+}
+
#else
static void rna_def_imageuser(BlenderRNA *brna)
@@ -467,6 +504,45 @@ static void rna_def_imageuser(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Pass", "Pass in multilayer image");
}
+static void rna_def_render_slot(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+ srna = RNA_def_struct(brna, "RenderSlot", NULL);
+ RNA_def_struct_ui_text(srna, "Render Slot", "Parameters defining the render slot");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "name");
+ RNA_def_property_ui_text(prop, "Name", "Render slot name");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+}
+
+static void rna_def_render_slots(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "RenderSlots", NULL);
+ RNA_def_struct_sdna(srna, "RenderSlot");
+ RNA_def_struct_ui_text(srna, "Render Slots", "Collection of the render slots");
+
+ prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "RenderSlot");
+ RNA_def_property_pointer_funcs(prop, "rna_render_slots_active_get", "rna_render_slots_active_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_NEVER_UNLINK);
+ RNA_def_property_ui_text(prop, "Active", "Active render slot of the image");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+
+ prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_NONE);
+ RNA_def_property_int_funcs(prop, "rna_render_slots_active_index_get",
+ "rna_render_slots_active_index_set",
+ NULL);
+ RNA_def_property_range(prop, 0, IMA_MAX_RENDER_SLOT);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_ui_text(prop, "Active Index", "Index of an active render slot of the image");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+}
+
static void rna_def_image(BlenderRNA *brna)
{
StructRNA *srna;
@@ -589,6 +665,13 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ prop = RNA_def_property(srna, "generated_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "gen_color");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Color", "Fill color for the generated image");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_generated_update");
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+
/* realtime properties */
prop = RNA_def_property(srna, "mapping", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
@@ -661,10 +744,12 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Bindcode", "OpenGL bindcode");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
- prop = RNA_def_property(srna, "render_slot", PROP_INT, PROP_UNSIGNED);
- RNA_def_property_range(prop, 0, IMA_MAX_RENDER_SLOT - 1);
- RNA_def_property_ui_text(prop, "Render Slot", "The current render slot displayed, only for viewer type images");
- RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, NULL);
+ prop = RNA_def_property(srna, "render_slots", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "RenderSlot");
+ RNA_def_property_ui_text(prop, "Render Slots", "Render slots of the image");
+ RNA_def_property_collection_funcs(prop, "rna_Image_render_slots_begin", "rna_iterator_array_next",
+ "rna_iterator_array_end", "rna_iterator_array_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_srna(prop, "RenderSlots");
/*
* Image.has_data and Image.depth are temporary,
@@ -730,6 +815,8 @@ static void rna_def_image(BlenderRNA *brna)
void RNA_def_image(BlenderRNA *brna)
{
+ rna_def_render_slot(brna);
+ rna_def_render_slots(brna);
rna_def_image(brna);
rna_def_imageuser(brna);
}
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 57d74c91c86..d9a59c4dc55 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -109,13 +109,13 @@ static void rna_Image_save_render(Image *image, bContext *C, ReportList *reports
}
}
-static void rna_Image_save(Image *image, ReportList *reports)
+static void rna_Image_save(Image *image, bContext *C, ReportList *reports)
{
ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
if (ibuf) {
char filename[FILE_MAX];
BLI_strncpy(filename, image->name, sizeof(filename));
- BLI_path_abs(filename, G.main->name);
+ BLI_path_abs(filename, ID_BLEND_PATH(G.main, &image->id));
if (image->packedfile) {
if (writePackedFile(reports, image->name, image->packedfile, 0) != RET_OK) {
@@ -141,9 +141,10 @@ static void rna_Image_save(Image *image, ReportList *reports)
}
BKE_image_release_ibuf(image, ibuf, NULL);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, image);
}
-static void rna_Image_pack(Image *image, ReportList *reports, int as_png)
+static void rna_Image_pack(Image *image, bContext *C, ReportList *reports, int as_png)
{
ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
@@ -160,6 +161,7 @@ static void rna_Image_pack(Image *image, ReportList *reports, int as_png)
}
BKE_image_release_ibuf(image, ibuf, NULL);
+ WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, image);
}
static void rna_Image_unpack(Image *image, ReportList *reports, int method)
@@ -299,11 +301,11 @@ void RNA_api_image(StructRNA *srna)
func = RNA_def_function(srna, "save", "rna_Image_save");
RNA_def_function_ui_description(func, "Save image to its source path");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
func = RNA_def_function(srna, "pack", "rna_Image_pack");
RNA_def_function_ui_description(func, "Pack an image as embedded data into the .blend file");
- RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_function_flag(func, FUNC_USE_CONTEXT | FUNC_USE_REPORTS);
RNA_def_boolean(func, "as_png", 0, "as_png", "Pack the image as PNG (needed for generated/dirty images)");
func = RNA_def_function(srna, "unpack", "rna_Image_unpack");
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index ecfb7f5e5f5..051e7277425 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -201,11 +201,13 @@ void rna_def_motionpath_common(struct StructRNA *srna);
void rna_def_texmat_common(struct StructRNA *srna, const char *texspace_editable);
void rna_def_mtex_common(struct BlenderRNA *brna, struct StructRNA *srna, const char *begin, const char *activeget,
const char *activeset, const char *activeeditable, const char *structname,
- const char *structname_slots, const char *update);
+ const char *structname_slots, const char *update, const char *update_index);
+void rna_def_texpaint_slots(struct BlenderRNA *brna, struct StructRNA *srna);
void rna_def_render_layer_common(struct StructRNA *srna, int scene);
void rna_def_actionbone_group_common(struct StructRNA *srna, int update_flag, const char *update_cb);
void rna_ActionGroup_colorset_set(struct PointerRNA *ptr, int value);
+int rna_ActionGroup_is_custom_colorset_get(struct PointerRNA *ptr);
void rna_ID_name_get(struct PointerRNA *ptr, char *value);
int rna_ID_name_length(struct PointerRNA *ptr);
@@ -412,4 +414,24 @@ void rna_RenderPass_rect_set(PointerRNA *ptr, const float *values);
# endif
#endif
+/* C11 for compile time range checks */
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+# define USE_RNA_RANGE_CHECK
+# define TYPEOF_MAX(x) \
+ _Generic((x), \
+ bool: 1, \
+ char: CHAR_MAX, signed char: SCHAR_MAX, unsigned char: UCHAR_MAX, \
+ signed short: SHRT_MAX, unsigned short: USHRT_MAX, \
+ signed int: INT_MAX, unsigned int: UINT_MAX, \
+ float: FLT_MAX, double: DBL_MAX)
+
+# define TYPEOF_MIN(x) \
+ _Generic((x), \
+ bool: 0, \
+ char: CHAR_MIN, signed char: SCHAR_MIN, unsigned char: 0, \
+ signed short: SHRT_MIN, unsigned short: 0, \
+ signed int: INT_MIN, unsigned int: 0, \
+ float: -FLT_MAX, double: -DBL_MAX)
+#endif
+
#endif /* __RNA_INTERNAL_H__ */
diff --git a/source/blender/makesrna/intern/rna_key.c b/source/blender/makesrna/intern/rna_key.c
index 950c369f22f..7d10511d1c4 100644
--- a/source/blender/makesrna/intern/rna_key.c
+++ b/source/blender/makesrna/intern/rna_key.c
@@ -92,6 +92,12 @@ static void rna_ShapeKey_name_set(PointerRNA *ptr, const char *value)
BKE_all_animdata_fix_paths_rename(NULL, "key_blocks", oldname, kb->name);
}
+static float rna_ShapeKey_frame_get(PointerRNA *ptr)
+{
+ KeyBlock *kb = (KeyBlock *)ptr->data;
+ return kb->pos * 100.0f; /* Because pos is ctime/100... */
+}
+
static void rna_ShapeKey_value_set(PointerRNA *ptr, float value)
{
KeyBlock *data = (KeyBlock *)ptr->data;
@@ -564,12 +570,14 @@ static void rna_def_keyblock(BlenderRNA *brna)
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_ui_text(prop, "Name", "Name of Shape Key");
RNA_def_property_string_funcs(prop, NULL, NULL, "rna_ShapeKey_name_set");
+ RNA_def_property_update(prop, 0, "rna_Key_update_data");
RNA_def_struct_name_property(srna, prop);
/* keys need to be sorted to edit this */
prop = RNA_def_property(srna, "frame", PROP_FLOAT, PROP_TIME);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_float_sdna(prop, NULL, "pos");
+ RNA_def_property_float_funcs(prop, "rna_ShapeKey_frame_get", NULL, NULL);
RNA_def_property_ui_text(prop, "Frame", "Frame for absolute keys");
RNA_def_property_update(prop, 0, "rna_Key_update_data");
diff --git a/source/blender/makesrna/intern/rna_lamp.c b/source/blender/makesrna/intern/rna_lamp.c
index 2455141972b..e9861b90956 100644
--- a/source/blender/makesrna/intern/rna_lamp.c
+++ b/source/blender/makesrna/intern/rna_lamp.c
@@ -410,7 +410,8 @@ static void rna_def_lamp(BlenderRNA *brna)
/* textures */
rna_def_mtex_common(brna, srna, "rna_Lamp_mtex_begin", "rna_Lamp_active_texture_get",
- "rna_Lamp_active_texture_set", NULL, "LampTextureSlot", "LampTextureSlots", "rna_Lamp_draw_update");
+ "rna_Lamp_active_texture_set", NULL, "LampTextureSlot", "LampTextureSlots",
+ "rna_Lamp_draw_update", "rna_Lamp_draw_update");
}
static void rna_def_lamp_falloff(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_lattice_api.c b/source/blender/makesrna/intern/rna_lattice_api.c
index acb71b29ea8..ed0489db1a2 100644
--- a/source/blender/makesrna/intern/rna_lattice_api.c
+++ b/source/blender/makesrna/intern/rna_lattice_api.c
@@ -38,14 +38,14 @@
#include "BLI_utildefines.h"
-#include "ED_lattice.h"
-
#include "rna_internal.h" /* own include */
#ifdef RNA_RUNTIME
-void rna_Lattice_transform(Lattice *lt, float *mat)
+static void rna_Lattice_transform(Lattice *lt, float *mat, int shape_keys)
{
- ED_lattice_transform(lt, (float (*)[4])mat);
+ BKE_lattice_transform(lt, (float (*)[4])mat, shape_keys);
+
+ DAG_id_tag_update(&lt->id, 0);
}
#else
@@ -58,6 +58,7 @@ void RNA_api_lattice(StructRNA *srna)
RNA_def_function_ui_description(func, "Transform lattice by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
}
#endif
diff --git a/source/blender/makesrna/intern/rna_linestyle.c b/source/blender/makesrna/intern/rna_linestyle.c
index 2b20dc2485d..638bc7a17ea 100644
--- a/source/blender/makesrna/intern/rna_linestyle.c
+++ b/source/blender/makesrna/intern/rna_linestyle.c
@@ -87,6 +87,10 @@ EnumPropertyItem linestyle_geometry_modifier_type_items[] = {
#include "BKE_texture.h"
#include "BKE_depsgraph.h"
+#include "ED_node.h"
+
+#include "RNA_access.h"
+
static StructRNA *rna_LineStyle_color_modifier_refine(struct PointerRNA *ptr)
{
LineStyleModifier *m = (LineStyleModifier *)ptr->data;
@@ -281,6 +285,144 @@ static void rna_LineStyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poin
WM_main_add_notifier(NC_LINESTYLE, linestyle);
}
+static void rna_LineStyle_use_nodes_update(bContext *C, PointerRNA *ptr)
+{
+ FreestyleLineStyle *linestyle = (FreestyleLineStyle *)ptr->data;
+
+ if (linestyle->use_nodes && linestyle->nodetree == NULL)
+ BKE_linestyle_default_shader(C, linestyle);
+
+ rna_LineStyle_update(CTX_data_main(C), CTX_data_scene(C), ptr);
+}
+
+static LineStyleModifier *rna_LineStyle_color_modifier_add(FreestyleLineStyle *linestyle, ReportList *reports,
+ const char *name, int type)
+{
+ LineStyleModifier *modifier = BKE_linestyle_color_modifier_add(linestyle, name, type);
+
+ if (!modifier) {
+ BKE_report(reports, RPT_ERROR, "Failed to add the color modifier");
+ return NULL;
+ }
+
+ DAG_id_tag_update(&linestyle->id, 0);
+ WM_main_add_notifier(NC_LINESTYLE, linestyle);
+
+ return modifier;
+}
+
+static void rna_LineStyle_color_modifier_remove(FreestyleLineStyle *linestyle, ReportList *reports,
+ PointerRNA *modifier_ptr)
+{
+ LineStyleModifier *modifier = modifier_ptr->data;
+
+ if (BKE_linestyle_color_modifier_remove(linestyle, modifier) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Color modifier '%s' could not be removed", modifier->name);
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(modifier_ptr);
+
+ DAG_id_tag_update(&linestyle->id, 0);
+ WM_main_add_notifier(NC_LINESTYLE, linestyle);
+}
+
+static LineStyleModifier *rna_LineStyle_alpha_modifier_add(FreestyleLineStyle *linestyle, ReportList *reports,
+ const char *name, int type)
+{
+ LineStyleModifier *modifier = BKE_linestyle_alpha_modifier_add(linestyle, name, type);
+
+ if (!modifier) {
+ BKE_report(reports, RPT_ERROR, "Failed to add the alpha modifier");
+ return NULL;
+ }
+
+ DAG_id_tag_update(&linestyle->id, 0);
+ WM_main_add_notifier(NC_LINESTYLE, linestyle);
+
+ return modifier;
+}
+
+static void rna_LineStyle_alpha_modifier_remove(FreestyleLineStyle *linestyle, ReportList *reports,
+ PointerRNA *modifier_ptr)
+{
+ LineStyleModifier *modifier = modifier_ptr->data;
+
+ if (BKE_linestyle_alpha_modifier_remove(linestyle, modifier) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Alpha modifier '%s' could not be removed", modifier->name);
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(modifier_ptr);
+
+ DAG_id_tag_update(&linestyle->id, 0);
+ WM_main_add_notifier(NC_LINESTYLE, linestyle);
+}
+
+static LineStyleModifier *rna_LineStyle_thickness_modifier_add(FreestyleLineStyle *linestyle, ReportList *reports,
+ const char *name, int type)
+{
+ LineStyleModifier *modifier = BKE_linestyle_thickness_modifier_add(linestyle, name, type);
+
+ if (!modifier) {
+ BKE_report(reports, RPT_ERROR, "Failed to add the thickness modifier");
+ return NULL;
+ }
+
+ DAG_id_tag_update(&linestyle->id, 0);
+ WM_main_add_notifier(NC_LINESTYLE, linestyle);
+
+ return modifier;
+}
+
+static void rna_LineStyle_thickness_modifier_remove(FreestyleLineStyle *linestyle, ReportList *reports,
+ PointerRNA *modifier_ptr)
+{
+ LineStyleModifier *modifier = modifier_ptr->data;
+
+ if (BKE_linestyle_thickness_modifier_remove(linestyle, modifier) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Thickness modifier '%s' could not be removed", modifier->name);
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(modifier_ptr);
+
+ DAG_id_tag_update(&linestyle->id, 0);
+ WM_main_add_notifier(NC_LINESTYLE, linestyle);
+}
+
+static LineStyleModifier *rna_LineStyle_geometry_modifier_add(FreestyleLineStyle *linestyle, ReportList *reports,
+ const char *name, int type)
+{
+ LineStyleModifier *modifier = BKE_linestyle_geometry_modifier_add(linestyle, name, type);
+
+ if (!modifier) {
+ BKE_report(reports, RPT_ERROR, "Failed to add the geometry modifier");
+ return NULL;
+ }
+
+ DAG_id_tag_update(&linestyle->id, 0);
+ WM_main_add_notifier(NC_LINESTYLE, linestyle);
+
+ return modifier;
+}
+
+static void rna_LineStyle_geometry_modifier_remove(FreestyleLineStyle *linestyle, ReportList *reports,
+ PointerRNA *modifier_ptr)
+{
+ LineStyleModifier *modifier = modifier_ptr->data;
+
+ if (BKE_linestyle_geometry_modifier_remove(linestyle, modifier) == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Geometry modifier '%s' could not be removed", modifier->name);
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(modifier_ptr);
+
+ DAG_id_tag_update(&linestyle->id, 0);
+ WM_main_add_notifier(NC_LINESTYLE, linestyle);
+}
+
#else
#include "BLI_math.h"
@@ -293,7 +435,7 @@ static void rna_def_linestyle_mtex(BlenderRNA *brna)
static EnumPropertyItem texco_items[] = {
{TEXCO_WINDOW, "WINDOW", 0, "Window", "Use screen coordinates as texture coordinates"},
{TEXCO_GLOB, "GLOBAL", 0, "Global", "Use global coordinates for the texture coordinates"},
- {TEXCO_STROKE, "ALONG_STROKE", 0, "Along stroke", "Use stroke lenght for texture coordinates"},
+ {TEXCO_STROKE, "ALONG_STROKE", 0, "Along stroke", "Use stroke length for texture coordinates"},
{TEXCO_ORCO, "ORCO", 0, "Generated", "Use the original undeformed coordinates of the object"},
{0, NULL, 0, NULL, NULL}
};
@@ -370,7 +512,7 @@ static void rna_def_linestyle_mtex(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_tips", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "texflag", MTEX_TIPS);
- RNA_def_property_ui_text(prop, "Use tips", "Lower half of the texture is for tips of the stroke");
+ RNA_def_property_ui_text(prop, "Use Tips", "Lower half of the texture is for tips of the stroke");
RNA_def_property_update(prop, 0, "rna_LineStyle_update");
prop = RNA_def_property(srna, "texture_coords", PROP_ENUM, PROP_NONE);
@@ -429,18 +571,19 @@ static void rna_def_modifier_type_common(StructRNA *srna, EnumPropertyItem *modi
RNA_def_property_enum_sdna(prop, NULL, "modifier.blend");
RNA_def_property_enum_items(prop, (color) ? ramp_blend_items : value_blend_items);
RNA_def_property_ui_text(prop, "Blend", "Specify how the modifier value is blended into the base value");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "influence", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "modifier.influence");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Influence", "Influence factor by which the modifier changes the property");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
}
prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "modifier.flags", LS_MODIFIER_ENABLED);
RNA_def_property_ui_text(prop, "Use", "Enable or disable this modifier during stroke rendering");
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "expanded", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "modifier.flags", LS_MODIFIER_EXPANDED);
@@ -479,18 +622,18 @@ static void rna_def_modifier_color_ramp_common(StructRNA *srna, int range)
RNA_def_property_pointer_sdna(prop, NULL, "color_ramp");
RNA_def_property_struct_type(prop, "ColorRamp");
RNA_def_property_ui_text(prop, "Color Ramp", "Color ramp used to change line color");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
if (range) {
prop = RNA_def_property(srna, "range_min", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "range_min");
RNA_def_property_ui_text(prop, "Range Min", "Lower bound of the input range the mapping is applied");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "range_max", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "range_max");
RNA_def_property_ui_text(prop, "Range Max", "Upper bound of the input range the mapping is applied");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
}
}
@@ -508,41 +651,41 @@ static void rna_def_modifier_curve_common(StructRNA *srna, bool range, bool valu
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, mapping_items);
RNA_def_property_ui_text(prop, "Mapping", "Select the mapping type");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "invert", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", LS_MODIFIER_INVERT);
RNA_def_property_ui_text(prop, "Invert", "Invert the fade-out direction of the linear mapping");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curve");
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_ui_text(prop, "Curve", "Curve used for the curve mapping");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
if (range) {
prop = RNA_def_property(srna, "range_min", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "range_min");
RNA_def_property_ui_text(prop, "Range Min", "Lower bound of the input range the mapping is applied");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "range_max", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "range_max");
RNA_def_property_ui_text(prop, "Range Max", "Upper bound of the input range the mapping is applied");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
}
if (value) {
prop = RNA_def_property(srna, "value_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "value_min");
RNA_def_property_ui_text(prop, "Value Min", "Minimum output value of the mapping");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "value_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "value_max");
RNA_def_property_ui_text(prop, "Value Max", "Maximum output value of the mapping");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
}
}
@@ -551,16 +694,21 @@ static void rna_def_modifier_material_common(StructRNA *srna)
PropertyRNA *prop;
static EnumPropertyItem mat_attr_items[] = {
- {LS_MODIFIER_MATERIAL_DIFF, "DIFF", 0, "Diffuse", ""},
- {LS_MODIFIER_MATERIAL_DIFF_R, "DIFF_R", 0, "Diffuse Red", ""},
- {LS_MODIFIER_MATERIAL_DIFF_G, "DIFF_G", 0, "Diffuse Green", ""},
- {LS_MODIFIER_MATERIAL_DIFF_B, "DIFF_B", 0, "Diffuse Blue", ""},
- {LS_MODIFIER_MATERIAL_SPEC, "SPEC", 0, "Specular", ""},
- {LS_MODIFIER_MATERIAL_SPEC_R, "SPEC_R", 0, "Specular Red", ""},
- {LS_MODIFIER_MATERIAL_SPEC_G, "SPEC_G", 0, "Specular Green", ""},
- {LS_MODIFIER_MATERIAL_SPEC_B, "SPEC_B", 0, "Specular Blue", ""},
+ {LS_MODIFIER_MATERIAL_LINE, "LINE", 0, "Line Color", ""},
+ {LS_MODIFIER_MATERIAL_LINE_R, "LINE_R", 0, "Line Color Red", ""},
+ {LS_MODIFIER_MATERIAL_LINE_G, "LINE_G", 0, "Line Color Green", ""},
+ {LS_MODIFIER_MATERIAL_LINE_B, "LINE_B", 0, "Line Color Blue", ""},
+ {LS_MODIFIER_MATERIAL_LINE_A, "LINE_A", 0, "Line Color Alpha", ""},
+ {LS_MODIFIER_MATERIAL_DIFF, "DIFF", 0, "Diffuse Color", ""},
+ {LS_MODIFIER_MATERIAL_DIFF_R, "DIFF_R", 0, "Diffuse Color Red", ""},
+ {LS_MODIFIER_MATERIAL_DIFF_G, "DIFF_G", 0, "Diffuse Color Green", ""},
+ {LS_MODIFIER_MATERIAL_DIFF_B, "DIFF_B", 0, "Diffuse Color Blue", ""},
+ {LS_MODIFIER_MATERIAL_SPEC, "SPEC", 0, "Specular Color", ""},
+ {LS_MODIFIER_MATERIAL_SPEC_R, "SPEC_R", 0, "Specular Color Red", ""},
+ {LS_MODIFIER_MATERIAL_SPEC_G, "SPEC_G", 0, "Specular Color Green", ""},
+ {LS_MODIFIER_MATERIAL_SPEC_B, "SPEC_B", 0, "Specular Color Blue", ""},
{LS_MODIFIER_MATERIAL_SPEC_HARD, "SPEC_HARD", 0, "Specular Hardness", ""},
- {LS_MODIFIER_MATERIAL_ALPHA, "ALPHA", 0, "Alpha", ""},
+ {LS_MODIFIER_MATERIAL_ALPHA, "ALPHA", 0, "Alpha Transparency", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -568,7 +716,7 @@ static void rna_def_modifier_material_common(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "mat_attr");
RNA_def_property_enum_items(prop, mat_attr_items);
RNA_def_property_ui_text(prop, "Material Attribute", "Specify which material attribute is used");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
}
@@ -624,7 +772,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Target", "Target object from which the distance is measured");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleColorModifier_Material", "LineStyleColorModifier");
RNA_def_struct_ui_text(srna, "Material", "Change line color based on a material attribute");
@@ -635,7 +783,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_ramp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", LS_MODIFIER_USE_RAMP);
RNA_def_property_ui_text(prop, "Ramp", "Use color ramp to map the BW average into an RGB color");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
/* alpha transparency modifiers */
@@ -667,7 +815,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Target", "Target object from which the distance is measured");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleAlphaModifier_Material", "LineStyleAlphaModifier");
RNA_def_struct_ui_text(srna, "Material", "Change alpha transparency based on a material attribute");
@@ -703,7 +851,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Object");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Target", "Target object from which the distance is measured");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleThicknessModifier_Material", "LineStyleThicknessModifier");
RNA_def_struct_ui_text(srna, "Material", "Change line thickness based on a material attribute");
@@ -719,20 +867,20 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
prop = RNA_def_property(srna, "orientation", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "orientation");
RNA_def_property_ui_text(prop, "Orientation", "Angle of the main direction");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "thickness_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "min_thickness");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_text(prop, "Min Thickness",
"Minimum thickness in the direction perpendicular to the main direction");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "thickness_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "max_thickness");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_text(prop, "Max Thickness", "Maximum thickness in the main direction");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
/* geometry modifiers */
@@ -751,7 +899,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "sampling");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_text(prop, "Sampling", "New sampling value to be used for subsequent modifiers");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_BezierCurve", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Bezier Curve",
@@ -764,7 +912,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Error",
"Maximum distance allowed between the new Bezier curve and the "
"original backbone geometry");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_SinusDisplacement", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Sinus Displacement", "Add sinus displacement to stroke backbone geometry");
@@ -773,17 +921,17 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
prop = RNA_def_property(srna, "wavelength", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "wavelength");
RNA_def_property_ui_text(prop, "Wavelength", "Wavelength of the sinus displacement");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "amplitude");
RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of the sinus displacement");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "phase", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "phase");
RNA_def_property_ui_text(prop, "Phase", "Phase of the sinus displacement");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_SpatialNoise", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Spatial Noise", "Add spatial noise to stroke backbone geometry");
@@ -792,27 +940,27 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "amplitude");
RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of the spatial noise");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "scale", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale");
RNA_def_property_ui_text(prop, "Scale", "Scale of the spatial noise");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "octaves", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "octaves");
RNA_def_property_ui_text(prop, "Octaves", "Number of octaves (i.e., the amount of detail of the spatial noise)");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", LS_MODIFIER_SPATIAL_NOISE_SMOOTH);
RNA_def_property_ui_text(prop, "Smooth", "If true, the spatial noise is smooth");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_pure_random", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", LS_MODIFIER_SPATIAL_NOISE_PURERANDOM);
RNA_def_property_ui_text(prop, "Pure Random", "If true, the spatial noise does not show any coherence");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_PerlinNoise1D", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Perlin Noise 1D", "Add one-dimensional Perlin noise to stroke backbone geometry");
@@ -821,28 +969,28 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
prop = RNA_def_property(srna, "frequency", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "frequency");
RNA_def_property_ui_text(prop, "Frequency", "Frequency of the Perlin noise");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "amplitude");
RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of the Perlin noise");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "octaves", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "octaves");
RNA_def_property_ui_text(prop, "Octaves", "Number of octaves (i.e., the amount of detail of the Perlin noise)");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "angle");
RNA_def_property_ui_text(prop, "Angle", "Displacement direction");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "seed");
RNA_def_property_ui_text(prop, "Seed",
"Seed for random number generation (if negative, time is used as a seed instead)");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_PerlinNoise2D", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Perlin Noise 2D", "Add two-dimensional Perlin noise to stroke backbone geometry");
@@ -851,28 +999,28 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
prop = RNA_def_property(srna, "frequency", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "frequency");
RNA_def_property_ui_text(prop, "Frequency", "Frequency of the Perlin noise");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "amplitude", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "amplitude");
RNA_def_property_ui_text(prop, "Amplitude", "Amplitude of the Perlin noise");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "octaves", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "octaves");
RNA_def_property_ui_text(prop, "Octaves", "Number of octaves (i.e., the amount of detail of the Perlin noise)");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "angle");
RNA_def_property_ui_text(prop, "Angle", "Displacement direction");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "seed", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "seed");
RNA_def_property_ui_text(prop, "Seed",
"Seed for random number generation (if negative, time is used as a seed instead)");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_BackboneStretcher", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Backbone Stretcher", "Stretch the beginning and the end of stroke backbone");
@@ -881,7 +1029,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
prop = RNA_def_property(srna, "backbone_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "backbone_length");
RNA_def_property_ui_text(prop, "Backbone Length", "Amount of backbone stretching");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_TipRemover", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Tip Remover",
@@ -891,7 +1039,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
prop = RNA_def_property(srna, "tip_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "tip_length");
RNA_def_property_ui_text(prop, "Tip Length", "Length of tips to be removed");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_Polygonalization", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Polygonalization", "Modify the stroke geometry so that it looks more 'polygonal'");
@@ -901,7 +1049,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "error");
RNA_def_property_ui_text(prop, "Error",
"Maximum distance between the original stroke and its polygonal approximation");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_GuidingLines", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Guiding Lines",
@@ -912,7 +1060,7 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "offset");
RNA_def_property_ui_text(prop, "Offset",
"Displacement that is applied to the main direction line along its normal");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_Blueprint", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "Blueprint",
@@ -923,33 +1071,33 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, blueprint_shape_items);
RNA_def_property_ui_text(prop, "Shape", "Select the shape of blueprint contour strokes");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "rounds", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "rounds");
RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_text(prop, "Rounds", "Number of rounds in contour strokes");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "backbone_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "backbone_length");
RNA_def_property_ui_text(prop, "Backbone Length", "Amount of backbone stretching");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "random_radius", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "random_radius");
RNA_def_property_ui_text(prop, "Random Radius", "Randomness of the radius");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "random_center", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "random_center");
RNA_def_property_ui_text(prop, "Random Center", "Randomness of the center");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "random_backbone", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "random_backbone");
RNA_def_property_ui_text(prop, "Random Backbone", "Randomness of the backbone stretching");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_2DOffset", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "2D Offset", "Add two-dimensional offsets to stroke backbone geometry");
@@ -958,22 +1106,22 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
prop = RNA_def_property(srna, "start", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "start");
RNA_def_property_ui_text(prop, "Start", "Displacement that is applied from the beginning of the stroke");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "end", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "end");
RNA_def_property_ui_text(prop, "End", "Displacement that is applied from the end of the stroke");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "x");
RNA_def_property_ui_text(prop, "X", "Displacement that is applied to the X coordinates of stroke vertices");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "y");
RNA_def_property_ui_text(prop, "Y", "Displacement that is applied to the Y coordinates of stroke vertices");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
srna = RNA_def_struct(brna, "LineStyleGeometryModifier_2DTransform", "LineStyleGeometryModifier");
RNA_def_struct_ui_text(srna, "2D Transform",
@@ -984,41 +1132,157 @@ static void rna_def_linestyle_modifiers(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "pivot");
RNA_def_property_enum_items(prop, transform_pivot_items);
RNA_def_property_ui_text(prop, "Pivot", "Pivot of scaling and rotation operations");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "scale_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale_x");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_text(prop, "Scale X", "Scaling factor that is applied along the X axis");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "scale_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "scale_y");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
RNA_def_property_ui_text(prop, "Scale Y", "Scaling factor that is applied along the Y axis");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "angle");
RNA_def_property_ui_text(prop, "Rotation Angle", "Rotation angle");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "pivot_u", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "pivot_u");
RNA_def_property_range(prop, 0.f, 1.f);
RNA_def_property_ui_text(prop, "Stroke Point Parameter",
"Pivot in terms of the stroke point parameter u (0 <= u <= 1)");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "pivot_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "pivot_x");
RNA_def_property_ui_text(prop, "Pivot X", "2D X coordinate of the absolute pivot");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "pivot_y", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "pivot_y");
RNA_def_property_ui_text(prop, "Pivot Y", "2D Y coordinate of the absolute pivot");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
+}
+
+static void rna_def_freestyle_color_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "LineStyleColorModifiers");
+ srna = RNA_def_struct(brna, "LineStyleColorModifiers", NULL);
+ RNA_def_struct_sdna(srna, "FreestyleLineStyle");
+ RNA_def_struct_ui_text(srna, "Color Modifiers", "Color modifiers for changing line colors");
+
+ func = RNA_def_function(srna, "new", "rna_LineStyle_color_modifier_add");
+ RNA_def_function_ui_description(func, "Add a color modifier to line style");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "name", "ColorModifier", 0, "", "New name for the color modifier (not unique)");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_enum(func, "type", linestyle_color_modifier_type_items, 0, "", "Color modifier type to add");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "modifier", "LineStyleColorModifier", "", "Newly added color modifier");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_LineStyle_color_modifier_remove");
+ RNA_def_function_ui_description(func, "Remove a color modifier from line style");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "modifier", "LineStyleColorModifier", "", "Color modifier to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+}
+
+static void rna_def_freestyle_alpha_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "LineStyleAlphaModifiers");
+ srna = RNA_def_struct(brna, "LineStyleAlphaModifiers", NULL);
+ RNA_def_struct_sdna(srna, "FreestyleLineStyle");
+ RNA_def_struct_ui_text(srna, "Alpha Modifiers", "Alpha modifiers for changing line alphas");
+
+ func = RNA_def_function(srna, "new", "rna_LineStyle_alpha_modifier_add");
+ RNA_def_function_ui_description(func, "Add a alpha modifier to line style");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "name", "AlphaModifier", 0, "", "New name for the alpha modifier (not unique)");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_enum(func, "type", linestyle_alpha_modifier_type_items, 0, "", "Alpha modifier type to add");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "modifier", "LineStyleAlphaModifier", "", "Newly added alpha modifier");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_LineStyle_alpha_modifier_remove");
+ RNA_def_function_ui_description(func, "Remove a alpha modifier from line style");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "modifier", "LineStyleAlphaModifier", "", "Alpha modifier to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+}
+
+static void rna_def_freestyle_thickness_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "LineStyleThicknessModifiers");
+ srna = RNA_def_struct(brna, "LineStyleThicknessModifiers", NULL);
+ RNA_def_struct_sdna(srna, "FreestyleLineStyle");
+ RNA_def_struct_ui_text(srna, "Thickness Modifiers", "Thickness modifiers for changing line thicknesss");
+
+ func = RNA_def_function(srna, "new", "rna_LineStyle_thickness_modifier_add");
+ RNA_def_function_ui_description(func, "Add a thickness modifier to line style");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "name", "ThicknessModifier", 0, "", "New name for the thickness modifier (not unique)");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_enum(func, "type", linestyle_thickness_modifier_type_items, 0, "", "Thickness modifier type to add");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Newly added thickness modifier");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_LineStyle_thickness_modifier_remove");
+ RNA_def_function_ui_description(func, "Remove a thickness modifier from line style");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "modifier", "LineStyleThicknessModifier", "", "Thickness modifier to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+}
+
+static void rna_def_freestyle_geometry_modifiers(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "LineStyleGeometryModifiers");
+ srna = RNA_def_struct(brna, "LineStyleGeometryModifiers", NULL);
+ RNA_def_struct_sdna(srna, "FreestyleLineStyle");
+ RNA_def_struct_ui_text(srna, "Geometry Modifiers", "Geometry modifiers for changing line geometrys");
+
+ func = RNA_def_function(srna, "new", "rna_LineStyle_geometry_modifier_add");
+ RNA_def_function_ui_description(func, "Add a geometry modifier to line style");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_string(func, "name", "GeometryModifier", 0, "", "New name for the geometry modifier (not unique)");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_enum(func, "type", linestyle_geometry_modifier_type_items, 0, "", "Geometry modifier type to add");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Newly added geometry modifier");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_LineStyle_geometry_modifier_remove");
+ RNA_def_function_ui_description(func, "Remove a geometry modifier from line style");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "modifier", "LineStyleGeometryModifier", "", "Geometry modifier to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
}
static void rna_def_linestyle(BlenderRNA *brna)
@@ -1059,6 +1323,8 @@ static void rna_def_linestyle(BlenderRNA *brna)
static EnumPropertyItem sort_key_items[] = {
{LS_SORT_KEY_DISTANCE_FROM_CAMERA, "DISTANCE_FROM_CAMERA", 0, "Distance from Camera", "Sort by distance from camera (closer lines lie on top of further lines)"},
{LS_SORT_KEY_2D_LENGTH, "2D_LENGTH", 0, "2D Length", "Sort by curvilinear 2D length (longer lines lie on top of shorter lines)"},
+ {LS_SORT_KEY_PROJECTED_X, "PROJECTED_X", 0, "Projected X", "Sort by the projected X value in the image coordinate system"},
+ {LS_SORT_KEY_PROJECTED_Y, "PROJECTED_Y", 0, "Projected Y", "Sort by the projected Y value in the image coordinate system"},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem sort_order_items[] = {
@@ -1080,39 +1346,39 @@ static void rna_def_linestyle(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_LINE_DATA);
rna_def_mtex_common(brna, srna, "rna_LineStyle_mtex_begin", "rna_LineStyle_active_texture_get",
- "rna_LineStyle_active_texture_set", NULL, "LineStyleTextureSlot", "LineStyleTextureSlots", "rna_LineStyle_update");
+ "rna_LineStyle_active_texture_set", NULL, "LineStyleTextureSlot", "LineStyleTextureSlots",
+ "rna_LineStyle_update", "rna_LineStyle_update");
prop = RNA_def_property(srna, "panel", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "panel");
RNA_def_property_enum_items(prop, panel_items);
RNA_def_property_ui_text(prop, "Panel", "Select the property panel to be shown");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "r");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Color", "Base line color, possibly modified by line color modifiers");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "alpha");
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Alpha Transparency",
"Base alpha transparency, possibly modified by alpha transparency modifiers");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "thickness", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "thickness");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_text(prop, "Thickness", "Base line thickness, possibly modified by line thickness modifiers");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "thickness_position", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "thickness_position");
RNA_def_property_enum_items(prop, thickness_position_items);
RNA_def_property_ui_text(prop, "Thickness Position",
"Thickness position of silhouettes and border edges (applicable when plain chaining is used with the Same Object option)");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "thickness_ratio", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "thickness_ratio");
@@ -1120,245 +1386,259 @@ static void rna_def_linestyle(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Thickness Ratio",
"A number between 0 (inside) and 1 (outside) specifying the relative position of "
"stroke thickness");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "color_modifiers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "color_modifiers", NULL);
RNA_def_property_struct_type(prop, "LineStyleColorModifier");
RNA_def_property_ui_text(prop, "Color Modifiers", "List of line color modifiers");
+ rna_def_freestyle_color_modifiers(brna, prop);
prop = RNA_def_property(srna, "alpha_modifiers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "alpha_modifiers", NULL);
RNA_def_property_struct_type(prop, "LineStyleAlphaModifier");
RNA_def_property_ui_text(prop, "Alpha Modifiers", "List of alpha transparency modifiers");
+ rna_def_freestyle_alpha_modifiers(brna, prop);
prop = RNA_def_property(srna, "thickness_modifiers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "thickness_modifiers", NULL);
RNA_def_property_struct_type(prop, "LineStyleThicknessModifier");
RNA_def_property_ui_text(prop, "Thickness Modifiers", "List of line thickness modifiers");
+ rna_def_freestyle_thickness_modifiers(brna, prop);
+
+ prop = RNA_def_property(srna, "geometry_modifiers", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "geometry_modifiers", NULL);
+ RNA_def_property_struct_type(prop, "LineStyleGeometryModifier");
+ RNA_def_property_ui_text(prop, "Geometry Modifiers", "List of stroke geometry modifiers");
+ rna_def_freestyle_geometry_modifiers(brna, prop);
prop = RNA_def_property(srna, "use_chaining", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", LS_NO_CHAINING);
RNA_def_property_ui_text(prop, "Chaining", "Enable chaining of feature edges");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "chaining", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "chaining");
RNA_def_property_enum_items(prop, chaining_items);
RNA_def_property_ui_text(prop, "Chaining Method", "Select the way how feature edges are jointed to form chains");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "rounds", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "rounds");
RNA_def_property_range(prop, 1, 1000);
RNA_def_property_ui_text(prop, "Rounds", "Number of rounds in a sketchy multiple touch");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
-
- prop = RNA_def_property(srna, "geometry_modifiers", PROP_COLLECTION, PROP_NONE);
- RNA_def_property_collection_sdna(prop, NULL, "geometry_modifiers", NULL);
- RNA_def_property_struct_type(prop, "LineStyleGeometryModifier");
- RNA_def_property_ui_text(prop, "Geometry Modifiers", "List of stroke geometry modifiers");
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_same_object", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_SAME_OBJECT);
RNA_def_property_ui_text(prop, "Same Object", "If true, only feature edges of the same object are joined");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_split_length", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_SPLIT_LENGTH);
RNA_def_property_ui_text(prop, "Use Split Length", "Enable chain splitting by curvilinear 2D length");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "split_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "split_length");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_text(prop, "Split Length", "Curvilinear 2D length for chain splitting");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_angle_min", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MIN_2D_ANGLE);
RNA_def_property_ui_text(prop, "Use Min 2D Angle",
"Split chains at points with angles smaller than the minimum 2D angle");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "angle_min", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "min_angle");
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_text(prop, "Min 2D Angle", "Minimum 2D angle for splitting chains");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_angle_max", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MAX_2D_ANGLE);
RNA_def_property_ui_text(prop, "Use Max 2D Angle",
"Split chains at points with angles larger than the maximum 2D angle");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "angle_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "max_angle");
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_text(prop, "Max 2D Angle", "Maximum 2D angle for splitting chains");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_length_min", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MIN_2D_LENGTH);
RNA_def_property_ui_text(prop, "Use Min 2D Length", "Enable the selection of chains by a minimum 2D length");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "length_min", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "min_length");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_text(prop, "Min 2D Length", "Minimum curvilinear 2D length for the selection of chains");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_length_max", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MAX_2D_LENGTH);
RNA_def_property_ui_text(prop, "Use Max 2D Length", "Enable the selection of chains by a maximum 2D length");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "length_max", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "max_length");
RNA_def_property_range(prop, 0.0f, 10000.0f);
RNA_def_property_ui_text(prop, "Max 2D Length", "Maximum curvilinear 2D length for the selection of chains");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
+
+ prop = RNA_def_property(srna, "use_chain_count", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_CHAIN_COUNT);
+ RNA_def_property_ui_text(prop, "Use Chain Count", "Enable the selection of first N chains");
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
+
+ prop = RNA_def_property(srna, "chain_count", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_int_sdna(prop, NULL, "chain_count");
+ RNA_def_property_ui_text(prop, "Chain Count", "Chain count for the selection of first N chains");
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_split_pattern", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_SPLIT_PATTERN);
RNA_def_property_ui_text(prop, "Use Split Pattern", "Enable chain splitting by dashed line patterns");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "split_dash1", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "split_dash1");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Split Dash 1", "Length of the 1st dash for splitting");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "split_gap1", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "split_gap1");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Split Gap 1", "Length of the 1st gap for splitting");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "split_dash2", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "split_dash2");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Split Dash 2", "Length of the 2nd dash for splitting");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "split_gap2", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "split_gap2");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Split Gap 2", "Length of the 2nd gap for splitting");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "split_dash3", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "split_dash3");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Split Dash 3", "Length of the 3rd dash for splitting");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "split_gap3", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "split_gap3");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Split Gap 3", "Length of the 3rd gap for splitting");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "material_boundary", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_MATERIAL_BOUNDARY);
RNA_def_property_ui_text(prop, "Material Boundary", "If true, chains of feature edges are split at material boundaries");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_sorting", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", LS_NO_SORTING);
RNA_def_property_ui_text(prop, "Sorting", "Arrange the stacking order of strokes");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "sort_key", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "sort_key");
RNA_def_property_enum_items(prop, sort_key_items);
RNA_def_property_ui_text(prop, "Sort Key", "Select the sort key to determine the stacking order of chains");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "sort_order", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, sort_order_items);
RNA_def_property_ui_text(prop, "Sort Order", "Select the sort order");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "integration_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "integration_type");
RNA_def_property_enum_items(prop, integration_type_items);
RNA_def_property_ui_text(prop, "Integration Type", "Select the way how the sort key is computed for each chain");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_dashed_line", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_DASHED_LINE);
RNA_def_property_ui_text(prop, "Dashed Line", "Enable or disable dashed line");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "caps", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "caps");
RNA_def_property_enum_items(prop, cap_items);
RNA_def_property_ui_text(prop, "Caps", "Select the shape of both ends of strokes");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "dash1", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "dash1");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Dash 1", "Length of the 1st dash for dashed lines");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "gap1", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "gap1");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Gap 1", "Length of the 1st gap for dashed lines");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "dash2", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "dash2");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Dash 2", "Length of the 2nd dash for dashed lines");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "gap2", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "gap2");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Gap 2", "Length of the 2nd gap for dashed lines");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "dash3", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "dash3");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Dash 3", "Length of the 3rd dash for dashed lines");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "gap3", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "gap3");
RNA_def_property_range(prop, 0, USHRT_MAX);
RNA_def_property_ui_text(prop, "Gap 3", "Length of the 3rd gap for dashed lines");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "use_texture", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", LS_TEXTURE);
RNA_def_property_ui_text(prop, "Use Textures", "Enable or disable textured strokes");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
prop = RNA_def_property(srna, "texture_spacing", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "texstep");
RNA_def_property_range(prop, 0.01f, 100.0f);
- RNA_def_property_ui_text(prop, "Texture spacing", "Spacing for textures along stroke lenght");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_ui_text(prop, "Texture spacing", "Spacing for textures along stroke length");
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_update");
/* nodes */
prop = RNA_def_property(srna, "node_tree", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "nodetree");
- RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node based textures");
+ RNA_def_property_ui_text(prop, "Node Tree", "Node tree for node-based shaders");
prop = RNA_def_property(srna, "use_nodes", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "use_nodes", 1);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
- RNA_def_property_ui_text(prop, "Use Nodes", "Use texture nodes for the line style");
- RNA_def_property_update(prop, NC_LINESTYLE, NULL);
+ RNA_def_property_ui_text(prop, "Use Nodes", "Use shader nodes for the line style");
+ RNA_def_property_update(prop, NC_LINESTYLE, "rna_LineStyle_use_nodes_update");
}
void RNA_def_linestyle(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_main.c b/source/blender/makesrna/intern/rna_main.c
index f163808c61b..65d81359045 100644
--- a/source/blender/makesrna/intern/rna_main.c
+++ b/source/blender/makesrna/intern/rna_main.c
@@ -281,6 +281,14 @@ static void rna_Main_linestyle_begin(CollectionPropertyIterator *iter, PointerRN
rna_iterator_listbase_begin(iter, &bmain->linestyle, NULL);
}
+static void rna_Main_version_get(PointerRNA *ptr, int *value)
+{
+ Main *bmain = (Main *)ptr->data;
+ value[0] = bmain->versionfile / 100;
+ value[1] = bmain->versionfile % 100;
+ value[2] = bmain->subversionfile;
+}
+
#ifdef UNIT_TEST
static PointerRNA rna_Test_test_get(PointerRNA *ptr)
@@ -376,6 +384,12 @@ void RNA_def_main(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Main_use_autopack_get", "rna_Main_use_autopack_set");
RNA_def_property_ui_text(prop, "Use Autopack", "Automatically pack all external data into .blend file");
+ prop = RNA_def_int_vector(srna, "version", 3, NULL, 0, INT_MAX,
+ "Version", "Version of the blender the .blend was saved with", 0, INT_MAX);
+ RNA_def_property_int_funcs(prop, "rna_Main_version_get", NULL, NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_flag(prop, PROP_THICK_WRAP);
+
for (i = 0; lists[i].name; i++) {
prop = RNA_def_property(srna, lists[i].identifier, PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, lists[i].type);
diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c
index bac1f132126..b4c332be373 100644
--- a/source/blender/makesrna/intern/rna_main_api.c
+++ b/source/blender/makesrna/intern/rna_main_api.c
@@ -683,14 +683,14 @@ static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, Poin
gpd->id.name + 2, ID_REAL_USERS(gpd));
}
-FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name)
+static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name)
{
- FreestyleLineStyle *linestyle = BKE_new_linestyle(name, bmain);
+ FreestyleLineStyle *linestyle = BKE_linestyle_new(name, bmain);
id_us_min(&linestyle->id);
return linestyle;
}
-void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle)
+static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle)
{
if (ID_REAL_USERS(linestyle) <= 0)
BKE_libblock_free(bmain, linestyle);
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 061f1595c8c..2e4f24fc0ce 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -82,6 +82,8 @@ EnumPropertyItem ramp_blend_items[] = {
#include "DNA_node_types.h"
#include "DNA_object_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
@@ -92,6 +94,8 @@ EnumPropertyItem ramp_blend_items[] = {
#include "BKE_paint.h"
#include "ED_node.h"
+#include "ED_image.h"
+#include "BKE_scene.h"
static void rna_Material_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
@@ -165,6 +169,54 @@ static void rna_Material_mtex_begin(CollectionPropertyIterator *iter, PointerRNA
rna_iterator_array_begin(iter, (void *)ma->mtex, sizeof(MTex *), MAX_MTEX, 0, NULL);
}
+static void rna_Material_texpaint_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ Material *ma = (Material *)ptr->data;
+ rna_iterator_array_begin(iter, (void *)ma->texpaintslot, sizeof(TexPaintSlot), ma->tot_slots, 0, NULL);
+}
+
+
+static void rna_Material_active_paint_texture_index_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ bScreen *sc;
+ Material *ma = ptr->id.data;
+
+ if (ma->use_nodes && ma->nodetree && BKE_scene_use_new_shading_nodes(scene)) {
+ struct bNode *node;
+ int index = 0;
+ for (node = ma->nodetree->nodes.first; node; node = node->next) {
+ if (node->typeinfo->nclass == NODE_CLASS_TEXTURE && node->typeinfo->type == SH_NODE_TEX_IMAGE && node->id) {
+ if (index++ == ma->paint_active_slot) {
+ break;
+ }
+ }
+ }
+ if (node)
+ nodeSetActive(ma->nodetree, node);
+ }
+
+ if (ma->texpaintslot) {
+ Image *image = ma->texpaintslot[ma->paint_active_slot].ima;
+ 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) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ if (!sima->pin)
+ ED_space_image_set(sima, scene, scene->obedit, image);
+ }
+ }
+ }
+ }
+ }
+
+ DAG_id_tag_update(&ma->id, 0);
+ WM_main_add_notifier(NC_MATERIAL | ND_SHADING, ma);
+}
+
static PointerRNA rna_Material_active_texture_get(PointerRNA *ptr)
{
Material *ma = (Material *)ptr->data;
@@ -290,7 +342,7 @@ static void rna_Material_use_nodes_update(bContext *C, PointerRNA *ptr)
if (ma->use_nodes && ma->nodetree == NULL)
ED_node_shader_default(C, &ma->id);
- rna_Material_update(CTX_data_main(C), CTX_data_scene(C), ptr);
+ rna_Material_draw_update(CTX_data_main(C), CTX_data_scene(C), ptr);
}
static EnumPropertyItem *rna_Material_texture_coordinates_itemf(bContext *UNUSED(C), PointerRNA *ptr,
@@ -307,7 +359,7 @@ static EnumPropertyItem *rna_Material_texture_coordinates_itemf(bContext *UNUSED
if (ma->material_type == MA_TYPE_VOLUME) {
}
- else if (ELEM3(ma->material_type, MA_TYPE_SURFACE, MA_TYPE_HALO, MA_TYPE_WIRE)) {
+ else if (ELEM(ma->material_type, MA_TYPE_SURFACE, MA_TYPE_HALO, MA_TYPE_WIRE)) {
RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_UV);
RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_STRAND);
RNA_enum_items_add_value(&item, &totitem, prop_texture_coordinates_items, TEXCO_WINDOW);
@@ -375,6 +427,7 @@ void rna_mtex_texture_slots_clear(ID *self_id, struct bContext *C, ReportList *r
id_us_min((ID *)mtex_ar[index]->tex);
MEM_freeN(mtex_ar[index]);
mtex_ar[index] = NULL;
+ DAG_id_tag_update(self_id, 0);
}
/* for redraw only */
@@ -931,6 +984,20 @@ static void rna_def_material_colors(StructRNA *srna)
RNA_def_property_range(prop, 0.0f, 1.0f);
RNA_def_property_ui_text(prop, "Specular Ramp Factor", "Blending factor (also uses alpha in Colorband)");
RNA_def_property_update(prop, 0, "rna_Material_update");
+
+ /* Freestyle line color */
+ prop = RNA_def_property(srna, "line_color", PROP_FLOAT, PROP_COLOR);
+ RNA_def_property_float_sdna(prop, NULL, "line_col");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Line Color", "Line color used for Freestyle line rendering");
+ RNA_def_property_update(prop, 0, "rna_Material_update");
+
+ prop = RNA_def_property(srna, "line_priority", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "line_priority");
+ RNA_def_property_range(prop, 0, 32767);
+ RNA_def_property_ui_text(prop, "Line Priority",
+ "The line color of a higher priority is used at material boundaries");
+ RNA_def_property_update(prop, 0, "rna_Material_update");
}
static void rna_def_material_diffuse(StructRNA *srna)
@@ -1517,7 +1584,7 @@ static void rna_def_material_sss(BlenderRNA *brna)
prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "sss_flag", MA_DIFF_SSS);
- RNA_def_property_ui_text(prop, "Enabled", "Enable diffuse subsurface scatting effects in a material");
+ RNA_def_property_ui_text(prop, "Enabled", "Enable diffuse subsurface scattering effects in a material");
RNA_def_property_update(prop, 0, "rna_Material_update");
}
@@ -2042,7 +2109,9 @@ void RNA_def_material(BlenderRNA *brna)
rna_def_animdata_common(srna);
rna_def_mtex_common(brna, srna, "rna_Material_mtex_begin", "rna_Material_active_texture_get",
"rna_Material_active_texture_set", "rna_Material_active_texture_editable",
- "MaterialTextureSlot", "MaterialTextureSlots", "rna_Material_update");
+ "MaterialTextureSlot", "MaterialTextureSlots", "rna_Material_update", "rna_Material_update");
+
+ rna_def_texpaint_slots(brna, srna);
/* only material has this one */
prop = RNA_def_property(srna, "use_textures", PROP_BOOLEAN, PROP_NONE);
@@ -2104,7 +2173,7 @@ static void rna_def_texture_slots(BlenderRNA *brna, PropertyRNA *cprop, const ch
void rna_def_mtex_common(BlenderRNA *brna, StructRNA *srna, const char *begin,
const char *activeget, const char *activeset, const char *activeeditable,
- const char *structname, const char *structname_slots, const char *update)
+ const char *structname, const char *structname_slots, const char *update, const char *update_index)
{
PropertyRNA *prop;
@@ -2129,7 +2198,59 @@ void rna_def_mtex_common(BlenderRNA *brna, StructRNA *srna, const char *begin,
RNA_def_property_int_sdna(prop, NULL, "texact");
RNA_def_property_range(prop, 0, MAX_MTEX - 1);
RNA_def_property_ui_text(prop, "Active Texture Index", "Index of active texture slot");
- RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, update);
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, update_index);
+}
+
+static void rna_def_tex_slot(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "TexPaintSlot", NULL);
+ RNA_def_struct_ui_text(srna, "Texture Paint Slot",
+ "Slot that contains information about texture painting");
+
+ prop = RNA_def_property(srna, "uv_layer", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_maxlength(prop, 64); /* else it uses the pointer size! */
+ RNA_def_property_string_sdna(prop, NULL, "uvname");
+ RNA_def_property_ui_text(prop, "UV Map", "Name of UV map");
+ RNA_def_property_update(prop, NC_GEOM | ND_DATA, "rna_Material_update");
+
+ prop = RNA_def_property(srna, "index", PROP_INT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Index", "Index of MTex slot in the material");
+}
+
+
+void rna_def_texpaint_slots(BlenderRNA *brna, StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ rna_def_tex_slot(brna);
+
+ /* mtex */
+ prop = RNA_def_property(srna, "texture_paint_images", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "texpaintslot", NULL);
+ RNA_def_property_collection_funcs(prop, "rna_Material_texpaint_begin", "rna_iterator_array_next", "rna_iterator_array_end",
+ "rna_iterator_array_dereference_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "Image");
+ RNA_def_property_ui_text(prop, "Texture Slot Images", "Texture images used for texture painting");
+
+ prop = RNA_def_property(srna, "texture_paint_slots", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop, "rna_Material_texpaint_begin", "rna_iterator_array_next", "rna_iterator_array_end",
+ "rna_iterator_array_get", NULL, NULL, NULL, NULL);
+ RNA_def_property_struct_type(prop, "TexPaintSlot");
+ RNA_def_property_ui_text(prop, "Texture Slots", "Texture slots defining the mapping and influence of textures");
+
+ prop = RNA_def_property(srna, "paint_active_slot", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_range(prop, 0, SHRT_MAX);
+ RNA_def_property_ui_text(prop, "Active Paint Texture Index", "Index of active texture paint slot");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, "rna_Material_active_paint_texture_index_update");
+
+ prop = RNA_def_property(srna, "paint_clone_slot", PROP_INT, PROP_UNSIGNED);
+ RNA_def_property_range(prop, 0, SHRT_MAX);
+ RNA_def_property_ui_text(prop, "Clone Paint Texture Index", "Index of clone texture paint slot");
+ RNA_def_property_update(prop, NC_MATERIAL | ND_SHADING_LINKS, NULL);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 8c0f9980108..b0b99dcd2ca 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -3121,11 +3121,13 @@ static void rna_def_mesh(BlenderRNA *brna)
"rna_Mesh_uv_texture_stencil_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mask UV Map", "UV map to mask the painted area");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "uv_texture_stencil_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_Mesh_uv_texture_stencil_index_get",
"rna_Mesh_uv_texture_stencil_index_set", "rna_Mesh_uv_texture_index_range");
RNA_def_property_ui_text(prop, "Mask UV Map Index", "Mask UV map index");
+ RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
/* Tessellated face colors - used by renderers */
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index 212859cfea4..cc1f57d8a14 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -139,9 +139,11 @@ static void rna_Mesh_calc_smooth_groups(Mesh *mesh, int use_bitflags, int *r_pol
r_group_total, use_bitflags);
}
-static void rna_Mesh_transform(Mesh *mesh, float *mat)
+static void rna_Mesh_transform(Mesh *mesh, float *mat, int shape_keys)
{
- ED_mesh_transform(mesh, (float (*)[4])mat);
+ BKE_mesh_transform(mesh, (float (*)[4])mat, shape_keys);
+
+ DAG_id_tag_update(&mesh->id, 0);
}
#else
@@ -155,6 +157,7 @@ void RNA_api_mesh(StructRNA *srna)
RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix");
parm = RNA_def_float_matrix(func, "matrix", 4, 4, NULL, 0.0f, 0.0f, "", "Matrix", 0.0f, 0.0f);
RNA_def_property_flag(parm, PROP_REQUIRED);
+ RNA_def_boolean(func, "shape_keys", 0, "", "Transform Shape Keys");
func = RNA_def_function(srna, "calc_normals", "BKE_mesh_calc_normals");
RNA_def_function_ui_description(func, "Calculate vertex normals");
@@ -206,11 +209,17 @@ void RNA_api_mesh(StructRNA *srna)
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "validate", "BKE_mesh_validate");
- RNA_def_function_ui_description(func, "validate geometry, return True when the mesh has had "
+ RNA_def_function_ui_description(func, "Validate geometry, return True when the mesh has had "
"invalid geometry corrected/removed");
RNA_def_boolean(func, "verbose", 0, "Verbose", "Output information about the errors found");
parm = RNA_def_boolean(func, "result", 0, "Result", "");
RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "validate_material_indices", "BKE_mesh_validate_material_indices");
+ RNA_def_function_ui_description(func, "Validate material indices of polygons, return True when the mesh has had "
+ "invalid indices corrected (to default 0)");
+ parm = RNA_def_boolean(func, "result", 0, "Result", "");
+ RNA_def_function_return(func, parm);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_meta_api.c b/source/blender/makesrna/intern/rna_meta_api.c
index 7fe59bc5be6..43dca6fe4f1 100644
--- a/source/blender/makesrna/intern/rna_meta_api.c
+++ b/source/blender/makesrna/intern/rna_meta_api.c
@@ -38,14 +38,16 @@
#include "BLI_utildefines.h"
-#include "ED_mball.h"
+#include "BKE_mball.h"
#include "rna_internal.h" /* own include */
#ifdef RNA_RUNTIME
-void rna_Meta_transform(struct MetaBall *mb, float *mat)
+static void rna_Meta_transform(struct MetaBall *mb, float *mat)
{
- ED_mball_transform(mb, (float (*)[4])mat);
+ BKE_mball_transform(mb, (float (*)[4])mat);
+
+ DAG_id_tag_update(&mb->id, 0);
}
#else
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 191d6d230db..4911c106f53 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -1279,6 +1279,11 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Force", "Relative force of the hook");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "cent");
+ RNA_def_property_ui_text(prop, "Hook Center", "");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
@@ -2234,6 +2239,13 @@ static void rna_def_modifier_bevel(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.15f, 1.0f, 0.05, 2);
RNA_def_property_ui_text(prop, "Profile", "The profile shape (0.5 = round)");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "material", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "mat");
+ RNA_def_property_range(prop, -1, SHRT_MAX);
+ RNA_def_property_ui_text(prop, "Material", "Material index of generated faces, -1 for automatic");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
}
static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
@@ -2596,6 +2608,11 @@ static void rna_def_modifier_solidify(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_FLIP);
RNA_def_property_ui_text(prop, "Flip Normals", "Invert the face direction");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_rim_only", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_NOSHELL);
+ RNA_def_property_ui_text(prop, "Only Rim", "Only add the rim to the original data");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_screw(BlenderRNA *brna)
@@ -3676,26 +3693,27 @@ void RNA_def_modifier(BlenderRNA *brna)
/* flags */
prop = RNA_def_property(srna, "show_viewport", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Realtime);
- RNA_def_property_ui_text(prop, "Realtime", "Display modifier in realtime");
+ RNA_def_property_ui_text(prop, "Realtime", "Display modifier in viewport");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_def_property_ui_icon(prop, ICON_RESTRICT_VIEW_OFF, 0);
prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Render);
- RNA_def_property_ui_text(prop, "Render", "Use modifier during rendering");
+ RNA_def_property_ui_text(prop, "Render", "Use modifier during render");
RNA_def_property_ui_icon(prop, ICON_SCENE, 0);
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, NULL);
prop = RNA_def_property(srna, "show_in_editmode", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_Editmode);
- RNA_def_property_ui_text(prop, "Edit Mode", "Use modifier while in the Edit mode");
+ RNA_def_property_ui_text(prop, "Edit Mode", "Display modifier in Edit mode");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_def_property_ui_icon(prop, ICON_EDITMODE_HLT, 0);
prop = RNA_def_property(srna, "show_on_cage", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", eModifierMode_OnCage);
- RNA_def_property_ui_text(prop, "On Cage", "Enable direct editing of modifier control cage");
+ RNA_def_property_ui_text(prop, "On Cage", "Adjust edit cage to modifier result");
+ RNA_def_property_ui_icon(prop, ICON_MESH_DATA, 0);
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "show_expanded", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index c39d3826d8b..e90de3631d6 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -658,30 +658,6 @@ static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *p
{
bNodeTree *ntree = (bNodeTree *)ptr->id.data;
- /* when using border, make it so no old data from outside of
- * border is hanging around
- * ideally shouldn't be in RNA callback, but how to teach
- * compo to only clear frame when border usage is actually
- * toggling
- */
- if (ntree->flag & NTREE_VIEWER_BORDER) {
- Image *ima = BKE_image_verify_viewer(IMA_TYPE_COMPOSITE, "Viewer Node");
- void *lock;
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock);
-
- if (ibuf) {
- if (ibuf->rect)
- memset(ibuf->rect, 0, 4 * ibuf->x * ibuf->y);
-
- if (ibuf->rect_float)
- memset(ibuf->rect_float, 0, 4 * ibuf->x * ibuf->y * sizeof(float));
-
- ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID;
- }
-
- BKE_image_release_ibuf(ima, ibuf, lock);
- }
-
WM_main_add_notifier(NC_NODE | NA_EDITED, NULL);
WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id);
@@ -2946,9 +2922,24 @@ static EnumPropertyItem node_ycc_items[] = {
};
static EnumPropertyItem node_glossy_items[] = {
- {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
- {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
- {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+ {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
+ {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+ {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem node_anisotropic_items[] = {
+ {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
+ {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
+ {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+
+static EnumPropertyItem node_glass_items[] = {
+ {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""},
+ {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""},
+ {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -3181,6 +3172,12 @@ static void def_sh_output(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_sh_output_linestyle(StructRNA *srna)
+{
+ def_sh_output(srna);
+ def_mix_rgb(srna);
+}
+
static void def_sh_material(StructRNA *srna)
{
PropertyRNA *prop;
@@ -3699,6 +3696,28 @@ static void def_glossy(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_glass(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, node_glass_items);
+ RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
+static void def_anisotropic(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "custom1");
+ RNA_def_property_enum_items(prop, node_anisotropic_items);
+ RNA_def_property_ui_text(prop, "Distribution", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_toon(StructRNA *srna)
{
PropertyRNA *prop;
@@ -3749,6 +3768,16 @@ static void def_sh_uvmap(StructRNA *srna)
RNA_def_struct_sdna_from(srna, "bNode", NULL);
}
+static void def_sh_uvalongstroke(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "use_tips", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
+ RNA_def_property_ui_text(prop, "Use Tips", "Lower half of the texture is for tips of the stroke");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
static void def_sh_normal_map(StructRNA *srna)
{
static EnumPropertyItem prop_space_items[] = {
@@ -6174,6 +6203,27 @@ static void def_cmp_planetrackdeform(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
+static void def_cmp_sunbeams(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "NodeSunBeams", "storage");
+
+ prop = RNA_def_property(srna, "source", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "source");
+ RNA_def_property_range(prop, -100.0f, 100.0f);
+ RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3);
+ RNA_def_property_ui_text(prop, "Source", "Source point of rays as a factor of the image width & height");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "ray_length", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_sdna(prop, NULL, "ray_length");
+ RNA_def_property_range(prop, 0.0f, 100.0f);
+ RNA_def_property_ui_range(prop, 0.0f, 1.0f, 10, 3);
+ RNA_def_property_ui_text(prop, "Ray Length", "Length of rays as a factor of the image size");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+}
+
/* -- Texture Nodes --------------------------------------------------------- */
static void def_tex_output(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 38073293df8..690468a5278 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -61,12 +61,12 @@
EnumPropertyItem object_mode_items[] = {
{OB_MODE_OBJECT, "OBJECT", ICON_OBJECT_DATAMODE, "Object Mode", ""},
{OB_MODE_EDIT, "EDIT", ICON_EDITMODE_HLT, "Edit Mode", ""},
+ {OB_MODE_POSE, "POSE", ICON_POSE_HLT, "Pose Mode", ""},
{OB_MODE_SCULPT, "SCULPT", ICON_SCULPTMODE_HLT, "Sculpt Mode", ""},
{OB_MODE_VERTEX_PAINT, "VERTEX_PAINT", ICON_VPAINT_HLT, "Vertex Paint", ""},
{OB_MODE_WEIGHT_PAINT, "WEIGHT_PAINT", ICON_WPAINT_HLT, "Weight Paint", ""},
{OB_MODE_TEXTURE_PAINT, "TEXTURE_PAINT", ICON_TPAINT_HLT, "Texture Paint", ""},
{OB_MODE_PARTICLE_EDIT, "PARTICLE_EDIT", ICON_PARTICLEMODE, "Particle Edit", ""},
- {OB_MODE_POSE, "POSE", ICON_POSE_HLT, "Pose Mode", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -370,8 +370,14 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value)
Object *ob = (Object *)ptr->data;
ID *id = value.data;
- if (id == NULL || ob->mode & OB_MODE_EDIT)
+ if (ob->mode & OB_MODE_EDIT) {
+ return;
+ }
+
+ /* assigning NULL only for empties */
+ if ((id == NULL) && (ob->type != OB_EMPTY)) {
return;
+ }
if (ob->type == OB_EMPTY) {
if (ob->data) {
@@ -379,7 +385,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value)
ob->data = NULL;
}
- if (id && GS(id->name) == ID_IM) {
+ if (!id || GS(id->name) == ID_IM) {
id_us_plus(id);
ob->data = id;
}
@@ -391,11 +397,10 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value)
if (ob->data) {
id_us_min((ID *)ob->data);
}
- if (id) {
- /* no need to type-check here ID. this is done in the _typef() function */
- BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
- id_us_plus(id);
- }
+
+ /* no need to type-check here ID. this is done in the _typef() function */
+ BLI_assert(OB_DATA_SUPPORT_ID(GS(id->name)));
+ id_us_plus(id);
ob->data = id;
test_object_materials(G.main, id);
@@ -710,6 +715,22 @@ static void rna_Object_active_material_set(PointerRNA *ptr, PointerRNA value)
assign_material(ob, value.data, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
}
+static int rna_Object_active_material_editable(PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+ bool is_editable;
+
+ if ((ob->matbits == NULL) || (ob->actcol == 0) || ob->matbits[ob->actcol - 1]) {
+ is_editable = (ob->id.lib == NULL);
+ }
+ else {
+ is_editable = ob->data ? (((ID *)ob->data)->lib == NULL) : false;
+ }
+
+ return is_editable ? PROP_EDITABLE : 0;
+}
+
+
static void rna_Object_active_particle_system_index_range(PointerRNA *ptr, int *min, int *max,
int *UNUSED(softmin), int *UNUSED(softmax))
{
@@ -2252,6 +2273,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_Object_active_material_get",
"rna_Object_active_material_set", NULL, NULL);
RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_editable_func(prop, "rna_Object_active_material_editable");
RNA_def_property_ui_text(prop, "Active Material", "Active material being displayed");
RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_MaterialSlot_update");
@@ -2602,7 +2624,7 @@ static void rna_def_object(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "dupfacesca");
RNA_def_property_range(prop, 0.001f, 10000.0f);
RNA_def_property_ui_text(prop, "Dupli Faces Scale", "Scale the DupliFace objects");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_Object_internal_update");
prop = RNA_def_property(srna, "dupli_group", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "dup_group");
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 0b6d6b36e7c..831e5486236 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -42,6 +42,8 @@
#include "DNA_modifier_types.h"
#include "DNA_object_types.h"
+#include "BKE_depsgraph.h"
+
#include "rna_internal.h" /* own include */
static EnumPropertyItem space_items[] = {
@@ -66,7 +68,6 @@ static EnumPropertyItem space_items[] = {
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
#include "BKE_font.h"
#include "BKE_global.h"
#include "BKE_main.h"
@@ -167,9 +168,9 @@ static void dupli_render_particle_set(Scene *scene, Object *ob, int level, int e
/* When no longer needed, duplilist should be freed with Object.free_duplilist */
static void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene *sce, int settings)
{
- int for_render = settings == eModifierMode_Render;
+ bool for_render = (settings == DAG_EVAL_RENDER);
EvaluationContext eval_ctx = {0};
- eval_ctx.for_render = for_render;
+ eval_ctx.mode = settings;
if (!(ob->transflag & OB_DUPLI)) {
BKE_report(reports, RPT_ERROR, "Object does not have duplis");
@@ -276,7 +277,6 @@ static int dm_tessface_to_poly_index(DerivedMesh *dm, int tessface_index)
return ORIGINDEX_NONE;
}
-/* BMESH_TODO, return polygon index, not tessface */
static void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start[3], float ray_end[3],
float r_location[3], float r_normal[3], int *index)
{
@@ -290,11 +290,8 @@ static void rna_Object_ray_cast(Object *ob, ReportList *reports, float ray_start
/* no need to managing allocation or freeing of the BVH data. this is generated and freed as needed */
bvhtree_from_mesh_faces(&treeData, ob->derivedFinal, 0.0f, 4, 6);
- if (treeData.tree == NULL) {
- BKE_reportf(reports, RPT_ERROR, "Object '%s' could not create internal data for ray casting", ob->id.name + 2);
- return;
- }
- else {
+ /* may fail if the mesh has no faces, in that case the ray-cast misses */
+ if (treeData.tree != NULL) {
BVHTreeRayHit hit;
float ray_nor[3], dist;
sub_v3_v3v3(ray_nor, ray_end, ray_start);
@@ -436,6 +433,13 @@ void RNA_api_object(StructRNA *srna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem dupli_eval_mode_items[] = {
+ {DAG_EVAL_VIEWPORT, "VIEWPORT", 0, "Viewport", "Generate duplis using viewport settings"},
+ {DAG_EVAL_PREVIEW, "PREVIEW", 0, "Preview", "Generate duplis using preview settings"},
+ {DAG_EVAL_RENDER, "RENDER", 0, "Render", "Generate duplis using render settings"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
#ifndef NDEBUG
static EnumPropertyItem mesh_dm_info_items[] = {
{0, "SOURCE", 0, "Source", "Source mesh"},
@@ -487,7 +491,7 @@ void RNA_api_object(StructRNA *srna)
"objects real matrix and layers");
parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene within which to evaluate duplis");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL);
- RNA_def_enum(func, "settings", mesh_type_items, 0, "", "Generate texture coordinates for rendering");
+ RNA_def_enum(func, "settings", dupli_eval_mode_items, 0, "", "Generate texture coordinates for rendering");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
func = RNA_def_function(srna, "dupli_list_clear", "rna_Object_free_duplilist");
diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c
index 0f37575146b..8da869417ff 100644
--- a/source/blender/makesrna/intern/rna_object_force.c
+++ b/source/blender/makesrna/intern/rna_object_force.c
@@ -598,9 +598,20 @@ static char *rna_FieldSettings_path(PointerRNA *ptr)
static void rna_EffectorWeight_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
{
- DAG_id_tag_update((ID *)ptr->id.data, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ ID *id = ptr->id.data;
- WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ if (id && GS(id->name) == ID_SCE) {
+ Scene *scene = (Scene *)id;
+ Base *base;
+
+ for (base = scene->base.first; base; base = base->next) {
+ BKE_ptcache_object_reset(scene, base->object, PTCACHE_RESET_DEPSGRAPH);
+ }
+ }
+ else {
+ DAG_id_tag_update(id, OB_RECALC_DATA | PSYS_RECALC_RESET);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+ }
}
static void rna_EffectorWeight_dependency_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
@@ -733,7 +744,7 @@ static EnumPropertyItem *rna_Effector_shape_itemf(bContext *UNUSED(C), PointerRN
return curve_shape_items;
}
- else if (ELEM3(ob->type, OB_MESH, OB_SURF, OB_FONT)) {
+ else if (ELEM(ob->type, OB_MESH, OB_SURF, OB_FONT)) {
if (ob->pd->forcefield == PFIELD_VORTEX)
return vortex_shape_items;
@@ -946,7 +957,7 @@ static void rna_def_collision(BlenderRNA *brna)
prop = RNA_def_property(srna, "thickness_inner", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "pdef_sbift");
RNA_def_property_range(prop, 0.001f, 1.0f);
- RNA_def_property_ui_text(prop, "Inner Thickness", "Inner face thickness");
+ RNA_def_property_ui_text(prop, "Inner Thickness", "Inner face thickness (only used by softbodies)");
RNA_def_property_update(prop, 0, "rna_CollisionSettings_update");
prop = RNA_def_property(srna, "thickness_outer", PROP_FLOAT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_packedfile.c b/source/blender/makesrna/intern/rna_packedfile.c
index 365ad5fdb9a..34810e8a91b 100644
--- a/source/blender/makesrna/intern/rna_packedfile.c
+++ b/source/blender/makesrna/intern/rna_packedfile.c
@@ -44,6 +44,20 @@ EnumPropertyItem unpack_method_items[] = {
};
#ifdef RNA_RUNTIME
+
+static void rna_PackedImage_data_get(PointerRNA *ptr, char *value)
+{
+ PackedFile *pf = (PackedFile *)ptr->data;
+ memcpy(value, pf->data, (size_t)pf->size);
+ value[pf->size] = '\0';
+}
+
+static int rna_PackedImage_data_len(PointerRNA *ptr)
+{
+ PackedFile *pf = (PackedFile *)ptr->data;
+ return pf->size; /* No need to include trailing NULL char here! */
+}
+
#else
void RNA_def_packedfile(BlenderRNA *brna)
@@ -58,6 +72,10 @@ void RNA_def_packedfile(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Size", "Size of packed file in bytes");
+ prop = RNA_def_property(srna, "data", PROP_STRING, PROP_BYTESTRING);
+ RNA_def_property_string_funcs(prop, "rna_PackedImage_data_get", "rna_PackedImage_data_len", NULL);
+ RNA_def_property_ui_text(prop, "Data", "Raw data (bytes, exact content of the embedded file)");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index f6f133c5114..113311383f4 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -316,9 +316,9 @@ static void rna_Particle_uv_on_emitter(ParticleData *particle, ReportList *repor
static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *object,
int particle_no, int step, float n_co[3])
{
- ParticleSettings *part = 0;
- ParticleData *pars = 0;
- ParticleCacheKey *cache = 0;
+ ParticleSettings *part = NULL;
+ ParticleData *pars = NULL;
+ ParticleCacheKey *cache = NULL;
int totchild = 0;
int path_nbr = 0;
int totpart;
@@ -432,25 +432,24 @@ static EnumPropertyItem *rna_Particle_Material_itemf(bContext *C, PointerRNA *UN
return item;
}
-static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, ReportList *reports,
- ParticleSystemModifierData *modifier, ParticleData *particle,
- int particle_no, int uv_no,
- float r_uv[2])
+/* return < 0 means invalid (no matching tessellated face could be found). */
+static int rna_ParticleSystem_tessfaceidx_on_emitter(ParticleSystem *particlesystem,
+ ParticleSystemModifierData *modifier, ParticleData *particle,
+ int particle_no, float (**r_fuv)[4])
{
- ParticleSettings *part = 0;
+ ParticleSettings *part = NULL;
int totpart;
int totchild = 0;
- int num;
+ int totface;
+ int num = -1;
- if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPUV)) {
- BKE_report(reports, RPT_ERROR, "Mesh has no UV data");
- return;
- }
DM_ensure_tessface(modifier->dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
+ totface = modifier->dm->getNumTessFaces(modifier->dm);
/* 1. check that everything is ok & updated */
- if (particlesystem == NULL)
- return;
+ if (!particlesystem || !totface) {
+ return num;
+ }
part = particlesystem->part;
@@ -468,52 +467,31 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep
totpart = particlesystem->totpart;
if (particle_no >= totpart + totchild)
- return;
+ return num;
-/* 3. start creating renderable things */
- /* setup per particle individual stuff */
+ /* 2. get matching face index. */
if (particle_no < totpart) {
-
- /* get uvco & mcol */
- num = (ELEM(particle->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ?
- particle->num : particle->num_dmcache;
+ num = (ELEM(particle->num_dmcache, DMCACHE_ISCHILD, DMCACHE_NOTFOUND)) ? particle->num : particle->num_dmcache;
if (num == DMCACHE_NOTFOUND)
- if (particle->num < modifier->dm->getNumTessFaces(modifier->dm))
- num = particle->num;
+ num = particle->num;
- if (r_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
- if (num != DMCACHE_NOTFOUND) {
- MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no);
- mtface += num;
-
- psys_interpolate_uvs(mtface, mface->v4, particle->fuv, r_uv);
- }
- else {
- r_uv[0] = 0.0f;
- r_uv[1] = 0.0f;
+ if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ if (num != DMCACHE_NOTFOUND && num < totface) {
+ *r_fuv = &particle->fuv;
+ return num;
}
}
}
else {
ChildParticle *cpa = particlesystem->child + particle_no - totpart;
-
num = cpa->num;
- /* get uvco & mcol */
if (part->childtype == PART_CHILD_FACES) {
- if (r_uv && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) {
- if (cpa->num != DMCACHE_NOTFOUND) {
- MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE);
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no);
- mtface += cpa->num;
-
- psys_interpolate_uvs(mtface, mface->v4, cpa->fuv, r_uv);
- }
- else {
- r_uv[0] = 0.0f;
- r_uv[1] = 0.0f;
+ if (ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ if (num != DMCACHE_NOTFOUND && num < totface) {
+ *r_fuv = &cpa->fuv;
+ return num;
}
}
}
@@ -522,137 +500,78 @@ static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, Rep
num = parent->num_dmcache;
if (num == DMCACHE_NOTFOUND)
- if (parent->num < modifier->dm->getNumTessFaces(modifier->dm))
- num = parent->num;
-
- if (r_uv && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
- if (num != DMCACHE_NOTFOUND) {
- MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
- MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no);
- mtface += num;
-
- psys_interpolate_uvs(mtface, mface->v4, parent->fuv, r_uv);
- }
- else {
- r_uv[0] = 0.0f;
- r_uv[1] = 0.0f;
+ num = parent->num;
+
+ if (ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
+ if (num != DMCACHE_NOTFOUND && num < totface) {
+ *r_fuv = &parent->fuv;
+ return num;
}
}
}
}
+
+ return -1;
}
-static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, ParticleSystemModifierData *modifier,
- ParticleData *particle, int particle_no, int vcol_no,
- float n_mcol[3])
+static void rna_ParticleSystem_uv_on_emitter(ParticleSystem *particlesystem, ReportList *reports,
+ ParticleSystemModifierData *modifier, ParticleData *particle,
+ int particle_no, int uv_no, float r_uv[2])
{
- ParticleSettings *part;
- int totpart;
- int totchild = 0;
- int num;
- MCol mcol = {255, 255, 255, 255};
-
- /* 1. check that everything is ok & updated */
- if (particlesystem == NULL)
+ if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPUV)) {
+ BKE_report(reports, RPT_ERROR, "Mesh has no UV data");
+ zero_v2(r_uv);
return;
-
- part = particlesystem->part;
-
- if (particlesystem->renderdata) {
- totchild = particlesystem->totchild;
- }
- else {
- totchild = (int)((float)particlesystem->totchild * (float)(part->disp) / 100.0f);
}
- /* can happen for disconnected/global hair */
- if (part->type == PART_HAIR && !particlesystem->childcache)
- totchild = 0;
-
- totpart = particlesystem->totpart;
-
- if (particle_no >= totpart + totchild)
- return;
-
- /* 3. start creating renderable things */
- /* setup per particle individual stuff */
- if (particle_no < totpart) {
+ {
+ float (*fuv)[4];
+ /* Note all sanity checks are done in this helper func. */
+ const int num = rna_ParticleSystem_tessfaceidx_on_emitter(particlesystem, modifier, particle,
+ particle_no, &fuv);
- /* get uvco & mcol */
- num = particle->num_dmcache;
+ if (num < 0) {
+ /* No matching face found. */
+ zero_v2(r_uv);
+ }
+ else {
+ MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
+ MTFace *mtface = (MTFace *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MTFACE, uv_no);
- if (num == DMCACHE_NOTFOUND)
- if (particle->num < modifier->dm->getNumTessFaces(modifier->dm))
- num = particle->num;
-
- if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
- if (num != DMCACHE_NOTFOUND) {
- MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
- MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no);
- mc += num * 4;
-
- psys_interpolate_mcol(mc, mface->v4, particle->fuv, &mcol);
- n_mcol[0] = (float)mcol.b / 255.0f;
- n_mcol[1] = (float)mcol.g / 255.0f;
- n_mcol[2] = (float)mcol.r / 255.0f;
- }
- else {
- n_mcol[0] = 0.0f;
- n_mcol[1] = 0.0f;
- n_mcol[2] = 0.0f;
- }
+ psys_interpolate_uvs(&mtface[num], mface->v4, *fuv, r_uv);
}
}
- else {
- ChildParticle *cpa = particlesystem->child + particle_no - totpart;
+}
- num = cpa->num;
+static void rna_ParticleSystem_mcol_on_emitter(ParticleSystem *particlesystem, ReportList *reports,
+ ParticleSystemModifierData *modifier, ParticleData *particle,
+ int particle_no, int vcol_no, float r_mcol[3])
+{
+ if (!CustomData_has_layer(&modifier->dm->loopData, CD_MLOOPCOL)) {
+ BKE_report(reports, RPT_ERROR, "Mesh has no VCol data");
+ zero_v3(r_mcol);
+ return;
+ }
- /* get uvco & mcol */
- if (part->childtype == PART_CHILD_FACES) {
- if (n_mcol && ELEM(PART_FROM_FACE, PART_FROM_FACE, PART_FROM_VOLUME)) {
- if (cpa->num != DMCACHE_NOTFOUND) {
- MFace *mface = modifier->dm->getTessFaceData(modifier->dm, cpa->num, CD_MFACE);
- MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no);
- mc += cpa->num * 4;
-
- psys_interpolate_mcol(mc, mface->v4, cpa->fuv, &mcol);
- n_mcol[0] = (float)mcol.b / 255.0f;
- n_mcol[1] = (float)mcol.g / 255.0f;
- n_mcol[2] = (float)mcol.r / 255.0f;
- }
- else {
- n_mcol[0] = 0.0f;
- n_mcol[1] = 0.0f;
- n_mcol[2] = 0.0f;
- }
- }
+ {
+ float (*fuv)[4];
+ /* Note all sanity checks are done in this helper func. */
+ const int num = rna_ParticleSystem_tessfaceidx_on_emitter(particlesystem, modifier, particle,
+ particle_no, &fuv);
+
+ if (num < 0) {
+ /* No matching face found. */
+ zero_v3(r_mcol);
}
else {
- ParticleData *parent = particlesystem->particles + cpa->parent;
- num = parent->num_dmcache;
-
- if (num == DMCACHE_NOTFOUND)
- if (parent->num < modifier->dm->getNumTessFaces(modifier->dm))
- num = parent->num;
-
- if (n_mcol && ELEM(part->from, PART_FROM_FACE, PART_FROM_VOLUME)) {
- if (num != DMCACHE_NOTFOUND) {
- MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
- MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no);
- mc += num * 4;
-
- psys_interpolate_mcol(mc, mface->v4, parent->fuv, &mcol);
- n_mcol[0] = (float)mcol.b / 255.0f;
- n_mcol[1] = (float)mcol.g / 255.0f;
- n_mcol[2] = (float)mcol.r / 255.0f;
- }
- else {
- n_mcol[0] = 0.0f;
- n_mcol[1] = 0.0f;
- n_mcol[2] = 0.0f;
- }
- }
+ MFace *mface = modifier->dm->getTessFaceData(modifier->dm, num, CD_MFACE);
+ MCol *mc = (MCol *)CustomData_get_layer_n(&modifier->dm->faceData, CD_MCOL, vcol_no);
+ MCol mcol;
+
+ psys_interpolate_mcol(&mc[num * 4], mface->v4, *fuv, &mcol);
+ r_mcol[0] = (float)mcol.b / 255.0f;
+ r_mcol[1] = (float)mcol.g / 255.0f;
+ r_mcol[2] = (float)mcol.r / 255.0f;
}
}
}
@@ -2072,7 +1991,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
rna_def_mtex_common(brna, srna, "rna_ParticleSettings_mtex_begin", "rna_ParticleSettings_active_texture_get",
"rna_ParticleSettings_active_texture_set", NULL, "ParticleSettingsTextureSlot",
- "ParticleSettingsTextureSlots", "rna_Particle_reset");
+ "ParticleSettingsTextureSlots", "rna_Particle_reset", NULL);
/* fluid particle type can't be checked from the type value in rna as it's not shown in the menu */
prop = RNA_def_property(srna, "is_fluid", PROP_BOOLEAN, PROP_NONE);
@@ -2142,7 +2061,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_dynamic_rotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_ROT_DYN);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_ui_text(prop, "Dynamic", "Particle rotations are effected by collisions and effectors");
+ RNA_def_property_ui_text(prop, "Dynamic", "Particle rotations are affected by collisions and effectors");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
prop = RNA_def_property(srna, "use_multiply_size_mass", PROP_BOOLEAN, PROP_NONE);
@@ -2194,7 +2113,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_self_effect", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", PART_SELF_EFFECT);
- RNA_def_property_ui_text(prop, "Self Effect", "Particle effectors effect themselves");
+ RNA_def_property_ui_text(prop, "Self Effect", "Particle effectors affect themselves");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
@@ -2520,7 +2439,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "simplify_refsize", PROP_INT, PROP_PIXEL);
RNA_def_property_int_sdna(prop, NULL, "simplify_refsize");
- RNA_def_property_range(prop, 1, 32768);
+ RNA_def_property_range(prop, 1, SHRT_MAX);
RNA_def_property_ui_text(prop, "Reference Size", "Reference size in pixels, after which simplification begins");
prop = RNA_def_property(srna, "simplify_rate", PROP_FLOAT, PROP_NONE);
@@ -3496,6 +3415,7 @@ static void rna_def_particle_system(BlenderRNA *brna)
/* extract hair mcols */
func = RNA_def_function(srna, "mcol_on_emitter", "rna_ParticleSystem_mcol_on_emitter");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
RNA_def_function_ui_description(func, "Obtain mcol for all particles");
prop = RNA_def_pointer(func, "modifier", "ParticleSystemModifier", "", "Particle modifier");
RNA_def_property_flag(prop, PROP_REQUIRED | PROP_NEVER_NULL);
diff --git a/source/blender/makesrna/intern/rna_pose.c b/source/blender/makesrna/intern/rna_pose.c
index 18e4ac6b004..f9d0e86183e 100644
--- a/source/blender/makesrna/intern/rna_pose.c
+++ b/source/blender/makesrna/intern/rna_pose.c
@@ -140,7 +140,32 @@ static char *rna_PoseBone_path(PointerRNA *ptr)
return BLI_sprintfN("pose.bones[\"%s\"]", name_esc);
}
+/* Bone groups only. */
+
+static bActionGroup *rna_bone_group_new(ID *id, bPose *pose, const char *name)
+{
+ bActionGroup *grp = BKE_pose_add_group(pose, name);
+ WM_main_add_notifier(NC_OBJECT | ND_POSE | NA_ADDED, id);
+ return grp;
+}
+
+static void rna_bone_group_remove(ID *id, bPose *pose, ReportList *reports, PointerRNA *grp_ptr)
+{
+ bActionGroup *grp = grp_ptr->data;
+ const int grp_idx = BLI_findindex(&pose->agroups, grp);
+
+ if (grp_idx == -1) {
+ BKE_reportf(reports, RPT_ERROR, "Bone group '%s' not found in this object", grp->name);
+ return;
+ }
+
+ BKE_pose_remove_group(pose, grp, grp_idx + 1);
+ WM_main_add_notifier(NC_OBJECT | ND_POSE | NA_REMOVED, id);
+}
+
+
/* shared for actions groups and bone groups */
+
void rna_ActionGroup_colorset_set(PointerRNA *ptr, int value)
{
bActionGroup *grp = ptr->data;
@@ -154,6 +179,13 @@ void rna_ActionGroup_colorset_set(PointerRNA *ptr, int value)
}
}
+int rna_ActionGroup_is_custom_colorset_get(PointerRNA *ptr)
+{
+ bActionGroup *grp = ptr->data;
+
+ return (bool)(grp->customCol < 0);
+}
+
static void rna_BoneGroup_name_set(PointerRNA *ptr, const char *value)
{
Object *ob = ptr->id.data;
@@ -650,6 +682,11 @@ void rna_def_actionbone_group_common(StructRNA *srna, int update_flag, const cha
RNA_def_property_ui_text(prop, "Color Set", "Custom color set to use");
RNA_def_property_update(prop, update_flag, update_cb);
+ prop = RNA_def_property(srna, "is_custom_color_set", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop, "rna_ActionGroup_is_custom_colorset_get", NULL);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Custom Color Set", "Color set is user-defined instead of a fixed theme color set");
+
/* TODO: editing the colors for this should result in changes to the color type... */
prop = RNA_def_property(srna, "colors", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
@@ -1241,14 +1278,30 @@ static void rna_def_bone_groups(BlenderRNA *brna, PropertyRNA *cprop)
StructRNA *srna;
PropertyRNA *prop;
-/* FunctionRNA *func; */
-/* PropertyRNA *parm; */
+ FunctionRNA *func;
+ PropertyRNA *parm;
RNA_def_property_srna(cprop, "BoneGroups");
srna = RNA_def_struct(brna, "BoneGroups", NULL);
RNA_def_struct_sdna(srna, "bPose");
RNA_def_struct_ui_text(srna, "Bone Groups", "Collection of bone groups");
+ func = RNA_def_function(srna, "new", "rna_bone_group_new");
+ RNA_def_function_ui_description(func, "Add a new bone group to the object");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID); /* ID needed for refresh */
+ RNA_def_string(func, "name", "Group", MAX_NAME, "", "Name of the new group");
+ /* return type */
+ parm = RNA_def_pointer(func, "group", "BoneGroup", "", "New bone group");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_bone_group_remove");
+ RNA_def_function_ui_description(func, "Remove a bone group from this object");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_SELF_ID); /* ID needed for refresh */
+ /* bone group to remove */
+ parm = RNA_def_pointer(func, "group", "BoneGroup", "", "Removed bone group");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+
prop = RNA_def_property(srna, "active", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "BoneGroup");
RNA_def_property_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 16cc82bbca1..0ee654d4ecc 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -71,6 +71,9 @@ EnumPropertyItem render_pass_type_items[] = {
{SCE_PASS_SUBSURFACE_DIRECT, "SUBSURFACE_DIRECT", 0, "Subsurface Direct", ""},
{SCE_PASS_SUBSURFACE_INDIRECT, "SUBSURFACE_INDIRECT", 0, "Subsurface Indirect", ""},
{SCE_PASS_SUBSURFACE_COLOR, "SUBSURFACE_COLOR", 0, "Subsurface Color", ""},
+#ifdef WITH_CYCLES_DEBUG
+ {SCE_PASS_DEBUG, "DEBUG", 0, "Pass used for render engine debugging", ""},
+#endif
{0, NULL, 0, NULL, NULL}
};
@@ -492,6 +495,13 @@ static void rna_def_render_engine(BlenderRNA *brna)
prop = RNA_def_string(func, "info", NULL, 0, "Info", "");
RNA_def_property_flag(prop, PROP_REQUIRED);
+ func = RNA_def_function(srna, "frame_set", "RE_engine_frame_set");
+ RNA_def_function_ui_description(func, "Evaluate scene at a different frame (for motion blur)");
+ prop = RNA_def_int(func, "frame", 0, INT_MIN, INT_MAX, "Frame", "", INT_MIN, INT_MAX);
+ RNA_def_property_flag(prop, PROP_REQUIRED);
+ prop = RNA_def_float(func, "subframe", 0.0f, 0.0f, 1.0f, "Subframe", "", 0.0f, 1.0f);
+ RNA_def_property_flag(prop, PROP_REQUIRED);
+
func = RNA_def_function(srna, "update_progress", "RE_engine_update_progress");
RNA_def_function_ui_description(func, "Update progress percentage of render");
prop = RNA_def_float(func, "progress", 0, 0.0f, 1.0f, "", "Percentage of render that's done", 0.0f, 1.0f);
@@ -537,6 +547,10 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "camera_override");
RNA_def_property_struct_type(prop, "Object");
+ prop = RNA_def_property(srna, "layer_override", PROP_BOOLEAN, PROP_LAYER_MEMBER);
+ RNA_def_property_boolean_sdna(prop, NULL, "layer_override", 1);
+ RNA_def_property_array(prop, 20);
+
prop = RNA_def_property(srna, "tile_x", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "tile_x");
prop = RNA_def_property(srna, "tile_y", PROP_INT, PROP_UNSIGNED);
@@ -573,6 +587,10 @@ static void rna_def_render_engine(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_PREVIEW);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+ prop = RNA_def_property(srna, "bl_use_texture_preview", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "type->flag", RE_USE_TEXTURE_PREVIEW);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
prop = RNA_def_property(srna, "bl_use_postprocess", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "type->flag", RE_USE_POSTPROCESS);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
@@ -672,6 +690,11 @@ 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", "");
@@ -701,6 +724,11 @@ 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, "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);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
RNA_define_verify_sdna(1);
}
diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c
index 78cd8d4bad4..86a8b162614 100644
--- a/source/blender/makesrna/intern/rna_rigidbody.c
+++ b/source/blender/makesrna/intern/rna_rigidbody.c
@@ -94,6 +94,8 @@ static EnumPropertyItem rigidbody_mesh_source_items[] = {
#include "BKE_depsgraph.h"
#include "BKE_rigidbody.h"
+#include "WM_api.h"
+
#define RB_FLAG_SET(dest, value, flag) { \
if (value) \
dest |= flag; \
@@ -151,6 +153,15 @@ static void rna_RigidBodyOb_reset(Main *UNUSED(bmain), Scene *scene, PointerRNA
BKE_rigidbody_cache_reset(rbw);
}
+static void rna_RigidBodyOb_shape_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ Object *ob = ptr->id.data;
+
+ rna_RigidBodyOb_reset(bmain, scene, ptr);
+
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, ob);
+}
+
static void rna_RigidBodyOb_shape_reset(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
@@ -797,7 +808,7 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyOb_shape_set", NULL);
RNA_def_property_ui_text(prop, "Collision Shape", "Collision Shape of object in Rigid Body Simulations");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
- RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
+ RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_shape_update");
prop = RNA_def_property(srna, "kinematic", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_KINEMATIC);
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index bf2858c44e6..70ce87ab68b 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -334,6 +334,7 @@ EnumPropertyItem bake_save_mode_items[] = {
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_mesh_types.h"
+#include "DNA_text_types.h"
#include "RNA_access.h"
@@ -356,6 +357,7 @@ EnumPropertyItem bake_save_mode_items[] = {
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_animsys.h"
+#include "BKE_freestyle.h"
#include "WM_api.h"
@@ -368,6 +370,10 @@ EnumPropertyItem bake_save_mode_items[] = {
#include "RE_engine.h"
+#ifdef WITH_FREESTYLE
+#include "FRS_freestyle.h"
+#endif
+
static void rna_SpaceImageEditor_uv_sculpt_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
{
ED_space_image_uv_sculpt_update(bmain->wm.first, scene->toolsettings);
@@ -878,7 +884,7 @@ static EnumPropertyItem *rna_ImageFormatSettings_color_depth_itemf(bContext *UNU
}
else {
const int depth_ok = BKE_imtype_valid_depths(imf->imtype);
- const int is_float = ELEM3(imf->imtype, R_IMF_IMTYPE_RADHDR, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER);
+ const int is_float = ELEM(imf->imtype, R_IMF_IMTYPE_RADHDR, R_IMF_IMTYPE_OPENEXR, R_IMF_IMTYPE_MULTILAYER);
EnumPropertyItem *item_8bit = &image_color_depth_items[0];
EnumPropertyItem *item_10bit = &image_color_depth_items[1];
@@ -1057,7 +1063,8 @@ static int rna_RenderSettings_active_layer_index_get(PointerRNA *ptr)
static void rna_RenderSettings_active_layer_index_set(PointerRNA *ptr, int value)
{
RenderData *rd = (RenderData *)ptr->data;
- rd->actlay = value;
+ int num_layers = BLI_countlist(&rd->layers);
+ rd->actlay = min_ff(value, num_layers - 1);
}
static void rna_RenderSettings_active_layer_index_range(PointerRNA *ptr, int *min, int *max,
@@ -1169,6 +1176,20 @@ static void rna_Scene_glsl_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi
DAG_id_tag_update(&scene->id, 0);
}
+static void rna_Scene_freestyle_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Scene *scene = (Scene *)ptr->id.data;
+
+ DAG_id_tag_update(&scene->id, 0);
+}
+
+static void rna_Scene_use_view_map_cache_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+#ifdef WITH_FREESTYLE
+ FRS_free_view_map_cache();
+#endif
+}
+
static void rna_SceneRenderLayer_name_set(PointerRNA *ptr, const char *value)
{
Scene *scene = (Scene *)ptr->id.data;
@@ -1306,7 +1327,7 @@ static void object_simplify_update(Object *ob)
ob->id.flag &= ~LIB_DOIT;
for (md = ob->modifiers.first; md; md = md->next) {
- if (ELEM3(md->type, eModifierType_Subsurf, eModifierType_Multires, eModifierType_ParticleSystem)) {
+ if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires, eModifierType_ParticleSystem)) {
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
}
@@ -1583,7 +1604,7 @@ static void rna_FreestyleLineSet_linestyle_set(PointerRNA *ptr, PointerRNA value
lineset->linestyle->id.us++;
}
-static FreestyleLineSet *FreestyleSettings_lineset_add(ID *id, struct FreestyleSettings *config, const char *name)
+static FreestyleLineSet *rna_FreestyleSettings_lineset_add(ID *id, FreestyleSettings *config, const char *name)
{
Scene *scene = (Scene *)id;
FreestyleLineSet *lineset = BKE_freestyle_lineset_add((FreestyleConfig *)config, name);
@@ -1594,8 +1615,8 @@ static FreestyleLineSet *FreestyleSettings_lineset_add(ID *id, struct FreestyleS
return lineset;
}
-static void FreestyleSettings_lineset_remove(ID *id, struct 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;
@@ -1639,6 +1660,37 @@ static void rna_FreestyleSettings_active_lineset_index_set(PointerRNA *ptr, int
BKE_freestyle_lineset_set_active_index(config, value);
}
+static FreestyleModuleConfig *rna_FreestyleSettings_module_add(ID *id, FreestyleSettings *config)
+{
+ Scene *scene = (Scene *)id;
+ FreestyleModuleConfig *module = BKE_freestyle_module_add((FreestyleConfig *)config);
+
+ DAG_id_tag_update(&scene->id, 0);
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ return module;
+}
+
+static void rna_FreestyleSettings_module_remove(ID *id, FreestyleSettings *config, ReportList *reports,
+ PointerRNA *module_ptr)
+{
+ Scene *scene = (Scene *)id;
+ FreestyleModuleConfig *module = module_ptr->data;
+
+ if (!BKE_freestyle_module_delete((FreestyleConfig *)config, module)) {
+ 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");
+ return;
+ }
+
+ RNA_POINTER_INVALIDATE(module_ptr);
+
+ DAG_id_tag_update(&scene->id, 0);
+ WM_main_add_notifier(NC_SCENE | ND_RENDER_OPTIONS, NULL);
+}
+
#else
static void rna_def_transform_orientation(BlenderRNA *brna)
@@ -2079,6 +2131,11 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Unified Weight",
"Instead of per-brush weight, the weight is shared across brushes");
+ prop = RNA_def_property(srna, "use_unified_color", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", UNIFIED_PAINT_COLOR);
+ RNA_def_property_ui_text(prop, "Use Unified Color",
+ "Instead of per-brush color, the color is shared across brushes");
+
/* unified paint settings that override the equivalent settings
* from the active brush */
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
@@ -2111,6 +2168,18 @@ static void rna_def_unified_paint_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Weight", "Weight to assign in vertex groups");
RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update");
+ 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, 0, "rna_UnifiedPaintSettings_update");
+
+ prop = RNA_def_property(srna, "secondary_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "secondary_rgb");
+ RNA_def_property_ui_text(prop, "Secondary Color", "");
+ RNA_def_property_update(prop, 0, "rna_UnifiedPaintSettings_update");
+
prop = RNA_def_property(srna, "use_pressure_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", UNIFIED_PAINT_BRUSH_SIZE_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
@@ -2147,7 +2216,7 @@ static void rna_def_statvis(BlenderRNA *brna)
prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, stat_type);
- RNA_def_property_ui_text(prop, "Type", "XXX");
+ RNA_def_property_ui_text(prop, "Type", "Type of data to visualize/check");
RNA_def_property_update(prop, 0, "rna_EditMesh_update");
@@ -2410,7 +2479,7 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_FRS);
RNA_def_property_ui_text(prop, "Freestyle", "Render stylized strokes in this Layer");
- if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ if (scene) RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
/* passes */
@@ -2651,6 +2720,31 @@ void rna_def_render_layer_common(StructRNA *srna, int scene)
else RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
+static void rna_def_freestyle_modules(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "FreestyleModules");
+ srna = RNA_def_struct(brna, "FreestyleModules", NULL);
+ RNA_def_struct_sdna(srna, "FreestyleSettings");
+ RNA_def_struct_ui_text(srna, "Style Modules", "A list of style modules (to be applied from top to bottom)");
+
+ func = RNA_def_function(srna, "new", "rna_FreestyleSettings_module_add");
+ RNA_def_function_ui_description(func, "Add a style module to scene render layer Freestyle settings");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID);
+ parm = RNA_def_pointer(func, "module", "FreestyleModuleSettings", "", "Newly created style module");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_FreestyleSettings_module_remove");
+ RNA_def_function_ui_description(func, "Remove a style module from scene render layer Freestyle settings");
+ RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "module", "FreestyleModuleSettings", "", "Style module to remove");
+ RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR);
+ RNA_def_property_clear_flag(parm, PROP_THICK_WRAP);
+}
+
static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
{
StructRNA *srna;
@@ -2667,16 +2761,16 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_struct_type(prop, "FreestyleLineSet");
RNA_def_property_pointer_funcs(prop, "rna_FreestyleSettings_active_lineset_get", NULL, NULL, NULL);
RNA_def_property_ui_text(prop, "Active Line Set", "Active line set being displayed");
- RNA_def_property_update(prop, NC_SCENE, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "active_index", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_funcs(prop, "rna_FreestyleSettings_active_lineset_index_get",
"rna_FreestyleSettings_active_lineset_index_set",
"rna_FreestyleSettings_active_lineset_index_range");
RNA_def_property_ui_text(prop, "Active Line Set Index", "Index of active line set slot");
- RNA_def_property_update(prop, NC_SCENE, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
- func = RNA_def_function(srna, "new", "FreestyleSettings_lineset_add");
+ 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);
parm = RNA_def_string(func, "name", "LineSet", 0, "", "New name for the line set (not unique)");
@@ -2684,7 +2778,7 @@ static void rna_def_freestyle_linesets(BlenderRNA *brna, PropertyRNA *cprop)
parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Newly created line set");
RNA_def_function_return(func, parm);
- func = RNA_def_function(srna, "remove", "FreestyleSettings_lineset_remove");
+ func = RNA_def_function(srna, "remove", "rna_FreestyleSettings_lineset_remove");
RNA_def_function_ui_description(func, "Remove a line set from scene render layer Freestyle settings");
RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "lineset", "FreestyleLineSet", "", "Line set to remove");
@@ -2762,7 +2856,7 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
RNA_def_property_pointer_funcs(prop, "rna_FreestyleLineSet_linestyle_get",
"rna_FreestyleLineSet_linestyle_set", NULL, NULL);
RNA_def_property_ui_text(prop, "Line Style", "Line style settings");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
@@ -2773,191 +2867,191 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_render", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_LINESET_ENABLED);
RNA_def_property_ui_text(prop, "Render", "Enable or disable this line set during stroke rendering");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_by_visibility", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_VISIBILITY);
RNA_def_property_ui_text(prop, "Selection by Visibility", "Select feature edges based on visibility");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_by_edge_types", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_EDGE_TYPES);
RNA_def_property_ui_text(prop, "Selection by Edge Types", "Select feature edges based on edge types");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_by_group", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_GROUP);
RNA_def_property_ui_text(prop, "Selection by Group", "Select feature edges based on a group of objects");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_by_image_border", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_IMAGE_BORDER);
RNA_def_property_ui_text(prop, "Selection by Image Border",
"Select feature edges by image border (less memory consumption)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_by_face_marks", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "selection", FREESTYLE_SEL_FACE_MARK);
RNA_def_property_ui_text(prop, "Selection by Face Marks", "Select feature edges by face marks");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "edge_type_negation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, edge_type_negation_items);
RNA_def_property_ui_text(prop, "Edge Type Negation",
"Specify either inclusion or exclusion of feature edges selected by edge types");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "edge_type_combination", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, edge_type_combination_items);
RNA_def_property_ui_text(prop, "Edge Type Combination",
"Specify a logical combination of selection conditions on feature edge types");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "group", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "group");
RNA_def_property_struct_type(prop, "Group");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Group", "A group of objects based on which feature edges are selected");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "group_negation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, group_negation_items);
RNA_def_property_ui_text(prop, "Group Negation",
"Specify either inclusion or exclusion of feature edges belonging to a group of objects");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "face_mark_negation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flags");
RNA_def_property_enum_items(prop, face_mark_negation_items);
RNA_def_property_ui_text(prop, "Face Mark Negation",
"Specify either inclusion or exclusion of feature edges selected by face marks");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
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_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ 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_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ 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);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_BORDER);
RNA_def_property_ui_text(prop, "Border", "Select border edges (open mesh edges)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
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_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ 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_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ 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);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_SUGGESTIVE_CONTOUR);
RNA_def_property_ui_text(prop, "Suggestive Contour", "Select suggestive contours (almost silhouette/contour edges)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_material_boundary", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_MATERIAL_BOUNDARY);
RNA_def_property_ui_text(prop, "Material Boundary", "Select edges at material boundaries");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "select_contour", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_CONTOUR);
RNA_def_property_ui_text(prop, "Contour", "Select contours (outer silhouettes of each object)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
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_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ 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);
RNA_def_property_boolean_sdna(prop, NULL, "edge_types", FREESTYLE_FE_EDGE_MARK);
RNA_def_property_ui_text(prop, "Edge Mark", "Select edge marks (edges annotated by Freestyle edge marks)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "exclude_silhouette", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_SILHOUETTE);
RNA_def_property_ui_text(prop, "Silhouette", "Exclude silhouette edges");
RNA_def_property_ui_icon(prop, ICON_X, 0);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "exclude_border", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_BORDER);
RNA_def_property_ui_text(prop, "Border", "Exclude border edges");
RNA_def_property_ui_icon(prop, ICON_X, 0);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "exclude_crease", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_CREASE);
RNA_def_property_ui_text(prop, "Crease", "Exclude crease edges");
RNA_def_property_ui_icon(prop, ICON_X, 0);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "exclude_ridge_valley", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_RIDGE_VALLEY);
RNA_def_property_ui_text(prop, "Ridge & Valley", "Exclude ridges and valleys");
RNA_def_property_ui_icon(prop, ICON_X, 0);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "exclude_suggestive_contour", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_SUGGESTIVE_CONTOUR);
RNA_def_property_ui_text(prop, "Suggestive Contour", "Exclude suggestive contours");
RNA_def_property_ui_icon(prop, ICON_X, 0);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "exclude_material_boundary", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_MATERIAL_BOUNDARY);
RNA_def_property_ui_text(prop, "Material Boundary", "Exclude edges at material boundaries");
RNA_def_property_ui_icon(prop, ICON_X, 0);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "exclude_contour", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_CONTOUR);
RNA_def_property_ui_text(prop, "Contour", "Exclude contours");
RNA_def_property_ui_icon(prop, ICON_X, 0);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "exclude_external_contour", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_EXTERNAL_CONTOUR);
RNA_def_property_ui_text(prop, "External Contour", "Exclude external contours");
RNA_def_property_ui_icon(prop, ICON_X, 0);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "exclude_edge_mark", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "exclude_edge_types", FREESTYLE_FE_EDGE_MARK);
RNA_def_property_ui_text(prop, "Edge Mark", "Exclude edge marks");
RNA_def_property_ui_icon(prop, ICON_X, 0);
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "visibility", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "qi");
RNA_def_property_enum_items(prop, visibility_items);
RNA_def_property_ui_text(prop, "Visibility", "Determine how to use visibility for feature edge selection");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "qi_start", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "qi_start");
RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_ui_text(prop, "Start", "First QI value of the QI range");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "qi_end", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "qi_end");
RNA_def_property_range(prop, 0, INT_MAX);
RNA_def_property_ui_text(prop, "End", "Last QI value of the QI range");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
/* FreestyleModuleSettings */
@@ -2969,12 +3063,12 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Text");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Style Module", "Python script to define a style module");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "is_displayed", 1);
RNA_def_property_ui_text(prop, "Use", "Enable or disable this style module during stroke rendering");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
/* FreestyleSettings */
@@ -2986,62 +3080,68 @@ static void rna_def_freestyle_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "modules", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "modules", NULL);
RNA_def_property_struct_type(prop, "FreestyleModuleSettings");
- RNA_def_property_ui_text(prop, "Style modules", "A list of style modules (to be applied from top to bottom)");
+ RNA_def_property_ui_text(prop, "Style Modules", "A list of style modules (to be applied from top to bottom)");
+ rna_def_freestyle_modules(brna, prop);
prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "mode");
RNA_def_property_enum_items(prop, freestyle_ui_mode_items);
RNA_def_property_ui_text(prop, "Control Mode", "Select the Freestyle control mode");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "use_culling", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_CULLING);
RNA_def_property_ui_text(prop, "Culling", "If enabled, out-of-view edges are ignored");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "use_suggestive_contours", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_SUGGESTIVE_CONTOURS_FLAG);
RNA_def_property_ui_text(prop, "Suggestive Contours", "Enable suggestive contours");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "use_ridges_and_valleys", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_RIDGES_AND_VALLEYS_FLAG);
RNA_def_property_ui_text(prop, "Ridges and Valleys", "Enable ridges and valleys");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "use_material_boundaries", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_MATERIAL_BOUNDARIES_FLAG);
RNA_def_property_ui_text(prop, "Material Boundaries", "Enable material boundaries");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "use_smoothness", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_FACE_SMOOTHNESS_FLAG);
RNA_def_property_ui_text(prop, "Face Smoothness", "Take face smoothness into account in view map calculation");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "use_advanced_options", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", FREESTYLE_ADVANCED_OPTIONS_FLAG);
RNA_def_property_ui_text(prop, "Advanced Options",
"Enable advanced edge detection options (sphere radius and Kr derivative epsilon)");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
+
+ 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_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);
RNA_def_property_float_sdna(prop, NULL, "sphere_radius");
RNA_def_property_range(prop, 0.0, 1000.0);
RNA_def_property_ui_text(prop, "Sphere Radius", "Sphere radius for computing curvatures");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "kr_derivative_epsilon", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "dkr_epsilon");
RNA_def_property_range(prop, -1000.0, 1000.0);
RNA_def_property_ui_text(prop, "Kr Derivative Epsilon", "Kr derivative epsilon for computing suggestive contours");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "crease_angle", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "crease_angle");
RNA_def_property_range(prop, 0.0, DEG2RAD(180.0));
RNA_def_property_ui_text(prop, "Crease Angle", "Angular threshold for detecting crease edges");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "linesets", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "linesets", NULL);
@@ -3151,8 +3251,10 @@ static void rna_def_bake_data(BlenderRNA *brna)
RNA_def_struct_nested(brna, srna, "RenderSettings");
RNA_def_struct_ui_text(srna, "Bake Data", "Bake data for a Scene datablock");
- prop = RNA_def_property(srna, "cage", PROP_STRING, PROP_NONE);
- RNA_def_property_ui_text(prop, "Cage", "Object to use as cage");
+ prop = RNA_def_property(srna, "cage_object", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "cage");
+ RNA_def_property_ui_text(prop, "Cage Object", "Object to use as cage "
+ "instead of calculating the cage from the active object with cage extrusion");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "filepath", PROP_STRING, PROP_FILEPATH);
@@ -3176,7 +3278,7 @@ static void rna_def_bake_data(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
prop = RNA_def_property(srna, "cage_extrusion", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0.0, MAXFLOAT);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1, 3);
RNA_def_property_ui_text(prop, "Cage Extrusion",
"Distance to use for the inward ray cast when using selected to active");
@@ -3242,6 +3344,12 @@ static void rna_def_bake_data(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Automatic Name",
"Automatically name the output file with the pass type (external only)");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
+ prop = RNA_def_property(srna, "use_cage", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", R_BAKE_CAGE);
+ RNA_def_property_ui_text(prop, "Cage",
+ "Cast rays to active object from a cage");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
}
static void rna_def_scene_game_data(BlenderRNA *brna)
@@ -4361,7 +4469,15 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_range(prop, 8, 65536);
RNA_def_property_ui_text(prop, "Tile Y", "Vertical tile size to use while rendering");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
-
+
+ prop = RNA_def_property(srna, "preview_start_resolution", PROP_INT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
+ RNA_def_property_range(prop, 8, 16384);
+ RNA_def_property_int_default(prop, 64);
+ RNA_def_property_ui_text(prop, "Start Resolution", "Resolution to start rendering preview at, "
+ "progressively increasing it to the full viewport size");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
prop = RNA_def_property(srna, "pixel_aspect_x", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "xasp");
RNA_def_property_flag(prop, PROP_PROPORTIONAL);
@@ -4447,7 +4563,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "alphamode");
RNA_def_property_enum_items(prop, alpha_mode_items);
RNA_def_property_ui_text(prop, "Alpha Mode", "Representation of alpha information in the RGBA pixels");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "octree_resolution", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "ocres");
@@ -4509,50 +4625,50 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_shadows", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SHADOW);
RNA_def_property_ui_text(prop, "Shadows", "Calculate shadows while rendering");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_envmaps", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_ENVMAP);
RNA_def_property_ui_text(prop, "Environment Maps", "Calculate environment maps while rendering");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_sss", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_SSS);
RNA_def_property_ui_text(prop, "Subsurface Scattering", "Calculate sub-surface scattering in materials rendering");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_raytrace", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_RAYTRACE);
RNA_def_property_ui_text(prop, "Raytracing",
"Pre-calculate the raytrace accelerator and render raytracing effects");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_textures", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "scemode", R_NO_TEX);
RNA_def_property_ui_text(prop, "Textures", "Use textures to affect material properties");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_edge_enhance", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_EDGE);
RNA_def_property_ui_text(prop, "Edge", "Create a toon outline around the edges of geometry");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "edge_threshold", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "edgeint");
RNA_def_property_range(prop, 0, 255);
RNA_def_property_ui_text(prop, "Edge Threshold", "Threshold for drawing outlines on geometry edges");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "edge_color", PROP_FLOAT, PROP_COLOR);
RNA_def_property_float_sdna(prop, NULL, "edgeR");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Edge Color", "Edge color");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_glsl_update");
prop = RNA_def_property(srna, "use_freestyle", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "mode", R_EDGE_FRS);
RNA_def_property_ui_text(prop, "Edge", "Draw stylized strokes using Freestyle");
- RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
/* threads */
prop = RNA_def_property(srna, "threads", PROP_INT, PROP_NONE);
@@ -4736,6 +4852,14 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
"and length of frame numbers");
RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+ /* Render result EXR cache. */
+ prop = RNA_def_property(srna, "use_render_cache", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_EXR_CACHE_FILE);
+ RNA_def_property_ui_text(prop, "Cache Result",
+ "Save render cache to EXR files (useful for heavy compositing, "
+ "Note: affects indirectly rendered scenes)");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL);
+
/* Bake */
prop = RNA_def_property(srna, "bake_type", PROP_ENUM, PROP_NONE);
@@ -5038,11 +5162,13 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "line_thickness_mode");
RNA_def_property_enum_items(prop, freestyle_thickness_items);
RNA_def_property_ui_text(prop, "Line Thickness Mode", "Line thickness mode for Freestyle line drawing");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
prop = RNA_def_property(srna, "line_thickness", PROP_FLOAT, PROP_PIXEL);
RNA_def_property_float_sdna(prop, NULL, "unit_line_thickness");
RNA_def_property_range(prop, 0.f, 10000.f);
RNA_def_property_ui_text(prop, "Line Thickness", "Line thickness in pixels");
+ RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, "rna_Scene_freestyle_update");
/* Bake Settings */
prop = RNA_def_property(srna, "bake", PROP_POINTER, PROP_NONE);
@@ -5528,7 +5654,7 @@ void RNA_def_scene(BlenderRNA *brna)
prop = RNA_def_property(srna, "gravity", PROP_FLOAT, PROP_ACCELERATION);
RNA_def_property_float_sdna(prop, NULL, "physics_settings.gravity");
RNA_def_property_array(prop, 3);
- RNA_def_property_range(prop, -200.0f, 200.0f);
+ RNA_def_property_ui_range(prop, -200.0f, 200.0f, 1, 2);
RNA_def_property_ui_text(prop, "Gravity", "Constant acceleration in a given direction");
RNA_def_property_update(prop, 0, "rna_Physics_update");
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index e0431fcff16..86a28fb80bf 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -116,7 +116,7 @@ static int rna_Screen_is_animation_playing_get(PointerRNA *UNUSED(ptr))
static int rna_Screen_fullscreen_get(PointerRNA *ptr)
{
bScreen *sc = (bScreen *)ptr->data;
- return (sc->full != 0);
+ return (sc->state == SCREENMAXIMIZED);
}
/* UI compatible list: should not be needed, but for now we need to keep EMPTY
@@ -128,6 +128,13 @@ static EnumPropertyItem *rna_Area_type_itemf(bContext *UNUSED(C), PointerRNA *UN
return space_type_items + 1;
}
+static int rna_Area_type_get(PointerRNA *ptr)
+{
+ ScrArea *sa = (ScrArea *)ptr->data;
+ /* read from this instead of 'spacetype' for correct reporting: T41435 */
+ return sa->butspacetype;
+}
+
static void rna_Area_type_set(PointerRNA *ptr, int value)
{
ScrArea *sa = (ScrArea *)ptr->data;
@@ -232,7 +239,7 @@ static void rna_def_area(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "spacetype");
RNA_def_property_enum_items(prop, space_type_items);
RNA_def_property_enum_default(prop, SPACE_VIEW3D);
- RNA_def_property_enum_funcs(prop, NULL, "rna_Area_type_set", "rna_Area_type_itemf");
+ RNA_def_property_enum_funcs(prop, "rna_Area_type_get", "rna_Area_type_set", "rna_Area_type_itemf");
RNA_def_property_ui_text(prop, "Editor Type", "Current editor type for this area");
RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -391,7 +398,7 @@ static void rna_def_screen(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_fullscreen", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Screen_fullscreen_get", NULL);
- RNA_def_property_ui_text(prop, "Fullscreen", "An area is maximized, filling this screen");
+ RNA_def_property_ui_text(prop, "Maximize", "An area is maximized, filling this screen");
/* Define Anim Playback Areas */
prop = RNA_def_property(srna, "use_play_top_left_3d_editor", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 54af55260e5..09e42e48e93 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -34,8 +34,13 @@
#include "DNA_ID.h"
#include "DNA_scene_types.h"
#include "DNA_brush_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_space_types.h"
#include "BKE_paint.h"
+#include "BKE_material.h"
+
+#include "ED_image.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -71,11 +76,14 @@ EnumPropertyItem symmetrize_direction_items[] = {
#include "MEM_guardedalloc.h"
#include "BKE_context.h"
+#include "BKE_DerivedMesh.h"
#include "BKE_pointcache.h"
#include "BKE_particle.h"
#include "BKE_depsgraph.h"
#include "BKE_pbvh.h"
+#include "GPU_buffers.h"
+
#include "ED_particle.h"
static EnumPropertyItem particle_edit_disconnected_hair_brush_items[] = {
@@ -226,8 +234,8 @@ static void rna_Sculpt_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNU
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
if (ob->sculpt) {
- ob->sculpt->bm_smooth_shading = (scene->toolsettings->sculpt->flags &
- SCULPT_DYNTOPO_SMOOTH_SHADING);
+ ob->sculpt->bm_smooth_shading = ((scene->toolsettings->sculpt->flags &
+ SCULPT_DYNTOPO_SMOOTH_SHADING) != 0);
}
}
}
@@ -238,7 +246,7 @@ static void rna_Sculpt_ShowDiffuseColor_update(Main *UNUSED(bmain), Scene *scene
if (ob && ob->sculpt) {
Sculpt *sd = scene->toolsettings->sculpt;
- ob->sculpt->show_diffuse_color = sd->flags & SCULPT_SHOW_DIFFUSE;
+ ob->sculpt->show_diffuse_color = ((sd->flags & SCULPT_SHOW_DIFFUSE) != 0);
if (ob->sculpt->pbvh)
pbvh_show_diffuse_color_set(ob->sculpt->pbvh, ob->sculpt->show_diffuse_color);
@@ -285,8 +293,119 @@ static void rna_Paint_brush_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
BKE_paint_invalidate_overlay_all();
WM_main_add_notifier(NC_BRUSH | NA_EDITED, br);
}
+
+static void rna_ImaPaint_viewport_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ /* not the best solution maybe, but will refresh the 3D viewport */
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+}
+
+static void rna_ImaPaint_mode_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ Object *ob = OBACT;
+
+ /* of course we need to invalidate here */
+ BKE_texpaint_slots_refresh_object(scene, ob);
+
+ /* we assume that changing the current mode will invalidate the uv layers so we need to refresh display */
+ GPU_drawobject_free(ob->derivedFinal);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+}
+
+static void rna_ImaPaint_stencil_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ Object *ob = OBACT;
+ GPU_drawobject_free(ob->derivedFinal);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+}
+
+static void rna_ImaPaint_canvas_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr))
+{
+ Object *ob = OBACT;
+ bScreen *sc;
+ Image *ima = scene->toolsettings->imapaint.canvas;
+
+ 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) {
+ if (sl->spacetype == SPACE_IMAGE) {
+ SpaceImage *sima = (SpaceImage *)sl;
+
+ if (!sima->pin)
+ ED_space_image_set(sima, scene, scene->obedit, ima);
+ }
+ }
+ }
+ }
+
+ GPU_drawobject_free(ob->derivedFinal);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL);
+}
+
+static int rna_ImaPaint_detect_data(ImagePaintSettings *imapaint)
+{
+ return imapaint->missing_data == 0;
+}
#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;
+
+ srna = RNA_def_struct(brna, "PaintCurve", "ID");
+ RNA_def_struct_ui_text(srna, "Paint Curve", "");
+ RNA_def_struct_ui_icon(srna, ICON_CURVE_BEZCURVE);
+}
+
+
static void rna_def_paint(BlenderRNA *brna)
{
StructRNA *srna;
@@ -302,6 +421,11 @@ static void rna_def_paint(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Brush", "Active Brush");
RNA_def_property_update(prop, 0, "rna_Paint_brush_update");
+ prop = RNA_def_property(srna, "palette", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "Palette", "Active Palette");
+
prop = RNA_def_property(srna, "show_brush", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", PAINT_SHOW_BRUSH);
RNA_def_property_ui_text(prop, "Show Brush", "");
@@ -507,11 +631,27 @@ static void rna_def_image_paint(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
+ FunctionRNA *func;
+
+ static EnumPropertyItem paint_type_items[] = {
+ {IMAGEPAINT_MODE_MATERIAL, "MATERIAL", 0,
+ "Material", "Detect image slots from the material"},
+ {IMAGEPAINT_MODE_IMAGE, "IMAGE", 0,
+ "Image", "Set image for texture painting directly"},
+ {0, NULL, 0, NULL, NULL}
+ };
srna = RNA_def_struct(brna, "ImagePaint", "Paint");
RNA_def_struct_sdna(srna, "ImagePaintSettings");
RNA_def_struct_path_func(srna, "rna_ImagePaintSettings_path");
RNA_def_struct_ui_text(srna, "Image Paint", "Properties of image and texture painting mode");
+
+ /* functions */
+ func = RNA_def_function(srna, "detect_data", "rna_ImaPaint_detect_data");
+ RNA_def_function_ui_description(func, "Check if required texpaint data exist");
+
+ /* return type */
+ RNA_def_function_return(func, RNA_def_boolean(func, "ok", 1, "", ""));
/* booleans */
prop = RNA_def_property(srna, "use_occlude", PROP_BOOLEAN, PROP_NONE);
@@ -532,13 +672,36 @@ static void rna_def_image_paint(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_stencil_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_STENCIL);
RNA_def_property_ui_text(prop, "Stencil Layer", "Set the mask layer from the UV map buttons");
- RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update");
prop = RNA_def_property(srna, "invert_stencil", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_STENCIL_INV);
RNA_def_property_ui_text(prop, "Invert", "Invert the stencil layer");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update");
+
+ prop = RNA_def_property(srna, "stencil_image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "stencil");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Stencil Image", "Image used as stencil");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_stencil_update");
+
+ prop = RNA_def_property(srna, "canvas", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Canvas", "Image used as canvas");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_canvas_update");
+
+ prop = RNA_def_property(srna, "clone_image", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "clone");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Clone Image", "Image used as clone source");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
+ prop = RNA_def_property(srna, "stencil_color", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_float_sdna(prop, NULL, "stencil_col");
+ RNA_def_property_ui_text(prop, "Stencil Color", "Stencil color in the viewport");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_viewport_update");
+
prop = RNA_def_property(srna, "use_clone_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_CLONE);
RNA_def_property_ui_text(prop, "Clone Map",
@@ -558,6 +721,36 @@ static void rna_def_image_paint(BlenderRNA *brna)
prop = RNA_def_int_array(srna, "screen_grab_size", 2, NULL, 0, 0, "screen_grab_size",
"Size to capture the image for re-projecting", 0, 0);
RNA_def_property_range(prop, 512, 16384);
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, paint_type_items);
+ RNA_def_property_ui_text(prop, "Mode", "Mode of operation for projection painting");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, "rna_ImaPaint_mode_update");
+
+ /* Missing data */
+ prop = RNA_def_property(srna, "missing_uvs", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "missing_data", IMAGEPAINT_MISSING_UVS);
+ RNA_def_property_ui_text(prop, "Missing UVs",
+ "A UV layer is missing on the mesh");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "missing_materials", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "missing_data", IMAGEPAINT_MISSING_MATERIAL);
+ RNA_def_property_ui_text(prop, "Missing Materials",
+ "The mesh is missing materials");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "missing_stencil", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "missing_data", IMAGEPAINT_MISSING_STENCIL);
+ RNA_def_property_ui_text(prop, "Missing Stencil",
+ "Image Painting does not have a stencil");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+
+ prop = RNA_def_property(srna, "missing_texture", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "missing_data", IMAGEPAINT_MISSING_TEX);
+ RNA_def_property_ui_text(prop, "Missing Texture",
+ "Image Painting does not have a texture to paint on");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
}
static void rna_def_particle_edit(BlenderRNA *brna)
@@ -741,6 +934,9 @@ 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);
rna_def_uv_sculpt(brna);
diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c
index f5e59119baa..3944b59dff7 100644
--- a/source/blender/makesrna/intern/rna_sensor.c
+++ b/source/blender/makesrna/intern/rna_sensor.c
@@ -405,6 +405,12 @@ static void rna_def_mouse_sensor(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ 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"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "MouseSensor", "Sensor");
RNA_def_struct_ui_text(srna, "Mouse Sensor", "Sensor to detect mouse events");
RNA_def_struct_sdna_from(srna, "bMouseSensor", "data");
@@ -419,6 +425,27 @@ static void rna_def_mouse_sensor(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_MOUSE_FOCUS_PULSE);
RNA_def_property_ui_text(prop, "Pulse", "Moving the mouse over a different object generates a pulse");
RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "use_material", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, prop_mouse_type_items);
+ RNA_def_property_ui_text(prop, "M/P", "Toggle collision on material or property");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "property", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "propname");
+ RNA_def_property_ui_text(prop, "Property", "Only look for objects with this property (blank = all objects)");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "material", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "matname");
+ RNA_def_property_ui_text(prop, "Material", "Only look for objects with this material (blank = all objects)");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
+
+ prop = RNA_def_property(srna, "use_x_ray", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SENS_RAY_XRAY);
+ RNA_def_property_ui_text(prop, "X-Ray", "Toggle X-Ray option (see through objects that don't have the property)");
+ RNA_def_property_update(prop, NC_LOGIC, NULL);
}
static void rna_def_keyboard_sensor(BlenderRNA *brna)
@@ -478,6 +505,8 @@ static void rna_def_property_sensor(BlenderRNA *brna)
{SENS_PROP_INTERVAL, "PROPINTERVAL", 0, "Interval", ""},
{SENS_PROP_CHANGED, "PROPCHANGED", 0, "Changed", ""},
/* {SENS_PROP_EXPRESSION, "PROPEXPRESSION", 0, "Expression", ""}, NOT_USED_IN_UI */
+ {SENS_PROP_LESSTHAN, "PROPLESSTHAN", 0, "Less Than", ""},
+ {SENS_PROP_GREATERTHAN, "PROPGREATERTHAN", 0, "Greater Than", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -498,7 +527,7 @@ static void rna_def_property_sensor(BlenderRNA *brna)
prop = RNA_def_property(srna, "value", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "value");
- RNA_def_property_ui_text(prop, "Value", "Check for this value in types in Equal or Not Equal types");
+ RNA_def_property_ui_text(prop, "Value", "Check for this value in types in Equal, Not Equal, Less Than and Greater Than types");
RNA_def_property_update(prop, NC_LOGIC, NULL);
prop = RNA_def_property(srna, "value_min", PROP_STRING, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index d478bf41287..00f0a6ff487 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -299,6 +299,14 @@ static void rna_Sequence_channel_set(PointerRNA *ptr, int value)
BKE_sequencer_sort(scene);
}
+static void rna_Sequence_frame_offset_range(PointerRNA *ptr, int *min, int *max,
+ int *UNUSED(softmin), int *UNUSED(softmax))
+{
+ Sequence *seq = (Sequence *)ptr->data;
+ *min = ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD) ? 0 : INT_MIN;
+ *max = INT_MAX;
+}
+
static void rna_Sequence_use_proxy_set(PointerRNA *ptr, int value)
{
Sequence *seq = (Sequence *)ptr->data;
@@ -531,6 +539,8 @@ static StructRNA *rna_Sequence_refine(struct PointerRNA *ptr)
return &RNA_ColorSequence;
case SEQ_TYPE_SPEED:
return &RNA_SpeedControlSequence;
+ case SEQ_TYPE_GAUSSIAN_BLUR:
+ return &RNA_GaussianBlurSequence;
default:
return &RNA_Sequence;
}
@@ -1366,6 +1376,7 @@ static void rna_def_sequence(BlenderRNA *brna)
{SEQ_TYPE_SPEED, "SPEED", 0, "Speed", ""},
{SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
{SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
+ {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1466,12 +1477,14 @@ static void rna_def_sequence(BlenderRNA *brna)
RNA_def_property_int_sdna(prop, NULL, "startofs");
// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
RNA_def_property_ui_text(prop, "Start Offset", "");
+ RNA_def_property_int_funcs(prop, NULL, NULL, "rna_Sequence_frame_offset_range");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
prop = RNA_def_property(srna, "frame_offset_end", PROP_INT, PROP_TIME);
RNA_def_property_int_sdna(prop, NULL, "endofs");
// RNA_def_property_clear_flag(prop, PROP_EDITABLE); /* overlap tests */
RNA_def_property_ui_text(prop, "End Offset", "");
+ RNA_def_property_int_funcs(prop, NULL, NULL, "rna_Sequence_frame_offset_range");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_frame_change_update");
prop = RNA_def_property(srna, "frame_still_start", PROP_INT, PROP_TIME);
@@ -2193,6 +2206,23 @@ static void rna_def_speed_control(StructRNA *srna)
RNA_def_property_boolean_sdna(prop, NULL, "flags", SEQ_SPEED_COMPRESS_IPO_Y);
RNA_def_property_ui_text(prop, "Scale to length", "Scale values from 0.0 to 1.0 to target sequence length");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+}
+
+static void rna_def_gaussian_blur(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ RNA_def_struct_sdna_from(srna, "GaussianBlurVars", "effectdata");
+ prop = RNA_def_property(srna, "size_x", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_ui_text(prop, "Size X", "Size of the blur along X axis");
+ RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, -1);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
+
+ prop = RNA_def_property(srna, "size_y", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_ui_text(prop, "Size Y", "Size of the blur along Y axis");
+ RNA_def_property_ui_range(prop, 0.0f, FLT_MAX, 1, -1);
+ RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_update");
}
static EffectInfo def_effects[] = {
@@ -2217,6 +2247,8 @@ static EffectInfo def_effects[] = {
"Sequence strip applying affine transformations to other strips", rna_def_transform, 1},
{"WipeSequence", "Wipe Sequence", "Sequence strip creating a wipe transition",
rna_def_wipe, 1},
+ {"GaussianBlurSequence", "Gaussian Blur Sequence", "Sequence strip creating a gaussian blur",
+ rna_def_gaussian_blur, 1},
{"", "", "", NULL, 0}
};
diff --git a/source/blender/makesrna/intern/rna_sequencer_api.c b/source/blender/makesrna/intern/rna_sequencer_api.c
index b3a37a4ce8e..70370f1ae36 100644
--- a/source/blender/makesrna/intern/rna_sequencer_api.c
+++ b/source/blender/makesrna/intern/rna_sequencer_api.c
@@ -402,7 +402,7 @@ void RNA_api_sequence_strip(StructRNA *srna)
func = RNA_def_function(srna, "update", "rna_Sequence_update_rnafunc");
RNA_def_function_flag(func, FUNC_USE_SELF_ID);
RNA_def_function_ui_description(func, "Update the strip dimensions");
- parm = RNA_def_boolean(func, "data", false, "Frame",
+ parm = RNA_def_boolean(func, "data", false, "Data",
"Update strip data");
func = RNA_def_function(srna, "strip_elem_from_frame", "BKE_sequencer_give_stripelem");
@@ -468,6 +468,7 @@ void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop)
{SEQ_TYPE_SPEED, "SPEED", 0, "Speed", ""},
{SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
{SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
+ {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_smoke.c b/source/blender/makesrna/intern/rna_smoke.c
index 6601b20e1ce..507753bd1df 100644
--- a/source/blender/makesrna/intern/rna_smoke.c
+++ b/source/blender/makesrna/intern/rna_smoke.c
@@ -333,7 +333,7 @@ static void rna_def_smoke_domain_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "resolution_max", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "maxres");
- RNA_def_property_range(prop, 24, 512);
+ RNA_def_property_range(prop, 6, 512);
RNA_def_property_ui_range(prop, 24, 512, 2, -1);
RNA_def_property_ui_text(prop, "Max Res", "Maximal resolution used in the fluid domain");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
@@ -737,21 +737,21 @@ static void rna_def_smoke_flow_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "velocity_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_multi");
- RNA_def_property_range(prop, -2.0, 2.0);
+ RNA_def_property_range(prop, -100.0, 100.0);
RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Source", "Multiplier of source velocity passed to smoke");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "velocity_normal", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_normal");
- RNA_def_property_range(prop, -2.0, 2.0);
+ RNA_def_property_range(prop, -100.0, 100.0);
RNA_def_property_ui_range(prop, -2.0, 2.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Normal", "Amount of normal directional velocity");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
prop = RNA_def_property(srna, "velocity_random", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "vel_random");
- RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_range(prop, 0.0, 10.0);
RNA_def_property_ui_range(prop, 0.0, 2.0, 0.05, 5);
RNA_def_property_ui_text(prop, "Random", "Amount of random velocity");
RNA_def_property_update(prop, NC_OBJECT | ND_MODIFIER, "rna_Smoke_reset");
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 39d6e665077..a314e995ba3 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -87,6 +87,18 @@ EnumPropertyItem space_type_items[] = {
{0, NULL, 0, NULL, NULL}
};
+static EnumPropertyItem pivot_items_full[] = {
+ {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
+ "Pivot around bounding box center of selected object(s)"},
+ {V3D_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"},
+ {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
+ "Individual Origins", "Pivot around each object's own origin"},
+ {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point",
+ "Pivot around the median point of selected objects"},
+ {V3D_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"},
+ {0, NULL, 0, NULL, NULL}
+};
+
static EnumPropertyItem draw_channels_items[] = {
{SI_USE_ALPHA, "COLOR_ALPHA", ICON_IMAGE_RGB_ALPHA, "Color and Alpha",
"Draw image with RGB colors and alpha transparency"},
@@ -454,12 +466,12 @@ static void rna_SpaceView3D_layer_update(Main *bmain, Scene *UNUSED(scene), Poin
DAG_on_visible_update(bmain, false);
}
-static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+static void rna_SpaceView3D_viewport_shade_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
View3D *v3d = (View3D *)(ptr->data);
ScrArea *sa = rna_area_from_space(ptr);
- ED_view3d_shade_update(bmain, v3d, sa);
+ ED_view3d_shade_update(bmain, scene, v3d, sa);
}
static void rna_SpaceView3D_matcap_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
@@ -616,9 +628,7 @@ static int rna_SpaceView3D_viewport_shade_get(PointerRNA *ptr)
View3D *v3d = (View3D *)ptr->data;
int drawtype = v3d->drawtype;
- if (drawtype == OB_MATERIAL && !BKE_scene_use_new_shading_nodes(scene))
- return OB_SOLID;
- else if (drawtype == OB_RENDER && !(type && type->view_draw))
+ if (drawtype == OB_RENDER && !(type && type->view_draw))
return OB_SOLID;
return drawtype;
@@ -637,9 +647,7 @@ static EnumPropertyItem *rna_SpaceView3D_viewport_shade_itemf(bContext *UNUSED(C
RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_WIRE);
RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_SOLID);
RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_TEXTURE);
-
- if (BKE_scene_use_new_shading_nodes(scene))
- RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_MATERIAL);
+ RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_MATERIAL);
if (type && type->view_draw)
RNA_enum_items_add_value(&item, &totitem, viewport_shade_items, OB_RENDER);
@@ -803,6 +811,24 @@ static void rna_SpaceImageEditor_scopes_update(Main *UNUSED(bmain), Scene *scene
ED_space_image_release_buffer(sima, ibuf, lock);
}
+static EnumPropertyItem *rna_SpaceImageEditor_pivot_itemf(bContext *UNUSED(C), PointerRNA *ptr,
+ PropertyRNA *UNUSED(prop), bool *UNUSED(r_free))
+{
+ static EnumPropertyItem pivot_items[] = {
+ {V3D_CENTER, "CENTER", ICON_ROTATE, "Bounding Box Center", ""},
+ {V3D_CENTROID, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""},
+ {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ SpaceImage *sima = (SpaceImage *)ptr->data;
+
+ if (sima->mode == SI_MODE_PAINT)
+ return pivot_items_full;
+ else
+ return pivot_items;
+}
+
/* Space Text Editor */
static void rna_SpaceTextEditor_word_wrap_set(PointerRNA *ptr, int value)
@@ -1274,25 +1300,25 @@ static int rna_SpaceNodeEditor_path_length(PointerRNA *ptr)
return ED_node_tree_path_length(snode);
}
-void rna_SpaceNodeEditor_path_clear(SpaceNode *snode, bContext *C)
+static void rna_SpaceNodeEditor_path_clear(SpaceNode *snode, bContext *C)
{
ED_node_tree_start(snode, NULL, NULL, NULL);
ED_node_tree_update(C);
}
-void rna_SpaceNodeEditor_path_start(SpaceNode *snode, bContext *C, PointerRNA *node_tree)
+static void rna_SpaceNodeEditor_path_start(SpaceNode *snode, bContext *C, PointerRNA *node_tree)
{
ED_node_tree_start(snode, (bNodeTree *)node_tree->data, NULL, NULL);
ED_node_tree_update(C);
}
-void rna_SpaceNodeEditor_path_append(SpaceNode *snode, bContext *C, PointerRNA *node_tree, PointerRNA *node)
+static void rna_SpaceNodeEditor_path_append(SpaceNode *snode, bContext *C, PointerRNA *node_tree, PointerRNA *node)
{
ED_node_tree_push(snode, node_tree->data, node->data);
ED_node_tree_update(C);
}
-void rna_SpaceNodeEditor_path_pop(SpaceNode *snode, bContext *C)
+static void rna_SpaceNodeEditor_path_pop(SpaceNode *snode, bContext *C)
{
ED_node_tree_pop(snode);
ED_node_tree_update(C);
@@ -1492,6 +1518,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_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");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
+
prop = RNA_def_property(srna, "show_normalized_coords", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SI_COORDFLOATS);
RNA_def_property_ui_text(prop, "Normalized Coordinates",
@@ -1752,24 +1783,12 @@ static void rna_def_space_view3d(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static EnumPropertyItem pivot_items[] = {
- {V3D_CENTER, "BOUNDING_BOX_CENTER", ICON_ROTATE, "Bounding Box Center",
- "Pivot around bounding box center of selected object(s)"},
- {V3D_CURSOR, "CURSOR", ICON_CURSOR, "3D Cursor", "Pivot around the 3D cursor"},
- {V3D_LOCAL, "INDIVIDUAL_ORIGINS", ICON_ROTATECOLLECTION,
- "Individual Origins", "Pivot around each object's own origin"},
- {V3D_CENTROID, "MEDIAN_POINT", ICON_ROTATECENTER, "Median Point",
- "Pivot around the median point of selected objects"},
- {V3D_ACTIVE, "ACTIVE_ELEMENT", ICON_ROTACTIVE, "Active Element", "Pivot around active object"},
- {0, NULL, 0, NULL, NULL}
- };
-
static EnumPropertyItem manipulators_items[] = {
- {V3D_MANIP_TRANSLATE, "TRANSLATE", ICON_MAN_TRANS, "Manipulator Translate",
+ {V3D_MANIP_TRANSLATE, "TRANSLATE", ICON_MAN_TRANS, "Translate",
"Use the manipulator for movement transformations"},
- {V3D_MANIP_ROTATE, "ROTATE", ICON_MAN_ROT, "Manipulator Rotate",
+ {V3D_MANIP_ROTATE, "ROTATE", ICON_MAN_ROT, "Rotate",
"Use the manipulator for rotation transformations"},
- {V3D_MANIP_SCALE, "SCALE", ICON_MAN_SCALE, "Manipulator Scale",
+ {V3D_MANIP_SCALE, "SCALE", ICON_MAN_SCALE, "Scale",
"Use the manipulator for scale transformations"},
{0, NULL, 0, NULL, NULL}
};
@@ -1925,6 +1944,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
RNA_def_property_float_sdna(prop, NULL, "grid");
RNA_def_property_ui_text(prop, "Grid Scale", "Distance between 3D View grid lines");
RNA_def_property_range(prop, 0.0f, FLT_MAX);
+ RNA_def_property_ui_range(prop, 0.001f, 1000.0f, 0.1f, 3);
RNA_def_property_float_default(prop, 1.0f);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
@@ -2042,7 +2062,7 @@ static void rna_def_space_view3d(BlenderRNA *brna)
prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "around");
- RNA_def_property_enum_items(prop, pivot_items);
+ RNA_def_property_enum_items(prop, pivot_items_full);
RNA_def_property_ui_text(prop, "Pivot Point", "Pivot center for rotation/scaling");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_SpaceView3D_pivot_update");
@@ -2310,13 +2330,6 @@ static void rna_def_space_image(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
- static EnumPropertyItem pivot_items[] = {
- {V3D_CENTER, "CENTER", ICON_ROTATE, "Bounding Box Center", ""},
- {V3D_CENTROID, "MEDIAN", ICON_ROTATECENTER, "Median Point", ""},
- {V3D_CURSOR, "CURSOR", ICON_CURSOR, "2D Cursor", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
StructRNA *srna;
PropertyRNA *prop;
@@ -2404,7 +2417,8 @@ static void rna_def_space_image(BlenderRNA *brna)
prop = RNA_def_property(srna, "pivot_point", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "around");
- RNA_def_property_enum_items(prop, pivot_items);
+ RNA_def_property_enum_items(prop, pivot_items_full);
+ RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_SpaceImageEditor_pivot_itemf");
RNA_def_property_ui_text(prop, "Pivot", "Rotation/Scaling Pivot");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, NULL);
@@ -3398,13 +3412,18 @@ static void rna_def_space_node(BlenderRNA *brna)
{SNODE_TEX_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Edit texture nodes from Object"},
{SNODE_TEX_WORLD, "WORLD", ICON_WORLD_DATA, "World", "Edit texture nodes from World"},
{SNODE_TEX_BRUSH, "BRUSH", ICON_BRUSH_DATA, "Brush", "Edit texture nodes from Brush"},
+#ifdef WITH_FREESTYLE
{SNODE_TEX_LINESTYLE, "LINESTYLE", ICON_LINE_DATA, "Line Style", "Edit texture nodes from Line Style"},
+#endif
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem shader_type_items[] = {
{SNODE_SHADER_OBJECT, "OBJECT", ICON_OBJECT_DATA, "Object", "Edit shader nodes from Object"},
{SNODE_SHADER_WORLD, "WORLD", ICON_WORLD_DATA, "World", "Edit shader nodes from World"},
+#ifdef WITH_FREESTYLE
+ {SNODE_SHADER_LINESTYLE, "LINESTYLE", ICON_LINE_DATA, "Line Style", "Edit shader nodes from Line Style"},
+#endif
{0, NULL, 0, NULL, NULL}
};
diff --git a/source/blender/makesrna/intern/rna_test.c b/source/blender/makesrna/intern/rna_test.c
index cf0dc5e332d..867e6dcd8ff 100644
--- a/source/blender/makesrna/intern/rna_test.c
+++ b/source/blender/makesrna/intern/rna_test.c
@@ -36,6 +36,10 @@
#ifdef RNA_RUNTIME
+#ifdef ARRAY_SIZE
+# undef ARRAY_SIZE
+#endif
+
#define ARRAY_SIZE 3
#define DYNAMIC_ARRAY_SIZE 64
#define MARRAY_DIM [3][4][5]
diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c
index 537ffe630a2..899da62d9d3 100644
--- a/source/blender/makesrna/intern/rna_tracking.c
+++ b/source/blender/makesrna/intern/rna_tracking.c
@@ -393,6 +393,7 @@ static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerR
nodeUpdateID(scene->nodetree, &clip->id);
WM_main_add_notifier(NC_SCENE | ND_NODES, NULL);
+ WM_main_add_notifier(NC_SCENE, NULL);
DAG_id_tag_update(&clip->id, 0);
}
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index f14fadfa722..92c5530202b 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -210,7 +210,12 @@ static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *dat
identifier, (int)sizeof(dummypt.idname));
return NULL;
}
-
+
+ if ((dummypt.category[0] == '\0') && (dummypt.region_type == RGN_TYPE_TOOLS)) {
+ /* Use a fallback, otherwise an empty value will draw the panel in every category. */
+ strcpy(dummypt.category, PNL_CATEGORY_FALLBACK);
+ }
+
if (!(art = region_type_find(reports, dummypt.space_type, dummypt.region_type)))
return NULL;
@@ -987,7 +992,6 @@ static void rna_def_panel(BlenderRNA *brna)
prop = RNA_def_property(srna, "bl_category", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "type->category");
- RNA_def_property_string_default(prop, BLF_I18NCONTEXT_DEFAULT_BPYRNA);
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 3cdff730b00..b13bdedaffd 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -462,6 +462,13 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_float(func, "percentage", 0.0f, 0.0f, 1.0f, "Percentage", "Percentage of width to split at", 0.0f, 1.0f);
RNA_def_boolean(func, "align", false, "", "Align buttons to each other");
+ /* radial/pie layout */
+ func = RNA_def_function(srna, "menu_pie", "uiLayoutRadial");
+ parm = RNA_def_pointer(func, "layout", "UILayout", "", "Sub-layout to put items in");
+ RNA_def_function_return(func, parm);
+ RNA_def_function_ui_description(func, "Sublayout. Items placed in this sublayout are placed "
+ "in a radial fashion around the menu center)");
+
/* Icon of a rna pointer */
func = RNA_def_function(srna, "icon", "rna_ui_get_rnaptr_icon");
parm = RNA_def_int(func, "icon_value", ICON_NONE, 0, INT_MAX, "", "Icon identifier", 0, INT_MAX);
@@ -700,6 +707,7 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_enum(func, "type", curve_type_items, 0, "Type", "Type of curves to display");
RNA_def_boolean(func, "levels", false, "", "Show black/white levels");
RNA_def_boolean(func, "brush", false, "", "Show brush options");
+ RNA_def_boolean(func, "use_negative_slope", false, "", "Use a negative slope by default");
func = RNA_def_function(srna, "template_color_ramp", "uiTemplateColorRamp");
RNA_def_function_ui_description(func, "Item. A color ramp widget");
@@ -739,6 +747,11 @@ void RNA_api_ui_layout(StructRNA *srna)
RNA_def_boolean(func, "lock_luminosity", false, "", "Keep the color at its original vector length");
RNA_def_boolean(func, "cubic", false, "", "Cubic saturation for picking values close to white");
+ func = RNA_def_function(srna, "template_palette", "uiTemplatePalette");
+ RNA_def_function_ui_description(func, "Item. A palette used to pick colors");
+ api_ui_item_rna_common(func);
+ RNA_def_boolean(func, "color", 0, "", "Display the colors as colors or values");
+
func = RNA_def_function(srna, "template_image_layers", "uiTemplateImageLayers");
RNA_def_function_flag(func, FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "image", "Image", "", "");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 7c101fb19be..1bad9570893 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -91,6 +91,7 @@ EnumPropertyItem navigation_mode_items[] = {
#include "BKE_idprop.h"
#include "GPU_draw.h"
+#include "GPU_select.h"
#include "BLF_api.h"
@@ -119,6 +120,16 @@ static void rna_userdef_dpi_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Po
WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
}
+static void rna_userdef_virtual_pixel_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
+{
+ /* font's are stored at each DPI level, without this we can easy load 100's of fonts */
+ BLF_cache_clear();
+
+ BKE_userdef_state();
+ WM_main_add_notifier(NC_WINDOW, NULL); /* full redraw */
+ WM_main_add_notifier(NC_SCREEN | NA_EDITED, NULL); /* refresh region sizes */
+}
+
static void rna_userdef_language_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
BLF_cache_clear();
@@ -332,6 +343,11 @@ static void rna_UserDef_viewport_lights_update(Main *bmain, Scene *scene, Pointe
rna_userdef_update(bmain, scene, ptr);
}
+static int rna_Scene_GPU_selection_supported(UserDef *UNUSED(U))
+{
+ return GPU_select_query_check_support();
+}
+
static void rna_userdef_autosave_update(Main *bmain, Scene *scene, PointerRNA *ptr)
{
wmWindowManager *wm = bmain->wm.first;
@@ -386,7 +402,7 @@ static void rna_userdef_pathcompare_remove(ReportList *reports, PointerRNA *path
static void rna_userdef_temp_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
{
- BLI_init_temporary_dir(U.tempdir);
+ BLI_temp_dir_init(U.tempdir);
}
static void rna_userdef_text_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *UNUSED(ptr))
@@ -947,6 +963,12 @@ static void rna_def_userdef_theme_ui(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "Menu Backdrop Colors", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "wcol_pie_menu", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_ui_text(prop, "Pie Menu Colors", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "wcol_tooltip", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "Tooltip Colors", "");
@@ -1292,7 +1314,23 @@ static void rna_def_userdef_theme_spaces_face(StructRNA *srna)
RNA_def_property_update(prop, 0, "rna_userdef_update");
}
-static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs, bool incl_lastsel, bool incl_vector)
+static void rna_def_userdef_theme_spaces_paint_curves(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ prop = RNA_def_property(srna, "paint_curve_handle", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Paint Curve Handle", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "paint_curve_pivot", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Paint Curve Pivot", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+}
+
+static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs, bool incl_lastsel,
+ bool incl_vector, bool incl_verthandle)
{
PropertyRNA *prop;
@@ -1377,8 +1415,8 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Align handle selected color", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- if (incl_nurbs == false) {
+
+ if (!incl_nurbs) {
/* assume that when nurbs are off, this is for 2D (i.e. anim) editors */
prop = RNA_def_property(srna, "handle_auto_clamped", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "handle_auto_clamped");
@@ -1400,6 +1438,23 @@ static void rna_def_userdef_theme_spaces_curves(StructRNA *srna, bool incl_nurbs
RNA_def_property_ui_text(prop, "Last selected point", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
}
+
+ if (incl_verthandle) {
+ prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Handle Vertex", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "handle_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Handle Vertex Select", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 255);
+ RNA_def_property_ui_text(prop, "Handle Vertex Size", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+ }
}
static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
@@ -1488,7 +1543,7 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
rna_def_userdef_theme_spaces_vertex(srna);
rna_def_userdef_theme_spaces_edge(srna);
rna_def_userdef_theme_spaces_face(srna);
- rna_def_userdef_theme_spaces_curves(srna, true, true, true);
+ rna_def_userdef_theme_spaces_curves(srna, true, true, true, false);
prop = RNA_def_property(srna, "extra_edge_len", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
@@ -1525,6 +1580,12 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Vertex Normal", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "split_normal", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "loop_normal");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Split Normal", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "bone_solid", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Bone Solid", "");
@@ -1567,6 +1628,8 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Skin Root", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+
+ rna_def_userdef_theme_spaces_paint_curves(srna);
}
@@ -1632,22 +1695,7 @@ static void rna_def_userdef_theme_space_graph(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_userdef_update");
rna_def_userdef_theme_spaces_vertex(srna);
- rna_def_userdef_theme_spaces_curves(srna, false, true, true);
-
- prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Handle Vertex", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "handle_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Handle Vertex Select", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 0, 255);
- RNA_def_property_ui_text(prop, "Handle Vertex Size", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
+ rna_def_userdef_theme_spaces_curves(srna, false, true, true, true);
}
static void rna_def_userdef_theme_space_file(BlenderRNA *brna)
@@ -1986,6 +2034,12 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Wires", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "wire_inner", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "syntaxr");
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_ui_text(prop, "Wire Color", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
prop = RNA_def_property(srna, "wire_select", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "edge_select");
RNA_def_property_array(prop, 3);
@@ -2258,7 +2312,9 @@ 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");
- rna_def_userdef_theme_spaces_curves(srna, false, false, false);
+ rna_def_userdef_theme_spaces_curves(srna, false, false, false, true);
+
+ rna_def_userdef_theme_spaces_paint_curves(srna);
}
static void rna_def_userdef_theme_space_seq(BlenderRNA *brna)
@@ -2734,32 +2790,12 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Path After", "Color of path after current frame");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "grid", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Grid", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
prop = RNA_def_property(srna, "frame_current", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "cframe");
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Current Frame", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- prop = RNA_def_property(srna, "handle_vertex", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Handle Vertex", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "handle_vertex_select", PROP_FLOAT, PROP_COLOR_GAMMA);
- RNA_def_property_array(prop, 3);
- RNA_def_property_ui_text(prop, "Handle Vertex Select", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
- prop = RNA_def_property(srna, "handle_vertex_size", PROP_INT, PROP_NONE);
- RNA_def_property_range(prop, 0, 255);
- RNA_def_property_ui_text(prop, "Handle Vertex Size", "");
- RNA_def_property_update(prop, 0, "rna_userdef_update");
-
prop = RNA_def_property(srna, "strips", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "strip");
RNA_def_property_array(prop, 3);
@@ -2772,7 +2808,7 @@ static void rna_def_userdef_theme_space_clip(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Strips Selected", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
- rna_def_userdef_theme_spaces_curves(srna, false, false, false);
+ rna_def_userdef_theme_spaces_curves(srna, false, false, false, true);
}
static void rna_def_userdef_themes(BlenderRNA *brna)
@@ -3141,7 +3177,7 @@ static void rna_def_userdef_view(BlenderRNA *brna)
/* display */
prop = RNA_def_property(srna, "show_tooltips", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_TOOLTIPS);
- RNA_def_property_ui_text(prop, "Tooltips", "Display tooltips");
+ RNA_def_property_ui_text(prop, "Tooltips", "Display tooltips (when off hold Alt to force display)");
prop = RNA_def_property(srna, "show_tooltips_python", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", USER_TOOLTIPS_PYTHON);
@@ -3195,6 +3231,31 @@ static void rna_def_userdef_view(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Sub Level Menu Open Delay",
"Time delay in 1/10 seconds before automatically opening sub level menus");
+ /* pie menus */
+ prop = RNA_def_property(srna, "pie_initial_timeout", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_text(prop, "Recenter Timeout",
+ "Pie menus will use the initial mouse position as center for this amount of time "
+ "(in 1/100ths of sec)");
+
+ prop = RNA_def_property(srna, "pie_animation_timeout", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_text(prop, "Animation Timeout",
+ "Time needed to fully animate the pie to unfolded state (in 1/100ths of sec)");
+
+ prop = RNA_def_property(srna, "pie_menu_radius", PROP_INT, PROP_PIXEL);
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_text(prop, "Radius", "Pie menu size in pixels");
+
+ prop = RNA_def_property(srna, "pie_menu_threshold", PROP_INT, PROP_PIXEL);
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_text(prop, "Threshold", "Distance from center needed before a selection can be made");
+
+ prop = RNA_def_property(srna, "pie_menu_confirm", PROP_INT, PROP_PIXEL);
+ RNA_def_property_range(prop, 0, 1000);
+ RNA_def_property_ui_text(prop, "Confirm Threshold",
+ "Distance threshold after which selection is made (zero to disable)");
+
prop = RNA_def_property(srna, "use_quit_dialog", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag", USER_QUIT_PROMPT);
RNA_def_property_ui_text(prop, "Prompt Quit",
@@ -3569,7 +3630,9 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
static void rna_def_userdef_system(BlenderRNA *brna)
{
+ FunctionRNA *func;
PropertyRNA *prop;
+ PropertyRNA *parm;
StructRNA *srna;
static EnumPropertyItem gl_texture_clamp_items[] = {
@@ -3689,6 +3752,19 @@ static void rna_def_userdef_system(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem gpu_select_method_items[] = {
+ {USER_SELECT_AUTO, "AUTO", 0, "Automatic", ""},
+ {USER_SELECT_USE_SELECT_RENDERMODE, "GL_SELECT", 0, "OpenGL Select", ""},
+ {USER_SELECT_USE_OCCLUSION_QUERY, "GL_QUERY", 0, "OpenGL Occlusion Queries", ""},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem virtual_pixel_mode_items[] = {
+ {VIRTUAL_PIXEL_NATIVE, "NATIVE", 0, "Native", "Use native pixel size of the display"},
+ {VIRTUAL_PIXEL_DOUBLE, "DOUBLE", 0, "Double", "Use double the native pixel size of the display"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "UserPreferencesSystem", NULL);
RNA_def_struct_sdna(srna, "UserDef");
RNA_def_struct_nested(brna, srna, "UserPreferences");
@@ -3707,7 +3783,18 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_range(prop, 48, 144);
RNA_def_property_ui_text(prop, "DPI", "Font size and resolution for display");
RNA_def_property_update(prop, 0, "rna_userdef_dpi_update");
-
+
+ prop = RNA_def_property(srna, "virtual_pixel_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "virtual_pixel");
+ RNA_def_property_enum_items(prop, virtual_pixel_mode_items);
+ RNA_def_property_ui_text(prop, "Virtual Pixel Mode", "Modify the pixel size for hi-res devices");
+ RNA_def_property_update(prop, 0, "rna_userdef_virtual_pixel_update");
+
+ prop = RNA_def_property(srna, "font_path_ui", PROP_STRING, PROP_FILEPATH);
+ RNA_def_property_string_sdna(prop, NULL, "font_path_ui");
+ RNA_def_property_ui_text(prop, "Interface Font", "Path to interface font");
+ RNA_def_property_update(prop, NC_WINDOW, "rna_userdef_language_update");
+
prop = RNA_def_property(srna, "scrollback", PROP_INT, PROP_UNSIGNED);
RNA_def_property_int_sdna(prop, NULL, "scrollback");
RNA_def_property_range(prop, 32, 32768);
@@ -3926,12 +4013,24 @@ static void rna_def_userdef_system(BlenderRNA *brna)
RNA_def_property_boolean_negative_sdna(prop, NULL, "text_render", USER_TEXT_DISABLE_AA);
RNA_def_property_ui_text(prop, "Text Anti-aliasing", "Draw user interface text anti-aliased");
RNA_def_property_update(prop, 0, "rna_userdef_text_update");
-
+
+ func = RNA_def_function(srna, "is_occlusion_query_supported", "rna_Scene_GPU_selection_supported");
+ parm = RNA_def_boolean(func, "is_supported", 0, "Occlusion Query Support",
+ "Check if GPU supports Occlusion Queries");
+ RNA_def_function_return(func, parm);
+
+ prop = RNA_def_property(srna, "select_method", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "gpu_select_method");
+ RNA_def_property_enum_items(prop, gpu_select_method_items);
+ RNA_def_property_ui_text(prop, "Selection Method",
+ "Use OpenGL occlusion queries or selection render mode to accelerate selection");
+
/* Full scene anti-aliasing */
prop = RNA_def_property(srna, "multi_sample", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "ogl_multisamples");
RNA_def_property_enum_items(prop, multi_sample_levels);
- RNA_def_property_ui_text(prop, "MultiSample", "Enable OpenGL multi-sampling, only for systems that support it, requires restart");
+ RNA_def_property_ui_text(prop, "MultiSample",
+ "Enable OpenGL multi-sampling, only for systems that support it, requires restart");
prop = RNA_def_property(srna, "use_region_overlap", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "uiflag2", USER_REGION_OVERLAP);
@@ -4267,6 +4366,10 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Temporary Directory", "The directory for storing temporary save files");
RNA_def_property_update(prop, 0, "rna_userdef_temp_update");
+ prop = RNA_def_property(srna, "render_cache_directory", PROP_STRING, PROP_DIRPATH);
+ RNA_def_property_string_sdna(prop, NULL, "render_cachedir");
+ RNA_def_property_ui_text(prop, "Render Cache Path", "Where to cache raw render results");
+
prop = RNA_def_property(srna, "image_editor", PROP_STRING, PROP_FILEPATH);
RNA_def_property_string_sdna(prop, NULL, "image_editor");
RNA_def_property_ui_text(prop, "Image Editor", "Path to an image editor");
@@ -4291,7 +4394,7 @@ static void rna_def_userdef_filepaths(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_auto_save_temporary_files", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", USER_AUTOSAVE);
RNA_def_property_ui_text(prop, "Auto Save Temporary Files",
- "Automatic saving of temporary files in temp directory, uses process ID");
+ "Automatic saving of temporary files in temp directory, uses process ID (Sculpt or edit mode data won't be saved!')");
RNA_def_property_update(prop, 0, "rna_userdef_autosave_update");
prop = RNA_def_property(srna, "auto_save_time", PROP_INT, PROP_NONE);
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 23b6d1e41ae..7513a687978 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -565,6 +565,24 @@ static int rna_Event_unicode_length(PointerRNA *ptr)
}
}
+static float rna_Event_pressure_get(PointerRNA *ptr)
+{
+ wmEvent *event = ptr->data;
+ return WM_event_tablet_data(event, NULL, NULL);
+}
+
+static int rna_Event_is_tablet_get(PointerRNA *ptr)
+{
+ wmEvent *event = ptr->data;
+ return WM_event_is_tablet(event);
+}
+
+static void rna_Event_tilt_get(PointerRNA *ptr, float *values)
+{
+ wmEvent *event = ptr->data;
+ WM_event_tablet_data(event, NULL, values);
+}
+
static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr)
{
struct uiPopupMenu *pup = ptr->data;
@@ -576,6 +594,17 @@ static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr)
return rptr;
}
+static PointerRNA rna_PieMenu_layout_get(PointerRNA *ptr)
+{
+ struct uiPieMenu *pie = ptr->data;
+ uiLayout *layout = uiPieMenuLayout(pie);
+
+ PointerRNA rptr;
+ RNA_pointer_create(ptr->id.data, &RNA_UILayout, layout, &rptr);
+
+ return rptr;
+}
+
static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value)
{
wmWindow *win = (wmWindow *)ptr->data;
@@ -587,7 +616,7 @@ static void rna_Window_screen_set(PointerRNA *ptr, PointerRNA value)
win->newscreen = value.data;
}
-int rna_Window_screen_assign_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
+static int rna_Window_screen_assign_poll(PointerRNA *UNUSED(ptr), PointerRNA value)
{
bScreen *screen = (bScreen *)value.id.data;
@@ -1608,6 +1637,21 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Mouse Previous Y Position", "The window relative vertical location of the mouse");
+ prop = RNA_def_property(srna, "pressure", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_Event_pressure_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Tablet Pressure", "The pressure of the tablet or 1.0 if no tablet present");
+
+ prop = RNA_def_property(srna, "tilt", PROP_FLOAT, PROP_XYZ_LENGTH);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_Event_tilt_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Tablet Tilt", "The pressure of the tablet or zeroes if no tablet present");
+
+ prop = RNA_def_property(srna, "is_tablet", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_Event_is_tablet_get", NULL);
+ RNA_def_property_ui_text(prop, "Tablet Pressure", "The pressure of the tablet or 1.0 if no tablet present");
/* modifiers */
prop = RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE);
@@ -1683,6 +1727,26 @@ static void rna_def_popupmenu(BlenderRNA *brna)
RNA_define_verify_sdna(1); /* not in sdna */
}
+static void rna_def_piemenu(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "UIPieMenu", NULL);
+ RNA_def_struct_ui_text(srna, "PieMenu", "");
+ RNA_def_struct_sdna(srna, "uiPieMenu");
+
+ RNA_define_verify_sdna(0); /* not in sdna */
+
+ /* could wrap more, for now this is enough */
+ prop = RNA_def_property(srna, "layout", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "UILayout");
+ RNA_def_property_pointer_funcs(prop, "rna_PieMenu_layout_get",
+ NULL, NULL, NULL);
+
+ RNA_define_verify_sdna(1); /* not in sdna */
+}
+
static void rna_def_window(BlenderRNA *brna)
{
StructRNA *srna;
@@ -2045,6 +2109,7 @@ void RNA_def_wm(BlenderRNA *brna)
rna_def_event(brna);
rna_def_timer(brna);
rna_def_popupmenu(brna);
+ rna_def_piemenu(brna);
rna_def_window(brna);
rna_def_windowmanager(brna);
rna_def_keyconfig(brna);
diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c
index 9b288903aa2..ad638f2187c 100644
--- a/source/blender/makesrna/intern/rna_wm_api.c
+++ b/source/blender/makesrna/intern/rna_wm_api.c
@@ -111,7 +111,7 @@ static void rna_event_timer_remove(struct wmWindowManager *wm, wmTimer *timer)
}
/* placeholder data for final implementation of a true progressbar */
-struct wmStaticProgress {
+static struct wmStaticProgress {
float min;
float max;
bool is_valid;
@@ -310,6 +310,24 @@ static void rna_PupMenuEnd(bContext *C, PointerRNA *handle)
uiPupMenuEnd(C, handle->data);
}
+/* pie menu wrapper */
+static PointerRNA rna_PieMenuBegin(bContext *C, const char *title, int icon, PointerRNA *event)
+{
+ PointerRNA r_ptr;
+ void *data;
+
+ data = (void *)uiPieMenuBegin(C, title, icon, event->data);
+
+ RNA_pointer_create(NULL, &RNA_UIPieMenu, data, &r_ptr);
+
+ return r_ptr;
+}
+
+static void rna_PieMenuEnd(bContext *C, PointerRNA *handle)
+{
+ uiPieMenuEnd(C, handle->data);
+}
+
#else
#define WM_GEN_INVOKE_EVENT (1 << 0)
@@ -461,6 +479,26 @@ void RNA_api_wm(StructRNA *srna)
RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
parm = RNA_def_pointer(func, "menu", "UIPopupMenu", "", "");
RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+
+ /* wrap uiPieMenuBegin */
+ func = RNA_def_function(srna, "piemenu_begin__internal", "rna_PieMenuBegin");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+ parm = RNA_def_string(func, "title", NULL, 0, "", "");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_property(func, "icon", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(parm, icon_items);
+ parm = RNA_def_pointer(func, "event", "Event", "", "");
+ RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ /* return */
+ parm = RNA_def_pointer(func, "menu_pie", "UIPieMenu", "", "");
+ RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
+ RNA_def_function_return(func, parm);
+
+ /* wrap uiPieMenuEnd */
+ func = RNA_def_function(srna, "piemenu_end__internal", "rna_PieMenuEnd");
+ RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_CONTEXT);
+ parm = RNA_def_pointer(func, "menu", "UIPieMenu", "", "");
+ RNA_def_property_flag(parm, PROP_RNAPTR | PROP_NEVER_NULL);
}
void RNA_api_operator(StructRNA *srna)
diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c
index c7997bebedb..f63350ea0ae 100644
--- a/source/blender/makesrna/intern/rna_world.c
+++ b/source/blender/makesrna/intern/rna_world.c
@@ -450,7 +450,8 @@ void RNA_def_world(BlenderRNA *brna)
rna_def_animdata_common(srna);
rna_def_mtex_common(brna, srna, "rna_World_mtex_begin", "rna_World_active_texture_get",
- "rna_World_active_texture_set", NULL, "WorldTextureSlot", "WorldTextureSlots", "rna_World_update");
+ "rna_World_active_texture_set", NULL, "WorldTextureSlot", "WorldTextureSlots",
+ "rna_World_update", "rna_World_update");
/* colors */
prop = RNA_def_property(srna, "horizon_color", PROP_FLOAT, PROP_COLOR);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index b841356709e..06e9f8f5b67 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -40,7 +40,6 @@ set(INC
set(INC_SYS
${ZLIB_INCLUDE_DIRS}
- ${GLEW_INCLUDE_PATH}
)
set(SRC
@@ -133,6 +132,10 @@ if(WITH_MOD_OCEANSIM)
add_definitions(-DWITH_OCEANSIM)
endif()
+if(WITH_BULLET)
+ add_definitions(-DWITH_BULLET)
+endif()
+
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
diff --git a/source/blender/modifiers/SConscript b/source/blender/modifiers/SConscript
index 0942bca4ef3..b4c8299250e 100644
--- a/source/blender/modifiers/SConscript
+++ b/source/blender/modifiers/SConscript
@@ -34,7 +34,6 @@ incs = [
'./intern',
'#/intern/guardedalloc',
'#/intern/elbeem/extern',
- '#/extern/glew/include',
'#/intern/opennl/extern',
'../render/extern/include',
'../bmesh',
@@ -53,6 +52,9 @@ defs = []
if env['WITH_BF_BOOLEAN']:
incs.append('#/extern/carve')
defs.append('WITH_MOD_BOOLEAN')
+else:
+ from os import path
+ sources.remove(path.join('intern', 'MOD_boolean_util.c'))
if env['WITH_BF_REMESH']:
incs.append('#/intern/dualcon')
@@ -64,6 +66,9 @@ if env['WITH_BF_FLUID']:
if env['WITH_BF_OCEANSIM']:
defs.append('WITH_OCEANSIM')
+if env['WITH_BF_BULLET']:
+ defs.append('WITH_BULLET')
+
if env['WITH_BF_GAMEENGINE']:
incs.append('#/extern/recastnavigation')
defs.append('WITH_GAMEENGINE')
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 0a4a6140c02..40db49afef2 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -22,7 +22,8 @@
* Ton Roosendaal,
* Ben Batt,
* Brecht Van Lommel,
- * Campbell Barton
+ * Campbell Barton,
+ * Patrice Bertrand
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -30,16 +31,14 @@
/** \file blender/modifiers/intern/MOD_array.c
* \ingroup modifiers
+ *
+ * Array modifier: duplicates the object multiple times along an axis.
*/
-
-/* Array modifier: duplicates the object multiple times along an axis */
-
#include "MEM_guardedalloc.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLI_ghash.h"
#include "DNA_curve_types.h"
#include "DNA_meshdata_types.h"
@@ -53,14 +52,8 @@
#include "MOD_util.h"
-#include "bmesh.h"
-
#include "depsgraph_private.h"
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
/* Due to cyclic dependencies it's possible that curve used for
* deformation here is not evaluated at the time of evaluating
* this modifier.
@@ -140,7 +133,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
-static float vertarray_size(MVert *mvert, int numVerts, int axis)
+static float vertarray_size(const MVert *mvert, int numVerts, int axis)
{
int i;
float min_co, max_co;
@@ -159,209 +152,312 @@ static float vertarray_size(MVert *mvert, int numVerts, int axis)
return max_co - min_co;
}
-static int *find_doubles_index_map(BMesh *bm, BMOperator *dupe_op,
- const ArrayModifierData *amd,
- int *index_map_length)
+BLI_INLINE float sum_v3(const float v[3])
{
- BMOperator find_op;
- BMOIter oiter;
- BMVert *v, *v2;
- BMElem *ele;
- int *index_map, i;
-
- BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "find_doubles verts=%av dist=%f keep_verts=%s",
- amd->merge_dist, dupe_op, "geom");
-
- BMO_op_exec(bm, &find_op);
-
- i = 0;
- BMO_ITER (ele, &oiter, dupe_op->slots_in, "geom", BM_ALL) {
- BM_elem_index_set(ele, i); /* set_dirty */
- i++;
- }
-
- BMO_ITER (ele, &oiter, dupe_op->slots_out, "geom.out", BM_ALL) {
- BM_elem_index_set(ele, i); /* set_dirty */
- i++;
- }
- /* above loops over all, so set all to dirty, if this is somehow
- * setting valid values, this line can be removed - campbell */
- bm->elem_index_dirty |= BM_ALL;
+ return v[0] + v[1] + v[2];
+}
- (*index_map_length) = i;
- index_map = MEM_callocN(sizeof(int) * (*index_map_length), "index_map");
+/* Structure used for sorting vertices, when processing doubles */
+typedef struct SortVertsElem {
+ int vertex_num; /* The original index of the vertex, prior to sorting */
+ float co[3]; /* Its coordinates */
+ float sum_co; /* sum_v3(co), just so we don't do the sum many times. */
+} SortVertsElem;
- /*element type argument doesn't do anything here*/
- BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) {
- v2 = BMO_iter_map_value_ptr(&oiter);
- index_map[BM_elem_index_get(v)] = BM_elem_index_get(v2) + 1;
- }
+static int svert_sum_cmp(const void *e1, const void *e2)
+{
+ const SortVertsElem *sv1 = (SortVertsElem *)e1;
+ const SortVertsElem *sv2 = (SortVertsElem *)e2;
- BMO_op_finish(bm, &find_op);
+ if (sv1->sum_co > sv2->sum_co) return 1;
+ else if (sv1->sum_co < sv2->sum_co) return -1;
+ else return 0;
+}
- return index_map;
+static void svert_from_mvert(SortVertsElem *sv, const MVert *mv, const int i_begin, const int i_end)
+{
+ int i;
+ for (i = i_begin; i < i_end; i++, sv++, mv++) {
+ sv->vertex_num = i;
+ copy_v3_v3(sv->co, mv->co);
+ sv->sum_co = sum_v3(mv->co);
+ }
}
-/* Used for start/end cap.
- *
- * this function expects all existing vertices to be tagged,
- * so we can know new verts are not tagged.
- *
- * All verts will be tagged on exit.
+/**
+ * Take as inputs two sets of verts, to be processed for detection of doubles and mapping.
+ * Each set of verts is defined by its start within mverts array and its num_verts;
+ * It builds a mapping for all vertices within source, to vertices within target, or -1 if no double found
+ * The int doubles_map[num_verts_source] array must have been allocated by caller.
*/
-static void bm_merge_dm_transform(BMesh *bm, DerivedMesh *dm, float mat[4][4],
- const ArrayModifierData *amd,
- BMOperator *dupe_op,
- BMOpSlot dupe_op_slot_args[BMO_OP_MAX_SLOTS], const char *dupe_slot_name,
- BMOperator *weld_op)
+static void dm_mvert_map_doubles(
+ int *doubles_map,
+ const MVert *mverts,
+ const int target_start,
+ const int target_num_verts,
+ const int source_start,
+ const int source_num_verts,
+ const float dist,
+ const bool with_follow)
{
- const bool is_input = (dupe_op->slots_in == dupe_op_slot_args);
- BMVert *v, *v2, *v3;
- BMIter iter;
-
- /* Add the DerivedMesh's elements to the BMesh. The pre-existing
- * elements were already tagged, so the new elements can be
- * identified by not having the BM_ELEM_TAG flag set. */
- DM_to_bmesh_ex(dm, bm, false);
-
- if (amd->flags & MOD_ARR_MERGE) {
- /* if merging is enabled, find doubles */
-
- BMOIter oiter;
- BMOperator find_op;
- BMOpSlot *slot_targetmap;
-
- BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- is_input ? /* ugh */
- "find_doubles verts=%Hv dist=%f keep_verts=%s" :
- "find_doubles verts=%Hv dist=%f keep_verts=%S",
- BM_ELEM_TAG, amd->merge_dist,
- dupe_op, dupe_slot_name);
-
- /* append the dupe's geom to the findop input verts */
- if (is_input) {
- BMO_slot_buffer_append(&find_op, slots_in, "verts",
- dupe_op, slots_in, dupe_slot_name);
- }
- else if (dupe_op->slots_out == dupe_op_slot_args) {
- BMO_slot_buffer_append(&find_op, slots_in, "verts",
- dupe_op, slots_out, dupe_slot_name);
- }
- else {
- BLI_assert(0);
- }
+ const float dist3 = (M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
+ int i_source, i_target, i_target_low_bound, target_end, source_end;
+ SortVertsElem *sorted_verts_target, *sorted_verts_source;
+ SortVertsElem *sve_source, *sve_target, *sve_target_low_bound;
+ bool target_scan_completed;
+
+ target_end = target_start + target_num_verts;
+ source_end = source_start + source_num_verts;
+
+ /* build array of MVerts to be tested for merging */
+ sorted_verts_target = MEM_mallocN(sizeof(SortVertsElem) * target_num_verts, __func__);
+ sorted_verts_source = MEM_mallocN(sizeof(SortVertsElem) * source_num_verts, __func__);
+
+ /* Copy target vertices index and cos into SortVertsElem array */
+ svert_from_mvert(sorted_verts_target, mverts + target_start, target_start, target_end);
+
+ /* Copy source vertices index and cos into SortVertsElem array */
+ svert_from_mvert(sorted_verts_source, mverts + source_start, source_start, source_end);
+
+ /* sort arrays according to sum of vertex coordinates (sumco) */
+ qsort(sorted_verts_target, target_num_verts, sizeof(SortVertsElem), svert_sum_cmp);
+ qsort(sorted_verts_source, source_num_verts, sizeof(SortVertsElem), svert_sum_cmp);
+
+ sve_target_low_bound = sorted_verts_target;
+ i_target_low_bound = 0;
+ target_scan_completed = false;
+
+ /* Scan source vertices, in SortVertsElem sorted array, */
+ /* all the while maintaining the lower bound of possible doubles in target vertices */
+ for (i_source = 0, sve_source = sorted_verts_source;
+ i_source < source_num_verts;
+ i_source++, sve_source++)
+ {
+ bool double_found;
+ float sve_source_sumco;
- /* transform and tag verts */
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
- mul_m4_v3(mat, v->co);
- BM_elem_flag_enable(v, BM_ELEM_TAG);
- }
+ /* If source has already been assigned to a target (in an earlier call, with other chunks) */
+ if (doubles_map[sve_source->vertex_num] != -1) {
+ continue;
}
- BMO_op_exec(bm, &find_op);
+ /* If target fully scanned already, then all remaining source vertices cannot have a double */
+ if (target_scan_completed) {
+ doubles_map[sve_source->vertex_num] = -1;
+ continue;
+ }
- slot_targetmap = BMO_slot_get(weld_op->slots_in, "targetmap");
+ sve_source_sumco = sum_v3(sve_source->co);
- /* add new merge targets to weld operator */
- BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) {
- v2 = BMO_iter_map_value_ptr(&oiter);
- /* check in case the target vertex (v2) is already marked
- * for merging */
- while ((v3 = BMO_slot_map_elem_get(slot_targetmap, v2))) {
- v2 = v3;
- }
- BMO_slot_map_elem_insert(weld_op, slot_targetmap, v, v2);
+ /* Skip all target vertices that are more than dist3 lower in terms of sumco */
+ /* and advance the overall lower bound, applicable to all remaining vertices as well. */
+ while ((i_target_low_bound < target_num_verts) &&
+ (sve_target_low_bound->sum_co < sve_source_sumco - dist3))
+ {
+ i_target_low_bound++;
+ sve_target_low_bound++;
}
-
- BMO_op_finish(bm, &find_op);
- }
- else {
- /* transform and tag verts */
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (!BM_elem_flag_test(v, BM_ELEM_TAG)) {
- mul_m4_v3(mat, v->co);
- BM_elem_flag_enable(v, BM_ELEM_TAG);
+ /* If end of target list reached, then no more possible doubles */
+ if (i_target_low_bound >= target_num_verts) {
+ doubles_map[sve_source->vertex_num] = -1;
+ target_scan_completed = true;
+ continue;
+ }
+ /* Test target candidates starting at the low bound of possible doubles, ordered in terms of sumco */
+ i_target = i_target_low_bound;
+ sve_target = sve_target_low_bound;
+
+ /* i_target will scan vertices in the [v_source_sumco - dist3; v_source_sumco + dist3] range */
+
+ double_found = false;
+ while ((i_target < target_num_verts) &&
+ (sve_target->sum_co <= sve_source_sumco + dist3))
+ {
+ /* Testing distance for candidate double in target */
+ /* v_target is within dist3 of v_source in terms of sumco; check real distance */
+ if (compare_len_v3v3(sve_source->co, sve_target->co, dist)) {
+ /* Double found */
+ /* If double target is itself already mapped to other vertex,
+ * behavior depends on with_follow option */
+ int target_vertex = sve_target->vertex_num;
+ if (doubles_map[target_vertex] != -1) {
+ if (with_follow) { /* with_follow option: map to initial target */
+ target_vertex = doubles_map[target_vertex];
+ }
+ else {
+ /* not with_follow: if target is mapped, then we do not map source, and stop searching */
+ break;
+ }
+ }
+ doubles_map[sve_source->vertex_num] = target_vertex;
+ double_found = true;
+ break;
}
+ i_target++;
+ sve_target++;
+ }
+ /* End of candidate scan: if none found then no doubles */
+ if (!double_found) {
+ doubles_map[sve_source->vertex_num] = -1;
}
}
+
+ MEM_freeN(sorted_verts_source);
+ MEM_freeN(sorted_verts_target);
}
-static void merge_first_last(BMesh *bm,
- const ArrayModifierData *amd,
- BMOperator *dupe_first,
- BMOperator *dupe_last,
- BMOperator *weld_op)
+
+static void dm_merge_transform(
+ DerivedMesh *result, DerivedMesh *cap_dm, float cap_offset[4][4],
+ unsigned int cap_verts_index, unsigned int cap_edges_index, int cap_loops_index, int cap_polys_index,
+ int cap_nverts, int cap_nedges, int cap_nloops, int cap_npolys)
{
- BMOperator find_op;
- BMOIter oiter;
- BMVert *v, *v2;
- BMOpSlot *slot_targetmap;
-
- BMO_op_initf(bm, &find_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "find_doubles verts=%s dist=%f keep_verts=%s",
- dupe_first, "geom", amd->merge_dist,
- dupe_first, "geom");
-
- /* append the last dupe's geom to the findop input verts */
- BMO_slot_buffer_append(&find_op, slots_in, "verts",
- dupe_last, slots_out, "geom.out");
-
- BMO_op_exec(bm, &find_op);
-
- /* add new merge targets to weld operator */
- slot_targetmap = BMO_slot_get(weld_op->slots_in, "targetmap");
- BMO_ITER (v, &oiter, find_op.slots_out, "targetmap.out", 0) {
- if (!BMO_slot_map_contains(slot_targetmap, v)) {
- v2 = BMO_iter_map_value_ptr(&oiter);
- BMO_slot_map_elem_insert(weld_op, slot_targetmap, v, v2);
- }
+ int *index_orig;
+ int i;
+ MVert *mv;
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+
+ /* needed for subsurf so arrays are allocated */
+ cap_dm->getVertArray(cap_dm);
+ cap_dm->getEdgeArray(cap_dm);
+ cap_dm->getNumLoops(cap_dm);
+ cap_dm->getNumPolys(cap_dm);
+
+ DM_copy_vert_data(cap_dm, result, 0, cap_verts_index, cap_nverts);
+ DM_copy_edge_data(cap_dm, result, 0, cap_edges_index, cap_nedges);
+ DM_copy_loop_data(cap_dm, result, 0, cap_loops_index, cap_nloops);
+ DM_copy_poly_data(cap_dm, result, 0, cap_polys_index, cap_npolys);
+
+ mv = CDDM_get_verts(result) + cap_verts_index;
+
+ for (i = 0; i < cap_nverts; i++, mv++) {
+ mul_m4_v3(cap_offset, mv->co);
+ /* Reset MVert flags for caps */
+ mv->flag = mv->bweight = 0;
+ }
+
+ /* adjust cap edge vertex indices */
+ me = CDDM_get_edges(result) + cap_edges_index;
+ for (i = 0; i < cap_nedges; i++, me++) {
+ me->v1 += cap_verts_index;
+ me->v2 += cap_verts_index;
+ }
+
+ /* adjust cap poly loopstart indices */
+ mp = CDDM_get_polys(result) + cap_polys_index;
+ for (i = 0; i < cap_npolys; i++, mp++) {
+ mp->loopstart += cap_loops_index;
+ }
+
+ /* adjust cap loop vertex and edge indices */
+ ml = CDDM_get_loops(result) + cap_loops_index;
+ for (i = 0; i < cap_nloops; i++, ml++) {
+ ml->v += cap_verts_index;
+ ml->e += cap_edges_index;
+ }
+
+ /* set origindex */
+ index_orig = result->getVertDataArray(result, CD_ORIGINDEX);
+ if (index_orig) {
+ fill_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);
+ }
+
+ index_orig = result->getPolyDataArray(result, CD_ORIGINDEX);
+ if (index_orig) {
+ fill_vn_i(index_orig + cap_polys_index, cap_npolys, ORIGINDEX_NONE);
}
- BMO_op_finish(bm, &find_op);
+ index_orig = result->getLoopDataArray(result, CD_ORIGINDEX);
+ if (index_orig) {
+ fill_vn_i(index_orig + cap_loops_index, cap_nloops, ORIGINDEX_NONE);
+ }
}
-static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
- Scene *scene, Object *ob, DerivedMesh *dm,
- ModifierApplyFlag flag)
+static DerivedMesh *arrayModifier_doArray(
+ ArrayModifierData *amd,
+ Scene *scene, Object *ob, DerivedMesh *dm,
+ ModifierApplyFlag flag)
{
- DerivedMesh *result;
- BMesh *bm = DM_to_bmesh(dm, false);
- BMOperator first_dupe_op, dupe_op, old_dupe_op, weld_op;
- BMVert **first_geom = NULL;
- int i, j;
- int index_len = -1; /* initialize to an invalid value */
+ const float eps = 1e-6f;
+ const MVert *src_mvert;
+ MVert *mv, *mv_prev, *result_dm_verts;
+
+ MEdge *me;
+ MLoop *ml;
+ MPoly *mp;
+ int i, j, c, count;
+ float length = amd->length;
/* offset matrix */
float offset[4][4];
+ float scale[3];
+ bool offset_has_scale;
+ float current_offset[4][4];
float final_offset[4][4];
- float length = amd->length;
- int count = amd->count, maxVerts;
- int *indexMap = NULL;
- DerivedMesh *start_cap = NULL, *end_cap = NULL;
- MVert *src_mvert;
- BMOpSlot *slot_targetmap = NULL; /* for weld_op */
-
- /* need to avoid infinite recursion here */
- if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH)
- start_cap = get_dm_for_modifier(amd->start_cap, flag);
- if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH)
- end_cap = get_dm_for_modifier(amd->end_cap, flag);
+ int *full_doubles_map = NULL;
+ int tot_doubles;
+
+ const bool use_merge = amd->flags & MOD_ARR_MERGE;
+ const bool use_recalc_normals = (dm->dirty & DM_DIRTY_NORMALS) || use_merge;
+ const bool use_offset_ob = ((amd->offset_type & MOD_ARR_OFF_OBJ) && amd->offset_ob);
+ /* allow pole vertices to be used by many faces */
+ const bool with_follow = use_offset_ob;
+
+ int start_cap_nverts = 0, start_cap_nedges = 0, start_cap_npolys = 0, start_cap_nloops = 0;
+ int end_cap_nverts = 0, end_cap_nedges = 0, end_cap_npolys = 0, end_cap_nloops = 0;
+ int result_nverts = 0, result_nedges = 0, result_npolys = 0, result_nloops = 0;
+ int chunk_nverts, chunk_nedges, chunk_nloops, chunk_npolys;
+ int first_chunk_start, first_chunk_nverts, last_chunk_start, last_chunk_nverts;
+
+ DerivedMesh *result, *start_cap_dm = NULL, *end_cap_dm = NULL;
+
+ chunk_nverts = dm->getNumVerts(dm);
+ chunk_nedges = dm->getNumEdges(dm);
+ chunk_nloops = dm->getNumLoops(dm);
+ chunk_npolys = dm->getNumPolys(dm);
+
+ count = amd->count;
+
+ if (amd->start_cap && amd->start_cap != ob && amd->start_cap->type == OB_MESH) {
+ start_cap_dm = get_dm_for_modifier(amd->start_cap, flag);
+ if (start_cap_dm) {
+ start_cap_nverts = start_cap_dm->getNumVerts(start_cap_dm);
+ start_cap_nedges = start_cap_dm->getNumEdges(start_cap_dm);
+ start_cap_nloops = start_cap_dm->getNumLoops(start_cap_dm);
+ start_cap_npolys = start_cap_dm->getNumPolys(start_cap_dm);
+ }
+ }
+ if (amd->end_cap && amd->end_cap != ob && amd->end_cap->type == OB_MESH) {
+ end_cap_dm = get_dm_for_modifier(amd->end_cap, flag);
+ if (end_cap_dm) {
+ end_cap_nverts = end_cap_dm->getNumVerts(end_cap_dm);
+ end_cap_nedges = end_cap_dm->getNumEdges(end_cap_dm);
+ end_cap_nloops = end_cap_dm->getNumLoops(end_cap_dm);
+ end_cap_npolys = end_cap_dm->getNumPolys(end_cap_dm);
+ }
+ }
- unit_m4(offset);
+ /* Build up offset array, cumulating all settings options */
+ unit_m4(offset);
src_mvert = dm->getVertArray(dm);
- maxVerts = dm->getNumVerts(dm);
if (amd->offset_type & MOD_ARR_OFF_CONST)
add_v3_v3v3(offset[3], offset[3], amd->offset);
+
if (amd->offset_type & MOD_ARR_OFF_RELATIVE) {
for (j = 0; j < 3; j++)
- offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, maxVerts, j);
+ offset[3][j] += amd->scale[j] * vertarray_size(src_mvert, chunk_nverts, j);
}
- if ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)) {
+ if (use_offset_ob) {
float obinv[4][4];
float result_mat[4][4];
@@ -370,12 +466,15 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
else
unit_m4(obinv);
- mul_serie_m4(result_mat, offset,
- obinv, amd->offset_ob->obmat,
- NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(result_mat, offset,
+ obinv, amd->offset_ob->obmat);
copy_m4_m4(offset, result_mat);
}
+ /* Check if there is some scaling. If scaling, then we will not translate mapping */
+ mat4_to_size(scale, offset);
+ offset_has_scale = !is_one_v3(scale);
+
if (amd->fit_type == MOD_ARR_FITCURVE && amd->curve_ob) {
Curve *cu = amd->curve_ob->data;
if (cu) {
@@ -397,195 +496,253 @@ static DerivedMesh *arrayModifier_doArray(ArrayModifierData *amd,
if (amd->fit_type == MOD_ARR_FITLENGTH || amd->fit_type == MOD_ARR_FITCURVE) {
float dist = len_v3(offset[3]);
- if (dist > 1e-6f)
+ if (dist > eps) {
/* this gives length = first copy start to last copy end
* add a tiny offset for floating point rounding errors */
- count = (length + 1e-6f) / dist;
- else
+ count = (length + eps) / dist;
+ }
+ else {
/* if the offset has no translation, just make one copy */
count = 1;
+ }
}
if (count < 1)
count = 1;
- /* calculate the offset matrix of the final copy (for merging) */
- unit_m4(final_offset);
+ /* The number of verts, edges, loops, polys, before eventually merging doubles */
+ result_nverts = chunk_nverts * count + start_cap_nverts + end_cap_nverts;
+ result_nedges = chunk_nedges * count + start_cap_nedges + end_cap_nedges;
+ result_nloops = chunk_nloops * count + start_cap_nloops + end_cap_nloops;
+ result_npolys = chunk_npolys * count + start_cap_npolys + end_cap_npolys;
- for (j = 0; j < count - 1; j++) {
- float tmp_mat[4][4];
- mul_m4_m4m4(tmp_mat, offset, final_offset);
- copy_m4_m4(final_offset, tmp_mat);
- }
+ /* Initialize a result dm */
+ result = CDDM_from_template(dm, result_nverts, result_nedges, 0, result_nloops, result_npolys);
+ result_dm_verts = CDDM_get_verts(result);
- /* BMESH_TODO: bumping up the stack level avoids computing the normals
- * after every top-level operator execution (and this modifier has the
- * potential to execute a *lot* of top-level BMOps. There should be a
- * cleaner way to do this. One possibility: a "mirror" BMOp would
- * certainly help by compressing it all into one top-level BMOp that
- * executes a lot of second-level BMOps. */
- BM_mesh_elem_toolflags_ensure(bm);
- BMO_push(bm, NULL);
- bmesh_edit_begin(bm, 0);
-
- if (amd->flags & MOD_ARR_MERGE) {
- BMO_op_init(bm, &weld_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "weld_verts");
-
- slot_targetmap = BMO_slot_get(weld_op.slots_in, "targetmap");
+ 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);
}
- BMO_op_initf(bm, &dupe_op, (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "duplicate geom=%avef");
- first_dupe_op = dupe_op;
-
- for (j = 0; j < count - 1; j++) {
- BMVert *v, *v2, *v3;
- BMOpSlot *geom_slot;
- BMOpSlot *geom_out_slot;
- BMOIter oiter;
+ /* copy customdata to original geometry */
+ DM_copy_vert_data(dm, result, 0, 0, chunk_nverts);
+ DM_copy_edge_data(dm, result, 0, 0, chunk_nedges);
+ DM_copy_loop_data(dm, result, 0, 0, chunk_nloops);
+ DM_copy_poly_data(dm, result, 0, 0, chunk_npolys);
- if (j != 0) {
- BMO_op_initf(bm, &dupe_op,
- (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE),
- "duplicate geom=%S", &old_dupe_op, "geom.out");
- }
- BMO_op_exec(bm, &dupe_op);
-
- geom_slot = BMO_slot_get(dupe_op.slots_in, "geom");
- geom_out_slot = BMO_slot_get(dupe_op.slots_out, "geom.out");
-
- if ((amd->flags & MOD_ARR_MERGEFINAL) && j == 0) {
- int first_geom_bytes = sizeof(BMVert *) * geom_slot->len;
-
- /* make a copy of the initial geometry ordering so the
- * last duplicate can be merged into it */
- first_geom = MEM_mallocN(first_geom_bytes, "first_geom");
- memcpy(first_geom, geom_slot->data.buf, first_geom_bytes);
- }
+ /* subsurf for eg wont have mesh data in the
+ * now add mvert/medge/mface layers */
- /* apply transformation matrix */
- BMO_ITER (v, &oiter, dupe_op.slots_out, "geom.out", BM_VERT) {
- mul_m4_v3(offset, v->co);
- }
+ if (!CustomData_has_layer(&dm->vertData, CD_MVERT)) {
+ dm->copyVertArray(dm, result_dm_verts);
+ }
+ if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE)) {
+ dm->copyEdgeArray(dm, CDDM_get_edges(result));
+ }
+ if (!CustomData_has_layer(&dm->polyData, CD_MPOLY)) {
+ dm->copyLoopArray(dm, CDDM_get_loops(result));
+ dm->copyPolyArray(dm, CDDM_get_polys(result));
+ }
- if (amd->flags & MOD_ARR_MERGE) {
- /*calculate merge mapping*/
- if (j == 0) {
- indexMap = find_doubles_index_map(bm, &dupe_op,
- amd, &index_len);
+ /* Remember first chunk, in case of cap merge */
+ first_chunk_start = 0;
+ first_chunk_nverts = chunk_nverts;
+
+ unit_m4(current_offset);
+ for (c = 1; c < count; c++) {
+ /* copy customdata to new geometry */
+ DM_copy_vert_data(result, result, 0, c * chunk_nverts, chunk_nverts);
+ DM_copy_edge_data(result, result, 0, c * chunk_nedges, chunk_nedges);
+ DM_copy_loop_data(result, result, 0, c * chunk_nloops, chunk_nloops);
+ DM_copy_poly_data(result, result, 0, c * chunk_npolys, chunk_npolys);
+
+ mv_prev = result_dm_verts;
+ mv = mv_prev + c * chunk_nverts;
+
+ /* recalculate cumulative offset here */
+ mul_m4_m4m4(current_offset, current_offset, offset);
+
+ /* apply offset to all new verts */
+ for (i = 0; i < chunk_nverts; i++, mv++, mv_prev++) {
+ mul_m4_v3(current_offset, mv->co);
+
+ /* We have to correct normals too, if we do not tag them as dirty! */
+ if (!use_recalc_normals) {
+ float no[3];
+ normal_short_to_float_v3(no, mv->no);
+ mul_mat3_m4_v3(current_offset, no);
+ normalize_v3(no);
+ normal_float_to_short_v3(mv->no, no);
}
+ }
-#define _E(s, i) ((BMVert **)(s)->data.buf)[i]
-
- /* ensure this is set */
- BLI_assert(index_len != -1);
+ /* adjust edge vertex indices */
+ me = CDDM_get_edges(result) + c * chunk_nedges;
+ for (i = 0; i < chunk_nedges; i++, me++) {
+ me->v1 += c * chunk_nverts;
+ me->v2 += c * chunk_nverts;
+ }
- for (i = 0; i < index_len; i++) {
- if (!indexMap[i]) continue;
+ mp = CDDM_get_polys(result) + c * chunk_npolys;
+ for (i = 0; i < chunk_npolys; i++, mp++) {
+ mp->loopstart += c * chunk_nloops;
+ }
- /* merge v (from 'geom.out') into v2 (from old 'geom') */
- v = _E(geom_out_slot, i - geom_slot->len);
- v2 = _E(geom_slot, indexMap[i] - 1);
+ /* adjust loop vertex and edge indices */
+ ml = CDDM_get_loops(result) + c * chunk_nloops;
+ for (i = 0; i < chunk_nloops; i++, ml++) {
+ ml->v += c * chunk_nverts;
+ ml->e += c * chunk_nedges;
+ }
- /* check in case the target vertex (v2) is already marked
- * for merging */
- while ((v3 = BMO_slot_map_elem_get(slot_targetmap, v2))) {
- v2 = v3;
+ /* Handle merge between chunk n and n-1 */
+ if (use_merge && (c >= 1)) {
+ if (!offset_has_scale && (c >= 2)) {
+ /* Mapping chunk 3 to chunk 2 is a translation of mapping 2 to 1
+ * ... that is except if scaling makes the distance grow */
+ int k;
+ int this_chunk_index = c * chunk_nverts;
+ int prev_chunk_index = (c - 1) * chunk_nverts;
+ for (k = 0; k < chunk_nverts; k++, this_chunk_index++, prev_chunk_index++) {
+ int target = full_doubles_map[prev_chunk_index];
+ if (target != -1) {
+ target += chunk_nverts; /* translate mapping */
+ if (full_doubles_map[target] != -1) {
+ if (with_follow) {
+ target = full_doubles_map[target];
+ }
+ else {
+ /* The rule here is to not follow mapping to chunk N-2, which could be too far
+ * so if target vertex was itself mapped, then this vertex is not mapped */
+ target = -1;
+ }
+ }
+ }
+ full_doubles_map[this_chunk_index] = target;
}
-
- BMO_slot_map_elem_insert(&weld_op, slot_targetmap, v, v2);
}
-
-#undef _E
+ else {
+ dm_mvert_map_doubles(
+ full_doubles_map,
+ result_dm_verts,
+ (c - 1) * chunk_nverts,
+ chunk_nverts,
+ c * chunk_nverts,
+ chunk_nverts,
+ amd->merge_dist,
+ with_follow);
+ }
}
-
- /* already copied earlier, but after executation more slot
- * memory may be allocated */
- if (j == 0)
- first_dupe_op = dupe_op;
-
- if (j >= 2)
- BMO_op_finish(bm, &old_dupe_op);
- old_dupe_op = dupe_op;
}
- if ((amd->flags & MOD_ARR_MERGE) &&
- (amd->flags & MOD_ARR_MERGEFINAL) &&
- (count > 1))
- {
- /* Merge first and last copies. Note that we can't use the
- * indexMap for this because (unless the array is forming a
- * loop) the offset between first and last is different from
- * dupe X to dupe X+1. */
-
- merge_first_last(bm, amd, &first_dupe_op, &dupe_op, &weld_op);
+ last_chunk_start = (count - 1) * chunk_nverts;
+ last_chunk_nverts = chunk_nverts;
+
+ copy_m4_m4(final_offset, current_offset);
+
+ if (use_merge && (amd->flags & MOD_ARR_MERGEFINAL) && (count > 1)) {
+ /* Merge first and last copies */
+ dm_mvert_map_doubles(
+ full_doubles_map,
+ result_dm_verts,
+ last_chunk_start,
+ last_chunk_nverts,
+ first_chunk_start,
+ first_chunk_nverts,
+ amd->merge_dist,
+ with_follow);
}
/* start capping */
- if (start_cap || end_cap) {
- BM_mesh_elem_hflag_enable_all(bm, BM_VERT, BM_ELEM_TAG, false);
-
- if (start_cap) {
- float startoffset[4][4];
- invert_m4_m4(startoffset, offset);
- bm_merge_dm_transform(bm, start_cap, startoffset, amd,
- &first_dupe_op, first_dupe_op.slots_in, "geom", &weld_op);
+ if (start_cap_dm) {
+ float start_offset[4][4];
+ int start_cap_start = result_nverts - start_cap_nverts - end_cap_nverts;
+ invert_m4_m4(start_offset, offset);
+ dm_merge_transform(
+ result, start_cap_dm, start_offset,
+ result_nverts - start_cap_nverts - end_cap_nverts,
+ result_nedges - start_cap_nedges - end_cap_nedges,
+ result_nloops - start_cap_nloops - end_cap_nloops,
+ result_npolys - start_cap_npolys - end_cap_npolys,
+ start_cap_nverts, start_cap_nedges, start_cap_nloops, start_cap_npolys);
+ /* Identify doubles with first chunk */
+ if (use_merge) {
+ dm_mvert_map_doubles(
+ full_doubles_map,
+ result_dm_verts,
+ first_chunk_start,
+ first_chunk_nverts,
+ start_cap_start,
+ start_cap_nverts,
+ amd->merge_dist,
+ false);
}
+ }
- if (end_cap) {
- float endoffset[4][4];
- mul_m4_m4m4(endoffset, offset, final_offset);
- bm_merge_dm_transform(bm, end_cap, endoffset, amd,
- &dupe_op, (count == 1) ? dupe_op.slots_in : dupe_op.slots_out,
- (count == 1) ? "geom" : "geom.out", &weld_op);
+ if (end_cap_dm) {
+ float end_offset[4][4];
+ int end_cap_start = result_nverts - end_cap_nverts;
+ mul_m4_m4m4(end_offset, current_offset, offset);
+ dm_merge_transform(
+ result, end_cap_dm, end_offset,
+ result_nverts - end_cap_nverts,
+ result_nedges - end_cap_nedges,
+ result_nloops - end_cap_nloops,
+ result_npolys - end_cap_npolys,
+ end_cap_nverts, end_cap_nedges, end_cap_nloops, end_cap_npolys);
+ /* Identify doubles with last chunk */
+ if (use_merge) {
+ dm_mvert_map_doubles(
+ full_doubles_map,
+ result_dm_verts,
+ last_chunk_start,
+ last_chunk_nverts,
+ end_cap_start,
+ end_cap_nverts,
+ amd->merge_dist,
+ false);
}
}
/* done capping */
- /* free remaining dupe operators */
- BMO_op_finish(bm, &first_dupe_op);
- if (count > 2)
- BMO_op_finish(bm, &dupe_op);
-
- /* run merge operator */
- if (amd->flags & MOD_ARR_MERGE) {
- BMO_op_exec(bm, &weld_op);
- BMO_op_finish(bm, &weld_op);
+ /* Handle merging */
+ tot_doubles = 0;
+ if (use_merge) {
+ for (i = 0; i < result_nverts; i++) {
+ if (full_doubles_map[i] != -1) {
+ if (i == full_doubles_map[i]) {
+ full_doubles_map[i] = -1;
+ }
+ else {
+ tot_doubles++;
+ }
+ }
+ }
+ if (tot_doubles > 0) {
+ result = CDDM_merge_verts(result, full_doubles_map, tot_doubles, CDDM_MERGE_VERTS_DUMP_IF_EQUAL);
+ }
+ MEM_freeN(full_doubles_map);
}
- /* Bump the stack level back down to match the adjustment up above */
- BMO_pop(bm);
-
- result = CDDM_from_bmesh(bm, false);
-
- if ((dm->dirty & DM_DIRTY_NORMALS) ||
- ((amd->offset_type & MOD_ARR_OFF_OBJ) && (amd->offset_ob)))
- {
- /* Update normals in case offset object has rotation. */
+ /* In case org dm has dirty normals, or we made some merging, mark normals as dirty in new dm!
+ * TODO: we may need to set other dirty flags as well?
+ */
+ if (use_recalc_normals) {
result->dirty |= DM_DIRTY_NORMALS;
}
- BM_mesh_free(bm);
-
- if (indexMap)
- MEM_freeN(indexMap);
- if (first_geom)
- MEM_freeN(first_geom);
-
return result;
}
+
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm,
ModifierApplyFlag flag)
{
- DerivedMesh *result;
ArrayModifierData *amd = (ArrayModifierData *) md;
-
- result = arrayModifier_doArray(amd, md->scene, ob, dm, flag);
-
- return result;
+ return arrayModifier_doArray(amd, md->scene, ob, dm, flag);
}
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index fc65990df20..1dca18dce37 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -57,6 +57,7 @@ static void initData(ModifierData *md)
bmd->val_flags = MOD_BEVEL_AMT_OFFSET;
bmd->lim_flags = 0;
bmd->e_flags = 0;
+ bmd->mat = -1;
bmd->profile = 0.5f;
bmd->bevel_angle = DEG2RADF(30.0f);
bmd->defgrp_name[0] = '\0';
@@ -73,6 +74,7 @@ static void copyData(ModifierData *md, ModifierData *target)
tbmd->val_flags = bmd->val_flags;
tbmd->lim_flags = bmd->lim_flags;
tbmd->e_flags = bmd->e_flags;
+ tbmd->mat = bmd->mat;
tbmd->profile = bmd->profile;
tbmd->bevel_angle = bmd->bevel_angle;
BLI_strncpy(tbmd->defgrp_name, bmd->defgrp_name, sizeof(tbmd->defgrp_name));
@@ -109,6 +111,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob,
const bool vertex_only = (bmd->flags & MOD_BEVEL_VERT) != 0;
const bool do_clamp = !(bmd->flags & MOD_BEVEL_OVERLAP_OK);
const int offset_type = bmd->val_flags;
+ const int mat = CLAMPIS(bmd->mat, -1, ob->totcol - 1);
bm = DM_to_bmesh(dm, true);
if ((bmd->lim_flags & MOD_BEVEL_VGROUP) && bmd->defgrp_name[0])
@@ -118,7 +121,12 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob,
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
if (!BM_vert_is_manifold(v))
continue;
- if (vgroup != -1) {
+ if (bmd->lim_flags & MOD_BEVEL_WEIGHT) {
+ weight = BM_elem_float_data_get(&bm->vdata, v, CD_BWEIGHT);
+ if (weight == 0.0f)
+ continue;
+ }
+ else if (vgroup != -1) {
weight = defvert_array_find_weight_safe(dvert, BM_elem_index_get(v), vgroup);
/* Check is against 0.5 rather than != 0.0 because cascaded bevel modifiers will
* interpolate weights for newly created vertices, and may cause unexpected "selection" */
@@ -165,7 +173,7 @@ static DerivedMesh *applyModifier(ModifierData *md, struct Object *ob,
BM_mesh_bevel(bm, bmd->value, offset_type, bmd->res, bmd->profile,
vertex_only, bmd->lim_flags & MOD_BEVEL_WEIGHT, do_clamp,
- dvert, vgroup);
+ dvert, vgroup, mat);
result = CDDM_from_bmesh(bm, true);
diff --git a/source/blender/modifiers/intern/MOD_boolean_util.c b/source/blender/modifiers/intern/MOD_boolean_util.c
index 99016a0a41b..6e62a21ec4c 100644
--- a/source/blender/modifiers/intern/MOD_boolean_util.c
+++ b/source/blender/modifiers/intern/MOD_boolean_util.c
@@ -267,9 +267,11 @@ typedef struct ExportMeshData {
DerivedMesh *dm_left;
DerivedMesh *dm_right;
MVert *mvert_left;
+ MEdge *medge_left;
MLoop *mloop_left;
MPoly *mpoly_left;
MVert *mvert_right;
+ MEdge *medge_right;
MLoop *mloop_right;
MPoly *mpoly_right;
@@ -321,6 +323,20 @@ BLI_INLINE MVert *which_mvert(ExportMeshData *export_data, int which_mesh)
return mvert;
}
+BLI_INLINE MEdge *which_medge(ExportMeshData *export_data, int which_mesh)
+{
+ MEdge *medge = NULL;
+ switch (which_mesh) {
+ case CARVE_MESH_LEFT:
+ medge = export_data->medge_left;
+ break;
+ case CARVE_MESH_RIGHT:
+ medge = export_data->medge_right;
+ break;
+ }
+ return medge;
+}
+
BLI_INLINE MLoop *which_mloop(ExportMeshData *export_data, int which_mesh)
{
MLoop *mloop = NULL;
@@ -367,7 +383,7 @@ static void exporter_InitGeomArrays(ExportMeshData *export_data,
DerivedMesh *dm_left = export_data->dm_left,
*dm_right = export_data->dm_right;
- /* Mask for custom data layers to be merhed from operands. */
+ /* Mask for custom data layers to be merged from operands. */
CustomDataMask merge_mask = CD_MASK_DERIVEDMESH & ~CD_MASK_ORIGINDEX;
export_data->dm = dm;
@@ -397,6 +413,9 @@ static void exporter_InitGeomArrays(ExportMeshData *export_data,
CustomData_merge(&dm_left->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys);
CustomData_merge(&dm_right->polyData, &dm->polyData, merge_mask, CD_DEFAULT, num_polys);
+ CustomData_merge(&dm_left->edgeData, &dm->edgeData, merge_mask, CD_DEFAULT, num_edges);
+ CustomData_merge(&dm_right->edgeData, &dm->edgeData, merge_mask, CD_DEFAULT, num_edges);
+
export_data->vert_origindex = dm->getVertDataArray(dm, CD_ORIGINDEX);
export_data->edge_origindex = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
export_data->poly_origindex = dm->getPolyDataArray(dm, CD_ORIGINDEX);
@@ -417,6 +436,7 @@ static void exporter_SetVert(ExportMeshData *export_data,
dm_orig = which_dm(export_data, which_orig_mesh);
if (dm_orig) {
BLI_assert(orig_vert_index >= 0 && orig_vert_index < dm_orig->getNumVerts(dm_orig));
+ mvert[vert_index] = which_mvert(export_data, which_orig_mesh)[orig_vert_index];
CustomData_copy_data(&dm_orig->vertData, &dm->vertData, orig_vert_index, vert_index, 1);
}
@@ -450,7 +470,9 @@ static void exporter_SetEdge(ExportMeshData *export_data,
if (dm_orig) {
BLI_assert(orig_edge_index >= 0 && orig_edge_index < dm_orig->getNumEdges(dm_orig));
- /* Copy all edge layers, including mpoly. */
+ *medge = which_medge(export_data, which_orig_mesh)[orig_edge_index];
+
+ /* Copy all edge layers, including medge. */
CustomData_copy_data(&dm_orig->edgeData, &dm->edgeData, orig_edge_index, edge_index, 1);
}
@@ -537,6 +559,7 @@ static void exporter_SetPoly(ExportMeshData *export_data,
BLI_assert(orig_poly_index >= 0 && orig_poly_index < dm_orig->getNumPolys(dm_orig));
/* Copy all poly layers, including mpoly. */
+ *mpoly = which_mpoly(export_data, which_orig_mesh)[orig_poly_index];
CustomData_copy_data(&dm_orig->polyData, &dm->polyData, orig_poly_index, poly_index, 1);
/* Set material of the curren poly.
@@ -604,7 +627,8 @@ static void exporter_SetLoop(ExportMeshData *export_data,
if (dm_orig) {
BLI_assert(orig_loop_index >= 0 && orig_loop_index < dm_orig->getNumLoops(dm_orig));
- /* Copy all loop layers, including mpoly. */
+ /* Copy all loop layers, including mloop. */
+ *mloop = which_mloop(export_data, which_orig_mesh)[orig_loop_index];
CustomData_copy_data(&dm_orig->loopData, &dm->loopData, orig_loop_index, loop_index, 1);
}
@@ -706,9 +730,11 @@ static void prepare_export_data(Object *object_left, DerivedMesh *dm_left, const
export_data->dm_right = dm_right;
export_data->mvert_left = dm_left_arrays->mvert;
+ export_data->medge_left = dm_left_arrays->medge;
export_data->mloop_left = dm_left_arrays->mloop;
export_data->mpoly_left = dm_left_arrays->mpoly;
export_data->mvert_right = dm_right_arrays->mvert;
+ export_data->medge_right = dm_right_arrays->medge;
export_data->mloop_right = dm_right_arrays->mloop;
export_data->mpoly_right = dm_right_arrays->mpoly;
@@ -766,6 +792,7 @@ DerivedMesh *NewBooleanDerivedMesh(DerivedMesh *dm, struct Object *ob,
/* Free memory used by export mesh. */
BLI_ghash_free(export_data.material_hash, NULL, NULL);
+ output_dm->cd_flag |= dm->cd_flag | dm_select->cd_flag;
output_dm->dirty |= DM_DIRTY_NORMALS;
carve_deleteMesh(output);
}
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index ec077631c85..c4654287cfc 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -151,8 +151,8 @@ static void sphere_do(
* we use its location, transformed to ob's local space */
if (ctrl_ob) {
if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- invert_m4_m4(ctrl_ob->imat, ctrl_ob->obmat);
- mul_m4_m4m4(mat, ctrl_ob->imat, ob->obmat);
+ invert_m4_m4(imat, ctrl_ob->obmat);
+ mul_m4_m4m4(mat, imat, ob->obmat);
invert_m4_m4(imat, mat);
}
@@ -275,8 +275,8 @@ static void cuboid_do(
if (ctrl_ob) {
if (flag & MOD_CAST_USE_OB_TRANSFORM) {
- invert_m4_m4(ctrl_ob->imat, ctrl_ob->obmat);
- mul_m4_m4m4(mat, ctrl_ob->imat, ob->obmat);
+ invert_m4_m4(imat, ctrl_ob->obmat);
+ mul_m4_m4m4(mat, imat, ob->obmat);
invert_m4_m4(imat, mat);
}
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 6bda8210f81..1561fd1a981 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -32,8 +32,10 @@
* \ingroup modifiers
*/
+#include <string.h>
#include "DNA_cloth_types.h"
+#include "DNA_key_types.h"
#include "DNA_scene_types.h"
#include "DNA_object_types.h"
@@ -45,6 +47,7 @@
#include "BKE_cloth.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
+#include "BKE_key.h"
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
@@ -68,7 +71,7 @@ static void initData(ModifierData *md)
}
static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3],
- int UNUSED(numVerts), ModifierApplyFlag UNUSED(flag))
+ int numVerts, ModifierApplyFlag UNUSED(flag))
{
DerivedMesh *dm;
ClothModifierData *clmd = (ClothModifierData *) md;
@@ -85,6 +88,26 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData,
if (dm == derivedData)
dm = CDDM_copy(dm);
+ /* TODO(sergey): For now it actually duplicates logic from DerivedMesh.c
+ * and needs some more generic solution. But starting experimenting with
+ * this so close to the release is not that nice..
+ *
+ * Also hopefully new cloth system will arrive soon..
+ */
+ 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) {
+ 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);
+ layerorco = DM_get_vert_data_layer(dm, CD_CLOTH_ORCO);
+ }
+
+ memcpy(layerorco, kb->data, sizeof(float) * 3 * numVerts);
+ }
+ }
+
CDDM_apply_vert_coords(dm, vertexCos);
DM_ensure_tessface(dm); /* BMESH - UNTIL MODIFIER IS UPDATED FOR MPoly */
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 127972a2e40..d3c7e7d4779 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -217,7 +217,7 @@ static MFace *get_dface(DerivedMesh *dm, DerivedMesh *split, int cur, int i, MFa
} (void)0
#define GET_ES(v1, v2) edgecut_get(eh, v1, v2)
-#define INT_UV(uvf, c0, c1) interp_v2_v2v2(uvf, mf->uv[c0], mf->uv[c1], 0.5f)
+#define INT_UV(uvf, c0, c1) mid_v2_v2v2(uvf, mf->uv[c0], mf->uv[c1])
static void remap_faces_3_6_9_12(DerivedMesh *dm, DerivedMesh *split, MFace *mf, int *facepa, int *vertpa, int i, EdgeHash *eh, int cur, int v1, int v2, int v3, int v4)
{
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index c89bc8c1d41..f6d7c03df32 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -156,8 +156,7 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
copy_m4_m4(dmat, hmd->object->obmat);
}
invert_m4_m4(ob->imat, ob->obmat);
- mul_serie_m4(mat, ob->imat, dmat, hmd->parentinv,
- NULL, NULL, NULL, NULL, NULL);
+ mul_m4_series(mat, ob->imat, dmat, hmd->parentinv);
modifier_get_vgroup(ob, dm, hmd->name, &dvert, &defgrp_index);
max_dvert = (dvert) ? numVerts : 0;
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index d3bd05baa6d..ffadcda3e8c 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -28,8 +28,9 @@
* \ingroup modifiers
*/
-#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_stackdefines.h"
+#include "BLI_math.h"
#include "BLI_string.h"
#include "MEM_guardedalloc.h"
@@ -603,7 +604,8 @@ static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh
int *index_anchors = MEM_mallocN(sizeof(int) * numVerts, __func__); /* over-alloc */
MFace *tessface;
STACK_DECLARE(index_anchors);
- STACK_INIT(index_anchors);
+
+ STACK_INIT(index_anchors, numVerts);
modifier_get_vgroup(ob, dm, lmd->anchor_grp_name, &dvert, &defgrp_index);
BLI_assert(dvert != NULL);
@@ -623,7 +625,6 @@ static void initSystem(LaplacianDeformModifierData *lmd, Object *ob, DerivedMesh
memcpy(sys->index_anchors, index_anchors, sizeof(int) * total_anchors);
memcpy(sys->co, vertexCos, sizeof(float[3]) * numVerts);
MEM_freeN(index_anchors);
- STACK_FREE(index_anchors);
lmd->vertexco = MEM_mallocN(sizeof(float[3]) * numVerts, "ModDeformCoordinates");
memcpy(lmd->vertexco, vertexCos, sizeof(float[3]) * numVerts);
lmd->total_verts = numVerts;
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 7f21376ef48..838336a8f8a 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -153,7 +153,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
const int defbase_tot = BLI_countlist(&ob->defbase);
/* check that there is armature object with bones to use, otherwise return original mesh */
- if (ELEM3(NULL, oba, oba->pose, ob->defbase.first))
+ if (ELEM(NULL, oba, oba->pose, ob->defbase.first))
return dm;
/* determine whether each vertexgroup is associated with a selected bone or not
diff --git a/source/blender/modifiers/intern/MOD_meshcache_mdd.c b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
index 0cbf07ca907..90fc750de3b 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_mdd.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_mdd.c
@@ -30,9 +30,11 @@
#include "BLI_sys_types.h"
#include "BLI_utildefines.h"
-#include "BLI_endian_switch.h"
#include "BLI_fileops.h"
#include "BLI_math.h"
+#ifdef __LITTLE_ENDIAN__
+# include "BLI_endian_switch.h"
+#endif
#include "MOD_meshcache_util.h" /* own include */
diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
index ac0363f8673..3ef0ee54886 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
@@ -32,6 +32,9 @@
#include "BLI_utildefines.h"
#include "BLI_fileops.h"
#include "BLI_math.h"
+#ifdef __BIG_ENDIAN__
+# include "BLI_endian_switch.h"
+#endif
#include "MOD_meshcache_util.h" /* own include */
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 959bbdcbca9..c509bf44fc8 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -37,6 +37,7 @@
#include "DNA_scene_types.h"
#include "BLI_math.h"
+#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BLF_translation.h"
@@ -53,6 +54,9 @@
#include "MOD_util.h"
+#ifdef __SSE2__
+# include <emmintrin.h>
+#endif
static void initData(ModifierData *md)
{
@@ -133,11 +137,15 @@ static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3
{
MDefCell *cell;
MDefInfluence *inf;
- float gridvec[3], dvec[3], ivec[3], co[3], wx, wy, wz;
+ float gridvec[3], dvec[3], ivec[3], wx, wy, wz;
float weight, cageweight, totweight, *cageco;
int i, j, a, x, y, z, size;
+#ifdef __SSE2__
+ __m128 co = _mm_setzero_ps();
+#else
+ float co[3] = {0.0f, 0.0f, 0.0f};
+#endif
- zero_v3(co);
totweight = 0.0f;
size = mmd->dyngridsize;
@@ -169,18 +177,103 @@ static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3
for (j = 0; j < cell->totinfluence; j++, inf++) {
cageco = dco[inf->vertex];
cageweight = weight * inf->weight;
+#ifdef __SSE2__
+ {
+ __m128 cageweight_r = _mm_set1_ps(cageweight);
+ /* This will load one extra element, this is ok because
+ * we ignore that part of register anyway.
+ */
+ __m128 cageco_r = _mm_loadu_ps(cageco);
+ co = _mm_add_ps(co,
+ _mm_mul_ps(cageco_r, cageweight_r));
+ }
+#else
co[0] += cageweight * cageco[0];
co[1] += cageweight * cageco[1];
co[2] += cageweight * cageco[2];
+#endif
totweight += cageweight;
}
}
+#ifdef __SSE2__
+ copy_v3_v3(vec, (float *)&co);
+#else
copy_v3_v3(vec, co);
+#endif
return totweight;
}
+typedef struct MeshdeformUserdata {
+ /*const*/ MeshDeformModifierData *mmd;
+ const MDeformVert *dvert;
+ /*const*/ float (*dco)[3];
+ int defgrp_index;
+ float (*vertexCos)[3];
+ float (*cagemat)[4];
+ float (*icagemat)[3];
+ SpinLock lock;
+} MeshdeformUserdata;
+
+static void meshdeform_vert_task(void *userdata, int iter)
+{
+ MeshdeformUserdata *data = userdata;
+ /*const*/ MeshDeformModifierData *mmd = data->mmd;
+ const MDeformVert *dvert = data->dvert;
+ const int defgrp_index = data->defgrp_index;
+ const int *offsets = mmd->bindoffsets;
+ const MDefInfluence *influences = influences = mmd->bindinfluences;
+ /*const*/ float (*dco)[3] = data->dco;
+ float (*vertexCos)[3] = data->vertexCos;
+ float co[3];
+ float weight, totweight, fac = 1.0f;
+
+ if (mmd->flag & MOD_MDEF_DYNAMIC_BIND)
+ if (!mmd->dynverts[iter])
+ return;
+
+ if (dvert) {
+ fac = defvert_find_weight(&dvert[iter], defgrp_index);
+
+ if (mmd->flag & MOD_MDEF_INVERT_VGROUP) {
+ fac = 1.0f - fac;
+ }
+
+ if (fac <= 0.0f) {
+ return;
+ }
+ }
+
+ if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
+ /* transform coordinate into cage's local space */
+ mul_v3_m4v3(co, data->cagemat, vertexCos[iter]);
+ totweight = meshdeform_dynamic_bind(mmd, dco, co);
+ }
+ else {
+ int a;
+ totweight = 0.0f;
+ zero_v3(co);
+
+ for (a = offsets[iter]; a < offsets[iter + 1]; a++) {
+ weight = influences[a].weight;
+ madd_v3_v3fl(co, dco[influences[a].vertex], weight);
+ totweight += weight;
+ }
+ }
+
+ if (totweight > 0.0f) {
+ mul_v3_fl(co, fac / totweight);
+ mul_m3_v3(data->icagemat, co);
+ BLI_spin_lock(&data->lock);
+ if (G.debug_value != 527)
+ add_v3_v3(vertexCos[iter], co);
+ else
+ copy_v3_v3(vertexCos[iter], co);
+ BLI_spin_unlock(&data->lock);
+ }
+}
+
static void meshdeformModifier_do(
ModifierData *md, Object *ob, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
@@ -188,12 +281,11 @@ static void meshdeformModifier_do(
MeshDeformModifierData *mmd = (MeshDeformModifierData *) md;
DerivedMesh *tmpdm, *cagedm;
MDeformVert *dvert = NULL;
- MDefInfluence *influences;
- const int *offsets;
float imat[4][4], cagemat[4][4], iobmat[4][4], icagemat[3][3], cmat[4][4];
- float weight, totweight, fac, co[3], (*dco)[3], (*bindcagecos)[3];
- int a, b, totvert, totcagevert, defgrp_index;
+ float co[3], (*dco)[3], (*bindcagecos)[3];
+ int a, totvert, totcagevert, defgrp_index;
float (*cagecos)[3];
+ MeshdeformUserdata data;
if (!mmd->object || (!mmd->bindcagecos && !mmd->bindfunc))
return;
@@ -273,11 +365,13 @@ static void meshdeformModifier_do(
/* setup deformation data */
cagedm->getVertCos(cagedm, cagecos);
- influences = mmd->bindinfluences;
- offsets = mmd->bindoffsets;
bindcagecos = (float(*)[3])mmd->bindcagecos;
- dco = MEM_callocN(sizeof(*dco) * totcagevert, "MDefDco");
+ /* We allocate 1 element extra to make it possible to
+ * load the values to SSE registers, which are float4.
+ */
+ dco = MEM_callocN(sizeof(*dco) * (totcagevert + 1), "MDefDco");
+ zero_v3(dco[totcagevert]);
for (a = 0; a < totcagevert; a++) {
/* get cage vertex in world space with binding transform */
copy_v3_v3(co, cagecos[a]);
@@ -293,51 +387,21 @@ static void meshdeformModifier_do(
modifier_get_vgroup(ob, dm, mmd->defgrp_name, &dvert, &defgrp_index);
- /* do deformation */
- fac = 1.0f;
-
- for (b = 0; b < totvert; b++) {
- if (mmd->flag & MOD_MDEF_DYNAMIC_BIND)
- if (!mmd->dynverts[b])
- continue;
-
- if (dvert) {
- fac = defvert_find_weight(&dvert[b], defgrp_index);
-
- if (mmd->flag & MOD_MDEF_INVERT_VGROUP) {
- fac = 1.0f - fac;
- }
-
- if (fac <= 0.0f) {
- continue;
- }
- }
-
- if (mmd->flag & MOD_MDEF_DYNAMIC_BIND) {
- /* transform coordinate into cage's local space */
- mul_v3_m4v3(co, cagemat, vertexCos[b]);
- totweight = meshdeform_dynamic_bind(mmd, dco, co);
- }
- else {
- totweight = 0.0f;
- zero_v3(co);
-
- for (a = offsets[b]; a < offsets[b + 1]; a++) {
- weight = influences[a].weight;
- madd_v3_v3fl(co, dco[influences[a].vertex], weight);
- totweight += weight;
- }
- }
-
- if (totweight > 0.0f) {
- mul_v3_fl(co, fac / totweight);
- mul_m3_v3(icagemat, co);
- if (G.debug_value != 527)
- add_v3_v3(vertexCos[b], co);
- else
- copy_v3_v3(vertexCos[b], co);
- }
- }
+ /* Initialize data to be pass to the for body function. */
+ data.mmd = mmd;
+ data.dvert = dvert;
+ data.dco = dco;
+ data.defgrp_index = defgrp_index;
+ data.vertexCos = vertexCos;
+ data.cagemat = cagemat;
+ data.icagemat = icagemat;
+ BLI_spin_init(&data.lock);
+
+ /* Do deformation. */
+ BLI_task_parallel_range(0, totvert, &data, meshdeform_vert_task);
+
+ /* Uninitialize user dtaa used by the task system. */
+ BLI_spin_end(&data.lock);
/* release cage derivedmesh */
MEM_freeN(dco);
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 5cece9d349f..5de4a76dcbe 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -290,7 +290,7 @@ static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
/* slow - so only call if one or more merge verts are found,
* users may leave this on and not realize there is nothing to merge - campbell */
if (tot_vtargetmap) {
- result = CDDM_merge_verts(result, vtargetmap, tot_vtargetmap);
+ result = CDDM_merge_verts(result, vtargetmap, tot_vtargetmap, CDDM_MERGE_VERTS_DUMP_IF_MAPPED);
}
MEM_freeN(vtargetmap);
}
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index c95cd96757f..deae10b5bcb 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -74,7 +74,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
MultiresModifierData *mmd = (MultiresModifierData *)md;
DerivedMesh *result;
Mesh *me = (Mesh *)ob->data;
- const int useRenderParams = flag & MOD_APPLY_RENDER;
+ const bool useRenderParams = (flag & MOD_APPLY_RENDER) != 0;
+ const bool ignore_simplify = (flag & MOD_APPLY_IGNORE_SIMPLIFY) != 0;
MultiresFlags flags = 0;
const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK);
@@ -91,6 +92,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm,
if (useRenderParams)
flags |= MULTIRES_USE_RENDER_PARAMS;
+ if (ignore_simplify)
+ flags |= MULTIRES_IGNORE_SIMPLIFY;
+
result = multires_make_derived_from_derived(dm, mmd, ob, flags);
if (result == dm)
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index ff7cc01232b..5900baaf537 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -362,7 +362,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) {
for (i = 0, mv_orig = mvert_orig; i < totvert; i++, mv_orig++) {
- const float v = dist_squared_to_plane_v3(mv_orig->co, uv_axis_plane);
+ const float v = dist_signed_squared_to_plane_v3(mv_orig->co, uv_axis_plane);
uv_v_minmax[0] = min_ff(v, uv_v_minmax[0]);
uv_v_minmax[1] = max_ff(v, uv_v_minmax[1]);
}
@@ -897,8 +897,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
if (has_mloop_orig == false && mloopuv_layers_tot) {
- uv_v_offset_a = dist_to_plane_v3(mvert_new[medge_new[i].v1].co, uv_axis_plane);
- uv_v_offset_b = dist_to_plane_v3(mvert_new[medge_new[i].v2].co, uv_axis_plane);
+ uv_v_offset_a = dist_signed_to_plane_v3(mvert_new[medge_new[i].v1].co, uv_axis_plane);
+ uv_v_offset_b = dist_signed_to_plane_v3(mvert_new[medge_new[i].v2].co, uv_axis_plane);
if (ltmd->flag & MOD_SCREW_UV_STRETCH_V) {
uv_v_offset_a = (uv_v_offset_a - uv_v_minmax[0]) * uv_v_range_inv;
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index eebb687aa8d..229f4911ab4 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -37,6 +37,7 @@
#include "DNA_object_types.h"
+#include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index ccba2097264..3314196b776 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -42,7 +42,6 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
-#include "BKE_shrinkwrap.h"
#include "depsgraph_private.h"
@@ -166,7 +165,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
/* Calculate matrixs do convert between coordinate spaces */
if (smd->origin) {
transf = &tmp_transf;
- space_transform_from_matrixs(transf, ob->obmat, smd->origin->obmat);
+ BLI_SPACE_TRANSFORM_SETUP(transf, ob, smd->origin);
}
/* Setup vars,
@@ -182,7 +181,9 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
float tmp[3];
copy_v3_v3(tmp, vertexCos[i]);
- if (transf) space_transform_apply(transf, tmp);
+ if (transf) {
+ BLI_space_transform_apply(transf, tmp);
+ }
lower = min_ff(lower, tmp[limit_axis]);
upper = max_ff(upper, tmp[limit_axis]);
@@ -220,7 +221,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
float co[3], dcut[3] = {0.0f, 0.0f, 0.0f};
if (transf) {
- space_transform_apply(transf, vertexCos[i]);
+ BLI_space_transform_apply(transf, vertexCos[i]);
}
copy_v3_v3(co, vertexCos[i]);
@@ -236,7 +237,7 @@ static void SimpleDeformModifier_do(SimpleDeformModifierData *smd, struct Object
interp_v3_v3v3(vertexCos[i], vertexCos[i], co, weight); /* Use vertex weight has coef of linear interpolation */
if (transf) {
- space_transform_invert(transf, vertexCos[i]);
+ BLI_space_transform_invert(transf, vertexCos[i]);
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 019eb54a9ee..1e422806d80 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -68,6 +68,7 @@
#include "BLI_heap.h"
#include "BLI_math.h"
#include "BLI_stack.h"
+#include "BLI_bitmap.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_deform.h"
@@ -217,6 +218,7 @@ static bool skin_frame_find_contained_faces(const Frame *frame,
/* Returns true if hull is successfully built, false otherwise */
static bool build_hull(SkinOutput *so, Frame **frames, int totframe)
{
+#ifdef WITH_BULLET
BMesh *bm = so->bm;
BMOperator op;
BMIter iter;
@@ -325,6 +327,11 @@ static bool build_hull(SkinOutput *so, Frame **frames, int totframe)
BM_mesh_delete_hflag_tagged(bm, BM_ELEM_TAG, BM_EDGE | BM_FACE);
return true;
+#else
+ (void)so, (void)frames, (void)totframe;
+ (void)skin_frame_find_contained_faces;
+ return false;
+#endif
}
/* Returns the average frame side length (frames are rectangular, so
@@ -641,7 +648,7 @@ typedef struct {
int e;
} EdgeStackElem;
-static void build_emats_stack(BLI_Stack *stack, int *visited_e, EMat *emat,
+static void build_emats_stack(BLI_Stack *stack, BLI_bitmap *visited_e, EMat *emat,
const MeshElemMap *emap, const MEdge *medge,
const MVertSkin *vs, const MVert *mvert)
{
@@ -654,11 +661,11 @@ static void build_emats_stack(BLI_Stack *stack, int *visited_e, EMat *emat,
e = stack_elem.e;
/* Skip if edge already visited */
- if (visited_e[e])
+ if (BLI_BITMAP_TEST(visited_e, e))
return;
/* Mark edge as visited */
- visited_e[e] = true;
+ BLI_BITMAP_ENABLE(visited_e, e);
/* Process edge */
@@ -704,11 +711,12 @@ static EMat *build_edge_mats(const MVertSkin *vs,
BLI_Stack *stack;
EMat *emat;
EdgeStackElem stack_elem;
- int *visited_e, i, v;
+ BLI_bitmap *visited_e;
+ int i, v;
stack = BLI_stack_new(sizeof(stack_elem), "build_edge_mats.stack");
- visited_e = MEM_callocN(sizeof(int) * totedge, "build_edge_mats.visited_e");
+ visited_e = BLI_BITMAP_NEW(totedge, "build_edge_mats.visited_e");
emat = MEM_callocN(sizeof(EMat) * totedge, "build_edge_mats.emat");
/* Edge matrices are built from the root nodes, add all roots with
@@ -730,7 +738,7 @@ static EMat *build_edge_mats(const MVertSkin *vs,
}
}
- while (!BLI_stack_empty(stack)) {
+ while (!BLI_stack_is_empty(stack)) {
build_emats_stack(stack, visited_e, emat, emap, medge, vs, mvert);
}
@@ -1703,6 +1711,11 @@ static BMesh *build_skin(SkinNode *skin_nodes,
so.bm = BM_mesh_create(&bm_mesh_allocsize_default);
so.mat_nr = 0;
+ /* BMESH_TODO: bumping up the stack level (see MOD_array.c) */
+ BM_mesh_elem_toolflags_ensure(so.bm);
+ BMO_push(so.bm, NULL);
+ bmesh_edit_begin(so.bm, 0);
+
if (input_dvert)
BM_data_layer_add(so.bm, &so.bm->vdata, CD_MDEFORMVERT);
@@ -1750,13 +1763,12 @@ static BMesh *build_skin(SkinNode *skin_nodes,
static void skin_set_orig_indices(DerivedMesh *dm)
{
- int *orig, totpoly, i;
+ int *orig, totpoly;
totpoly = dm->getNumPolys(dm);
orig = CustomData_add_layer(&dm->polyData, CD_ORIGINDEX,
CD_CALLOC, NULL, totpoly);
- for (i = 0; i < totpoly; i++)
- orig[i] = ORIGINDEX_NONE;
+ fill_vn_i(orig, totpoly, ORIGINDEX_NONE);
}
/*
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index c212c13e396..813ef285058 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -20,6 +20,7 @@
*
* Contributor(s): Campbell Barton
* Shinsuke Irie
+ * Martin Felke
*
* ***** END GPL LICENSE BLOCK *****
*
@@ -35,6 +36,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
+#include "BLI_stackdefines.h"
#include "BLI_bitmap.h"
#include "BLI_math.h"
@@ -207,7 +209,6 @@ static DerivedMesh *applyModifier(
DerivedMesh *dm,
ModifierApplyFlag UNUSED(flag))
{
- unsigned int i;
DerivedMesh *result;
const SolidifyModifierData *smd = (SolidifyModifierData *) md;
@@ -219,7 +220,7 @@ static DerivedMesh *applyModifier(
const unsigned int numEdges = (unsigned int)dm->getNumEdges(dm);
const unsigned int numFaces = (unsigned int)dm->getNumPolys(dm);
const unsigned int numLoops = (unsigned int)dm->getNumLoops(dm);
- unsigned int newLoops = 0, newFaces = 0, newEdges = 0;
+ unsigned int newLoops = 0, newFaces = 0, newEdges = 0, newVerts = 0;
/* only use material offsets if we have 2 or more materials */
const short mat_nr_max = ob->totcol > 1 ? ob->totcol - 1 : 0;
@@ -250,12 +251,16 @@ static DerivedMesh *applyModifier(
const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
const bool do_clamp = (smd->offset_clamp != 0.0f);
+ const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) == 0;
/* weights */
- MDeformVert *dvert, *dv = NULL;
+ MDeformVert *dvert;
const int defgrp_invert = ((smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0);
int defgrp_index;
+ /* array size is doubled in case of using a shell */
+ const unsigned int stride = do_shell ? 2 : 1;
+
modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
orig_mvert = dm->getVertArray(dm);
@@ -273,12 +278,13 @@ static DerivedMesh *applyModifier(
face_nors, true);
}
- STACK_INIT(new_vert_arr);
- STACK_INIT(new_edge_arr);
+ STACK_INIT(new_vert_arr, numVerts * 2);
+ STACK_INIT(new_edge_arr, numEdges * 2);
if (smd->flag & MOD_SOLIDIFY_RIM) {
BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
unsigned int eidx;
+ unsigned int i;
#define INVALID_UNUSED ((unsigned int)-1)
#define INVALID_PAIR ((unsigned int)-2)
@@ -325,23 +331,23 @@ static DerivedMesh *applyModifier(
for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) {
- BLI_BITMAP_SET(orig_mvert_tag, ed->v1);
- BLI_BITMAP_SET(orig_mvert_tag, ed->v2);
+ BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1);
+ BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2);
STACK_PUSH(new_edge_arr, eidx);
newFaces++;
newLoops += 4;
}
}
-#undef INVALID_UNUSED
-#undef INVALID_PAIR
-
for (i = 0; i < numVerts; i++) {
- if (BLI_BITMAP_GET(orig_mvert_tag, i)) {
+ if (BLI_BITMAP_TEST(orig_mvert_tag, i)) {
old_vert_arr[i] = STACK_SIZE(new_vert_arr);
STACK_PUSH(new_vert_arr, i);
newEdges++;
}
+ else {
+ old_vert_arr[i] = INVALID_UNUSED;
+ }
}
MEM_freeN(orig_mvert_tag);
@@ -352,64 +358,126 @@ static DerivedMesh *applyModifier(
dm_calc_normal(dm, face_nors, vert_nors);
}
+ newVerts = do_shell ? 0 : newEdges;
+
result = CDDM_from_template(dm,
- (int)(numVerts * 2),
- (int)((numEdges * 2) + newEdges), 0,
- (int)((numLoops * 2) + newLoops),
- (int)((numFaces * 2) + newFaces));
+ (int)((numVerts * stride) + newVerts),
+ (int)((numEdges * stride) + newEdges + newVerts), 0,
+ (int)((numLoops * stride) + newLoops),
+ (int)((numFaces * stride) + newFaces));
mpoly = CDDM_get_polys(result);
mloop = CDDM_get_loops(result);
medge = CDDM_get_edges(result);
mvert = CDDM_get_verts(result);
- DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
- DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges);
+ if (do_shell) {
+ DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
+ DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts);
- DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
- DM_copy_vert_data(dm, result, 0, (int)numVerts, (int)numVerts);
+ DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
+ DM_copy_edge_data(dm, result, 0, (int)numEdges, (int)numEdges);
- DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
- DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops);
+ DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
+ DM_copy_loop_data(dm, result, 0, (int)numLoops, (int)numLoops);
- DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
- DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces);
-
- /* flip normals */
- mp = mpoly + numFaces;
- for (i = 0; i < dm->numPolyData; i++, mp++) {
- MLoop *ml2;
- unsigned int e;
- int j;
-
- ml2 = mloop + mp->loopstart + dm->numLoopData;
- for (j = 0; j < mp->totloop; j++) {
- CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
- mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1);
+ DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
+ DM_copy_poly_data(dm, result, 0, (int)numFaces, (int)numFaces);
+ }
+ else {
+ int i, j;
+ DM_copy_vert_data(dm, result, 0, 0, (int)numVerts);
+ for (i = 0, j = (int)numVerts; i < numVerts; i++) {
+ if (old_vert_arr[i] != INVALID_UNUSED) {
+ DM_copy_vert_data(dm, result, i, j, 1);
+ j++;
+ }
}
- if (mat_ofs) {
- mp->mat_nr += mat_ofs;
- CLAMP(mp->mat_nr, 0, mat_nr_max);
- }
+ DM_copy_edge_data(dm, result, 0, 0, (int)numEdges);
- e = ml2[0].e;
- for (j = 0; j < mp->totloop - 1; j++) {
- ml2[j].e = ml2[j + 1].e;
+ for (i = 0, j = (int)numEdges; i < numEdges; i++) {
+ if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) {
+ MEdge *ed_src, *ed_dst;
+ DM_copy_edge_data(dm, result, i, j, 1);
+
+ ed_src = &medge[i];
+ ed_dst = &medge[j];
+ ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts;
+ ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts;
+ j++;
+ }
}
- ml2[mp->totloop - 1].e = e;
- mp->loopstart += dm->numLoopData;
+ /* will be created later */
+ DM_copy_loop_data(dm, result, 0, 0, (int)numLoops);
+ DM_copy_poly_data(dm, result, 0, 0, (int)numFaces);
+ }
+
+#undef INVALID_UNUSED
+#undef INVALID_PAIR
+
- for (j = 0; j < mp->totloop; j++) {
- ml2[j].e += numEdges;
- ml2[j].v += numVerts;
+ /* initializes: (i_end, do_shell_align, mv) */
+#define INIT_VERT_ARRAY_OFFSETS(test) \
+ if (((ofs_new >= ofs_orig) == do_flip) == test) { \
+ i_end = numVerts; \
+ do_shell_align = true; \
+ mv = mvert; \
+ } \
+ else { \
+ if (do_shell) { \
+ i_end = numVerts; \
+ do_shell_align = true; \
+ } \
+ else { \
+ i_end = newVerts ; \
+ do_shell_align = false; \
+ } \
+ mv = &mvert[numVerts]; \
+ } (void)0
+
+
+ /* flip normals */
+
+ if (do_shell) {
+ unsigned int i;
+
+ mp = mpoly + numFaces;
+ for (i = 0; i < dm->numPolyData; i++, mp++) {
+ MLoop *ml2;
+ unsigned int e;
+ int j;
+
+ ml2 = mloop + mp->loopstart + dm->numLoopData;
+ for (j = 0; j < mp->totloop; j++) {
+ CustomData_copy_data(&dm->loopData, &result->loopData, mp->loopstart + j,
+ mp->loopstart + (mp->totloop - j - 1) + dm->numLoopData, 1);
+ }
+
+ if (mat_ofs) {
+ mp->mat_nr += mat_ofs;
+ CLAMP(mp->mat_nr, 0, mat_nr_max);
+ }
+
+ e = ml2[0].e;
+ for (j = 0; j < mp->totloop - 1; j++) {
+ ml2[j].e = ml2[j + 1].e;
+ }
+ ml2[mp->totloop - 1].e = e;
+
+ mp->loopstart += dm->numLoopData;
+
+ for (j = 0; j < mp->totloop; j++) {
+ ml2[j].e += numEdges;
+ ml2[j].v += numVerts;
+ }
}
- }
- for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) {
- ed->v1 += numVerts;
- ed->v2 += numVerts;
+ for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) {
+ ed->v1 += numVerts;
+ ed->v2 += numVerts;
+ }
}
/* note, copied vertex layers don't have flipped normals yet. do this after applying offset */
@@ -424,6 +492,8 @@ static DerivedMesh *applyModifier(
const float offset_sq = offset * offset;
if (do_clamp) {
+ unsigned int i;
+
vert_lens = MEM_mallocN(sizeof(float) * numVerts, "vert_lens");
fill_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
for (i = 0; i < numEdges; i++) {
@@ -434,19 +504,24 @@ static DerivedMesh *applyModifier(
}
if (ofs_new != 0.0f) {
+ unsigned int i_orig, i_end;
+ bool do_shell_align;
+
scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
- mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? numVerts : 0);
- dv = dvert;
- for (i = 0; i < numVerts; i++, mv++) {
- if (dv) {
+
+ INIT_VERT_ARRAY_OFFSETS(false);
+
+ for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
+ const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ if (dvert) {
+ MDeformVert *dv = &dvert[i];
if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
- dv++;
}
if (do_clamp) {
/* always reset becaise we may have set before */
- if (dv == NULL) {
+ if (dvert == NULL) {
scalar_short_vgroup = scalar_short;
}
if (vert_lens[i] < offset_sq) {
@@ -459,19 +534,25 @@ static DerivedMesh *applyModifier(
}
if (ofs_orig != 0.0f) {
+ unsigned int i_orig, i_end;
+ bool do_shell_align;
+
scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
- mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? 0 : numVerts); /* as above but swapped */
- dv = dvert;
- for (i = 0; i < numVerts; i++, mv++) {
- if (dv) {
+
+ /* as above but swapped */
+ INIT_VERT_ARRAY_OFFSETS(true);
+
+ for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
+ const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ if (dvert) {
+ MDeformVert *dv = &dvert[i];
if (defgrp_invert) scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
else scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) * scalar_short;
- dv++;
}
if (do_clamp) {
/* always reset becaise we may have set before */
- if (dv == NULL) {
+ if (dvert == NULL) {
scalar_short_vgroup = scalar_short;
}
if (vert_lens[i] < offset_sq) {
@@ -495,6 +576,7 @@ static DerivedMesh *applyModifier(
float *vert_angles = MEM_callocN(sizeof(float) * numVerts * 2, "mod_solid_pair"); /* 2 in 1 */
float *vert_accum = vert_angles + numVerts;
unsigned int vidx;
+ unsigned int i;
if (vert_nors == NULL) {
vert_nors = MEM_mallocN(sizeof(float) * numVerts * 3, "mod_solid_vno");
@@ -557,9 +639,9 @@ static DerivedMesh *applyModifier(
/* vertex group support */
if (dvert) {
+ MDeformVert *dv = dvert;
float scalar;
- dv = dvert;
if (defgrp_invert) {
for (i = 0; i < numVerts; i++, dv++) {
scalar = 1.0f - defvert_find_weight(dv, defgrp_index);
@@ -595,21 +677,29 @@ static DerivedMesh *applyModifier(
MEM_freeN(vert_lens_sq);
}
- if (ofs_new) {
- mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? numVerts : 0);
+ if (ofs_new != 0.0f) {
+ unsigned int i_orig, i_end;
+ bool do_shell_align;
+
+ INIT_VERT_ARRAY_OFFSETS(false);
- for (i = 0; i < numVerts; i++, mv++) {
+ for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
+ const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (vert_accum[i]) { /* zero if unselected */
madd_v3_v3fl(mv->co, vert_nors[i], ofs_new * (vert_angles[i] / vert_accum[i]));
}
}
}
- if (ofs_orig) {
+ if (ofs_orig != 0.0f) {
+ unsigned int i_orig, i_end;
+ bool do_shell_align;
+
/* same as above but swapped, intentional use of 'ofs_new' */
- mv = mvert + (((ofs_new >= ofs_orig) == do_flip) ? 0 : numVerts);
+ INIT_VERT_ARRAY_OFFSETS(true);
- for (i = 0; i < numVerts; i++, mv++) {
+ for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
+ const unsigned int i = do_shell_align ? i_orig : new_vert_arr[i_orig];
if (vert_accum[i]) { /* zero if unselected */
madd_v3_v3fl(mv->co, vert_nors[i], ofs_orig * (vert_angles[i] / vert_accum[i]));
}
@@ -626,7 +716,8 @@ static DerivedMesh *applyModifier(
if ((dm->dirty & DM_DIRTY_NORMALS) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
result->dirty |= DM_DIRTY_NORMALS;
}
- else {
+ else if (do_shell) {
+ unsigned int i;
/* flip vertex normals for copied verts */
mv = mvert + numVerts;
for (i = 0; i < numVerts; i++, mv++) {
@@ -635,6 +726,7 @@ static DerivedMesh *applyModifier(
}
if (smd->flag & MOD_SOLIDIFY_RIM) {
+ unsigned int i;
/* bugger, need to re-calculate the normals for the new edge faces.
* This could be done in many ways, but probably the quickest way
@@ -667,11 +759,11 @@ static DerivedMesh *applyModifier(
/* add faces & edges */
origindex_edge = result->getEdgeDataArray(result, CD_ORIGINDEX);
- ed = &medge[numEdges * 2];
- orig_ed = &origindex_edge[numEdges * 2];
+ ed = &medge[(numEdges * stride) + newVerts]; /* start after copied edges */
+ orig_ed = &origindex_edge[(numEdges * stride) + newVerts];
for (i = 0; i < newEdges; i++, ed++, orig_ed++) {
ed->v1 = new_vert_arr[i];
- ed->v2 = new_vert_arr[i] + numVerts;
+ ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts;
ed->flag |= ME_EDGEDRAW;
*orig_ed = ORIGINDEX_NONE;
@@ -682,8 +774,8 @@ static DerivedMesh *applyModifier(
}
/* faces */
- mp = mpoly + (numFaces * 2);
- ml = mloop + (numLoops * 2);
+ mp = mpoly + (numFaces * stride);
+ ml = mloop + (numLoops * stride);
j = 0;
for (i = 0; i < newFaces; i++, mp++) {
unsigned int eidx = new_edge_arr[i];
@@ -702,8 +794,8 @@ static DerivedMesh *applyModifier(
ed = medge + eidx;
/* copy most of the face settings */
- DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * 2) + i), 1);
- mp->loopstart = (int)(j + numLoops * 2);
+ DM_copy_poly_data(dm, result, (int)fidx, (int)((numFaces * stride) + i), 1);
+ mp->loopstart = (int)(j + (numLoops * stride));
mp->flag = mpoly[fidx].flag;
/* notice we use 'mp->totloop' which is later overwritten,
@@ -714,36 +806,36 @@ static DerivedMesh *applyModifier(
mp->totloop = 4;
- CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)(numLoops * 2 + j + 0), 1);
- CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)(numLoops * 2 + j + 1), 1);
- CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)(numLoops * 2 + j + 2), 1);
- CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)(numLoops * 2 + j + 3), 1);
+ CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 0), 1);
+ CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 1), 1);
+ CustomData_copy_data(&dm->loopData, &result->loopData, k1, (int)((numLoops * stride) + j + 2), 1);
+ CustomData_copy_data(&dm->loopData, &result->loopData, k2, (int)((numLoops * stride) + j + 3), 1);
if (flip == false) {
ml[j].v = ed->v1;
ml[j++].e = eidx;
ml[j].v = ed->v2;
- ml[j++].e = numEdges * 2 + old_vert_arr[ed->v2];
+ ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newVerts;
- ml[j].v = ed->v2 + numVerts;
- ml[j++].e = eidx + numEdges;
+ ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
+ ml[j++].e = (do_shell ? eidx : i) + numEdges;
- ml[j].v = ed->v1 + numVerts;
- ml[j++].e = numEdges * 2 + old_vert_arr[ed->v1];
+ ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
+ ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newVerts;
}
else {
ml[j].v = ed->v2;
ml[j++].e = eidx;
ml[j].v = ed->v1;
- ml[j++].e = numEdges * 2 + old_vert_arr[ed->v1];
+ ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newVerts;
- ml[j].v = ed->v1 + numVerts;
- ml[j++].e = eidx + numEdges;
+ ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
+ ml[j++].e = (do_shell ? eidx : i) + numEdges;
- ml[j].v = ed->v2 + numVerts;
- ml[j++].e = numEdges * 2 + old_vert_arr[ed->v2];
+ ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
+ ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newVerts;
}
origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE;
@@ -756,14 +848,14 @@ static DerivedMesh *applyModifier(
}
if (crease_outer) {
/* crease += crease_outer; without wrapping */
- unsigned char *cr = (unsigned char *)&(ed->crease);
+ char *cr = &(ed->crease);
int tcr = *cr + crease_outer;
*cr = tcr > 255 ? 255 : tcr;
}
if (crease_inner) {
/* crease += crease_inner; without wrapping */
- unsigned char *cr = (unsigned char *)&(medge[numEdges + eidx].crease);
+ char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease);
int tcr = *cr + crease_inner;
*cr = tcr > 255 ? 255 : tcr;
}
@@ -784,7 +876,7 @@ static DerivedMesh *applyModifier(
#ifdef SOLIDIFY_SIDE_NORMALS
if (do_side_normals) {
- ed = medge + (numEdges * 2);
+ ed = medge + (numEdges * stride);
for (i = 0; i < newEdges; i++, ed++) {
float nor_cpy[3];
short *nor_short;
@@ -813,9 +905,6 @@ static DerivedMesh *applyModifier(
MEM_freeN(edge_order);
}
- STACK_FREE(new_vert_arr);
- STACK_FREE(new_edge_arr);
-
if (old_vert_arr)
MEM_freeN(old_vert_arr);
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 3de85047ebf..f17858264f8 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -98,8 +98,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
SubsurfModifierData *smd = (SubsurfModifierData *) md;
SubsurfFlags subsurf_flags = 0;
DerivedMesh *result;
- const int useRenderParams = flag & MOD_APPLY_RENDER;
- const int isFinalCalc = flag & MOD_APPLY_USECACHE;
+ const bool useRenderParams = (flag & MOD_APPLY_RENDER) != 0;
+ const bool isFinalCalc = (flag & MOD_APPLY_USECACHE) != 0;
if (useRenderParams)
subsurf_flags |= SUBSURF_USE_RENDER_PARAMS;
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 386d6d985fb..829c2b88995 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -198,7 +198,7 @@ DerivedMesh *get_dm(Object *ob, struct BMEditMesh *em, DerivedMesh *dm,
DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob));
}
}
- else if (ELEM3(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
+ else if (ELEM(ob->type, OB_FONT, OB_CURVE, OB_SURF)) {
dm = CDDM_from_curve(ob);
}
diff --git a/source/blender/modifiers/intern/MOD_weightvg_util.c b/source/blender/modifiers/intern/MOD_weightvg_util.c
index 12ecae8ad4f..744b6b62c2a 100644
--- a/source/blender/modifiers/intern/MOD_weightvg_util.c
+++ b/source/blender/modifiers/intern/MOD_weightvg_util.c
@@ -66,9 +66,9 @@ void weightvg_do_map(int num, float *new_w, short falloff_type, CurveMapping *cm
/* Return immediately, if we have nothing to do! */
/* Also security checks... */
if (((falloff_type == MOD_WVG_MAPPING_CURVE) && (cmap == NULL)) ||
- !ELEM7(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH,
- MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM,
- MOD_WVG_MAPPING_STEP))
+ !ELEM(falloff_type, MOD_WVG_MAPPING_CURVE, MOD_WVG_MAPPING_SHARP, MOD_WVG_MAPPING_SMOOTH,
+ MOD_WVG_MAPPING_ROOT, MOD_WVG_MAPPING_SPHERE, MOD_WVG_MAPPING_RANDOM,
+ MOD_WVG_MAPPING_STEP))
{
return;
}
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index f5ae8561300..71d4742980e 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -43,7 +43,6 @@
#include "BKE_deform.h"
#include "BKE_library.h"
#include "BKE_modifier.h"
-#include "BKE_shrinkwrap.h" /* For SpaceTransform stuff. */
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
@@ -73,12 +72,12 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
DerivedMesh *target, const SpaceTransform *loc2trgt)
{
int i;
- BVHTreeFromMesh treeData_v = NULL_BVHTreeFromMesh;
- BVHTreeFromMesh treeData_e = NULL_BVHTreeFromMesh;
- BVHTreeFromMesh treeData_f = NULL_BVHTreeFromMesh;
- BVHTreeNearest nearest_v = NULL_BVHTreeNearest;
- BVHTreeNearest nearest_e = NULL_BVHTreeNearest;
- BVHTreeNearest nearest_f = NULL_BVHTreeNearest;
+ BVHTreeFromMesh treeData_v = {NULL};
+ BVHTreeFromMesh treeData_e = {NULL};
+ BVHTreeFromMesh treeData_f = {NULL};
+ BVHTreeNearest nearest_v = {0};
+ BVHTreeNearest nearest_e = {0};
+ BVHTreeNearest nearest_f = {0};
if (dist_v) {
/* Create a bvh-tree of the given target's verts. */
@@ -120,7 +119,7 @@ static void get_vert2geom_distance(int numVerts, float (*v_cos)[3],
/* Convert the vertex to tree coordinates. */
copy_v3_v3(tmp_co, v_cos[i]);
- space_transform_apply(loc2trgt, tmp_co);
+ BLI_space_transform_apply(loc2trgt, tmp_co);
/* Use local proximity heuristics (to reduce the nearest search).
*
@@ -465,7 +464,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
DerivedMesh *target_dm = obr->derivedFinal;
bool free_target_dm = false;
if (!target_dm) {
- if (ELEM3(obr->type, OB_CURVE, OB_SURF, OB_FONT))
+ if (ELEM(obr->type, OB_CURVE, OB_SURF, OB_FONT))
target_dm = CDDM_from_curve(obr);
else if (obr->type == OB_MESH) {
Mesh *me = (Mesh *)obr->data;
@@ -484,7 +483,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
float *dists_e = use_trgt_edges ? MEM_mallocN(sizeof(float) * numIdx, "dists_e") : NULL;
float *dists_f = use_trgt_faces ? MEM_mallocN(sizeof(float) * numIdx, "dists_f") : NULL;
- SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr);
+ BLI_SPACE_TRANSFORM_SETUP(&loc2trgt, ob, obr);
get_vert2geom_distance(numIdx, v_cos, dists_v, dists_e, dists_f,
target_dm, &loc2trgt);
for (i = 0; i < numIdx; i++) {
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 76986583ef5..7349ca9f9ef 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -60,7 +60,7 @@ static void copyData(ModifierData *md, ModifierData *target)
static bool isDisabled(ModifierData *UNUSED(md), int UNUSED(useRenderParams))
{
- return 0;
+ return false;
}
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
@@ -75,6 +75,11 @@ static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
}
+static bool dependsOnNormals(ModifierData *UNUSED(md))
+{
+ return true;
+}
+
static DerivedMesh *WireframeModifier_do( WireframeModifierData *wmd, Object *ob, DerivedMesh *dm)
{
DerivedMesh *result;
@@ -135,7 +140,7 @@ ModifierTypeInfo modifierType_Wireframe = {
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
/* dependsOnTime */ NULL,
- /* dependsOnNormals */ NULL,
+ /* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
/* foreachIDLink */ NULL,
/* foreachTexLink */ NULL,
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 754a3c11d78..9eb6c1674a3 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -38,6 +38,7 @@ set(INC
../makesrna
../render/extern/include
../../../intern/guardedalloc
+ ../../../intern/glew-mx
)
set(INC_SYS
@@ -105,6 +106,7 @@ set(SRC
composite/nodes/node_composite_setalpha.c
composite/nodes/node_composite_splitViewer.c
composite/nodes/node_composite_stabilize2d.c
+ composite/nodes/node_composite_sunbeams.c
composite/nodes/node_composite_texture.c
composite/nodes/node_composite_tonemap.c
composite/nodes/node_composite_trackpos.c
@@ -144,6 +146,7 @@ set(SRC
shader/nodes/node_shader_rgb.c
shader/nodes/node_shader_sepcombRGB.c
shader/nodes/node_shader_sepcombHSV.c
+ shader/nodes/node_shader_sepcombXYZ.c
shader/nodes/node_shader_squeeze.c
shader/nodes/node_shader_texture.c
shader/nodes/node_shader_valToRgb.c
@@ -182,6 +185,7 @@ set(SRC
shader/nodes/node_shader_output_lamp.c
shader/nodes/node_shader_output_material.c
shader/nodes/node_shader_output_world.c
+ shader/nodes/node_shader_output_linestyle.c
shader/nodes/node_shader_particle_info.c
shader/nodes/node_shader_script.c
shader/nodes/node_shader_subsurface_scattering.c
@@ -200,6 +204,7 @@ set(SRC
shader/nodes/node_shader_tex_wave.c
shader/nodes/node_shader_volume_scatter.c
shader/nodes/node_shader_volume_absorption.c
+ shader/nodes/node_shader_uvAlongStroke.c
shader/nodes/node_shader_uvmap.c
shader/node_shader_tree.c
shader/node_shader_util.c
@@ -275,4 +280,10 @@ if(WITH_COMPOSITOR)
add_definitions(-DWITH_COMPOSITOR)
endif()
+add_definitions(${GL_DEFINITIONS})
+
+if(WITH_FREESTYLE)
+ add_definitions(-DWITH_FREESTYLE)
+endif()
+
blender_add_lib(bf_nodes "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h
index ad5f35b8faa..961fdbfc0fb 100644
--- a/source/blender/nodes/NOD_composite.h
+++ b/source/blender/nodes/NOD_composite.h
@@ -125,7 +125,7 @@ void register_node_type_cmp_mask(void);
void register_node_type_cmp_glare(void);
void register_node_type_cmp_tonemap(void);
void register_node_type_cmp_lensdist(void);
-
+void register_node_type_cmp_sunbeams(void);
void register_node_type_cmp_colorcorrection(void);
void register_node_type_cmp_boxmask(void);
diff --git a/source/blender/nodes/NOD_shader.h b/source/blender/nodes/NOD_shader.h
index 91b103da0e2..595a3b12bc6 100644
--- a/source/blender/nodes/NOD_shader.h
+++ b/source/blender/nodes/NOD_shader.h
@@ -71,6 +71,8 @@ void register_node_type_sh_seprgb(void);
void register_node_type_sh_combrgb(void);
void register_node_type_sh_sephsv(void);
void register_node_type_sh_combhsv(void);
+void register_node_type_sh_sepxyz(void);
+void register_node_type_sh_combxyz(void);
void register_node_type_sh_hue_sat(void);
void register_node_type_sh_tex_brick(void);
@@ -112,10 +114,12 @@ void register_node_type_sh_subsurface_scattering(void);
void register_node_type_sh_mix_shader(void);
void register_node_type_sh_add_shader(void);
void register_node_type_sh_uvmap(void);
+void register_node_type_sh_uvalongstroke(void);
void register_node_type_sh_output_lamp(void);
void register_node_type_sh_output_material(void);
void register_node_type_sh_output_world(void);
+void register_node_type_sh_output_linestyle(void);
void register_node_type_sh_tex_image(void);
void register_node_type_sh_tex_environment(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 434e737772d..166fa29fca0 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -69,6 +69,7 @@ DefNode( ShaderNode, SH_NODE_HUE_SAT, 0, "HUE_S
DefNode( ShaderNode, SH_NODE_OUTPUT_MATERIAL, def_sh_output, "OUTPUT_MATERIAL", OutputMaterial, "Material Output", "" )
DefNode( ShaderNode, SH_NODE_OUTPUT_LAMP, def_sh_output, "OUTPUT_LAMP", OutputLamp, "Lamp Output", "" )
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_MIX_SHADER, 0, "MIX_SHADER", MixShader, "Mix Shader", "" )
@@ -77,11 +78,11 @@ DefNode( ShaderNode, SH_NODE_ATTRIBUTE, def_sh_attribute, "AT
DefNode( ShaderNode, SH_NODE_AMBIENT_OCCLUSION, 0, "AMBIENT_OCCLUSION", AmbientOcclusion, "Ambient Occlusion", "" )
DefNode( ShaderNode, SH_NODE_BACKGROUND, 0, "BACKGROUND", Background, "Background", "" )
DefNode( ShaderNode, SH_NODE_HOLDOUT, 0, "HOLDOUT", Holdout, "Holdout", "" )
-DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, 0, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BSDF_ANISOTROPIC", BsdfAnisotropic, "Anisotropic BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" )
-DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glossy, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" )
-DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glossy, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" )
+DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glass, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" )
DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" )
@@ -120,6 +121,9 @@ DefNode( ShaderNode, SH_NODE_VECT_TRANSFORM, def_sh_vect_transform, "VE
DefNode( ShaderNode, SH_NODE_SEPHSV, 0, "SEPHSV", SeparateHSV, "Separate HSV", "" )
DefNode( ShaderNode, SH_NODE_COMBHSV, 0, "COMBHSV", CombineHSV, "Combine HSV", "" )
DefNode( ShaderNode, SH_NODE_UVMAP, def_sh_uvmap, "UVMAP", UVMap, "UV Map", "" )
+DefNode( ShaderNode, SH_NODE_UVALONGSTROKE, def_sh_uvalongstroke, "UVALONGSTROKE", UVAlongStroke, "UV Along Stroke", "" )
+DefNode( ShaderNode, SH_NODE_SEPXYZ, 0, "SEPXYZ", SeparateXYZ, "Separate XYZ", "" )
+DefNode( ShaderNode, SH_NODE_COMBXYZ, 0, "COMBXYZ", CombineXYZ, "Combine XYZ", "" )
DefNode( CompositorNode, CMP_NODE_VIEWER, def_cmp_viewer, "VIEWER", Viewer, "Viewer", "" )
DefNode( CompositorNode, CMP_NODE_RGB, 0, "RGB", RGB, "RGB", "" )
@@ -206,6 +210,7 @@ DefNode( CompositorNode, CMP_NODE_TRACKPOS, def_cmp_trackpos, "TRACK
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_CORNERPIN, 0, "CORNERPIN", CornerPin, "Corner Pin", "" )
+DefNode( CompositorNode, CMP_NODE_SUNBEAMS, def_cmp_sunbeams, "SUNBEAMS", SunBeams, "Sun Beams", "" )
DefNode( TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" )
DefNode( TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" )
diff --git a/source/blender/nodes/SConscript b/source/blender/nodes/SConscript
index 683a1c475e4..aed846355c3 100644
--- a/source/blender/nodes/SConscript
+++ b/source/blender/nodes/SConscript
@@ -39,7 +39,8 @@ incs = [
'./shader',
'./texture',
'#/intern/guardedalloc',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../blenfont',
'../blenkernel',
'../blenlib',
@@ -48,12 +49,11 @@ incs = [
'../makesdna',
'../makesrna',
'../render/extern/include',
- env['BF_OPENGL_INC'],
env['BF_ZLIB_INC'],
]
incs = ' '.join(incs)
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_PYTHON']:
incs += ' ' + env['BF_PYTHON_INC']
@@ -72,6 +72,9 @@ if env['WITH_BF_COMPOSITOR']:
incs += ' ../compositor '
defs.append("WITH_COMPOSITOR")
+if env['WITH_BF_FREESTYLE']:
+ defs.append('WITH_FREESTYLE')
+
env.BlenderLib ( libname = 'bf_nodes', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [190,105] )
env.BlenderLib ( libname = 'bf_cmpnodes', sources = cmpsources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [175,101] )
env.BlenderLib ( libname = 'bf_shdnodes', sources = shdsources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [175,101] )
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index cd69cf4982d..6d5b85da569 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -104,9 +104,9 @@ static void free_cache(bNodeTree *ntree)
}
/* local tree then owns all compbufs */
-static void localize(bNodeTree *localtree, bNodeTree *ntree)
+static void localize(bNodeTree *UNUSED(localtree), bNodeTree *ntree)
{
- bNode *node, *node_next;
+ bNode *node;
bNodeSocket *sock;
for (node = ntree->nodes.first; node; node = node->next) {
@@ -132,26 +132,6 @@ static void localize(bNodeTree *localtree, bNodeTree *ntree)
sock->new_sock->new_sock = sock;
}
}
-
- /* replace muted nodes and reroute nodes by internal links */
- for (node = localtree->nodes.first; node; node = node_next) {
- node_next = node->next;
-
- if (node->flag & NODE_MUTED || node->type == NODE_REROUTE) {
- /* make sure the update tag isn't lost when removing the muted node.
- * propagate this to all downstream nodes.
- */
- if (node->need_exec) {
- bNodeLink *link;
- for (link = localtree->links.first; link; link = link->next)
- if (link->fromnode == node && link->tonode)
- link->tonode->need_exec = 1;
- }
-
- nodeInternalRelink(localtree, node);
- nodeFreeNode(localtree, node);
- }
- }
}
static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.c b/source/blender/nodes/composite/nodes/node_composite_sunbeams.c
new file mode 100644
index 00000000000..4d937d63b75
--- /dev/null
+++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.c
@@ -0,0 +1,63 @@
+/*
+ * ***** 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): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/composite/nodes/node_composite_sunbeams.c
+ * \ingroup cmpnodes
+ */
+
+#include "node_composite_util.h"
+
+static bNodeSocketTemplate inputs[] = {
+ { SOCK_RGBA, 1, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate outputs[] = {
+ { SOCK_RGBA, 0, N_("Image")},
+ { -1, 0, "" }
+};
+
+static void init(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeSunBeams *data = MEM_callocN(sizeof(NodeSunBeams), "sun beams node");
+
+ data->source[0] = 0.5f;
+ data->source[1] = 0.5f;
+
+ node->storage = data;
+}
+
+void register_node_type_cmp_sunbeams(void)
+{
+ static bNodeType ntype;
+
+ cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0);
+ node_type_socket_templates(&ntype, inputs, outputs);
+ node_type_init(&ntype, init);
+ node_type_storage(&ntype, "NodeSunBeams", node_free_standard_storage, node_copy_standard_storage);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index ae834f9e7cc..c58c9c902ec 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -336,6 +336,40 @@ void ntree_update_reroute_nodes(bNodeTree *ntree)
node_reroute_inherit_type_recursive(ntree, node);
}
+static bool node_is_connected_to_output_recursive(bNodeTree *ntree, bNode *node)
+{
+ bNodeLink *link;
+
+ /* avoid redundant checks, and infinite loops in case of cyclic node links */
+ if (node->done)
+ return false;
+ node->done = 1;
+
+ /* main test, done before child loop so it catches output nodes themselves as well */
+ if (node->typeinfo->nclass == NODE_CLASS_OUTPUT && node->flag & NODE_DO_OUTPUT)
+ return true;
+
+ /* test all connected nodes, first positive find is sufficient to return true */
+ for (link = ntree->links.first; link; link = link->next) {
+ if (link->fromnode == node) {
+ if (node_is_connected_to_output_recursive(ntree, link->tonode))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool BKE_node_is_connected_to_output(bNodeTree *ntree, bNode *node)
+{
+ bNode *tnode;
+
+ /* clear flags */
+ for (tnode = ntree->nodes.first; tnode; tnode = tnode->next)
+ tnode->done = 0;
+
+ return node_is_connected_to_output_recursive(ntree, node);
+}
+
void BKE_node_tree_unlink_id(ID *id, struct bNodeTree *ntree)
{
bNode *node;
diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c
index 0e5f72c831b..2347564c696 100644
--- a/source/blender/nodes/intern/node_exec.c
+++ b/source/blender/nodes/intern/node_exec.c
@@ -47,7 +47,7 @@
/* supported socket types in old nodes */
int node_exec_socket_use_stack(bNodeSocket *sock)
{
- return ELEM4(sock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER);
+ return ELEM(sock->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER);
}
/* for a given socket, find the actual stack entry */
@@ -159,6 +159,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, bNodeTree *ntree, bNo
int index;
bNode **nodelist;
int totnodes, n;
+ /* XXX texnodes have threading issues with muting, have to disable it there ... */
/* ensure all sock->link pointers and node levels are correct */
ntreeUpdateTree(G.main, ntree);
@@ -304,7 +305,7 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call
*/
// if (node->typeinfo->compatibility == NODE_NEW_SHADING)
// return false;
- if (node->typeinfo->execfunc)
+ if (node->typeinfo->execfunc && !(node->flag & NODE_MUTED))
node->typeinfo->execfunc(callerdata, thread, node, &nodeexec->data, nsin, nsout);
}
}
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index 53f97e0d36c..299172ae4cc 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -38,6 +38,7 @@
#include "DNA_scene_types.h"
#include "DNA_space_types.h"
#include "DNA_world_types.h"
+#include "DNA_linestyle_types.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
@@ -48,6 +49,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_scene.h"
@@ -79,7 +81,9 @@ static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tre
Scene *scene = CTX_data_scene(C);
Object *ob = OBACT;
- if (!BKE_scene_use_new_shading_nodes(scene) || snode->shaderfrom == SNODE_SHADER_OBJECT) {
+ if ((snode->shaderfrom == SNODE_SHADER_OBJECT) ||
+ (BKE_scene_use_new_shading_nodes(scene) == false))
+ {
if (ob) {
*r_from = &ob->id;
if (ob->type == OB_LAMP) {
@@ -95,6 +99,16 @@ static void shader_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tre
}
}
}
+#ifdef WITH_FREESTYLE
+ else if (snode->shaderfrom == SNODE_SHADER_LINESTYLE) {
+ FreestyleLineStyle *linestyle = BKE_linestyle_active_from_scene(scene);
+ if (linestyle) {
+ *r_from = NULL;
+ *r_id = &linestyle->id;
+ *r_ntree = linestyle->nodetree;
+ }
+ }
+#endif
else { /* SNODE_SHADER_WORLD */
if (scene->world) {
*r_from = NULL;
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index b00d96de935..49881381253 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -195,24 +195,48 @@ static void data_from_gpu_stack_list(ListBase *sockets, bNodeStack **ns, GPUNode
bNode *nodeGetActiveTexture(bNodeTree *ntree)
{
/* this is the node we texture paint and draw in textured draw */
- bNode *node, *tnode, *inactivenode = NULL;
+ bNode *node, *tnode, *inactivenode = NULL, *activetexnode = NULL, *activegroup = NULL;
+ bool hasgroup = false;
if (!ntree)
return NULL;
for (node = ntree->nodes.first; node; node = node->next) {
- if (node->flag & NODE_ACTIVE_TEXTURE)
- return node;
+ if (node->flag & NODE_ACTIVE_TEXTURE) {
+ activetexnode = node;
+ /* if active we can return immediately */
+ if (node->flag & NODE_ACTIVE)
+ return node;
+ }
else if (!inactivenode && node->typeinfo->nclass == NODE_CLASS_TEXTURE)
inactivenode = node;
+ else if (node->type == NODE_GROUP) {
+ if (node->flag & NODE_ACTIVE)
+ activegroup = node;
+ else
+ hasgroup = true;
+ }
+ }
+
+ /* first, check active group for textures */
+ if (activegroup) {
+ tnode = nodeGetActiveTexture((bNodeTree *)activegroup->id);
+ /* active node takes priority, so ignore any other possible nodes here */
+ if (tnode)
+ return tnode;
}
+
+ if (activetexnode)
+ return activetexnode;
- /* node active texture node in this tree, look inside groups */
- for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == NODE_GROUP) {
- tnode = nodeGetActiveTexture((bNodeTree *)node->id);
- if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode))
- return tnode;
+ if (hasgroup) {
+ /* node active texture node in this tree, look inside groups */
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == NODE_GROUP) {
+ tnode = nodeGetActiveTexture((bNodeTree *)node->id);
+ if (tnode && ((tnode->flag & NODE_ACTIVE_TEXTURE) || !inactivenode))
+ return tnode;
+ }
}
}
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 dd14006cd8a..b9c94fc3aee 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c
@@ -44,6 +44,11 @@ static bNodeSocketTemplate sh_node_bsdf_anisotropic_out[] = {
{ -1, 0, "" }
};
+static void node_shader_init_anisotropic(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_GGX;
+}
+
static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[3].link)
@@ -61,7 +66,7 @@ void register_node_type_sh_bsdf_anisotropic(void)
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_anisotropic_in, sh_node_bsdf_anisotropic_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
+ node_type_init(&ntype, node_shader_init_anisotropic);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_bsdf_anisotropic);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
index a59cbd6f46e..75ca4b87f09 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c
@@ -30,7 +30,7 @@
/* **************** OUTPUT ******************** */
static bNodeSocketTemplate sh_node_bsdf_glass_in[] = {
- { SOCK_RGBA, 1, N_("Color"), 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
+ { SOCK_RGBA, 1, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Roughness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR},
{ SOCK_FLOAT, 1, N_("IOR"), 1.45f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f},
{ SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE},
@@ -42,6 +42,11 @@ static bNodeSocketTemplate sh_node_bsdf_glass_out[] = {
{ -1, 0, "" }
};
+static void node_shader_init_glass(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_BECKMANN;
+}
+
static int node_shader_gpu_bsdf_glass(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[3].link)
@@ -59,7 +64,7 @@ void register_node_type_sh_bsdf_glass(void)
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_glass_in, sh_node_bsdf_glass_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
+ node_type_init(&ntype, node_shader_init_glass);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_bsdf_glass);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
index b8ad5e4fbed..9518784eebe 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c
@@ -41,6 +41,11 @@ static bNodeSocketTemplate sh_node_bsdf_glossy_out[] = {
{ -1, 0, "" }
};
+static void node_shader_init_glossy(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_GGX;
+}
+
static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[2].link)
@@ -58,7 +63,7 @@ void register_node_type_sh_bsdf_glossy(void)
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_glossy_in, sh_node_bsdf_glossy_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
+ node_type_init(&ntype, node_shader_init_glossy);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_bsdf_glossy);
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
index b48a4be9f7a..dbc8807a845 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c
@@ -43,9 +43,6 @@ static bNodeSocketTemplate sh_node_bsdf_hair_out[] = {
static int node_shader_gpu_bsdf_hair(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
- if (!in[2].link)
- in[2].link = GPU_builtin(GPU_VIEW_NORMAL);
-
return GPU_stack_link(mat, "node_bsdf_hair", in, out);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
index 5d1bcc81adb..90db7a5771d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
+++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c
@@ -42,6 +42,11 @@ static bNodeSocketTemplate sh_node_bsdf_refraction_out[] = {
{ -1, 0, "" }
};
+static void node_shader_init_refraction(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ node->custom1 = SHD_GLOSSY_BECKMANN;
+}
+
static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (!in[3].link)
@@ -59,7 +64,7 @@ void register_node_type_sh_bsdf_refraction(void)
node_type_compatibility(&ntype, NODE_NEW_SHADING);
node_type_socket_templates(&ntype, sh_node_bsdf_refraction_in, sh_node_bsdf_refraction_out);
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
- node_type_init(&ntype, NULL);
+ node_type_init(&ntype, node_shader_init_refraction);
node_type_storage(&ntype, "", NULL, NULL);
node_type_gpu(&ntype, node_shader_gpu_bsdf_refraction);
diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.c
index 231af7e7d37..49ebb15d7a4 100644
--- a/source/blender/nodes/shader/nodes/node_shader_camera.c
+++ b/source/blender/nodes/shader/nodes/node_shader_camera.c
@@ -47,7 +47,7 @@ static void node_shader_exec_camera(void *data, int UNUSED(thread), bNode *UNUSE
ShadeInput *shi = ((ShaderCallData *)data)->shi; /* Data we need for shading. */
copy_v3_v3(out[0]->vec, shi->co); /* get view vector */
- out[1]->vec[0] = fabs(shi->co[2]); /* get view z-depth */
+ out[1]->vec[0] = fabsf(shi->co[2]); /* get view z-depth */
out[2]->vec[0] = normalize_v3(out[0]->vec); /* get view distance */
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_math.c b/source/blender/nodes/shader/nodes/node_shader_math.c
index d5ba8231cce..dc5971909d2 100644
--- a/source/blender/nodes/shader/nodes/node_shader_math.c
+++ b/source/blender/nodes/shader/nodes/node_shader_math.c
@@ -74,25 +74,25 @@ static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode
case 4: /* Sine */
{
if (in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
- r = sin(a);
+ r = sinf(a);
else
- r = sin(b);
+ r = sinf(b);
break;
}
case 5: /* Cosine */
{
if (in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
- r = cos(a);
+ r = cosf(a);
else
- r = cos(b);
+ r = cosf(b);
break;
}
case 6: /* Tangent */
{
if (in[0]->hasinput || !in[1]->hasinput) /* This one only takes one input, so we've got to choose. */
- r = tan(a);
+ r = tanf(a);
else
- r = tan(b);
+ r = tanf(b);
break;
}
case 7: /* Arc-Sine */
@@ -100,14 +100,14 @@ static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode
if (in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
/* Can't do the impossible... */
if (a <= 1 && a >= -1)
- r = asin(a);
+ r = asinf(a);
else
r = 0.0;
}
else {
/* Can't do the impossible... */
if (b <= 1 && b >= -1)
- r = asin(b);
+ r = asinf(b);
else
r = 0.0;
}
@@ -118,14 +118,14 @@ static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode
if (in[0]->hasinput || !in[1]->hasinput) { /* This one only takes one input, so we've got to choose. */
/* Can't do the impossible... */
if (a <= 1 && a >= -1)
- r = acos(a);
+ r = acosf(a);
else
r = 0.0;
}
else {
/* Can't do the impossible... */
if (b <= 1 && b >= -1)
- r = acos(b);
+ r = acosf(b);
else
r = 0.0;
}
@@ -218,7 +218,7 @@ static void node_shader_exec_math(void *UNUSED(data), int UNUSED(thread), bNode
}
case 18: /* Absolute */
{
- r = fabs(a);
+ r = fabsf(a);
break;
}
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.c
index 22b27ce4b71..fcd738f0b15 100644
--- a/source/blender/nodes/shader/nodes/node_shader_normal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_normal.c
@@ -61,7 +61,12 @@ static void node_shader_exec_normal(void *UNUSED(data), int UNUSED(thread), bNod
static int gpu_shader_normal(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
GPUNodeLink *vec = GPU_uniform(out[0].vec);
- return GPU_stack_link(mat, "normal", in, out, vec);
+ int ret = GPU_stack_link(mat, "normal", in, out, vec);
+ if (ret && GPU_material_use_new_shading_nodes(mat)) {
+ float fac[3] = {1.0f, 0.0f, 0.0f};
+ GPU_link(mat, "invert", GPU_uniform(fac), out[1].link, &out[1].link);
+ }
+ return ret;
}
void register_node_type_sh_normal(void)
diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
new file mode 100644
index 00000000000..2eb68f23912
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c
@@ -0,0 +1,54 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_output_linestyle_in[] = {
+ { SOCK_RGBA, 1, N_("Color"), 1.0f, 0.0f, 1.0f, 1.0f },
+ { SOCK_FLOAT, 1, N_("Color Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR },
+ { SOCK_FLOAT, 1, N_("Alpha"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR },
+ { SOCK_FLOAT, 1, N_("Alpha Fac"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR },
+ { -1, 0, "" }
+};
+
+/* node type definition */
+void register_node_type_sh_output_linestyle(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL);
+ node_type_init(&ntype, NULL);
+
+ /* Do not allow muting output node. */
+ node_type_internal_links(&ntype, NULL);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
new file mode 100644
index 00000000000..605a3b9faa3
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
@@ -0,0 +1,93 @@
+/*
+ * ***** 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): Thomas Dinges
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/nodes/shader/nodes/node_shader_sepcombXYZ.c
+ * \ingroup shdnodes
+ */
+
+
+#include "node_shader_util.h"
+
+/* **************** SEPARATE XYZ ******************** */
+static bNodeSocketTemplate sh_node_sepxyz_in[] = {
+ { SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate sh_node_sepxyz_out[] = {
+ { SOCK_FLOAT, 0, N_("X")},
+ { SOCK_FLOAT, 0, N_("Y")},
+ { SOCK_FLOAT, 0, N_("Z")},
+ { -1, 0, "" }
+};
+
+static int gpu_shader_sepxyz(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, "separate_xyz", in, out);
+}
+
+void register_node_type_sh_sepxyz(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTOR, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_sepxyz_in, sh_node_sepxyz_out);
+ node_type_gpu(&ntype, gpu_shader_sepxyz);
+
+ nodeRegisterType(&ntype);
+}
+
+
+
+/* **************** COMBINE XYZ ******************** */
+static bNodeSocketTemplate sh_node_combxyz_in[] = {
+ { SOCK_FLOAT, 1, N_("X"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_UNSIGNED},
+ { SOCK_FLOAT, 1, N_("Y"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_UNSIGNED},
+ { SOCK_FLOAT, 1, N_("Z"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_UNSIGNED},
+ { -1, 0, "" }
+};
+static bNodeSocketTemplate sh_node_combxyz_out[] = {
+ { SOCK_VECTOR, 0, N_("Vector")},
+ { -1, 0, "" }
+};
+
+static int gpu_shader_combxyz(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ return GPU_stack_link(mat, "combine_xyz", in, out);
+}
+
+void register_node_type_sh_combxyz(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTOR, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, sh_node_combxyz_in, sh_node_combxyz_out);
+ node_type_gpu(&ntype, gpu_shader_combxyz);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c b/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c
new file mode 100644
index 00000000000..48eb4cadba4
--- /dev/null
+++ b/source/blender/nodes/shader/nodes/node_shader_uvAlongStroke.c
@@ -0,0 +1,50 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "../node_shader_util.h"
+
+#include "DNA_customdata_types.h"
+
+/* **************** OUTPUT ******************** */
+
+static bNodeSocketTemplate sh_node_uvalongstroke_out[] = {
+ { SOCK_VECTOR, 0, N_("UV"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { -1, 0, "" }
+};
+
+/* node type definition */
+void register_node_type_sh_uvalongstroke(void)
+{
+ static bNodeType ntype;
+
+ sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT, 0);
+ node_type_compatibility(&ntype, NODE_NEW_SHADING);
+ node_type_socket_templates(&ntype, NULL, sh_node_uvalongstroke_out);
+ node_type_init(&ntype, NULL);
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
index fff1bc1df95..0f96cb45fe0 100644
--- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c
+++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.c
@@ -42,6 +42,14 @@ static void node_shader_init_uvmap(bNodeTree *UNUSED(ntree), bNode *node)
node->storage = attr;
}
+static int node_shader_gpu_uvmap(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
+{
+ NodeShaderUVMap *attr = node->storage;
+ GPUNodeLink *mtface = GPU_attribute(CD_MTFACE, attr->uv_map);
+
+ return GPU_stack_link(mat, "node_uvmap", in, out, mtface);
+}
+
/* node type definition */
void register_node_type_sh_uvmap(void)
{
@@ -53,6 +61,7 @@ void register_node_type_sh_uvmap(void)
node_type_size_preset(&ntype, NODE_SIZE_MIDDLE);
node_type_init(&ntype, node_shader_init_uvmap);
node_type_storage(&ntype, "NodeShaderUVMap", node_free_standard_storage, node_copy_standard_storage);
+ node_type_gpu(&ntype, node_shader_gpu_uvmap);
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
index b40bf6bc71a..f2ea2faa5a7 100644
--- a/source/blender/nodes/shader/nodes/node_shader_vectMath.c
+++ b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
@@ -59,14 +59,14 @@ static void node_shader_exec_vect_math(void *UNUSED(data), int UNUSED(thread), b
out[0]->vec[1] = vec1[1] + vec2[1];
out[0]->vec[2] = vec1[2] + vec2[2];
- out[1]->vec[0] = (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
+ out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[0])) / 3;
}
else if (node->custom1 == 1) { /* Subtract */
out[0]->vec[0] = vec1[0] - vec2[0];
out[0]->vec[1] = vec1[1] - vec2[1];
out[0]->vec[2] = vec1[2] - vec2[2];
- out[1]->vec[0] = (fabs(out[0]->vec[0]) + fabs(out[0]->vec[0]) + fabs(out[0]->vec[0])) / 3;
+ out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[0])) / 3;
}
else if (node->custom1 == 2) { /* Average */
out[0]->vec[0] = vec1[0] + vec2[0];
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 882c843f317..1b790f87faf 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -44,6 +44,7 @@
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_linestyle.h"
#include "BKE_main.h"
#include "BKE_node.h"
#include "BKE_paint.h"
@@ -110,7 +111,7 @@ static void texture_get_from_context(const bContext *C, bNodeTreeType *UNUSED(tr
}
}
else if (snode->texfrom == SNODE_TEX_LINESTYLE) {
- FreestyleLineStyle *linestyle = CTX_data_linestyle_from_scene(scene);
+ FreestyleLineStyle *linestyle = BKE_linestyle_active_from_scene(scene);
if (linestyle) {
*r_from = (ID *)linestyle;
tx = give_current_linestyle_texture(linestyle);
@@ -136,6 +137,10 @@ static void foreach_nodeclass(Scene *UNUSED(scene), void *calldata, bNodeClassCa
func(calldata, NODE_CLASS_LAYOUT, N_("Layout"));
}
+/* XXX muting disabled in previews because of threading issues with the main execution
+ * it works here, but disabled for consistency
+ */
+#if 1
static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
{
bNode *node, *node_next;
@@ -150,6 +155,11 @@ static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree))
}
}
}
+#else
+static void localize(bNodeTree *UNUSED(localtree), bNodeTree *UNUSED(ntree))
+{
+}
+#endif
static void local_sync(bNodeTree *localtree, bNodeTree *ntree)
{
diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c
index e01b7ec49f1..42c684b8247 100644
--- a/source/blender/nodes/texture/node_texture_util.c
+++ b/source/blender/nodes/texture/node_texture_util.c
@@ -140,11 +140,19 @@ void tex_do_preview(bNodePreview *preview, const float coord[2], const float col
void tex_output(bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack *out, TexFn texfn, TexCallData *cdata)
{
TexDelegate *dg;
- if (!out->data)
- /* Freed in tex_end_exec (node.c) */
- dg = out->data = MEM_mallocN(sizeof(TexDelegate), "tex delegate");
- else
- dg = out->data;
+
+ if (node->flag & NODE_MUTED) {
+ /* do not add a delegate if the node is muted */
+ return;
+ }
+ else {
+ if (!out->data)
+ /* Freed in tex_end_exec (node.c) */
+ dg = out->data = MEM_mallocN(sizeof(TexDelegate), "tex delegate");
+ else
+ dg = out->data;
+ }
+
dg->cdata = cdata;
dg->fn = texfn;
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index 4765ee5f02a..94e778e10fb 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -72,24 +72,24 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
}
case 4: /* Sine */
{
- *out = sin(in0);
+ *out = sinf(in0);
break;
}
case 5: /* Cosine */
{
- *out = cos(in0);
+ *out = cosf(in0);
break;
}
case 6: /* Tangent */
{
- *out = tan(in0);
+ *out = tanf(in0);
break;
}
case 7: /* Arc-Sine */
{
/* Can't do the impossible... */
if (in0 <= 1 && in0 >= -1)
- *out = asin(in0);
+ *out = asinf(in0);
else
*out = 0.0;
break;
@@ -98,7 +98,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
{
/* Can't do the impossible... */
if (in0 <= 1 && in0 >= -1)
- *out = acos(in0);
+ *out = acosf(in0);
else
*out = 0.0;
break;
@@ -174,7 +174,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
- case 17: /* Modulo */
+ case 17: /* Modulo */
{
if (in1 == 0.0f)
*out = 0.0f;
@@ -185,7 +185,7 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
case 18: /* Absolute */
{
- *out = fabs(in0);
+ *out = fabsf(in0);
break;
}
diff --git a/source/blender/python/SConscript b/source/blender/python/SConscript
index a008678f4d3..d7c47d11ca3 100644
--- a/source/blender/python/SConscript
+++ b/source/blender/python/SConscript
@@ -33,7 +33,8 @@ incs = [
'.',
'#/intern/guardedalloc',
'#/intern/memutil',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#/intern/audaspace/intern',
'#/intern/cycles/blender',
'../blenfont',
@@ -62,7 +63,7 @@ sources = env.Glob('bmesh/*.c')
env.BlenderLib( libname = 'bf_python_bmesh', sources = Split(sources), includes = Split(incs), defines = defs, libtype = ['core','player'], priority = [362,165])
# generic
-defs = ['GLEW_STATIC']
+defs = env['BF_GL_DEFINITIONS']
if is_debug:
defs.append('_DEBUG')
@@ -85,7 +86,7 @@ env.BlenderLib( libname = 'bf_python_manta', sources = Split(sources), includes
# bpy
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if is_debug:
defs.append('_DEBUG')
diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c
index 9c9b69186ab..2c07df98973 100644
--- a/source/blender/python/bmesh/bmesh_py_ops_call.c
+++ b/source/blender/python/bmesh/bmesh_py_ops_call.c
@@ -507,7 +507,7 @@ static int bpy_slot_from_py(BMesh *bm, BMOperator *bmop, BMOpSlot *slot, PyObjec
return -1;
}
}
- /* fall-through */
+ break;
}
default:
/* TODO --- many others */
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c
index c2b496f914b..a31345cd7f5 100644
--- a/source/blender/python/bmesh/bmesh_py_types.c
+++ b/source/blender/python/bmesh/bmesh_py_types.c
@@ -645,7 +645,7 @@ static int bpy_bmfaceseq_active_set(BPy_BMElem *self, PyObject *value, void *UNU
return 0;
}
else if (BPy_BMFace_Check(value)) {
- BPY_BM_CHECK_SOURCE_INT(value, bm, "faces.active = f");
+ BPY_BM_CHECK_SOURCE_INT(bm, "faces.active = f", value);
bm->act_face = ((BPy_BMFace *)value)->f;
return 0;
@@ -1217,6 +1217,44 @@ static PyObject *bpy_bmesh_calc_volume(BPy_BMElem *self, PyObject *args, PyObjec
}
}
+PyDoc_STRVAR(bpy_bmesh_calc_tessface_doc,
+".. method:: calc_tessface()\n"
+"\n"
+" Calculate triangle tessellation from quads/ngons.\n"
+"\n"
+" :return: The triangulated faces.\n"
+" :rtype: list of :class:`BMLoop` tuples\n"
+);
+static PyObject *bpy_bmesh_calc_tessface(BPy_BMElem *self)
+{
+ BMesh *bm;
+
+ int looptris_tot;
+ int tottri;
+ BMLoop *(*looptris)[3];
+
+ PyObject *ret;
+ int i;
+
+ BPY_BM_CHECK_OBJ(self);
+
+ bm = self->bm;
+
+ looptris_tot = poly_to_tri_count(bm->totface, bm->totloop);
+ looptris = PyMem_MALLOC(sizeof(*looptris) * looptris_tot);
+
+ BM_bmesh_calc_tessellation(bm, looptris, &tottri);
+
+ ret = PyList_New(tottri);
+ for (i = 0; i < tottri; i++) {
+ PyList_SET_ITEM(ret, i, BPy_BMLoop_Array_As_Tuple(bm, looptris[i], 3));
+ }
+
+ PyMem_FREE(looptris);
+
+ return ret;
+}
+
/* Elem
* ---- */
@@ -1373,7 +1411,7 @@ static PyObject *bpy_bmvert_copy_from_face_interp(BPy_BMVert *self, PyObject *ar
else {
BMesh *bm = self->bm;
- BPY_BM_CHECK_SOURCE_OBJ(py_face, bm, "copy_from_face_interp()");
+ BPY_BM_CHECK_SOURCE_OBJ(bm, "copy_from_face_interp()", py_face);
BM_vert_interp_from_face(bm, self->v, py_face->f);
@@ -1519,7 +1557,7 @@ static PyObject *bpy_bmedge_other_vert(BPy_BMEdge *self, BPy_BMVert *value)
return NULL;
}
- BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "BMEdge.other_vert(vert)");
+ BPY_BM_CHECK_SOURCE_OBJ(self->bm, "BMEdge.other_vert(vert)", value);
other = BM_edge_other_vert(self->e, value->v);
@@ -1576,7 +1614,7 @@ static PyObject *bpy_bmface_copy_from_face_interp(BPy_BMFace *self, PyObject *ar
else {
BMesh *bm = self->bm;
- BPY_BM_CHECK_SOURCE_OBJ(py_face, bm, "BMFace.copy_from_face_interp(face)");
+ BPY_BM_CHECK_SOURCE_OBJ(bm, "BMFace.copy_from_face_interp(face)", py_face);
BM_face_interp_from_face(bm, self->f, py_face->f, do_vertex);
@@ -1773,7 +1811,7 @@ static PyObject *bpy_bmloop_copy_from_face_interp(BPy_BMLoop *self, PyObject *ar
else {
BMesh *bm = self->bm;
- BPY_BM_CHECK_SOURCE_OBJ(py_face, bm, "BMLoop.copy_from_face_interp(face)");
+ BPY_BM_CHECK_SOURCE_OBJ(bm, "BMLoop.copy_from_face_interp(face)", py_face);
BM_loop_interp_from_face(bm, self->l, py_face->f, do_vertex, do_multires);
@@ -2056,7 +2094,7 @@ static PyObject *bpy_bmvertseq_remove(BPy_BMElemSeq *self, BPy_BMVert *value)
else {
BMesh *bm = self->bm;
- BPY_BM_CHECK_SOURCE_OBJ(value, bm, "verts.remove(vert)");
+ BPY_BM_CHECK_SOURCE_OBJ(bm, "verts.remove(vert)", value);
BM_vert_kill(bm, value->v);
bpy_bm_generic_invalidate((BPy_BMGeneric *)value);
@@ -2080,7 +2118,7 @@ static PyObject *bpy_bmedgeseq_remove(BPy_BMElemSeq *self, BPy_BMEdge *value)
else {
BMesh *bm = self->bm;
- BPY_BM_CHECK_SOURCE_OBJ(value, bm, "edges.remove(edges)");
+ BPY_BM_CHECK_SOURCE_OBJ(bm, "edges.remove(edges)", value);
BM_edge_kill(bm, value->e);
bpy_bm_generic_invalidate((BPy_BMGeneric *)value);
@@ -2104,7 +2142,7 @@ static PyObject *bpy_bmfaceseq_remove(BPy_BMElemSeq *self, BPy_BMFace *value)
else {
BMesh *bm = self->bm;
- BPY_BM_CHECK_SOURCE_OBJ(value, bm, "faces.remove(face)");
+ BPY_BM_CHECK_SOURCE_OBJ(bm, "faces.remove(face)", value);
BM_face_kill(bm, value->f);
bpy_bm_generic_invalidate((BPy_BMGeneric *)value);
@@ -2488,6 +2526,7 @@ static struct PyMethodDef bpy_bmesh_methods[] = {
/* calculations */
{"calc_volume", (PyCFunction)bpy_bmesh_calc_volume, METH_VARARGS | METH_KEYWORDS, bpy_bmesh_calc_volume_doc},
+ {"calc_tessface", (PyCFunction)bpy_bmesh_calc_tessface, METH_NOARGS, bpy_bmesh_calc_tessface_doc},
{NULL, NULL, 0, NULL}
};
@@ -3545,18 +3584,34 @@ int bpy_bm_generic_valid_check(BPy_BMGeneric *self)
}
}
-int bpy_bm_generic_valid_check_source(BPy_BMGeneric *self, BMesh *bm_source, const char *error_prefix)
+int bpy_bm_generic_valid_check_source(BMesh *bm_source, const char *error_prefix, void **args, unsigned int args_tot)
{
- int ret = bpy_bm_generic_valid_check(self);
- if (LIKELY(ret == 0)) {
- if (UNLIKELY(self->bm != bm_source)) {
- /* could give more info here */
- PyErr_Format(PyExc_ValueError,
- "%.200s: BMesh data of type %.200s is from another mesh",
- error_prefix, Py_TYPE(self)->tp_name);
- ret = -1;
+ int ret = 0;
+
+ while (args_tot--) {
+ BPy_BMGeneric *py_bm_elem = args[args_tot];
+ if (py_bm_elem) {
+
+ BLI_assert(BPy_BMesh_Check(py_bm_elem) ||
+ BPy_BMElem_Check(py_bm_elem));
+
+ ret = bpy_bm_generic_valid_check(py_bm_elem);
+ if (UNLIKELY(ret == -1)) {
+ break;
+ }
+ else {
+ if (UNLIKELY(py_bm_elem->bm != bm_source)) {
+ /* could give more info here */
+ PyErr_Format(PyExc_ValueError,
+ "%.200s: BMesh data of type %.200s is from another mesh",
+ error_prefix, Py_TYPE(py_bm_elem)->tp_name);
+ ret = -1;
+ break;
+ }
+ }
}
}
+
return ret;
}
@@ -3669,7 +3724,6 @@ err_cleanup:
}
}
-
PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len)
{
Py_ssize_t i;
@@ -3677,6 +3731,44 @@ PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_
for (i = 0; i < elem_len; i++) {
PyTuple_SET_ITEM(ret, i, BPy_BMElem_CreatePyObject(bm, elem[i]));
}
+ return ret;
+}
+PyObject *BPy_BMVert_Array_As_Tuple(BMesh *bm, BMVert **elem, Py_ssize_t elem_len)
+{
+ Py_ssize_t i;
+ PyObject *ret = PyTuple_New(elem_len);
+ for (i = 0; i < elem_len; i++) {
+ PyTuple_SET_ITEM(ret, i, BPy_BMVert_CreatePyObject(bm, elem[i]));
+ }
+ return ret;
+}
+PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_len)
+{
+ Py_ssize_t i;
+ PyObject *ret = PyTuple_New(elem_len);
+ for (i = 0; i < elem_len; i++) {
+ PyTuple_SET_ITEM(ret, i, BPy_BMEdge_CreatePyObject(bm, elem[i]));
+ }
+
+ return ret;
+}
+PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len)
+{
+ Py_ssize_t i;
+ PyObject *ret = PyTuple_New(elem_len);
+ for (i = 0; i < elem_len; i++) {
+ PyTuple_SET_ITEM(ret, i, BPy_BMFace_CreatePyObject(bm, elem[i]));
+ }
+
+ return ret;
+}
+PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop **elem, Py_ssize_t elem_len)
+{
+ Py_ssize_t i;
+ PyObject *ret = PyTuple_New(elem_len);
+ for (i = 0; i < elem_len; i++) {
+ PyTuple_SET_ITEM(ret, i, BPy_BMLoop_CreatePyObject(bm, elem[i]));
+ }
return ret;
}
diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h
index 0909ce0d26a..a2c2c312e71 100644
--- a/source/blender/python/bmesh/bmesh_py_types.h
+++ b/source/blender/python/bmesh/bmesh_py_types.h
@@ -164,13 +164,18 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_
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);
+PyObject *BPy_BMEdge_Array_As_Tuple(BMesh *bm, BMEdge **elem, Py_ssize_t elem_len);
+PyObject *BPy_BMFace_Array_As_Tuple(BMesh *bm, BMFace **elem, Py_ssize_t elem_len);
+PyObject *BPy_BMLoop_Array_As_Tuple(BMesh *bm, BMLoop **elem, Py_ssize_t elem_len);
+
int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype);
char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32]);
char *BPy_BMElem_StringFromHType(const char htype);
// void bpy_bm_generic_invalidate(BPy_BMGeneric *self);
int bpy_bm_generic_valid_check(BPy_BMGeneric *self);
-int bpy_bm_generic_valid_check_source(BPy_BMGeneric *self, BMesh *bm_source, const char *error_prefix);
+int bpy_bm_generic_valid_check_source(BMesh *bm_source, const char *error_prefix, void **args, unsigned int args_n) ATTR_NONNULL(1, 2);
#define BPY_BM_CHECK_OBJ(obj) \
if (UNLIKELY(bpy_bm_generic_valid_check((BPy_BMGeneric *)obj) == -1)) { return NULL; } (void)0
@@ -178,10 +183,18 @@ int bpy_bm_generic_valid_check_source(BPy_BMGeneric *self, BMesh *bm_source, co
if (UNLIKELY(bpy_bm_generic_valid_check((BPy_BMGeneric *)obj) == -1)) { return -1; } (void)0
/* macros like BPY_BM_CHECK_OBJ/BPY_BM_CHECK_INT that ensure we're from the right BMesh */
-#define BPY_BM_CHECK_SOURCE_OBJ(obj, bm, errmsg) \
- if (UNLIKELY(bpy_bm_generic_valid_check_source((BPy_BMGeneric *)obj, bm, errmsg) == -1)) { return NULL; } (void)0
-#define BPY_BM_CHECK_SOURCE_INT(obj, bm, errmsg) \
- if (UNLIKELY(bpy_bm_generic_valid_check_source((BPy_BMGeneric *)obj, bm, errmsg) == -1)) { return -1; } (void)0
+#define BPY_BM_CHECK_SOURCE_OBJ(bm, errmsg, ...) { \
+ void *_args[] = {__VA_ARGS__}; \
+ if (UNLIKELY(bpy_bm_generic_valid_check_source(bm, errmsg, _args, ARRAY_SIZE(_args)) == -1)) { \
+ return NULL; \
+ } \
+} (void)0
+#define BPY_BM_CHECK_SOURCE_INT(bm, errmsg, ...) { \
+ void *_args[] = {__VA_ARGS__}; \
+ if (UNLIKELY(bpy_bm_generic_valid_check_source(bm, errmsg, _args, ARRAY_SIZE(_args)) == -1)) { \
+ return -1; \
+ } \
+} (void)0
#define BPY_BM_IS_VALID(obj) (LIKELY((obj)->bm != NULL))
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index dfb3ae75df4..6ecb01a8528 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -281,7 +281,7 @@ static PyObject *bpy_bmlayeritem_copy_from(BPy_BMLayerItem *self, BPy_BMLayerIte
}
BPY_BM_CHECK_OBJ(self);
- BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "layer.copy_from()");
+ BPY_BM_CHECK_SOURCE_OBJ(self->bm, "layer.copy_from()", value);
if ((self->htype != value->htype) ||
(self->type != value->type))
diff --git a/source/blender/python/bmesh/bmesh_py_types_select.c b/source/blender/python/bmesh/bmesh_py_types_select.c
index b8e04a0cab8..3c72112e7ce 100644
--- a/source/blender/python/bmesh/bmesh_py_types_select.c
+++ b/source/blender/python/bmesh/bmesh_py_types_select.c
@@ -112,7 +112,7 @@ static PyObject *bpy_bmeditselseq_add(BPy_BMEditSelSeq *self, BPy_BMElem *value)
return NULL;
}
- BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "select_history.add()");
+ BPY_BM_CHECK_SOURCE_OBJ(self->bm, "select_history.add()", value);
BM_select_history_store(self->bm, value->ele);
@@ -137,7 +137,7 @@ static PyObject *bpy_bmeditselseq_remove(BPy_BMEditSelSeq *self, BPy_BMElem *val
return NULL;
}
- BPY_BM_CHECK_SOURCE_OBJ(value, self->bm, "select_history.remove()");
+ BPY_BM_CHECK_SOURCE_OBJ(self->bm, "select_history.remove()", value);
if (BM_select_history_remove(self->bm, value->ele) == false) {
PyErr_SetString(PyExc_ValueError,
diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c
index 236d6badd55..7088036245a 100644
--- a/source/blender/python/bmesh/bmesh_py_utils.c
+++ b/source/blender/python/bmesh/bmesh_py_utils.c
@@ -90,7 +90,7 @@ static PyObject *bpy_bm_utils_vert_collapse_edge(PyObject *UNUSED(self), PyObjec
bm = py_edge->bm;
- e_new = BM_vert_collapse_edge(bm, py_edge->e, py_vert->v, true);
+ e_new = BM_vert_collapse_edge(bm, py_edge->e, py_vert->v, true, true);
if (e_new) {
return BPy_BMEdge_CreatePyObject(bm, e_new);
@@ -156,7 +156,7 @@ static PyObject *bpy_bm_utils_vert_collapse_faces(PyObject *UNUSED(self), PyObje
bm = py_edge->bm;
- e_new = BM_vert_collapse_faces(bm, py_edge->e, py_vert->v, CLAMPIS(fac, 0.0f, 1.0f), do_join_faces, true);
+ e_new = BM_vert_collapse_faces(bm, py_edge->e, py_vert->v, CLAMPIS(fac, 0.0f, 1.0f), true, do_join_faces, true);
if (e_new) {
return BPy_BMEdge_CreatePyObject(bm, e_new);
@@ -198,6 +198,65 @@ static PyObject *bpy_bm_utils_vert_dissolve(PyObject *UNUSED(self), PyObject *ar
return PyBool_FromLong((BM_vert_dissolve(bm, py_vert->v)));
}
+PyDoc_STRVAR(bpy_bm_utils_vert_splice_doc,
+".. method:: vert_splice(vert, vert_target)\n"
+"\n"
+" Splice vert into vert_target.\n"
+"\n"
+" :arg vert: The vertex to be removed.\n"
+" :type vert: :class:`bmesh.types.BMVert`\n"
+" :arg vert_target: The vertex to use.\n"
+" :type vert_target: :class:`bmesh.types.BMVert`\n"
+"\n"
+" .. note:: The verts mustn't share an edge or face.\n"
+);
+static PyObject *bpy_bm_utils_vert_splice(PyObject *UNUSED(self), PyObject *args)
+{
+ BPy_BMVert *py_vert;
+ BPy_BMVert *py_vert_target;
+
+ BMesh *bm;
+
+ bool ok;
+
+ if (!PyArg_ParseTuple(args, "O!O!:vert_splice",
+ &BPy_BMVert_Type, &py_vert,
+ &BPy_BMVert_Type, &py_vert_target))
+ {
+ return NULL;
+ }
+
+ BPY_BM_CHECK_OBJ(py_vert);
+ BPY_BM_CHECK_OBJ(py_vert_target);
+
+ bm = py_vert->bm;
+ BPY_BM_CHECK_SOURCE_OBJ(bm, "vert_splice", py_vert_target);
+
+ if (py_vert->v == py_vert_target->v) {
+ PyErr_SetString(PyExc_ValueError,
+ "vert_splice(...): vert arguments match");
+ return NULL;
+ }
+
+ if (BM_edge_exists(py_vert->v, py_vert_target->v)) {
+ PyErr_SetString(PyExc_ValueError,
+ "vert_splice(...): verts can't share an edge");
+ return NULL;
+ }
+
+ if (BM_vert_pair_share_face_check(py_vert->v, py_vert_target->v)) {
+ PyErr_SetString(PyExc_ValueError,
+ "vert_splice(...): verts can't share a face");
+ return NULL;
+ }
+
+ /* should always succeed */
+ ok = BM_vert_splice(bm, py_vert->v, py_vert_target->v);
+ BLI_assert(ok == true);
+
+ Py_RETURN_NONE;
+}
+
PyDoc_STRVAR(bpy_bm_utils_vert_separate_doc,
".. method:: vert_separate(vert, edges)\n"
"\n"
@@ -247,7 +306,7 @@ static PyObject *bpy_bm_utils_vert_separate(PyObject *UNUSED(self), PyObject *ar
BM_vert_separate(bm, py_vert->v, &elem, &elem_len, edge_array, edge_array_len);
/* return collected verts */
- ret = BPy_BMElem_Array_As_Tuple(bm, (BMHeader **)elem, elem_len);
+ ret = BPy_BMVert_Array_As_Tuple(bm, elem, elem_len);
MEM_freeN(elem);
PyMem_FREE(edge_array);
@@ -477,6 +536,78 @@ static PyObject *bpy_bm_utils_face_split(PyObject *UNUSED(self), PyObject *args,
}
+PyDoc_STRVAR(bpy_bm_utils_face_split_edgenet_doc,
+".. method:: face_split_edgenet(face, edgenet)\n"
+"\n"
+" Splits a face into any number of regions defined by an edgenet.\n"
+"\n"
+" :arg face: The face to split.\n"
+" :type face: :class:`bmesh.types.BMFace`\n"
+" :arg face: The face to split.\n"
+" :type face: :class:`bmesh.types.BMFace`\n"
+" :arg edgenet: Sequence of edges.\n"
+" :type edgenet: :class:`bmesh.types.BMEdge`\n"
+" :return: The newly created faces.\n"
+" :rtype: tuple of (:class:`bmesh.types.BMFace`)\n"
+);
+static PyObject *bpy_bm_utils_face_split_edgenet(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ static const char *kwlist[] = {"face", "edgenet", NULL};
+
+ BPy_BMFace *py_face;
+ PyObject *edge_seq;
+
+ BMEdge **edge_array;
+ Py_ssize_t edge_array_len;
+
+ BMesh *bm;
+
+ BMFace **face_arr;
+ int face_arr_len;
+ bool ok;
+
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "O!O:face_split_edgenet", (char **)kwlist,
+ &BPy_BMFace_Type, &py_face,
+ &edge_seq))
+ {
+ return NULL;
+ }
+
+ BPY_BM_CHECK_OBJ(py_face);
+
+ bm = py_face->bm;
+
+ edge_array = BPy_BMElem_PySeq_As_Array(&bm, edge_seq, 1, PY_SSIZE_T_MAX,
+ &edge_array_len, BM_EDGE,
+ true, true, "face_split_edgenet(...)");
+
+ if (edge_array == NULL) {
+ return NULL;
+ }
+
+ /* --- main function body --- */
+
+ ok = BM_face_split_edgenet(bm, py_face->f, edge_array, edge_array_len,
+ &face_arr, &face_arr_len);
+
+ PyMem_FREE(edge_array);
+
+ if (ok) {
+ PyObject *ret = BPy_BMFace_Array_As_Tuple(bm, face_arr, face_arr_len);
+ if (face_arr) {
+ MEM_freeN(face_arr);
+ }
+ return ret;
+ }
+ else {
+ PyErr_SetString(PyExc_ValueError,
+ "face_split_edgenet(...): couldn't split the face, internal error");
+ return NULL;
+ }
+}
+
+
PyDoc_STRVAR(bpy_bm_utils_face_join_doc,
".. method:: face_join(faces, remove=True)\n"
"\n"
@@ -548,7 +679,7 @@ static PyObject *bpy_bm_utils_face_vert_separate(PyObject *UNUSED(self), PyObjec
BMesh *bm;
BMLoop *l;
- BMVert *v_new;
+ BMVert *v_old, *v_new;
if (!PyArg_ParseTuple(args, "O!O!:face_vert_separate",
&BPy_BMFace_Type, &py_face,
@@ -560,7 +691,7 @@ static PyObject *bpy_bm_utils_face_vert_separate(PyObject *UNUSED(self), PyObjec
bm = py_face->bm;
BPY_BM_CHECK_OBJ(py_face);
- BPY_BM_CHECK_SOURCE_OBJ(py_vert, bm, "face_vert_separate()");
+ BPY_BM_CHECK_SOURCE_OBJ(bm, "face_vert_separate()", py_vert);
l = BM_face_vert_share_loop(py_face->f, py_vert->v);
@@ -570,9 +701,10 @@ static PyObject *bpy_bm_utils_face_vert_separate(PyObject *UNUSED(self), PyObjec
return NULL;
}
+ v_old = l->v;
v_new = BM_face_loop_separate(bm, l);
- if (v_new != l->v) {
+ if (v_new != v_old) {
return BPy_BMVert_CreatePyObject(bm, v_new);
}
else {
@@ -620,7 +752,8 @@ PyDoc_STRVAR(bpy_bm_utils_loop_separate_doc,
static PyObject *bpy_bm_utils_loop_separate(PyObject *UNUSED(self), BPy_BMLoop *value)
{
BMesh *bm;
- BMVert *v_new;
+ BMLoop *l;
+ BMVert *v_old, *v_new;
if (!BPy_BMLoop_Check(value)) {
PyErr_Format(PyExc_TypeError,
@@ -632,10 +765,12 @@ static PyObject *bpy_bm_utils_loop_separate(PyObject *UNUSED(self), BPy_BMLoop *
BPY_BM_CHECK_OBJ(value);
bm = value->bm;
+ l = value->l;
- v_new = BM_face_loop_separate(bm, value->l);
+ v_old = l->v;
+ v_new = BM_face_loop_separate(bm, l);
- if (v_new != value->l->v) {
+ if (v_new != v_old) {
return BPy_BMVert_CreatePyObject(bm, v_new);
}
else {
@@ -648,10 +783,12 @@ static struct PyMethodDef BPy_BM_utils_methods[] = {
{"vert_collapse_edge", (PyCFunction)bpy_bm_utils_vert_collapse_edge, METH_VARARGS, bpy_bm_utils_vert_collapse_edge_doc},
{"vert_collapse_faces", (PyCFunction)bpy_bm_utils_vert_collapse_faces, METH_VARARGS, bpy_bm_utils_vert_collapse_faces_doc},
{"vert_dissolve", (PyCFunction)bpy_bm_utils_vert_dissolve, METH_VARARGS, bpy_bm_utils_vert_dissolve_doc}, /* could use METH_O */
+ {"vert_splice", (PyCFunction)bpy_bm_utils_vert_splice, METH_VARARGS, bpy_bm_utils_vert_splice_doc},
{"vert_separate", (PyCFunction)bpy_bm_utils_vert_separate, METH_VARARGS, bpy_bm_utils_vert_separate_doc},
{"edge_split", (PyCFunction)bpy_bm_utils_edge_split, METH_VARARGS, bpy_bm_utils_edge_split_doc},
{"edge_rotate", (PyCFunction)bpy_bm_utils_edge_rotate, METH_VARARGS, bpy_bm_utils_edge_rotate_doc},
{"face_split", (PyCFunction)bpy_bm_utils_face_split, METH_VARARGS | METH_KEYWORDS, bpy_bm_utils_face_split_doc},
+ {"face_split_edgenet", (PyCFunction)bpy_bm_utils_face_split_edgenet, METH_VARARGS | METH_KEYWORDS, bpy_bm_utils_face_split_edgenet_doc},
{"face_join", (PyCFunction)bpy_bm_utils_face_join, METH_VARARGS, bpy_bm_utils_face_join_doc},
{"face_vert_separate", (PyCFunction)bpy_bm_utils_face_vert_separate, METH_VARARGS, bpy_bm_utils_face_vert_separate_doc},
{"face_flip", (PyCFunction)bpy_bm_utils_face_flip, METH_O, bpy_bm_utils_face_flip_doc},
diff --git a/source/blender/python/generic/CMakeLists.txt b/source/blender/python/generic/CMakeLists.txt
index aec2faa89e6..155247a4249 100644
--- a/source/blender/python/generic/CMakeLists.txt
+++ b/source/blender/python/generic/CMakeLists.txt
@@ -22,8 +22,10 @@ set(INC
.
../../blenkernel
../../blenlib
+ ../../gpu
../../makesdna
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
)
set(INC_SYS
@@ -46,6 +48,6 @@ set(SRC
py_capi_utils.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_python_ext "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c
index 292d3317a2e..c599ce26f6c 100644
--- a/source/blender/python/generic/bgl.c
+++ b/source/blender/python/generic/bgl.c
@@ -33,7 +33,7 @@
#include <Python.h>
#include "bgl.h" /*This must come first */
-#include <GL/glew.h>
+#include "GPU_glew.h"
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
@@ -301,7 +301,7 @@ static PyObject *Buffer_new(PyTypeObject *UNUSED(type), PyObject *args, PyObject
if (!PyArg_ParseTuple(args, "iO|O: bgl.Buffer", &type, &length_ob, &init)) {
return NULL;
}
- if (!ELEM5(type, GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE)) {
+ if (!ELEM(type, GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT, GL_DOUBLE)) {
PyErr_SetString(PyExc_AttributeError,
"invalid first argument type, should be one of "
"GL_BYTE, GL_SHORT, GL_INT, GL_FLOAT or GL_DOUBLE");
@@ -1381,10 +1381,16 @@ static struct PyModuleDef BGL_module_def = {
NULL, /* m_free */
};
+static void expp_addconst_int(PyObject *dict, const char *name, int value)
+{
+ PyObject *item;
+ PyDict_SetItemString(dict, name, item = PyLong_FromLong(value));
+ Py_DECREF(item);
+}
PyObject *BPyInit_bgl(void)
{
- PyObject *submodule, *dict, *item;
+ PyObject *submodule, *dict;
submodule = PyModule_Create(&BGL_module_def);
dict = PyModule_GetDict(submodule);
@@ -1394,11 +1400,7 @@ PyObject *BPyInit_bgl(void)
PyModule_AddObject(submodule, "Buffer", (PyObject *)&BGL_bufferType);
Py_INCREF((PyObject *)&BGL_bufferType);
-#define EXPP_ADDCONST(x) PyDict_SetItemString(dict, #x, item = PyLong_FromLong((int)x)); Py_DECREF(item)
-
-/* So, for example:
- * EXPP_ADDCONST(GL_CURRENT_BIT) becomes
- * PyDict_SetItemString(dict, "GL_CURRENT_BIT", item = PyLong_FromLong(GL_CURRENT_BIT)); Py_DECREF(item) */
+#define EXPP_ADDCONST(x) expp_addconst_int(dict, #x, x)
EXPP_ADDCONST(GL_CURRENT_BIT);
EXPP_ADDCONST(GL_POINT_BIT);
@@ -1896,9 +1898,20 @@ PyObject *BPyInit_bgl(void)
EXPP_ADDCONST(GL_TEXTURE7);
EXPP_ADDCONST(GL_TEXTURE8);
+ EXPP_ADDCONST(GL_MAX_TEXTURE_UNITS);
+
EXPP_ADDCONST(GL_DEPTH_COMPONENT32);
EXPP_ADDCONST(GL_TEXTURE_COMPARE_MODE);
+ EXPP_ADDCONST(GL_MAX_VARYING_FLOATS);
+ EXPP_ADDCONST(GL_MAX_VERTEX_ATTRIBS);
+ EXPP_ADDCONST(GL_MAX_VARYING_FLOATS);
+ EXPP_ADDCONST(GL_MAX_VERTEX_UNIFORM_COMPONENTS);
+ EXPP_ADDCONST(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS);
+ EXPP_ADDCONST(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS);
+ EXPP_ADDCONST(GL_MAX_TEXTURE_IMAGE_UNITS);
+ EXPP_ADDCONST(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS);
+
return submodule;
}
diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c
index dcdda2c440e..8c9e84af8ed 100644
--- a/source/blender/python/generic/idprop_py_api.c
+++ b/source/blender/python/generic/idprop_py_api.c
@@ -1541,7 +1541,7 @@ PyObject *BPyInit_idprop(void)
}
-#ifdef DEBUG
+#ifndef NDEBUG
/* -------------------------------------------------------------------- */
/* debug only function */
diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c
index 33ff63a9a28..36ae30ada22 100644
--- a/source/blender/python/generic/py_capi_utils.c
+++ b/source/blender/python/generic/py_capi_utils.c
@@ -40,8 +40,9 @@
/* only for BLI_strncpy_wchar_from_utf8, should replace with py funcs but too late in release now */
#include "BLI_string_utf8.h"
-#ifdef _WIN32 /* BLI_setenv */
-#include "BLI_path_util.h"
+#ifdef _WIN32
+#include "BLI_path_util.h" /* BLI_setenv() */
+#include "BLI_math_base.h" /* finite() */
#endif
/* array utility function */
@@ -418,7 +419,7 @@ PyObject *PyC_ExceptionBuffer(void)
if (!(string_io_mod = PyImport_ImportModule("io"))) {
goto error_cleanup;
}
- else if (!(string_io = PyObject_CallMethod(string_io_mod, (char *)"StringIO", NULL))) {
+ else if (!(string_io = PyObject_CallMethod(string_io_mod, "StringIO", NULL))) {
goto error_cleanup;
}
else if (!(string_io_getvalue = PyObject_GetAttrString(string_io, "getvalue"))) {
@@ -543,8 +544,9 @@ PyObject *PyC_DefaultNameSpace(const char *filename)
Py_DECREF(mod_main); /* sys.modules owns now */
PyModule_AddStringConstant(mod_main, "__name__", "__main__");
if (filename) {
- /* __file__ mainly for nice UI'ness */
- PyModule_AddObject(mod_main, "__file__", PyUnicode_DecodeFSDefault(filename));
+ /* __file__ mainly for nice UI'ness
+ * note: this wont map to a real file when executing text-blocks and buttons. */
+ PyModule_AddObject(mod_main, "__file__", PyC_UnicodeFromByte(filename));
}
PyModule_AddObject(mod_main, "__builtins__", interp->builtins);
Py_INCREF(interp->builtins); /* AddObject steals a reference */
@@ -605,8 +607,7 @@ void PyC_SetHomePath(const char *py_path_bundle)
/* cant use this, on linux gives bug: #23018, TODO: try LANG="en_US.UTF-8" /usr/bin/blender, suggested 22008 */
/* mbstowcs(py_path_bundle_wchar, py_path_bundle, FILE_MAXDIR); */
- BLI_strncpy_wchar_from_utf8(py_path_bundle_wchar, py_path_bundle,
- sizeof(py_path_bundle_wchar) / sizeof(wchar_t));
+ BLI_strncpy_wchar_from_utf8(py_path_bundle_wchar, py_path_bundle, ARRAY_SIZE(py_path_bundle_wchar));
Py_SetPythonHome(py_path_bundle_wchar);
// printf("found python (wchar_t) '%ls'\n", py_path_bundle_wchar);
@@ -650,12 +651,12 @@ void PyC_RunQuicky(const char *filepath, int n, ...)
const char *format = va_arg(vargs, char *);
void *ptr = va_arg(vargs, void *);
- ret = PyObject_CallFunction(calcsize, (char *)"s", format);
+ ret = PyObject_CallFunction(calcsize, "s", format);
if (ret) {
sizes[i] = PyLong_AsLong(ret);
Py_DECREF(ret);
- ret = PyObject_CallFunction(unpack, (char *)"sy#", format, (char *)ptr, sizes[i]);
+ ret = PyObject_CallFunction(unpack, "sy#", format, (char *)ptr, sizes[i]);
}
if (ret == NULL) {
@@ -904,3 +905,73 @@ PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag)
return ret;
}
+
+
+/**
+ * \return -1 on error, else 0
+ *
+ * \note it is caller's responsibility to acquire & release GIL!
+ */
+int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename)
+{
+ PyObject *py_dict, *mod, *retval;
+ int error_ret = 0;
+ PyObject *main_mod = NULL;
+
+ PyC_MainModule_Backup(&main_mod);
+
+ py_dict = PyC_DefaultNameSpace(filename);
+
+ mod = PyImport_ImportModule("math");
+ if (mod) {
+ PyDict_Merge(py_dict, PyModule_GetDict(mod), 0); /* 0 - don't overwrite existing values */
+ Py_DECREF(mod);
+ }
+ else { /* highly unlikely but possibly */
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
+
+ if (retval == NULL) {
+ error_ret = -1;
+ }
+ else {
+ double val;
+
+ if (PyTuple_Check(retval)) {
+ /* Users my have typed in 10km, 2m
+ * add up all values */
+ int i;
+ val = 0.0;
+
+ for (i = 0; i < PyTuple_GET_SIZE(retval); i++) {
+ const double val_item = PyFloat_AsDouble(PyTuple_GET_ITEM(retval, i));
+ if (val_item == -1 && PyErr_Occurred()) {
+ val = -1;
+ break;
+ }
+ val += val_item;
+ }
+ }
+ else {
+ val = PyFloat_AsDouble(retval);
+ }
+ Py_DECREF(retval);
+
+ if (val == -1 && PyErr_Occurred()) {
+ error_ret = -1;
+ }
+ else if (!finite(val)) {
+ *value = 0.0;
+ }
+ else {
+ *value = val;
+ }
+ }
+
+ PyC_MainModule_Restore(main_mod);
+
+ return error_ret;
+}
diff --git a/source/blender/python/generic/py_capi_utils.h b/source/blender/python/generic/py_capi_utils.h
index 0afc4dd98d9..559a8e15678 100644
--- a/source/blender/python/generic/py_capi_utils.h
+++ b/source/blender/python/generic/py_capi_utils.h
@@ -73,4 +73,6 @@ int PyC_FlagSet_ValueFromID(PyC_FlagSet *item, const char *identifier, int
int PyC_FlagSet_ToBitfield(PyC_FlagSet *items, PyObject *value, int *r_value, const char *error_prefix);
PyObject *PyC_FlagSet_FromBitfield(PyC_FlagSet *items, int flag);
+int PyC_RunString_AsNumber(const char *expr, double *value, const char *filename);
+
#endif /* __PY_CAPI_UTILS_H__ */
diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt
index 48877944563..d77bfbedd43 100644
--- a/source/blender/python/intern/CMakeLists.txt
+++ b/source/blender/python/intern/CMakeLists.txt
@@ -68,6 +68,7 @@ set(SRC
bpy_rna_callback.c
bpy_traceback.c
bpy_util.c
+ bpy_utils_units.c
stubs.c
gpu.h
@@ -91,6 +92,7 @@ set(SRC
bpy_rna_callback.h
bpy_traceback.h
bpy_util.h
+ bpy_utils_units.h
../BPY_extern.h
)
@@ -262,5 +264,6 @@ if(WITH_PLAYER)
add_definitions(-DWITH_PLAYER)
endif()
+add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_python "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c
index 89104821cb0..134e718bce5 100644
--- a/source/blender/python/intern/bpy.c
+++ b/source/blender/python/intern/bpy.c
@@ -49,6 +49,9 @@
#include "bpy_props.h"
#include "bpy_library.h"
#include "bpy_operator.h"
+#include "bpy_utils_units.h"
+
+#include "../generic/py_capi_utils.h"
#include "MEM_guardedalloc.h"
@@ -56,6 +59,7 @@
#include "../generic/idprop_py_api.h"
#include "../generic/bgl.h"
#include "../generic/blf_py_api.h"
+#include "../generic/blf_py_api.h"
#include "../mathutils/mathutils.h"
#ifdef WITH_FREESTYLE
@@ -79,11 +83,11 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self))
const char *path;
path = BLI_get_folder(BLENDER_SYSTEM_SCRIPTS, NULL);
- item = PyUnicode_DecodeFSDefault(path ? path : "");
+ item = PyC_UnicodeFromByte(path ? path : "");
BLI_assert(item != NULL);
PyTuple_SET_ITEM(ret, 0, item);
path = BLI_get_folder(BLENDER_USER_SCRIPTS, NULL);
- item = PyUnicode_DecodeFSDefault(path ? path : "");
+ item = PyC_UnicodeFromByte(path ? path : "");
BLI_assert(item != NULL);
PyTuple_SET_ITEM(ret, 1, item);
@@ -93,7 +97,7 @@ static PyObject *bpy_script_paths(PyObject *UNUSED(self))
static bool bpy_blend_paths_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
{
PyObject *list = (PyObject *)userdata;
- PyObject *item = PyUnicode_DecodeFSDefault(path_src);
+ PyObject *item = PyC_UnicodeFromByte(path_src);
PyList_Append(list, item);
Py_DECREF(item);
return false; /* never edits the path */
@@ -170,7 +174,7 @@ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObj
if (!path)
path = BLI_get_user_folder_notest(folder_id, subdir);
- return PyUnicode_DecodeFSDefault(path ? path : "");
+ return PyC_UnicodeFromByte(path ? path : "");
}
PyDoc_STRVAR(bpy_resource_path_doc,
@@ -209,7 +213,7 @@ static PyObject *bpy_resource_path(PyObject *UNUSED(self), PyObject *args, PyObj
path = BLI_get_folder_version(folder_id, (major * 100) + minor, false);
- return PyUnicode_DecodeFSDefault(path ? path : "");
+ return PyC_UnicodeFromByte(path ? path : "");
}
PyDoc_STRVAR(bpy_escape_identifier_doc,
@@ -334,6 +338,7 @@ void BPy_init_modules(void)
/* ops is now a python module that does the conversion from SOME_OT_foo -> some.foo */
PyModule_AddObject(mod, "ops", BPY_operator_module());
PyModule_AddObject(mod, "app", BPY_app_struct());
+ PyModule_AddObject(mod, "_utils_units", BPY_utils_units());
/* 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 795015c42a0..16cdd44ce38 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -107,7 +107,7 @@ static PyStructSequence_Desc app_info_desc = {
(char *)"bpy.app", /* name */
(char *)"This module contains application values that remain unchanged during runtime.", /* doc */
app_info_fields, /* fields */
- (sizeof(app_info_fields) / sizeof(PyStructSequence_Field)) - 1
+ ARRAY_SIZE(app_info_fields) - 1
};
static PyObject *make_app_info(void)
@@ -250,7 +250,7 @@ PyDoc_STRVAR(bpy_app_tempdir_doc,
);
static PyObject *bpy_app_tempdir_get(PyObject *UNUSED(self), void *UNUSED(closure))
{
- return PyC_UnicodeFromByte(BLI_temporary_dir());
+ return PyC_UnicodeFromByte(BLI_temp_dir_session());
}
PyDoc_STRVAR(bpy_app_driver_dict_doc,
@@ -283,6 +283,7 @@ static PyGetSetDef bpy_app_getsets[] = {
{(char *)"debug_events", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_EVENTS},
{(char *)"debug_handlers", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_HANDLERS},
{(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_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_build_options.c b/source/blender/python/intern/bpy_app_build_options.c
index f43b67cf42f..022713558d7 100644
--- a/source/blender/python/intern/bpy_app_build_options.c
+++ b/source/blender/python/intern/bpy_app_build_options.c
@@ -26,6 +26,8 @@
#include <Python.h>
+#include "BLI_utildefines.h"
+
#include "bpy_app_build_options.h"
static PyTypeObject BlenderAppBuildOptionsType;
@@ -74,7 +76,7 @@ static PyStructSequence_Desc app_builtopts_info_desc = {
(char *)"bpy.app.build_options", /* name */
(char *)"This module contains information about options blender is built with", /* doc */
app_builtopts_info_fields, /* fields */
- (sizeof(app_builtopts_info_fields) / sizeof(PyStructSequence_Field)) - 1
+ ARRAY_SIZE(app_builtopts_info_fields) - 1
};
static PyObject *make_builtopts_info(void)
diff --git a/source/blender/python/intern/bpy_app_ffmpeg.c b/source/blender/python/intern/bpy_app_ffmpeg.c
index 2f7577928c5..fd516e4547f 100644
--- a/source/blender/python/intern/bpy_app_ffmpeg.c
+++ b/source/blender/python/intern/bpy_app_ffmpeg.c
@@ -60,7 +60,7 @@ static PyStructSequence_Desc app_ffmpeg_info_desc = {
(char *)"bpy.app.ffmpeg", /* name */
(char *)"This module contains information about FFmpeg blender is linked against", /* doc */
app_ffmpeg_info_fields, /* fields */
- (sizeof(app_ffmpeg_info_fields) / sizeof(PyStructSequence_Field)) - 1
+ ARRAY_SIZE(app_ffmpeg_info_fields) - 1
};
static PyObject *make_ffmpeg_info(void)
diff --git a/source/blender/python/intern/bpy_app_handlers.c b/source/blender/python/intern/bpy_app_handlers.c
index b3be5a819fb..44da322efc0 100644
--- a/source/blender/python/intern/bpy_app_handlers.c
+++ b/source/blender/python/intern/bpy_app_handlers.c
@@ -49,6 +49,7 @@ static PyStructSequence_Field app_cb_info_fields[] = {
{(char *)"render_pre", (char *)"Callback list - on render (before)"},
{(char *)"render_post", (char *)"Callback list - on render (after)"},
{(char *)"render_stats", (char *)"Callback list - on printing render statistics"},
+ {(char *)"render_init", (char *)"Callback list - on initialization of a render job"},
{(char *)"render_complete", (char *)"Callback list - on completion of render job"},
{(char *)"render_cancel", (char *)"Callback list - on canceling a render job"},
{(char *)"load_pre", (char *)"Callback list - on loading a new blend file (before)"},
@@ -59,6 +60,7 @@ static PyStructSequence_Field app_cb_info_fields[] = {
{(char *)"scene_update_post", (char *)"Callback list - on updating the scenes data (after)"},
{(char *)"game_pre", (char *)"Callback list - on starting the game engine"},
{(char *)"game_post", (char *)"Callback list - on ending the game engine"},
+ {(char *)"version_update", (char *)"Callback list - on ending the versioning code"},
/* sets the permanent tag */
# define APP_CB_OTHER_FIELDS 1
@@ -71,11 +73,11 @@ static PyStructSequence_Desc app_cb_info_desc = {
(char *)"bpy.app.handlers", /* name */
(char *)"This module contains callbacks", /* doc */
app_cb_info_fields, /* fields */
- (sizeof(app_cb_info_fields) / sizeof(PyStructSequence_Field)) - 1
+ ARRAY_SIZE(app_cb_info_fields) - 1
};
#if 0
-# if (BLI_CB_EVT_TOT != ((sizeof(app_cb_info_fields) / sizeof(PyStructSequence_Field))))
+# if (BLI_CB_EVT_TOT != ARRAY_SIZE(app_cb_info_fields))
# error "Callbacks are out of sync"
# endif
#endif
@@ -238,8 +240,11 @@ PyObject *BPY_app_handlers_struct(void)
void BPY_app_handlers_reset(const short do_all)
{
+ PyGILState_STATE gilstate;
int pos = 0;
+ gilstate = PyGILState_Ensure();
+
if (do_all) {
for (pos = 0; pos < BLI_CB_EVT_TOT; pos++) {
/* clear list */
@@ -277,6 +282,8 @@ void BPY_app_handlers_reset(const short do_all)
Py_DECREF(perm_id_str);
}
+
+ PyGILState_Release(gilstate);
}
/* the actual callback - not necessarily called from py */
diff --git a/source/blender/python/intern/bpy_app_ocio.c b/source/blender/python/intern/bpy_app_ocio.c
index eff52bc9dae..02e4044219a 100644
--- a/source/blender/python/intern/bpy_app_ocio.c
+++ b/source/blender/python/intern/bpy_app_ocio.c
@@ -46,7 +46,7 @@ static PyStructSequence_Desc app_ocio_info_desc = {
(char *)"bpy.app.ocio", /* name */
(char *)"This module contains information about OpenColorIO blender is linked against", /* doc */
app_ocio_info_fields, /* fields */
- (sizeof(app_ocio_info_fields) / sizeof(PyStructSequence_Field)) - 1
+ ARRAY_SIZE(app_ocio_info_fields) - 1
};
static PyObject *make_ocio_info(void)
diff --git a/source/blender/python/intern/bpy_app_oiio.c b/source/blender/python/intern/bpy_app_oiio.c
index b5f0f321c6d..60daf3ddd8b 100644
--- a/source/blender/python/intern/bpy_app_oiio.c
+++ b/source/blender/python/intern/bpy_app_oiio.c
@@ -46,7 +46,7 @@ static PyStructSequence_Desc app_oiio_info_desc = {
(char *)"bpy.app.oiio", /* name */
(char *)"This module contains information about OpeImageIO blender is linked against", /* doc */
app_oiio_info_fields, /* fields */
- (sizeof(app_oiio_info_fields) / sizeof(PyStructSequence_Field)) - 1
+ ARRAY_SIZE(app_oiio_info_fields) - 1
};
static PyObject *make_oiio_info(void)
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index e168bf33eb5..0114e8e65e4 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -86,16 +86,15 @@ static unsigned int _ghashutil_keyhash(const void *ptr)
return hash ^ BLI_ghashutil_strhash(key->msgid);
}
-static int _ghashutil_keycmp(const void *a, const void *b)
+static bool _ghashutil_keycmp(const void *a, const void *b)
{
const GHashKey *A = a;
const GHashKey *B = b;
/* Note: comparing msgid first, most of the time it will be enough! */
- int cmp = BLI_ghashutil_strcmp(A->msgid, B->msgid);
- if (cmp == 0)
+ if (BLI_ghashutil_strcmp(A->msgid, B->msgid) == false)
return BLI_ghashutil_strcmp(A->msgctxt, B->msgctxt);
- return cmp;
+ return true; /* true means they are not equal! */
}
static void _ghashutil_keyfree(void *ptr)
@@ -390,13 +389,13 @@ static BLF_i18n_contexts_descriptor _contexts[] = BLF_I18NCONTEXTS_DESC;
* This allows us to avoid many handwriting, and above all, to keep all context definition stuff in BLF_translation.h!
*/
static PyStructSequence_Field
-app_translations_contexts_fields[sizeof(_contexts) / sizeof(BLF_i18n_contexts_descriptor)] = {{NULL}};
+app_translations_contexts_fields[ARRAY_SIZE(_contexts)] = {{NULL}};
static PyStructSequence_Desc app_translations_contexts_desc = {
(char *)"bpy.app.translations.contexts", /* name */
(char *)"This named tuple contains all pre-defined translation contexts", /* doc */
app_translations_contexts_fields, /* fields */
- (sizeof(app_translations_contexts_fields) / sizeof(PyStructSequence_Field)) - 1
+ ARRAY_SIZE(app_translations_contexts_fields) - 1
};
static PyObject *app_translations_contexts_make(void)
diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c
index 3a2a09dc3b3..060cd4c4997 100644
--- a/source/blender/python/intern/bpy_interface.c
+++ b/source/blender/python/intern/bpy_interface.c
@@ -214,26 +214,29 @@ static PyObject *CCL_initPython(void)
#endif
static struct _inittab bpy_internal_modules[] = {
- {(char *)"mathutils", PyInit_mathutils},
-// {(char *)"mathutils.geometry", PyInit_mathutils_geometry},
-// {(char *)"mathutils.noise", PyInit_mathutils_noise},
-// {(char *)"mathutils.kdtree", PyInit_mathutils_kdtree},
- {(char *)"_bpy_path", BPyInit__bpy_path},
- {(char *)"bgl", BPyInit_bgl},
- {(char *)"blf", BPyInit_blf},
- {(char *)"bmesh", BPyInit_bmesh},
- {(char *)"manta", PyInit_Manta},
- // {(char *)"bmesh.types", BPyInit_bmesh_types},
- // {(char *)"bmesh.utils", BPyInit_bmesh_utils},
- // {(char *)"bmesh.utils", BPyInit_bmesh_geometry},
+ {"mathutils", PyInit_mathutils},
+#if 0
+ {"mathutils.geometry", PyInit_mathutils_geometry},
+ {"mathutils.noise", PyInit_mathutils_noise},
+ {"mathutils.kdtree", PyInit_mathutils_kdtree},
+#endif
+ {"_bpy_path", BPyInit__bpy_path},
+ {"bgl", BPyInit_bgl},
+ {"blf", BPyInit_blf},
+ {"bmesh", BPyInit_bmesh},
+#if 0
+ {"bmesh.types", BPyInit_bmesh_types},
+ {"bmesh.utils", BPyInit_bmesh_utils},
+ {"bmesh.utils", BPyInit_bmesh_geometry},
+#endif
#ifdef WITH_AUDASPACE
- {(char *)"aud", AUD_initPython},
+ {"aud", AUD_initPython},
#endif
#ifdef WITH_CYCLES
- {(char *)"_cycles", CCL_initPython},
+ {"_cycles", CCL_initPython},
#endif
- {(char *)"gpu", GPU_initPython},
- {(char *)"idprop", BPyInit_idprop},
+ {"gpu", GPU_initPython},
+ {"idprop", BPyInit_idprop},
{NULL, NULL}
};
@@ -246,7 +249,7 @@ void BPY_python_start(int argc, const char **argv)
/* not essential but nice to set our name */
static wchar_t program_path_wchar[FILE_MAX]; /* python holds a reference */
- BLI_strncpy_wchar_from_utf8(program_path_wchar, BLI_program_path(), sizeof(program_path_wchar) / sizeof(wchar_t));
+ BLI_strncpy_wchar_from_utf8(program_path_wchar, BLI_program_path(), ARRAY_SIZE(program_path_wchar));
Py_SetProgramName(program_path_wchar);
/* must run before python initializes */
@@ -419,7 +422,7 @@ static void python_script_error_jump_text(struct Text *text)
typedef struct {
PyObject_HEAD
PyObject *md_dict;
- /* ommit other values, we only want the dict. */
+ /* omit other values, we only want the dict. */
} PyModuleObject;
#endif
@@ -569,15 +572,12 @@ void BPY_DECREF_RNA_INVALIDATE(void *pyob_ptr)
PyGILState_Release(gilstate);
}
-
/* return -1 on error, else 0 */
int BPY_button_exec(bContext *C, const char *expr, double *value, const bool verbose)
{
PyGILState_STATE gilstate;
- PyObject *py_dict, *mod, *retval;
int error_ret = 0;
- PyObject *main_mod = NULL;
-
+
if (!value || !expr) return -1;
if (expr[0] == '\0') {
@@ -587,59 +587,8 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const bool ver
bpy_context_set(C, &gilstate);
- PyC_MainModule_Backup(&main_mod);
-
- py_dict = PyC_DefaultNameSpace("<blender button>");
-
- mod = PyImport_ImportModule("math");
- if (mod) {
- PyDict_Merge(py_dict, PyModule_GetDict(mod), 0); /* 0 - don't overwrite existing values */
- Py_DECREF(mod);
- }
- else { /* highly unlikely but possibly */
- PyErr_Print();
- PyErr_Clear();
- }
-
- retval = PyRun_String(expr, Py_eval_input, py_dict, py_dict);
-
- if (retval == NULL) {
- error_ret = -1;
- }
- else {
- double val;
+ error_ret = PyC_RunString_AsNumber(expr, value, "<blender button>");
- if (PyTuple_Check(retval)) {
- /* Users my have typed in 10km, 2m
- * add up all values */
- int i;
- val = 0.0;
-
- for (i = 0; i < PyTuple_GET_SIZE(retval); i++) {
- const double val_item = PyFloat_AsDouble(PyTuple_GET_ITEM(retval, i));
- if (val_item == -1 && PyErr_Occurred()) {
- val = -1;
- break;
- }
- val += val_item;
- }
- }
- else {
- val = PyFloat_AsDouble(retval);
- }
- Py_DECREF(retval);
-
- if (val == -1 && PyErr_Occurred()) {
- error_ret = -1;
- }
- else if (!finite(val)) {
- *value = 0.0;
- }
- else {
- *value = val;
- }
- }
-
if (error_ret) {
if (verbose) {
BPy_errors_to_report(CTX_wm_reports(C));
@@ -649,10 +598,8 @@ int BPY_button_exec(bContext *C, const char *expr, double *value, const bool ver
}
}
- PyC_MainModule_Restore(main_mod);
-
bpy_context_clear(C, &gilstate);
-
+
return error_ret;
}
diff --git a/source/blender/python/intern/bpy_intern_string.c b/source/blender/python/intern/bpy_intern_string.c
index 9c93af1786c..fd32c91a480 100644
--- a/source/blender/python/intern/bpy_intern_string.c
+++ b/source/blender/python/intern/bpy_intern_string.c
@@ -69,12 +69,12 @@ void bpy_intern_string_init(void)
#undef BPY_INTERN_STR
- BLI_assert(i == (sizeof(bpy_intern_str_arr) / sizeof(*bpy_intern_str_arr)));
+ BLI_assert(i == ARRAY_SIZE(bpy_intern_str_arr));
}
void bpy_intern_string_exit(void)
{
- unsigned int i = sizeof(bpy_intern_str_arr) / sizeof(*bpy_intern_str_arr);
+ unsigned int i = ARRAY_SIZE(bpy_intern_str_arr);
while (i--) {
Py_DECREF(bpy_intern_str_arr[i]);
}
diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c
index 2c526601fcd..1e97d7aeada 100644
--- a/source/blender/python/intern/bpy_operator.c
+++ b/source/blender/python/intern/bpy_operator.c
@@ -58,7 +58,7 @@
#include "BKE_report.h"
#include "BKE_context.h"
-/* so operators called can spawn threads which aquire the GIL */
+/* so operators called can spawn threads which acquire the GIL */
#define BPY_RELEASE_GIL
diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c
index 6e36680ec4a..9a8c3d89e8d 100644
--- a/source/blender/python/intern/bpy_props.c
+++ b/source/blender/python/intern/bpy_props.c
@@ -79,8 +79,8 @@ static EnumPropertyItem property_flag_enum_items[] = {
{0, NULL, 0, NULL, NULL}};
#define BPY_PROPDEF_OPTIONS_ENUM_DOC \
-" :type default: string or set\n" \
" :arg options: Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'ENUM_FLAG', 'LIBRARY_EDITABLE'].\n" \
+" :type options: set\n" \
/* subtypes */
/* XXX Keep in sync with rna_rna.c's property_subtype_items ???
@@ -1818,23 +1818,62 @@ static void bpy_prop_callback_assign_enum(struct PropertyRNA *prop, PyObject *ge
" :arg name: Name used in the user interface.\n" \
" :type name: string\n" \
-
#define BPY_PROPDEF_DESC_DOC \
" :arg description: Text used for the tooltip and api documentation.\n" \
" :type description: string\n" \
-
#define BPY_PROPDEF_UNIT_DOC \
" :arg unit: Enumerator in ['NONE', 'LENGTH', 'AREA', 'VOLUME', 'ROTATION', 'TIME', 'VELOCITY', 'ACCELERATION'].\n" \
" :type unit: string\n" \
+#define BPY_PROPDEF_NUM_MIN_DOC \
+" :arg min: Hard minimum, trying to assign a value below will silently assign this minimum instead.\n" \
+
+#define BPY_PROPDEF_NUM_MAX_DOC \
+" :arg max: Hard maximum, trying to assign a value above will silently assign this maximum instead.\n" \
+
+#define BPY_PROPDEF_NUM_SOFTMIN_DOC \
+" :arg soft_min: Soft minimum (>= *min*), user won't be able to drag the widget below this value in the UI.\n" \
+
+#define BPY_PROPDEF_NUM_SOFTMAX_DOC \
+" :arg soft_max: Soft maximum (<= *max*), user won't be able to drag the widget above this value in the UI.\n" \
+
+#define BPY_PROPDEF_VECSIZE_DOC \
+" :arg size: Vector dimensions in [1, " STRINGIFY(PYRNA_STACK_ARRAY) "].\n" \
+" :type size: int\n" \
+
+#define BPY_PROPDEF_INT_STEP_DOC \
+" :arg step: Step of increment/decrement in UI, in [1, 100], defaults to 1 (WARNING: unused currently!).\n" \
+" :type step: int\n" \
+
+#define BPY_PROPDEF_FLOAT_STEP_DOC \
+" :arg step: Step of increment/decrement in UI, in [1, 100], defaults to 3 (WARNING: actual value is /100).\n" \
+" :type step: int\n" \
+
+#define BPY_PROPDEF_FLOAT_PREC_DOC \
+" :arg precision: Maximum number of decimal digits to display, in [0, 6].\n" \
+" :type precision: int\n" \
#define BPY_PROPDEF_UPDATE_DOC \
-" :arg update: function to be called when this value is modified,\n" \
+" :arg update: Function to be called when this value is modified,\n" \
" This function must take 2 values (self, context) and return None.\n" \
" *Warning* there are no safety checks to avoid infinite recursion.\n" \
" :type update: function\n" \
+#define BPY_PROPDEF_GET_DOC \
+" :arg get: Function to be called when this value is 'read',\n" \
+" This function must take 1 value (self) and return the value of the property.\n" \
+" :type get: function\n" \
+
+#define BPY_PROPDEF_SET_DOC \
+" :arg set: Function to be called when this value is 'written',\n" \
+" This function must take 2 values (self, value) and return None.\n" \
+" :type set: function\n" \
+
+#define BPY_PROPDEF_TYPE_DOC \
+" :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n" \
+" :type type: class\n" \
+
#if 0
static int bpy_struct_id_used(StructRNA *srna, char *identifier)
{
@@ -1865,6 +1904,8 @@ BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_SUBTYPE_NUMBER_DOC
BPY_PROPDEF_UPDATE_DOC
+BPY_PROPDEF_GET_DOC
+BPY_PROPDEF_SET_DOC
);
static PyObject *BPy_BoolProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -1946,9 +1987,10 @@ BPY_PROPDEF_DESC_DOC
" :type default: sequence\n"
BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_SUBTYPE_ARRAY_DOC
-" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n"
-" :type size: int\n"
+BPY_PROPDEF_VECSIZE_DOC
BPY_PROPDEF_UPDATE_DOC
+BPY_PROPDEF_GET_DOC
+BPY_PROPDEF_SET_DOC
);
static PyObject *BPy_BoolVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -2042,9 +2084,20 @@ PyDoc_STRVAR(BPy_IntProperty_doc,
"\n"
BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
+BPY_PROPDEF_NUM_MIN_DOC
+" :type min: int\n"
+BPY_PROPDEF_NUM_MAX_DOC
+" :type max: int\n"
+BPY_PROPDEF_NUM_SOFTMAX_DOC
+" :type soft_min: int\n"
+BPY_PROPDEF_NUM_SOFTMIN_DOC
+" :type soft_max: int\n"
+BPY_PROPDEF_INT_STEP_DOC
BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_SUBTYPE_NUMBER_DOC
BPY_PROPDEF_UPDATE_DOC
+BPY_PROPDEF_GET_DOC
+BPY_PROPDEF_SET_DOC
);
static PyObject *BPy_IntProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -2116,6 +2169,7 @@ PyDoc_STRVAR(BPy_IntVectorProperty_doc,
"default=(0, 0, 0), min=-2**31, max=2**31-1, "
"soft_min=-2**31, "
"soft_max=2**31-1, "
+ "step=1, "
"options={'ANIMATABLE'}, "
"subtype='NONE', "
"size=3, "
@@ -2129,11 +2183,21 @@ BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
" :arg default: sequence of ints the length of *size*.\n"
" :type default: sequence\n"
+BPY_PROPDEF_NUM_MIN_DOC
+" :type min: int\n"
+BPY_PROPDEF_NUM_MAX_DOC
+" :type max: int\n"
+BPY_PROPDEF_NUM_SOFTMIN_DOC
+" :type soft_min: int\n"
+BPY_PROPDEF_NUM_SOFTMAX_DOC
+" :type soft_max: int\n"
+BPY_PROPDEF_INT_STEP_DOC
BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_SUBTYPE_ARRAY_DOC
-" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n"
-" :type size: int\n"
+BPY_PROPDEF_VECSIZE_DOC
BPY_PROPDEF_UPDATE_DOC
+BPY_PROPDEF_GET_DOC
+BPY_PROPDEF_SET_DOC
);
static PyObject *BPy_IntVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -2234,12 +2298,22 @@ PyDoc_STRVAR(BPy_FloatProperty_doc,
"\n"
BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
+BPY_PROPDEF_NUM_MIN_DOC
+" :type min: float\n"
+BPY_PROPDEF_NUM_MAX_DOC
+" :type max: float\n"
+BPY_PROPDEF_NUM_SOFTMIN_DOC
+" :type soft_min: float\n"
+BPY_PROPDEF_NUM_SOFTMAX_DOC
+" :type soft_max: float\n"
+BPY_PROPDEF_FLOAT_STEP_DOC
+BPY_PROPDEF_FLOAT_PREC_DOC
BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_SUBTYPE_NUMBER_DOC
BPY_PROPDEF_UNIT_DOC
BPY_PROPDEF_UPDATE_DOC
-" :arg precision: Number of digits of precision to display.\n"
-" :type precision: int\n"
+BPY_PROPDEF_GET_DOC
+BPY_PROPDEF_SET_DOC
);
static PyObject *BPy_FloatProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -2325,6 +2399,7 @@ PyDoc_STRVAR(BPy_FloatVectorProperty_doc,
"precision=2, "
"options={'ANIMATABLE'}, "
"subtype='NONE', "
+ "unit='NONE', "
"size=3, "
"update=None, "
"get=None, "
@@ -2336,14 +2411,23 @@ BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
" :arg default: sequence of floats the length of *size*.\n"
" :type default: sequence\n"
+BPY_PROPDEF_NUM_MIN_DOC
+" :type min: float\n"
+BPY_PROPDEF_NUM_MAX_DOC
+" :type max: float\n"
+BPY_PROPDEF_NUM_SOFTMIN_DOC
+" :type soft_min: float\n"
+BPY_PROPDEF_NUM_SOFTMAX_DOC
+" :type soft_max: float\n"
BPY_PROPDEF_OPTIONS_DOC
+BPY_PROPDEF_FLOAT_STEP_DOC
+BPY_PROPDEF_FLOAT_PREC_DOC
BPY_PROPDEF_SUBTYPE_ARRAY_DOC
BPY_PROPDEF_UNIT_DOC
-" :arg size: Vector dimensions in [1, and " STRINGIFY(PYRNA_STACK_ARRAY) "].\n"
-" :type size: int\n"
-" :arg precision: Number of digits of precision to display.\n"
-" :type precision: int\n"
+BPY_PROPDEF_VECSIZE_DOC
BPY_PROPDEF_UPDATE_DOC
+BPY_PROPDEF_GET_DOC
+BPY_PROPDEF_SET_DOC
);
static PyObject *BPy_FloatVectorProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -2449,9 +2533,13 @@ BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
" :arg default: initializer string.\n"
" :type default: string\n"
+" :arg maxlen: maximum length of the string.\n"
+" :type maxlen: int\n"
BPY_PROPDEF_OPTIONS_DOC
BPY_PROPDEF_SUBTYPE_STRING_DOC
BPY_PROPDEF_UPDATE_DOC
+BPY_PROPDEF_GET_DOC
+BPY_PROPDEF_SET_DOC
);
static PyObject *BPy_StringProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -2526,12 +2614,6 @@ PyDoc_STRVAR(BPy_EnumProperty_doc,
"\n"
" Returns a new enumerator property definition.\n"
"\n"
-BPY_PROPDEF_NAME_DOC
-BPY_PROPDEF_DESC_DOC
-" :arg default: The default value for this enum, a string from the identifiers used in *items*.\n"
-" If the *ENUM_FLAG* option is used this must be a set of such string identifiers instead.\n"
-BPY_PROPDEF_OPTIONS_ENUM_DOC
-" :type options: set\n"
" :arg items: sequence of enum items formatted:\n"
" [(identifier, name, description, icon, number), ...] where the identifier is used\n"
" for python access and other values are used for the interface.\n"
@@ -2545,7 +2627,15 @@ BPY_PROPDEF_OPTIONS_ENUM_DOC
" 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"
+BPY_PROPDEF_NAME_DOC
+BPY_PROPDEF_DESC_DOC
+" :arg default: The default value for this enum, a string from the identifiers used in *items*.\n"
+" If the *ENUM_FLAG* option is used this must be a set of such string identifiers instead.\n"
+" :type default: string or set\n"
+BPY_PROPDEF_OPTIONS_ENUM_DOC
BPY_PROPDEF_UPDATE_DOC
+BPY_PROPDEF_GET_DOC
+BPY_PROPDEF_SET_DOC
);
static PyObject *BPy_EnumProperty(PyObject *self, PyObject *args, PyObject *kw)
{
@@ -2685,15 +2775,15 @@ static StructRNA *pointer_type_from_py(PyObject *value, const char *error_prefix
}
PyDoc_STRVAR(BPy_PointerProperty_doc,
-".. function:: PointerProperty(type=\"\", "
+".. function:: PointerProperty(type=None, "
+ "name=\"\", "
"description=\"\", "
"options={'ANIMATABLE'}, "
"update=None)\n"
"\n"
" Returns a new pointer property definition.\n"
"\n"
-" :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n"
-" :type type: class\n"
+BPY_PROPDEF_TYPE_DOC
BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC
@@ -2750,15 +2840,14 @@ static PyObject *BPy_PointerProperty(PyObject *self, PyObject *args, PyObject *k
}
PyDoc_STRVAR(BPy_CollectionProperty_doc,
-".. function:: CollectionProperty(items, "
- "type=\"\", "
+".. function:: CollectionProperty(type=None, "
+ "name=\"\", "
"description=\"\", "
"options={'ANIMATABLE'})\n"
"\n"
" Returns a new collection property definition.\n"
"\n"
-" :arg type: A subclass of :class:`bpy.types.PropertyGroup`.\n"
-" :type type: class\n"
+BPY_PROPDEF_TYPE_DOC
BPY_PROPDEF_NAME_DOC
BPY_PROPDEF_DESC_DOC
BPY_PROPDEF_OPTIONS_DOC
@@ -2884,7 +2973,8 @@ 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.",
+ " 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.",
-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 38a0f74f009..f6e97d6a2d8 100644
--- a/source/blender/python/intern/bpy_rna.c
+++ b/source/blender/python/intern/bpy_rna.c
@@ -604,18 +604,34 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
#ifdef USE_MATHUTILS
int subtype, totdim;
int len;
- bool is_thick;
const int flag = RNA_property_flag(prop);
+ const int type = RNA_property_type(prop);
+ const bool is_thick = (flag & PROP_THICK_WRAP) != 0;
/* disallow dynamic sized arrays to be wrapped since the size could change
* to a size mathutils does not support */
- if ((RNA_property_type(prop) != PROP_FLOAT) || (flag & PROP_DYNAMIC))
+ if (flag & PROP_DYNAMIC) {
return NULL;
+ }
len = RNA_property_array_length(ptr, prop);
+ if (type == PROP_FLOAT) {
+ /* pass */
+ }
+ else if (type == PROP_INT) {
+ if (is_thick) {
+ goto thick_wrap_slice;
+ }
+ else {
+ return NULL;
+ }
+ }
+ else {
+ return NULL;
+ }
+
subtype = RNA_property_subtype(prop);
totdim = RNA_property_array_dimension(ptr, prop, NULL);
- is_thick = (flag & PROP_THICK_WRAP) != 0;
if (totdim == 1 || (totdim == 2 && subtype == PROP_MATRIX)) {
if (!is_thick)
@@ -712,6 +728,7 @@ PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
if (is_thick) {
/* this is an array we cant reference (since its not thin wrappable)
* and cannot be coerced into a mathutils type, so return as a list */
+thick_wrap_slice:
ret = pyrna_prop_array_subscript_slice(NULL, ptr, prop, 0, len, len);
}
else {
@@ -1363,7 +1380,7 @@ PyObject *pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
if (subtype == PROP_BYTESTRING) {
ret = PyBytes_FromStringAndSize(buf, buf_len);
}
- else if (ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
+ else if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
ret = PyC_UnicodeFromByteAndSize(buf, buf_len);
}
else {
@@ -1629,7 +1646,7 @@ static int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyOb
/* Unicode String */
#ifdef USE_STRING_COERCE
PyObject *value_coerce = NULL;
- if (ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
+ if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
/* TODO, get size */
param = PyC_UnicodeAsByte(value, &value_coerce);
}
@@ -2312,12 +2329,11 @@ static PyObject *pyrna_prop_array_subscript_slice(BPy_PropertyArrayRNA *self, Po
int count, totdim;
PyObject *tuple;
- PYRNA_PROP_CHECK_OBJ((BPy_PropertyRNA *)self);
+ /* isn't needed, internal use only */
+ // PYRNA_PROP_CHECK_OBJ((BPy_PropertyRNA *)self);
tuple = PyTuple_New(stop - start);
- /* PYRNA_PROP_CHECK_OBJ(self); isn't needed, internal use only */
-
totdim = RNA_property_array_dimension(ptr, prop, NULL);
if (totdim > 1) {
@@ -2903,7 +2919,7 @@ static int pyrna_struct_contains(BPy_StructRNA *self, PyObject *value)
}
static PySequenceMethods pyrna_prop_array_as_sequence = {
- (lenfunc)pyrna_prop_array_length, /* Cant set the len otherwise it can evaluate as false */
+ (lenfunc)pyrna_prop_array_length,
NULL, /* sq_concat */
NULL, /* sq_repeat */
(ssizeargfunc)pyrna_prop_array_subscript_int, /* sq_item */ /* Only set this so PySequence_Check() returns True */
@@ -2916,7 +2932,7 @@ static PySequenceMethods pyrna_prop_array_as_sequence = {
};
static PySequenceMethods pyrna_prop_collection_as_sequence = {
- (lenfunc)pyrna_prop_collection_length, /* Cant set the len otherwise it can evaluate as false */
+ (lenfunc)pyrna_prop_collection_length,
NULL, /* sq_concat */
NULL, /* sq_repeat */
(ssizeargfunc)pyrna_prop_collection_subscript_int, /* sq_item */ /* Only set this so PySequence_Check() returns True */
@@ -4894,7 +4910,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat
if (subtype == PROP_BYTESTRING) {
ret = PyBytes_FromString(data_ch);
}
- else if (ELEM3(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
+ else if (ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME)) {
ret = PyC_UnicodeFromByte(data_ch);
}
else {
@@ -6255,7 +6271,7 @@ static PyObject *pyrna_srna_Subtype(StructRNA *srna)
/* always use O not N when calling, N causes refcount errors */
#if 0
- newclass = PyObject_CallFunction(metaclass, (char *)"s(O) {sss()}",
+ newclass = PyObject_CallFunction(metaclass, "s(O) {sss()}",
idname, py_base, "__module__", "bpy.types", "__slots__");
#else
{
diff --git a/source/blender/python/intern/bpy_utils_units.c b/source/blender/python/intern/bpy_utils_units.c
new file mode 100644
index 00000000000..cdbd57bcebe
--- /dev/null
+++ b/source/blender/python/intern/bpy_utils_units.c
@@ -0,0 +1,332 @@
+/*
+ * ***** 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_units.c
+ * \ingroup pythonintern
+ *
+ * This file defines a singleton py object accessed via 'bpy.utils.units',
+ * which exposes various data and functions useful in units handling.
+ */
+
+/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */
+#define PY_SSIZE_T_CLEAN
+
+#include <Python.h>
+#include <structmember.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_ghash.h"
+
+#include "BPY_extern.h"
+#include "bpy_utils_units.h"
+
+#include "../generic/py_capi_utils.h"
+
+#include "BKE_unit.h"
+
+/***** C-defined systems and types *****/
+
+static PyTypeObject BPyUnitsSystemsType;
+static PyTypeObject BPyUnitsCategoriesType;
+
+/* XXX Maybe better as externs of BKE_unit.h ? */
+static const char *bpyunits_usystem_items[] = {
+ "NONE",
+ "METRIC",
+ "IMPERIAL",
+ NULL,
+};
+
+static const char *bpyunits_ucategorie_items[] = {
+ "NONE",
+ "LENGTH",
+ "AREA",
+ "VOLUME",
+ "MASS",
+ "ROTATION",
+ "TIME",
+ "VELOCITY",
+ "ACCELERATION",
+ "CAMERA",
+ NULL,
+};
+
+/**
+ * These fields are just empty placeholders, actual values get set in initializations functions.
+ * This allows us to avoid many handwriting, and above all, to keep all systems/categories definition stuff in
+ * ``BKE_unit.h``.
+ */
+static PyStructSequence_Field bpyunits_systems_fields[ARRAY_SIZE(bpyunits_usystem_items)];
+static PyStructSequence_Field bpyunits_categories_fields[ARRAY_SIZE(bpyunits_ucategorie_items)];
+
+static PyStructSequence_Desc bpyunits_systems_desc = {
+ (char *)"bpy.utils.units.systems", /* name */
+ (char *)"This named tuple contains all pre-defined unit systems", /* doc */
+ bpyunits_systems_fields, /* fields */
+ ARRAY_SIZE(bpyunits_systems_fields) - 1
+};
+static PyStructSequence_Desc bpyunits_categories_desc = {
+ (char *)"bpy.utils.units.categories", /* name */
+ (char *)"This named tuple contains all pre-defined unit names", /* doc */
+ bpyunits_categories_fields, /* fields */
+ ARRAY_SIZE(bpyunits_categories_fields) - 1
+};
+
+/**
+ * Simple utility function to initialize #PyStructSequence_Desc
+ */
+static PyObject *py_structseq_from_strings(
+ PyTypeObject *py_type,
+ PyStructSequence_Desc *py_sseq_desc,
+ const char **str_items)
+{
+ PyObject *py_struct_seq;
+ int pos = 0;
+
+ const char **str_iter;
+ PyStructSequence_Field *desc;
+
+ /* initialize array */
+ /* We really populate the contexts' fields here! */
+ for (str_iter = str_items, desc = py_sseq_desc->fields; *str_iter; str_iter++, desc++) {
+ desc->name = (char *)*str_iter;
+ desc->doc = NULL;
+ }
+ /* end sentinel */
+ desc->name = desc->doc = NULL;
+
+ PyStructSequence_InitType(py_type, py_sseq_desc);
+
+ /* initialize pytype */
+ py_struct_seq = PyStructSequence_New(py_type);
+ BLI_assert(py_struct_seq != NULL);
+
+ for (str_iter = str_items; *str_iter; str_iter++) {
+ PyStructSequence_SET_ITEM(py_struct_seq, pos++, PyUnicode_FromString((*str_iter)));
+ }
+
+ return py_struct_seq;
+}
+
+static bool bpyunits_validate(const char *usys_str, const char *ucat_str, int *r_usys, int *r_ucat)
+{
+ *r_usys = BLI_str_index_in_array(usys_str, bpyunits_usystem_items);
+ if (*r_usys < 0) {
+ PyErr_Format(PyExc_ValueError,
+ "Unknown unit system specified: %.200s.",
+ usys_str);
+ return false;
+ }
+
+ *r_ucat = BLI_str_index_in_array(ucat_str, bpyunits_ucategorie_items);
+ if (*r_ucat < 0) {
+ PyErr_Format(PyExc_ValueError,
+ "Unknown unit category specified: %.200s.",
+ ucat_str);
+ return false;
+ }
+
+ if (!bUnit_IsValid(*r_usys, *r_ucat)) {
+ PyErr_Format(PyExc_ValueError,
+ "%.200s / %.200s unit system/category combination is not valid.",
+ usys_str, ucat_str);
+ return false;
+ }
+
+ return true;
+}
+
+PyDoc_STRVAR(bpyunits_to_value_doc,
+".. 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.), "
+" 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"
+" :type str_ref_unit: string or None\n"
+" :return: The converted/interpreted value.\n"
+" :rtype: float\n"
+" :raises ValueError: if conversion fails to generate a valid python float value.\n"
+);
+static PyObject *bpyunits_to_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ static const char *kwlist[] = {"unit_system", "unit_category", "str_input", "str_ref_unit", NULL};
+
+ char *usys_str = NULL, *ucat_str = NULL, *inpt = NULL, *uref = NULL;
+ const float scale = 1.0f;
+
+ char *str;
+ Py_ssize_t str_len;
+ double result;
+ int usys, ucat;
+ PyObject *ret;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "sss#|z:bpy.utils.units.to_value", (char **)kwlist,
+ &usys_str, &ucat_str, &inpt, &str_len, &uref))
+ {
+ return NULL;
+ }
+
+ if (!bpyunits_validate(usys_str, ucat_str, &usys, &ucat)) {
+ return NULL;
+ }
+
+ str_len = str_len * 2 + 64;
+ str = PyMem_MALLOC(sizeof(*str) * (size_t)str_len);
+ BLI_strncpy(str, inpt, (size_t)str_len);
+
+ bUnit_ReplaceString(str, (int)str_len, uref, scale, usys, ucat);
+
+ if (PyC_RunString_AsNumber(str, &result, "<bpy_units_api>") != 0) {
+ if (PyErr_Occurred()) {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+ PyErr_Format(PyExc_ValueError,
+ "'%.200s' (converted as '%s') could not be evaluated.",
+ inpt, str);
+ ret = NULL;
+ }
+ else {
+ ret = PyFloat_FromDouble(result);
+ }
+
+ PyMem_FREE(str);
+ return ret;
+}
+
+PyDoc_STRVAR(bpyunits_to_string_doc,
+".. 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.), "
+" from :attr:`bpy.utils.units.categories`.\n"
+" :type unit_category: string\n"
+" :arg value: The value to convert to a string.\n"
+" :type value: float\n"
+" :arg precision: Number of digits after the comma.\n"
+" :type precision: int\n"
+" :arg split_unit: Whether to use several units if needed (1m1cm), or always only one (1.01m).\n"
+" :type split_unit: bool\n"
+" :arg compatible_unit: Whether to use keyboard-friendly units (1m2) or nicer utf-8 ones (1m²).\n"
+" :type compatible_unit: bool\n"
+" :return: The converted string.\n"
+" :rtype: str\n"
+" :raises ValueError: if conversion fails to generate a valid python string.\n"
+);
+static PyObject *bpyunits_to_string(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
+{
+ static const char *kwlist[] = {"unit_system", "unit_category", "value",
+ "precision", "split_unit", "compatible_unit", NULL};
+
+ char *usys_str = NULL, *ucat_str = NULL;
+ double value = 0.0;
+ int precision = 3, split_unit = false, compatible_unit = false;
+
+ int usys, ucat;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kw, "ssd|ipp:bpy.utils.units.to_string", (char **)kwlist,
+ &usys_str, &ucat_str, &value, &precision, &split_unit, &compatible_unit))
+ {
+ return NULL;
+ }
+
+ if (!bpyunits_validate(usys_str, ucat_str, &usys, &ucat)) {
+ return NULL;
+ }
+
+ {
+ /* Maximum expected length of string result:
+ * - number itself: precision + decimal dot + up to four 'above dot' digits.
+ * - unit: up to ten chars (six currently, let's be conservative, also because we use some utf8 chars).
+ * This can be repeated twice (e.g. 1m20cm), and we add ten more spare chars (spaces, trailing '\0'...).
+ * So in practice, 64 should be more than enough.
+ */
+ char buf1[64], buf2[64], *str;
+ PyObject *result;
+
+ bUnit_AsString(buf1, sizeof(buf1), value, precision, usys, ucat, (bool)split_unit, false);
+
+ if (compatible_unit) {
+ bUnit_ToUnitAltName(buf2, sizeof(buf2), buf1, usys, ucat);
+ str = buf2;
+ }
+ else {
+ str = buf1;
+ }
+
+ result = PyUnicode_FromString(str);
+
+ return result;
+ }
+}
+
+static PyMethodDef bpyunits_methods[] = {
+ {"to_value", (PyCFunction)bpyunits_to_value, METH_VARARGS | METH_KEYWORDS, bpyunits_to_value_doc},
+ {"to_string", (PyCFunction)bpyunits_to_string, METH_VARARGS | METH_KEYWORDS, bpyunits_to_string_doc},
+ {NULL, NULL, 0, NULL}
+};
+
+PyDoc_STRVAR(bpyunits_doc,
+"This module contains some data/methods regarding units handling."
+);
+
+static struct PyModuleDef bpyunits_module = {
+ PyModuleDef_HEAD_INIT,
+ "bpy.utils.units",
+ bpyunits_doc,
+ -1, /* multiple "initialization" just copies the module dict. */
+ bpyunits_methods,
+ NULL, NULL, NULL, NULL
+};
+
+PyObject *BPY_utils_units(void)
+{
+ PyObject *submodule, *item;
+
+ submodule = PyModule_Create(&bpyunits_module);
+ PyDict_SetItemString(PyImport_GetModuleDict(), bpyunits_module.m_name, submodule);
+ Py_INCREF(submodule);
+
+ /* Finalize our unit systems and types structseq definitions! */
+
+ /* bpy.utils.units.system */
+ item = py_structseq_from_strings(&BPyUnitsSystemsType, &bpyunits_systems_desc, bpyunits_usystem_items);
+ PyModule_AddObject(submodule, "systems", item); /* steals ref */
+
+ /* bpy.utils.units.categories */
+ item = py_structseq_from_strings(&BPyUnitsCategoriesType, &bpyunits_categories_desc, bpyunits_ucategorie_items);
+ PyModule_AddObject(submodule, "categories", item); /* steals ref */
+
+ return submodule;
+}
diff --git a/source/blender/python/intern/bpy_utils_units.h b/source/blender/python/intern/bpy_utils_units.h
new file mode 100644
index 00000000000..5f840a2304d
--- /dev/null
+++ b/source/blender/python/intern/bpy_utils_units.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_units.h
+ * \ingroup pythonintern
+ */
+
+#ifndef __BPY_UTILS_UNITS_H__
+#define __BPY_UTILS_UNITS_H__
+
+PyObject *BPY_utils_units(void);
+
+#endif /* __BPY_UTILS_UNITS_H__ */
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 1ecb2c08bc1..349f8483fb0 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -477,8 +477,10 @@ static struct PyModuleDef M_Mathutils_module_def = {
/* submodules only */
#include "mathutils_geometry.h"
-#include "mathutils_kdtree.h"
-#include "mathutils_noise.h"
+#ifndef MATH_STANDALONE
+# include "mathutils_kdtree.h"
+# include "mathutils_noise.h"
+#endif
PyMODINIT_FUNC PyInit_mathutils(void)
{
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 5d8252d3c72..f6d124938a4 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -83,14 +83,23 @@ static const char *euler_order_str(EulerObject *self)
short euler_order_from_string(const char *str, const char *error_prefix)
{
if ((str[0] && str[1] && str[2] && str[3] == '\0')) {
+
+#ifdef __LITTLE_ENDIAN__
+# define MAKE_ID3(a, b, c) (((a)) | ((b) << 8) | ((c) << 16))
+#else
+# define MAKE_ID3(a, b, c) (((a) << 24) | ((b) << 16) | ((c) << 8))
+#endif
+
switch (*((PY_INT32_T *)str)) {
- case 'X' | 'Y' << 8 | 'Z' << 16: return EULER_ORDER_XYZ;
- case 'X' | 'Z' << 8 | 'Y' << 16: return EULER_ORDER_XZY;
- case 'Y' | 'X' << 8 | 'Z' << 16: return EULER_ORDER_YXZ;
- case 'Y' | 'Z' << 8 | 'X' << 16: return EULER_ORDER_YZX;
- case 'Z' | 'X' << 8 | 'Y' << 16: return EULER_ORDER_ZXY;
- case 'Z' | 'Y' << 8 | 'X' << 16: return EULER_ORDER_ZYX;
+ case MAKE_ID3('X', 'Y', 'Z'): return EULER_ORDER_XYZ;
+ case MAKE_ID3('X', 'Z', 'Y'): return EULER_ORDER_XZY;
+ case MAKE_ID3('Y', 'X', 'Z'): return EULER_ORDER_YXZ;
+ case MAKE_ID3('Y', 'Z', 'X'): return EULER_ORDER_YZX;
+ case MAKE_ID3('Z', 'X', 'Y'): return EULER_ORDER_ZXY;
+ case MAKE_ID3('Z', 'Y', 'X'): return EULER_ORDER_ZYX;
}
+
+#undef MAKE_ID3
}
PyErr_Format(PyExc_ValueError,
@@ -203,7 +212,7 @@ static PyObject *Euler_rotate_axis(EulerObject *self, PyObject *args)
return NULL;
}
- if (!(ELEM3(axis, 'X', 'Y', 'Z'))) {
+ if (!(ELEM(axis, 'X', 'Y', 'Z'))) {
PyErr_SetString(PyExc_ValueError,
"Euler.rotate_axis(): "
"expected axis to be 'X', 'Y' or 'Z'");
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 6129bb869f5..282f29b4934 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -31,9 +31,9 @@
#include "BLI_math.h"
#include "BLI_utildefines.h"
-#include "BLI_string.h"
#ifndef MATH_STANDALONE
+# include "BLI_string.h"
# include "BLI_dynstr.h"
#endif
@@ -910,56 +910,141 @@ static float matrix_determinant_internal(const MatrixObject *self)
}
}
+static void adjoint_matrix_n(float *mat_dst, const float *mat_src, const unsigned short dim)
+{
+ /* calculate the classical adjoint */
+ switch (dim) {
+ case 2:
+ {
+ adjoint_m2_m2((float (*)[2])mat_dst, (float (*)[2])mat_src);
+ break;
+ }
+ case 3:
+ {
+ adjoint_m3_m3((float (*)[3])mat_dst, (float (*)[3])mat_src);
+ break;
+ }
+ case 4:
+ {
+ adjoint_m4_m4((float (*)[4])mat_dst, (float (*)[4])mat_src);
+ break;
+ }
+ default:
+ BLI_assert(0);
+ }
+}
+
+static void matrix_invert_with_det_n_internal(float *mat_dst, const float *mat_src, const float det, const unsigned short dim)
+{
+ float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
+ unsigned short i, j, k;
+
+ BLI_assert(det != 0.0f);
+
+ adjoint_matrix_n(mat, mat_src, dim);
+
+ /* divide by determinant & set values */
+ k = 0;
+ for (i = 0; i < dim; i++) { /* num_col */
+ for (j = 0; j < dim; j++) { /* num_row */
+ mat_dst[MATRIX_ITEM_INDEX_NUMROW(dim, j, i)] = mat[k++] / det;
+ }
+ }
+}
+
/**
- * \param r_mat can be from ``self->matrix`` or not. */
+ * \param r_mat can be from ``self->matrix`` or not.
+ */
static bool matrix_invert_internal(const MatrixObject *self, float *r_mat)
{
float det;
-
+ BLI_assert(self->num_col == self->num_row);
det = matrix_determinant_internal(self);
if (det != 0.0f) {
- float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
- int x, y, z;
+ matrix_invert_with_det_n_internal(r_mat, self->matrix, det, self->num_col);
+ return true;
+ }
+ else {
+ return false;
+ }
+}
+
+/**
+ * Similar to ``matrix_invert_internal`` but should never error.
+ * \param r_mat can be from ``self->matrix`` or not.
+ */
+static void matrix_invert_safe_internal(const MatrixObject *self, float *r_mat)
+{
+ float det;
+ float *in_mat = self->matrix;
+ BLI_assert(self->num_col == self->num_row);
+ det = matrix_determinant_internal(self);
+
+ if (det == 0.0f) {
+ const float eps = PSEUDOINVERSE_EPSILON;
+
+ /* We will copy self->matrix into r_mat (if needed), and modify it in place to add diagonal epsilon. */
+ in_mat = r_mat;
- /* calculate the classical adjoint */
switch (self->num_col) {
case 2:
{
- adjoint_m2_m2((float (*)[2])mat, (float (*)[2])self->matrix);
+ float (*mat)[2] = (float (*)[2])in_mat;
+
+ if (in_mat != self->matrix) {
+ copy_m2_m2(mat, (float (*)[2])self->matrix);
+ }
+ mat[0][0] += eps;
+ mat[1][1] += eps;
+
+ if (UNLIKELY((det = determinant_m2(mat[0][0], mat[0][1], mat[1][0], mat[1][1])) == 0.0f)) {
+ unit_m2(mat);
+ det = 1.0f;
+ }
break;
}
case 3:
{
- adjoint_m3_m3((float (*)[3])mat, (float (*)[3])self->matrix);
+ float (*mat)[3] = (float (*)[3])in_mat;
+
+ if (in_mat != self->matrix) {
+ copy_m3_m3(mat, (float (*)[3])self->matrix);
+ }
+ mat[0][0] += eps;
+ mat[1][1] += eps;
+ mat[2][2] += eps;
+
+ if (UNLIKELY((det = determinant_m3_array(mat)) == 0.0f)) {
+ unit_m3(mat);
+ det = 1.0f;
+ }
break;
}
case 4:
{
- adjoint_m4_m4((float (*)[4])mat, (float (*)[4])self->matrix);
+ float (*mat)[4] = (float (*)[4])in_mat;
+
+ if (in_mat != self->matrix) {
+ copy_m4_m4(mat, (float (*)[4])self->matrix);
+ }
+ mat[0][0] += eps;
+ mat[1][1] += eps;
+ mat[2][2] += eps;
+ mat[3][3] += eps;
+
+ if (UNLIKELY(det = determinant_m4(mat)) == 0.0f) {
+ unit_m4(mat);
+ det = 1.0f;
+ }
break;
}
default:
BLI_assert(0);
}
- /* divide by determinate */
- for (x = 0; x < (self->num_col * self->num_row); x++) {
- mat[x] /= det;
- }
- /* set values */
- z = 0;
- for (x = 0; x < self->num_col; x++) {
- for (y = 0; y < self->num_row; y++) {
- r_mat[MATRIX_ITEM_INDEX(self, y, x)] = mat[z];
- z++;
- }
- }
-
- return true;
- }
- else {
- return false;
}
+
+ matrix_invert_with_det_n_internal(r_mat, in_mat, det, self->num_col);
}
@@ -1398,6 +1483,56 @@ static PyObject *Matrix_inverted_noargs(MatrixObject *self)
Py_RETURN_NONE;
}
+PyDoc_STRVAR(Matrix_invert_safe_doc,
+".. method:: invert_safe()\n"
+"\n"
+" Set the matrix to its inverse, will never error.\n"
+" If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n"
+" If tweaked matrix is still degenerated, set to the identity matrix instead.\n"
+"\n"
+" .. seealso:: <http://en.wikipedia.org/wiki/Inverse_matrix>\n"
+);
+static PyObject *Matrix_invert_safe(MatrixObject *self)
+{
+ if (BaseMath_ReadCallback(self) == -1)
+ return NULL;
+
+ if (matrix_invert_is_compat(self) == false) {
+ return NULL;
+ }
+
+ matrix_invert_safe_internal(self, self->matrix);
+
+ (void)BaseMath_WriteCallback(self);
+ Py_RETURN_NONE;
+}
+
+PyDoc_STRVAR(Matrix_inverted_safe_doc,
+".. method:: inverted_safe()\n"
+"\n"
+" Return an inverted copy of the matrix, will never error.\n"
+" If degenerated (e.g. zero scale on an axis), add some epsilon to its diagonal, to get an invertible one.\n"
+" If tweaked matrix is still degenerated, return the identity matrix instead.\n"
+"\n"
+" :return: the inverted matrix.\n"
+" :rtype: :class:`Matrix`\n"
+);
+static PyObject *Matrix_inverted_safe(MatrixObject *self)
+{
+ float mat[MATRIX_MAX_DIM * MATRIX_MAX_DIM];
+
+ if (BaseMath_ReadCallback(self) == -1)
+ return NULL;
+
+ if (matrix_invert_is_compat(self) == false) {
+ return NULL;
+ }
+
+ matrix_invert_safe_internal(self, mat);
+
+ return Matrix_copy_notest(self, mat);
+}
+
/*---------------------------matrix.adjugate() ---------------------*/
PyDoc_STRVAR(Matrix_adjugate_doc,
".. method:: adjugate()\n"
@@ -1421,34 +1556,16 @@ static PyObject *Matrix_adjugate(MatrixObject *self)
}
/* calculate the classical adjoint */
- switch (self->num_col) {
- case 2:
- {
- float mat[2][2];
- adjoint_m2_m2(mat, (float (*)[2])self->matrix);
- copy_v4_v4((float *)self->matrix, (float *)mat);
- break;
- }
- case 3:
- {
- float mat[3][3];
- adjoint_m3_m3(mat, (float (*)[3])self->matrix);
- copy_m3_m3((float (*)[3])self->matrix, mat);
- break;
- }
- case 4:
- {
- float mat[4][4];
- adjoint_m4_m4(mat, (float (*)[4])self->matrix);
- copy_m4_m4((float (*)[4])self->matrix, mat);
- break;
- }
- default:
- PyErr_Format(PyExc_ValueError,
- "Matrix adjugate(d): size (%d) unsupported",
- (int)self->num_col);
- return NULL;
+ if (self->num_col <= 4) {
+ adjoint_matrix_n(self->matrix, self->matrix, self->num_col);
}
+ else {
+ PyErr_Format(PyExc_ValueError,
+ "Matrix adjugate(d): size (%d) unsupported",
+ (int)self->num_col);
+ return NULL;
+ }
+
(void)BaseMath_WriteCallback(self);
Py_RETURN_NONE;
@@ -1755,10 +1872,7 @@ static PyObject *Matrix_identity(MatrixObject *self)
}
if (self->num_col == 2) {
- MATRIX_ITEM(self, 0, 0) = 1.0f;
- MATRIX_ITEM(self, 0, 1) = 0.0f;
- MATRIX_ITEM(self, 1, 0) = 0.0f;
- MATRIX_ITEM(self, 1, 1) = 1.0f;
+ unit_m2((float (*)[2])self->matrix);
}
else if (self->num_col == 3) {
unit_m3((float (*)[3])self->matrix);
@@ -2559,6 +2673,8 @@ static struct PyMethodDef Matrix_methods[] = {
{"normalized", (PyCFunction) Matrix_normalized, METH_NOARGS, Matrix_normalized_doc},
{"invert", (PyCFunction) Matrix_invert, METH_VARARGS, Matrix_invert_doc},
{"inverted", (PyCFunction) Matrix_inverted, METH_VARARGS, Matrix_inverted_doc},
+ {"invert_safe", (PyCFunction) Matrix_invert_safe, METH_NOARGS, Matrix_invert_safe_doc},
+ {"inverted_safe", (PyCFunction) Matrix_inverted_safe, METH_NOARGS, Matrix_inverted_safe_doc},
{"adjugate", (PyCFunction) Matrix_adjugate, METH_NOARGS, Matrix_adjugate_doc},
{"adjugated", (PyCFunction) Matrix_adjugated, METH_NOARGS, Matrix_adjugated_doc},
{"to_3x3", (PyCFunction) Matrix_to_3x3, METH_NOARGS, Matrix_to_3x3_doc},
diff --git a/source/blender/python/mathutils/mathutils_Matrix.h b/source/blender/python/mathutils/mathutils_Matrix.h
index c7fb23d8776..f94af9e540e 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.h
+++ b/source/blender/python/mathutils/mathutils_Matrix.h
@@ -41,6 +41,7 @@ extern PyTypeObject matrix_access_Type;
# define MATRIX_ITEM_ASSERT(_mat, _row, _col) (void)0
#endif
+#define MATRIX_ITEM_INDEX_NUMROW(_totrow, _row, _col) ((_totrow * (_col)) + (_row))
#define MATRIX_ITEM_INDEX(_mat, _row, _col) (MATRIX_ITEM_ASSERT(_mat, _row, _col),(((_mat)->num_row * (_col)) + (_row)))
#define MATRIX_ITEM_PTR( _mat, _row, _col) ((_mat)->matrix + MATRIX_ITEM_INDEX(_mat, _row, _col))
#define MATRIX_ITEM( _mat, _row, _col) ((_mat)->matrix [MATRIX_ITEM_INDEX(_mat, _row, _col)])
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index 75fe05ae2f5..ae3476f5802 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -947,7 +947,7 @@ static PyObject *Quaternion_magnitude_get(QuaternionObject *self, void *UNUSED(c
if (BaseMath_ReadCallback(self) == -1)
return NULL;
- return PyFloat_FromDouble(sqrt(dot_qtqt(self->quat, self->quat)));
+ return PyFloat_FromDouble(sqrtf(dot_qtqt(self->quat, self->quat)));
}
PyDoc_STRVAR(Quaternion_angle_doc,
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index a719691d5d4..15a9860be0a 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -814,17 +814,20 @@ static PyObject *Vector_orthogonal(VectorObject *self)
{
float vec[3];
- if (self->size != 3) {
+ if (self->size > 3) {
PyErr_SetString(PyExc_TypeError,
"Vector.orthogonal(): "
- "Vector must be 3D");
+ "Vector must be 3D or 2D");
return NULL;
}
if (BaseMath_ReadCallback(self) == -1)
return NULL;
- ortho_v3_v3(vec, self->vec);
+ if (self->size == 3)
+ ortho_v3_v3(vec, self->vec);
+ else
+ ortho_v2_v2(vec, self->vec);
return Vector_CreatePyObject(vec, self->size, Py_NEW, Py_TYPE(self));
}
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index 139764abb00..0f0ffe9fec5 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -149,6 +149,11 @@ static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *
/* calculate t, ray intersects triangle */
t = dot_v3v3(e2, qvec) * inv_det;
+ /* ray hit behind */
+ if (t < 0.0f) {
+ Py_RETURN_NONE;
+ }
+
mul_v3_fl(dir, t);
add_v3_v3v3(pvec, orig, dir);
@@ -229,6 +234,11 @@ static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject
}
result = isect_line_line_v3(v1, v2, v3, v4, i1, i2);
+ /* The return-code isnt exposed,
+ * this way we can check know how close the lines are. */
+ if (result == 1) {
+ closest_to_line_v3(i2, i1, v3, v4);
+ }
if (result == 0) {
/* colinear */
@@ -597,7 +607,7 @@ static PyObject *M_Geometry_intersect_line_plane(PyObject *UNUSED(self), PyObjec
return NULL;
}
- if (ELEM4(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) {
+ if (ELEM(2, line_a->size, line_b->size, plane_co->size, plane_no->size)) {
PyErr_SetString(PyExc_ValueError,
"geometry.intersect_line_plane(...): "
" can't use 2D Vectors");
@@ -654,7 +664,7 @@ static PyObject *M_Geometry_intersect_plane_plane(PyObject *UNUSED(self), PyObje
return NULL;
}
- if (ELEM4(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) {
+ if (ELEM(2, plane_a_co->size, plane_a_no->size, plane_b_co->size, plane_b_no->size)) {
PyErr_SetString(PyExc_ValueError,
"geometry.intersect_plane_plane(...): "
" can't use 2D Vectors");
@@ -726,7 +736,7 @@ static PyObject *M_Geometry_intersect_line_sphere(PyObject *UNUSED(self), PyObje
return NULL;
}
- if (ELEM3(2, line_a->size, line_b->size, sphere_co->size)) {
+ if (ELEM(2, line_a->size, line_b->size, sphere_co->size)) {
PyErr_SetString(PyExc_ValueError,
"geometry.intersect_line_sphere(...): "
" can't use 2D Vectors");
@@ -893,13 +903,69 @@ static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObjec
return ret;
}
+PyDoc_STRVAR(M_Geometry_intersect_point_tri_doc,
+".. function:: intersect_point_tri(pt, tri_p1, tri_p2, tri_p3)\n"
+"\n"
+" Takes 4 vectors: one is the point and the next 3 define the triangle.\n"
+"\n"
+" :arg pt: Point\n"
+" :type pt: :class:`mathutils.Vector`\n"
+" :arg tri_p1: First point of the triangle\n"
+" :type tri_p1: :class:`mathutils.Vector`\n"
+" :arg tri_p2: Second point of the triangle\n"
+" :type tri_p2: :class:`mathutils.Vector`\n"
+" :arg tri_p3: Third point of the triangle\n"
+" :type tri_p3: :class:`mathutils.Vector`\n"
+" :return: Point on the triangles plane or None if its outside the triangle\n"
+" :rtype: :class:`mathutils.Vector` or None\n"
+);
+static PyObject *M_Geometry_intersect_point_tri(PyObject *UNUSED(self), PyObject *args)
+{
+ VectorObject *pt_vec, *tri_p1, *tri_p2, *tri_p3;
+ float vi[3];
+
+ if (!PyArg_ParseTuple(args, "O!O!O!O!:intersect_point_tri",
+ &vector_Type, &pt_vec,
+ &vector_Type, &tri_p1,
+ &vector_Type, &tri_p2,
+ &vector_Type, &tri_p3))
+ {
+ return NULL;
+ }
+
+ if (BaseMath_ReadCallback(pt_vec) == -1 ||
+ BaseMath_ReadCallback(tri_p1) == -1 ||
+ BaseMath_ReadCallback(tri_p2) == -1 ||
+ BaseMath_ReadCallback(tri_p3) == -1)
+ {
+ return NULL;
+ }
+
+ if (pt_vec->size < 3 ||
+ tri_p1->size < 3 ||
+ tri_p2->size < 3 ||
+ tri_p3->size < 3)
+ {
+ PyErr_SetString(PyExc_ValueError,
+ "One of more of the vector arguments wasn't a 3D vector");
+ return NULL;
+ }
+
+ if (isect_point_tri_v3(pt_vec->vec, tri_p1->vec, tri_p2->vec, tri_p3->vec, vi)) {
+ return Vector_CreatePyObject(vi, 3, Py_NEW, NULL);
+ }
+ else {
+ Py_RETURN_NONE;
+ }
+}
+
PyDoc_STRVAR(M_Geometry_intersect_point_tri_2d_doc,
".. function:: intersect_point_tri_2d(pt, tri_p1, tri_p2, tri_p3)\n"
"\n"
" Takes 4 vectors (using only the x and y coordinates): one is the point and the next 3 define the triangle. Returns 1 if the point is within the triangle, otherwise 0.\n"
"\n"
" :arg pt: Point\n"
-" :type v1: :class:`mathutils.Vector`\n"
+" :type pt: :class:`mathutils.Vector`\n"
" :arg tri_p1: First point of the triangle\n"
" :type tri_p1: :class:`mathutils.Vector`\n"
" :arg tri_p2: Second point of the triangle\n"
@@ -1021,7 +1087,7 @@ static PyObject *M_Geometry_distance_point_to_plane(PyObject *UNUSED(self), PyOb
}
plane_from_point_normal_v3(plane, plane_co->vec, plane_no->vec);
- return PyFloat_FromDouble(dist_to_plane_v3(pt->vec, plane));
+ return PyFloat_FromDouble(dist_signed_to_plane_v3(pt->vec, plane));
}
PyDoc_STRVAR(M_Geometry_barycentric_transform_doc,
@@ -1053,7 +1119,7 @@ static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObje
VectorObject *vec_t1_src, *vec_t2_src, *vec_t3_src;
float vec[3];
- if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!:barycentric_transform",
+ if (!PyArg_ParseTuple(args, "O!O!O!O!O!O!O!::barycentric_transform",
&vector_Type, &vec_pt,
&vector_Type, &vec_t1_src,
&vector_Type, &vec_t2_src,
@@ -1089,9 +1155,10 @@ static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObje
return NULL;
}
- barycentric_transform(vec, vec_pt->vec,
- vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec,
- vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec);
+ transform_point_by_tri_v3(
+ vec, vec_pt->vec,
+ vec_t1_tar->vec, vec_t2_tar->vec, vec_t3_tar->vec,
+ vec_t1_src->vec, vec_t2_src->vec, vec_t3_src->vec);
return Vector_CreatePyObject(vec, 3, Py_NEW, NULL);
}
@@ -1606,6 +1673,7 @@ static PyObject *M_Geometry_convex_hull_2d(PyObject *UNUSED(self), PyObject *poi
static PyMethodDef M_Geometry_methods[] = {
{"intersect_ray_tri", (PyCFunction) M_Geometry_intersect_ray_tri, METH_VARARGS, M_Geometry_intersect_ray_tri_doc},
{"intersect_point_line", (PyCFunction) M_Geometry_intersect_point_line, METH_VARARGS, M_Geometry_intersect_point_line_doc},
+ {"intersect_point_tri", (PyCFunction) M_Geometry_intersect_point_tri, METH_VARARGS, M_Geometry_intersect_point_tri_doc},
{"intersect_point_tri_2d", (PyCFunction) M_Geometry_intersect_point_tri_2d, METH_VARARGS, M_Geometry_intersect_point_tri_2d_doc},
{"intersect_point_quad_2d", (PyCFunction) M_Geometry_intersect_point_quad_2d, METH_VARARGS, M_Geometry_intersect_point_quad_2d_doc},
{"intersect_line_line", (PyCFunction) M_Geometry_intersect_line_line, METH_VARARGS, M_Geometry_intersect_line_line_doc},
diff --git a/source/blender/python/mathutils/mathutils_kdtree.c b/source/blender/python/mathutils/mathutils_kdtree.c
index 0833d522a60..519778aea7d 100644
--- a/source/blender/python/mathutils/mathutils_kdtree.c
+++ b/source/blender/python/mathutils/mathutils_kdtree.c
@@ -102,7 +102,7 @@ static int PyKDTree__tp_init(PyKDTree *self, PyObject *args, PyObject *kwargs)
unsigned int maxsize;
const char *keywords[] = {"size", NULL};
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, (char *)"I:KDTree", (char **)keywords, &maxsize)) {
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "I:KDTree", (char **)keywords, &maxsize)) {
return -1;
}
@@ -425,7 +425,7 @@ PyMODINIT_FUNC PyInit_mathutils_kdtree(void)
if (PyType_Ready(&PyKDTree_Type)) {
return NULL;
}
- PyModule_AddObject(m, (char *)"KDTree", (PyObject *) &PyKDTree_Type);
+ PyModule_AddObject(m, "KDTree", (PyObject *) &PyKDTree_Type);
return m;
}
diff --git a/source/blender/python/rna_dump.py b/source/blender/python/rna_dump.py
index 15cc60d997e..7259ceb67a0 100644
--- a/source/blender/python/rna_dump.py
+++ b/source/blender/python/rna_dump.py
@@ -1,22 +1,22 @@
- # ***** 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 #****
+# ##### 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 #####
# <pep8 compliant>
diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m
index 9318c896d7c..d42d0ee8ebb 100644
--- a/source/blender/quicktime/apple/qtkit_import.m
+++ b/source/blender/quicktime/apple/qtkit_import.m
@@ -88,6 +88,7 @@ int anim_is_quicktime(const char *name)
".swf",
".txt",
".mpg",
+ ".vob", /* disabled, vob is essential .mpg, don't handle */
".avi", /* wouldn't be appropriate ;) */
".mov", /* disabled, suboptimal decoding speed */
".mp4", /* disabled, suboptimal decoding speed */
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 8e326e770fc..e516c954737 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -162,6 +162,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_CYCLES AND WITH_CYCLES_DEBUG)
+ add_definitions(-DWITH_CYCLES_DEBUG)
+endif()
+
if(APPLE)
# SSE math is enabled by default on x86_64
if(CMAKE_OSX_ARCHITECTURES MATCHES "i386")
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index 297e4fcecd4..7f459444a39 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -103,6 +103,9 @@ if env['WITH_BF_GAMEENGINE']:
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_CYCLES'] and env['WITH_BF_CYCLES_DEBUG']:
+ defs.append('WITH_CYCLES_DEBUG')
+
if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
incs += ' ' + env['BF_PTHREADS_INC']
diff --git a/source/blender/render/extern/include/RE_bake.h b/source/blender/render/extern/include/RE_bake.h
index d59819c8ef4..481da452529 100644
--- a/source/blender/render/extern/include/RE_bake.h
+++ b/source/blender/render/extern/include/RE_bake.h
@@ -39,7 +39,7 @@ typedef struct BakeImage {
struct Image *image;
int width;
int height;
- int offset;
+ size_t offset;
} BakeImage;
typedef struct BakeImages {
@@ -61,7 +61,10 @@ typedef struct BakeHighPolyData {
struct ModifierData *tri_mod;
struct Mesh *me;
char restrict_flag;
- float mat_lowtohigh[4][4];
+
+ float obmat[4][4];
+ float imat[4][4];
+ float rotmat[4][4];
} BakeHighPolyData;
/* external_engine.c */
@@ -69,37 +72,37 @@ bool RE_bake_has_engine(struct Render *re);
bool RE_bake_engine(
struct Render *re, struct Object *object, const BakePixel pixel_array[],
- const int num_pixels, const int depth, const ScenePassType pass_type, float result[]);
+ const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]);
/* bake.c */
int RE_pass_depth(const ScenePassType pass_type);
bool RE_bake_internal(
struct Render *re, struct Object *object, const BakePixel pixel_array[],
- const int num_pixels, const int depth, const ScenePassType pass_type, float result[]);
+ const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[]);
-void RE_bake_pixels_populate_from_objects(
+bool RE_bake_pixels_populate_from_objects(
struct Mesh *me_low, BakePixel pixel_array_from[],
- BakeHighPolyData highpoly[], const int tot_highpoly, const int num_pixels,
- const float cage_extrusion);
+ 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);
void RE_bake_pixels_populate(
struct Mesh *me, struct BakePixel *pixel_array,
- const int num_pixels, const struct BakeImages *bake_images);
+ const size_t num_pixels, const struct BakeImages *bake_images, const char *uv_layer);
-void RE_bake_mask_fill(const BakePixel pixel_array[], const int num_pixels, char *mask);
+void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask);
void RE_bake_margin(struct ImBuf *ibuf, char *mask, const int margin);
void RE_bake_normal_world_to_object(
- const BakePixel pixel_array[], const int num_pixels, const int depth, float result[],
+ const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[],
struct Object *ob, const BakeNormalSwizzle normal_swizzle[3]);
void RE_bake_normal_world_to_tangent(
- const BakePixel pixel_array[], const int num_pixels, const int depth, float result[],
- struct Mesh *me, const BakeNormalSwizzle normal_swizzle[3]);
+ const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[],
+ struct Mesh *me, const BakeNormalSwizzle normal_swizzle[3], float mat[4][4]);
void RE_bake_normal_world_to_world(
- const BakePixel pixel_array[], const int num_pixels, const int depth, float result[],
+ const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[],
const BakeNormalSwizzle normal_swizzle[3]);
-void RE_bake_ibuf_clear(struct BakeImages *bake_images, const bool is_tangent);
+void RE_bake_ibuf_clear(struct Image *image, const bool is_tangent);
#endif /* __RE_BAKE_H__ */
diff --git a/source/blender/render/extern/include/RE_engine.h b/source/blender/render/extern/include/RE_engine.h
index 2c6492b5c5a..4b0473f7483 100644
--- a/source/blender/render/extern/include/RE_engine.h
+++ b/source/blender/render/extern/include/RE_engine.h
@@ -60,6 +60,7 @@ struct BakePixel;
#define RE_USE_SHADING_NODES 16
#define RE_USE_EXCLUDE_LAYERS 32
#define RE_USE_SAVE_BUFFERS 64
+#define RE_USE_TEXTURE_PREVIEW 128
/* RenderEngine.flag */
#define RE_ENGINE_ANIMATION 1
@@ -104,6 +105,7 @@ typedef struct RenderEngine {
int flag;
struct Object *camera_override;
+ unsigned int layer_override;
int tile_x;
int tile_y;
@@ -147,6 +149,8 @@ int RE_engine_render(struct Render *re, int do_all);
bool RE_engine_is_external(struct Render *re);
+void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe);
+
/* Engine Types */
void RE_engines_init(void);
diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h
index 031d6b5a51a..61795c2c173 100644
--- a/source/blender/render/extern/include/RE_pipeline.h
+++ b/source/blender/render/extern/include/RE_pipeline.h
@@ -72,8 +72,13 @@ typedef struct RenderPass {
char chan_id[8]; /* amount defined in openexr_multi.h */
float *rect;
int rectx, recty;
+ int debug_type;
} RenderPass;
+enum {
+ RENDER_PASS_DEBUG_BVH_TRAVERSAL_STEPS = 0,
+};
+
/* 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 */
@@ -190,7 +195,11 @@ struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name)
float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype);
/* obligatory initialize call, disprect is optional */
-void RE_InitState(struct Render *re, struct Render *source, struct RenderData *rd, struct SceneRenderLayer *srl, int winx, int winy, rcti *disprect);
+void RE_InitState(struct Render *re, struct Render *source, struct RenderData *rd,
+ struct SceneRenderLayer *srl,
+ int winx, int winy, rcti *disprect);
+void RE_ChangeResolution(struct Render *re, int winx, int winy, rcti *disprect);
+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 */
@@ -231,6 +240,7 @@ void RE_BlenderAnim(struct Render *re, struct Main *bmain, struct Scene *scene,
unsigned int lay_override, int sfra, int efra, int tfra);
#ifdef WITH_FREESTYLE
void RE_RenderFreestyleStrokes(struct Render *re, struct Main *bmain, struct Scene *scene, int render);
+void RE_RenderFreestyleExternal(struct Render *re);
#endif
/* error reporting */
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
index eb861d440d8..6d083ec785d 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -61,5 +61,7 @@ void RE_free_sample_material(struct Material *mat);
void RE_sample_material_color(struct Material *mat, float color[3], float *alpha, const float volume_co[3], const float surface_co[3],
int face_index, short hit_quad, struct DerivedMesh *orcoDm, struct Object *ob);
+void RE_init_texture_rng(void);
+void RE_exit_texture_rng(void);
#endif /* __RE_RENDER_EXT_H__ */
diff --git a/source/blender/render/intern/include/render_result.h b/source/blender/render/intern/include/render_result.h
index 457f1377e9b..90ff69dbfbe 100644
--- a/source/blender/render/intern/include/render_result.h
+++ b/source/blender/render/intern/include/render_result.h
@@ -81,9 +81,14 @@ 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_path(struct Scene *scene, const char *layname, int sample, char *filepath);
-int render_result_exr_file_read(struct Render *re, int sample);
+int render_result_exr_file_read_sample(struct Render *re, int sample);
int render_result_exr_file_read_path(struct RenderResult *rr, struct RenderLayer *rl_single, const char *filepath);
+/* EXR cache */
+
+void render_result_exr_file_cache_write(struct Render *re);
+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);
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index eeb0544cf73..b87b1e6f367 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -192,7 +192,7 @@ struct Render
RenderData r;
World wrld;
struct Object *camera_override;
- unsigned int lay;
+ unsigned int lay, layer_override;
ListBase parts;
@@ -240,7 +240,7 @@ struct Render
ListBase volumes;
#ifdef WITH_FREESTYLE
- struct Main freestyle_bmain;
+ struct Main *freestyle_bmain;
ListBase freestyle_renders;
#endif
@@ -595,7 +595,9 @@ typedef struct LampRen {
float imat[3][3];
float spottexfac;
float sh_invcampos[3], sh_zfac; /* sh_= spothalo */
-
+
+ float lampmat[4][4]; /* worls space lamp matrix, used for scene rotation */
+
float mat[3][3]; /* 3x3 part from lampmat x viewmat */
float area[8][3], areasize;
diff --git a/source/blender/render/intern/include/renderpipeline.h b/source/blender/render/intern/include/renderpipeline.h
index e713d4880d6..a831ab3c29c 100644
--- a/source/blender/render/intern/include/renderpipeline.h
+++ b/source/blender/render/intern/include/renderpipeline.h
@@ -34,11 +34,13 @@
#define __RENDERPIPELINE_H__
struct Render;
+struct RenderData;
struct RenderLayer;
struct RenderResult;
struct RenderLayer *render_get_active_layer(struct Render *re, struct RenderResult *rr);
float panorama_pixel_rot(struct Render *re);
+void render_update_anim_renderdata(struct Render *re, struct RenderData *rd);
#endif /* __RENDERPIPELINE_H__ */
diff --git a/source/blender/render/intern/raytrace/rayobject_octree.cpp b/source/blender/render/intern/raytrace/rayobject_octree.cpp
index 24804b8c0ad..6cbb0761358 100644
--- a/source/blender/render/intern/raytrace/rayobject_octree.cpp
+++ b/source/blender/render/intern/raytrace/rayobject_octree.cpp
@@ -657,7 +657,7 @@ static void RE_rayobject_octree_done(RayObject *tree)
oc->ocfacy = (oc->ocres - 0.1f) / t01;
oc->ocfacz = (oc->ocres - 0.1f) / t02;
- oc->ocsize = sqrt(t00 * t00 + t01 * t01 + t02 * t02); /* global, max size octree */
+ oc->ocsize = sqrtf(t00 * t00 + t01 * t01 + t02 * t02); /* global, max size octree */
for (c = 0; c < oc->ro_nodes_used; c++) {
octree_fill_rayface(oc, oc->ro_nodes[c]);
diff --git a/source/blender/render/intern/source/bake.c b/source/blender/render/intern/source/bake.c
index f2793a9bc5b..15634c93491 100644
--- a/source/blender/render/intern/source/bake.c
+++ b/source/blender/render/intern/source/bake.c
@@ -174,7 +174,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua
/* only do AO for a full bake (and obviously AO bakes)
* AO for light bakes is a leftover and might not be needed */
- if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT))
+ if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_AO, RE_BAKE_LIGHT))
shade_samples_do_AO(ssamp);
if (shi->mat->nodetree && shi->mat->use_nodes) {
@@ -303,7 +303,7 @@ static void bake_shade(void *handle, Object *ob, ShadeInput *shi, int UNUSED(qua
rgb_float_to_uchar(col, shr.combined);
}
- if (ELEM3(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) {
+ if (ELEM(bs->type, RE_BAKE_ALL, RE_BAKE_TEXTURE, RE_BAKE_VERTEX_COLORS)) {
col[3] = FTOCHAR(shr.alpha);
}
else {
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 258208eeec6..90deac2de32 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -120,7 +120,7 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v)
BakePixel *pixel;
const int width = bd->bk_image->width;
- const int offset = bd->bk_image->offset;
+ const size_t offset = bd->bk_image->offset;
const int i = offset + y * width + x;
pixel = &bd->pixel_array[i];
@@ -134,9 +134,9 @@ static void store_bake_pixel(void *handle, int x, int y, float u, float v)
pixel->dv_dy = bd->dv_dy;
}
-void RE_bake_mask_fill(const BakePixel pixel_array[], const int num_pixels, char *mask)
+void RE_bake_mask_fill(const BakePixel pixel_array[], const size_t num_pixels, char *mask)
{
- int i;
+ size_t i;
if (!mask)
return;
@@ -158,19 +158,66 @@ void RE_bake_margin(ImBuf *ibuf, char *mask, const int margin)
IMB_rectfill_alpha(ibuf, 1.0f);
}
+
/**
* This function returns the coordinate and normal of a barycentric u,v for a face defined by the primitive_id index.
+ * The returned normal is actually the direction from the same barycentric coordinate in the cage to the base mesh
+ * The returned coordinate is the point in the cage mesh
*/
-static void calc_point_from_barycentric(
- TriTessFace *triangles, int primitive_id, float u, float v, float cage_extrusion,
+static void calc_point_from_barycentric_cage(
+ TriTessFace *triangles_low, TriTessFace *triangles_cage,
+ float mat_low[4][4], float mat_cage[4][4],
+ int primitive_id, float u, float v,
float r_co[3], float r_dir[3])
{
+ float data[2][3][3];
+ float coord[2][3];
+ float dir[3];
+ int i;
+
+ TriTessFace *triangle[2];
+
+ triangle[0] = &triangles_low[primitive_id];
+ triangle[1] = &triangles_cage[primitive_id];
+
+ for (i = 0; i < 2; i++) {
+ copy_v3_v3(data[i][0], triangle[i]->mverts[0]->co);
+ copy_v3_v3(data[i][1], triangle[i]->mverts[1]->co);
+ copy_v3_v3(data[i][2], triangle[i]->mverts[2]->co);
+ interp_barycentric_tri_v3(data[i], u, v, coord[i]);
+ }
+
+ /* convert from local to world space */
+ mul_m4_v3(mat_low, coord[0]);
+ mul_m4_v3(mat_cage, coord[1]);
+
+ sub_v3_v3v3(dir, coord[0], coord[1]);
+ normalize_v3(dir);
+
+ copy_v3_v3(r_co, coord[1]);
+ copy_v3_v3(r_dir, dir);
+}
+
+/**
+ * This function returns the coordinate and normal of a barycentric u,v for a face defined by the primitive_id index.
+ * The returned coordinate is extruded along the normal by cage_extrusion
+ */
+static void calc_point_from_barycentric_extrusion(
+ TriTessFace *triangles,
+ float mat[4][4], float imat[4][4],
+ int primitive_id, float u, float v,
+ float cage_extrusion,
+ float r_co[3], float r_dir[3],
+ const bool is_cage)
+{
float data[3][3];
float coord[3];
float dir[3];
float cage[3];
+ bool is_smooth;
TriTessFace *triangle = &triangles[primitive_id];
+ is_smooth = triangle->is_smooth || is_cage;
copy_v3_v3(data[0], triangle->mverts[0]->co);
copy_v3_v3(data[1], triangle->mverts[1]->co);
@@ -178,18 +225,28 @@ static void calc_point_from_barycentric(
interp_barycentric_tri_v3(data, u, v, coord);
- normal_short_to_float_v3(data[0], triangle->mverts[0]->no);
- normal_short_to_float_v3(data[1], triangle->mverts[1]->no);
- normal_short_to_float_v3(data[2], triangle->mverts[2]->no);
+ if (is_smooth) {
+ normal_short_to_float_v3(data[0], triangle->mverts[0]->no);
+ normal_short_to_float_v3(data[1], triangle->mverts[1]->no);
+ normal_short_to_float_v3(data[2], triangle->mverts[2]->no);
- interp_barycentric_tri_v3(data, u, v, dir);
- normalize_v3_v3(cage, dir);
- mul_v3_fl(cage, cage_extrusion);
+ interp_barycentric_tri_v3(data, u, v, dir);
+ normalize_v3(dir);
+ }
+ else {
+ copy_v3_v3(dir, triangle->normal);
+ }
+ mul_v3_v3fl(cage, dir, cage_extrusion);
add_v3_v3(coord, cage);
- normalize_v3_v3(dir, dir);
- mul_v3_fl(dir, -1.0f);
+ normalize_v3(dir);
+ negate_v3(dir);
+
+ /* convert from local to world space */
+ mul_m4_v3(mat, coord);
+ mul_transposed_mat3_m4_v3(imat, dir);
+ normalize_v3(dir);
copy_v3_v3(r_co, coord);
copy_v3_v3(r_dir, dir);
@@ -215,7 +272,7 @@ static void calc_barycentric_from_point(
*/
static bool cast_ray_highpoly(
BVHTreeFromMesh *treeData, TriTessFace *triangles[], BakeHighPolyData *highpoly,
- float const co_low[3], const float dir[3], const int pixel_id, const int tot_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)
{
int i;
@@ -228,26 +285,38 @@ static bool cast_ray_highpoly(
hits = MEM_mallocN(sizeof(BVHTreeRayHit) * tot_highpoly, "Bake Highpoly to Lowpoly: BVH Rays");
for (i = 0; i < tot_highpoly; i++) {
- float co_high[3];
+ float co_high[3], dir_high[3];
+
hits[i].index = -1;
/* TODO: we should use FLT_MAX here, but sweepsphere code isn't prepared for that */
hits[i].dist = 10000.0f;
- copy_v3_v3(co_high, co_low);
+ /* transform the ray from the world space to the highpoly space */
+ mul_v3_m4v3(co_high, highpoly[i].imat, co);
- /* transform the ray from the lowpoly to the highpoly space */
- mul_m4_v3(highpoly[i].mat_lowtohigh, co_high);
+ /* rotates */
+ mul_v3_m4v3(dir_high, highpoly[i].rotmat, dir);
+ normalize_v3(dir_high);
/* cast ray */
- BLI_bvhtree_ray_cast(treeData[i].tree, co_high, dir, 0.0f, &hits[i], treeData[i].raycast_callback, &treeData[i]);
+ if (treeData[i].tree) {
+ BLI_bvhtree_ray_cast(treeData[i].tree, co_high, dir_high, 0.0f, &hits[i], treeData[i].raycast_callback, &treeData[i]);
+ }
if (hits[i].index != -1) {
/* cull backface */
- const float dot = dot_v3v3(dir, hits[i].no);
+ const float dot = dot_v3v3(dir_high, hits[i].no);
if (dot < 0.0f) {
- if (hits[i].dist < hit_distance) {
+ float distance;
+ float hit_world[3];
+
+ /* distance comparison in world space */
+ mul_v3_m4v3(hit_world, highpoly[i].obmat, hits[i].co);
+ distance = len_squared_v3v3(hit_world, co);
+
+ if (distance < hit_distance) {
hit_mesh = i;
- hit_distance = hits[i].dist;
+ hit_distance = distance;
}
}
}
@@ -287,7 +356,7 @@ static void mesh_calc_tri_tessface(
MFace *mface;
MVert *mvert;
TSpace *tspace;
- float *precomputed_normals;
+ float *precomputed_normals = NULL;
bool calculate_normal;
mface = CustomData_get_layer(&me->fdata, CD_MFACE);
@@ -310,7 +379,7 @@ static void mesh_calc_tri_tessface(
p_id = -1;
for (i = 0; i < me->totface; i++) {
MFace *mf = &mface[i];
- TSpace *ts = &tspace[i * 4];
+ TSpace *ts = tangent ? &tspace[i * 4] : NULL;
p_id++;
@@ -367,44 +436,68 @@ static void mesh_calc_tri_tessface(
BLI_assert(p_id < me->totface * 2);
}
-void RE_bake_pixels_populate_from_objects(
+bool RE_bake_pixels_populate_from_objects(
struct Mesh *me_low, BakePixel pixel_array_from[],
- BakeHighPolyData highpoly[], const int tot_highpoly, const int num_pixels,
- const float cage_extrusion)
+ 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)
{
- int i;
+ size_t i;
int primitive_id;
float u, v;
+ float imat_low [4][4];
+ bool is_cage = me_cage != NULL;
+ bool result = true;
+ DerivedMesh *dm_low = NULL;
DerivedMesh **dm_highpoly;
BVHTreeFromMesh *treeData;
/* Note: all coordinates are in local space */
- TriTessFace *tris_low;
+ TriTessFace *tris_low = NULL;
+ TriTessFace *tris_cage = NULL;
TriTessFace **tris_high;
/* assume all lowpoly tessfaces can be quads */
- tris_low = MEM_callocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh");
tris_high = MEM_callocN(sizeof(TriTessFace *) * tot_highpoly, "MVerts Highpoly Mesh Array");
/* assume all highpoly tessfaces are triangles */
- dm_highpoly = MEM_callocN(sizeof(DerivedMesh *) * tot_highpoly, "Highpoly Derived Meshes");
+ dm_highpoly = MEM_mallocN(sizeof(DerivedMesh *) * tot_highpoly, "Highpoly Derived Meshes");
treeData = MEM_callocN(sizeof(BVHTreeFromMesh) * tot_highpoly, "Highpoly BVH Trees");
- mesh_calc_tri_tessface(tris_low, me_low, false, NULL);
+ if (!is_cage) {
+ dm_low = CDDM_from_mesh(me_low);
+ tris_low = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh");
+ mesh_calc_tri_tessface(tris_low, me_low, true, dm_low);
+ }
+ else if (is_custom_cage) {
+ tris_low = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Lowpoly Mesh");
+ mesh_calc_tri_tessface(tris_low, me_low, false, NULL);
+
+ tris_cage = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Cage Mesh");
+ mesh_calc_tri_tessface(tris_cage, me_cage, false, NULL);
+ }
+ else {
+ tris_cage = MEM_mallocN(sizeof(TriTessFace) * (me_low->totface * 2), "MVerts Cage Mesh");
+ mesh_calc_tri_tessface(tris_cage, me_cage, false, NULL);
+ }
+
+ invert_m4_m4(imat_low, mat_low);
for (i = 0; i < tot_highpoly; i++) {
- tris_high[i] = MEM_callocN(sizeof(TriTessFace) * highpoly[i].me->totface, "MVerts Highpoly Mesh");
+ tris_high[i] = MEM_mallocN(sizeof(TriTessFace) * highpoly[i].me->totface, "MVerts Highpoly Mesh");
mesh_calc_tri_tessface(tris_high[i], highpoly[i].me, false, NULL);
dm_highpoly[i] = CDDM_from_mesh(highpoly[i].me);
- /* Create a bvh-tree for each highpoly object */
- bvhtree_from_mesh_faces(&treeData[i], dm_highpoly[i], 0.0, 2, 6);
+ if (dm_highpoly[i]->getNumTessFaces(dm_highpoly[i]) != 0) {
+ /* Create a bvh-tree for each highpoly object */
+ bvhtree_from_mesh_faces(&treeData[i], dm_highpoly[i], 0.0, 2, 6);
- if (&treeData[i].tree == NULL) {
- printf("Baking: Out of memory\n");
- goto cleanup;
+ if (treeData[i].tree == NULL) {
+ printf("Baking: out of memory while creating BHVTree for object \"%s\"\n", highpoly[i].ob->id.name + 2);
+ result = false;
+ goto cleanup;
+ }
}
}
@@ -426,7 +519,15 @@ void RE_bake_pixels_populate_from_objects(
v = pixel_array_from[i].uv[1];
/* calculate from low poly mesh cage */
- calc_point_from_barycentric(tris_low, primitive_id, u, v, cage_extrusion, co, dir);
+ if (is_custom_cage) {
+ calc_point_from_barycentric_cage(tris_low, tris_cage, mat_low, mat_cage, primitive_id, u, v, co, dir);
+ }
+ else if (is_cage) {
+ calc_point_from_barycentric_extrusion(tris_cage, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, true);
+ }
+ else {
+ calc_point_from_barycentric_extrusion(tris_low, mat_low, imat_low, primitive_id, u, v, cage_extrusion, co, dir, false);
+ }
/* cast ray */
if (!cast_ray_highpoly(treeData, tris_high, highpoly, co, dir, i, tot_highpoly,
@@ -442,14 +543,31 @@ void RE_bake_pixels_populate_from_objects(
cleanup:
for (i = 0; i < tot_highpoly; i++) {
free_bvhtree_from_mesh(&treeData[i]);
- dm_highpoly[i]->release(dm_highpoly[i]);
- MEM_freeN(tris_high[i]);
+
+ if (dm_highpoly[i]) {
+ dm_highpoly[i]->release(dm_highpoly[i]);
+ }
+
+ if (tris_high[i]) {
+ MEM_freeN(tris_high[i]);
+ }
}
- MEM_freeN(tris_low);
MEM_freeN(tris_high);
MEM_freeN(treeData);
MEM_freeN(dm_highpoly);
+
+ if (dm_low) {
+ dm_low->release(dm_low);
+ }
+ if (tris_low) {
+ MEM_freeN(tris_low);
+ }
+ if (tris_cage) {
+ MEM_freeN(tris_cage);
+ }
+
+ return result;
}
static void bake_differentials(BakeDataZSpan *bd, const float *uv1, const float *uv2, const float *uv3)
@@ -476,11 +594,11 @@ static void bake_differentials(BakeDataZSpan *bd, const float *uv1, const float
void RE_bake_pixels_populate(
Mesh *me, BakePixel pixel_array[],
- const int num_pixels, const BakeImages *bake_images)
+ const size_t num_pixels, const BakeImages *bake_images, const char *uv_layer)
{
BakeDataZSpan bd;
- int i, a;
- int p_id;
+ size_t i;
+ int a, p_id;
MTFace *mtface;
MFace *mface;
@@ -501,7 +619,14 @@ void RE_bake_pixels_populate(
zbuf_alloc_span(&bd.zspan[i], bake_images->data[i].width, bake_images->data[i].height, R.clipcrop);
}
- mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
+ if ((uv_layer == NULL) || (uv_layer[0] == '\0')) {
+ mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
+ }
+ else {
+ int uv_id = CustomData_get_named_layer(&me->fdata, CD_MTFACE, uv_layer);
+ mtface = CustomData_get_layer_n(&me->fdata, CD_MTFACE, uv_id);
+ }
+
mface = CustomData_get_layer(&me->fdata, CD_MFACE);
if (mtface == NULL)
@@ -600,16 +725,17 @@ static void normal_compress(float out[3], const float in[3], const BakeNormalSwi
* This function converts an object space normal map to a tangent space normal map for a given low poly mesh
*/
void RE_bake_normal_world_to_tangent(
- const BakePixel pixel_array[], const int num_pixels, const int depth,
- float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3])
+ const BakePixel pixel_array[], const size_t num_pixels, const int depth,
+ float result[], Mesh *me, const BakeNormalSwizzle normal_swizzle[3],
+ float mat[4][4])
{
- int i;
+ size_t i;
TriTessFace *triangles;
DerivedMesh *dm = CDDM_from_mesh(me);
- triangles = MEM_callocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh");
+ triangles = MEM_mallocN(sizeof(TriTessFace) * (me->totface * 2), "MVerts Mesh");
mesh_calc_tri_tessface(triangles, me, true, dm);
BLI_assert(num_pixels >= 3);
@@ -630,7 +756,7 @@ void RE_bake_normal_world_to_tangent(
float tsm[3][3]; /* tangent space matrix */
float itsm[3][3];
- int offset;
+ size_t offset;
float nor[3]; /* texture normal */
bool is_smooth;
@@ -689,6 +815,9 @@ void RE_bake_normal_world_to_tangent(
/* texture values */
normal_uncompress(nor, &result[offset]);
+ /* converts from world space to local space */
+ mul_transposed_mat3_m4_v3(mat, nor);
+
invert_m3_m3(itsm, tsm);
mul_m3_v3(itsm, nor);
normalize_v3(nor);
@@ -705,16 +834,16 @@ void RE_bake_normal_world_to_tangent(
}
void RE_bake_normal_world_to_object(
- const BakePixel pixel_array[], const int num_pixels, const int depth,
+ const BakePixel pixel_array[], const size_t num_pixels, const int depth,
float result[], struct Object *ob, const BakeNormalSwizzle normal_swizzle[3])
{
- int i;
+ size_t i;
float iobmat[4][4];
invert_m4_m4(iobmat, ob->obmat);
for (i = 0; i < num_pixels; i++) {
- int offset;
+ size_t offset;
float nor[3];
if (pixel_array[i].primitive_id == -1)
@@ -723,7 +852,8 @@ void RE_bake_normal_world_to_object(
offset = i * depth;
normal_uncompress(nor, &result[offset]);
- mul_m4_v3(iobmat, nor);
+ /* rotates only without translation */
+ mul_mat3_m4_v3(iobmat, nor);
normalize_v3(nor);
/* save back the values */
@@ -732,13 +862,13 @@ void RE_bake_normal_world_to_object(
}
void RE_bake_normal_world_to_world(
- const BakePixel pixel_array[], const int num_pixels, const int depth,
+ const BakePixel pixel_array[], const size_t num_pixels, const int depth,
float result[], const BakeNormalSwizzle normal_swizzle[3])
{
- int i;
+ size_t i;
for (i = 0; i < num_pixels; i++) {
- int offset;
+ size_t offset;
float nor[3];
if (pixel_array[i].primitive_id == -1)
@@ -752,31 +882,25 @@ void RE_bake_normal_world_to_world(
}
}
-void RE_bake_ibuf_clear(BakeImages *bake_images, const bool is_tangent)
+void RE_bake_ibuf_clear(Image *image, const bool is_tangent)
{
ImBuf *ibuf;
void *lock;
- Image *image;
- int i;
const float vec_alpha[4] = {0.0f, 0.0f, 0.0f, 0.0f};
const float vec_solid[4] = {0.0f, 0.0f, 0.0f, 1.0f};
const float nor_alpha[4] = {0.5f, 0.5f, 1.0f, 0.0f};
const float nor_solid[4] = {0.5f, 0.5f, 1.0f, 1.0f};
- for (i = 0; i < bake_images->size; i ++) {
- image = bake_images->data[i].image;
+ ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
+ BLI_assert(ibuf);
- ibuf = BKE_image_acquire_ibuf(image, NULL, &lock);
- BLI_assert(ibuf);
+ if (is_tangent)
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
+ else
+ IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
- if (is_tangent)
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? nor_alpha : nor_solid);
- else
- IMB_rectfill(ibuf, (ibuf->planes == R_IMF_PLANES_RGBA) ? vec_alpha : vec_solid);
-
- BKE_image_release_ibuf(image, ibuf, lock);
- }
+ BKE_image_release_ibuf(image, ibuf, lock);
}
/* ************************************************************* */
@@ -784,12 +908,12 @@ void RE_bake_ibuf_clear(BakeImages *bake_images, const bool is_tangent)
/**
* not the real UV, but the internal per-face UV instead
* I'm using it to test if everything is correct */
-static bool bake_uv(const BakePixel pixel_array[], const int num_pixels, const int depth, float result[])
+static bool bake_uv(const BakePixel pixel_array[], const size_t num_pixels, const int depth, float result[])
{
- int i;
+ size_t i;
for (i=0; i < num_pixels; i++) {
- int offset = i * depth;
+ size_t offset = i * depth;
copy_v2_v2(&result[offset], pixel_array[i].uv);
}
@@ -798,7 +922,7 @@ static bool bake_uv(const BakePixel pixel_array[], const int num_pixels, const i
bool RE_bake_internal(
Render *UNUSED(re), Object *UNUSED(object), const BakePixel pixel_array[],
- const int num_pixels, const int depth, const ScenePassType pass_type, float result[])
+ const size_t num_pixels, const int depth, const ScenePassType pass_type, float result[])
{
switch (pass_type) {
case SCE_PASS_UV:
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index cb5f75efd16..69dd9607c3b 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -762,7 +762,7 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, Par
w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
dx= re->winx*cross[0]*re->winmat[0][0];
dy= re->winy*cross[1]*re->winmat[1][1];
- w= sqrt(dx*dx + dy*dy)/w;
+ w = sqrtf(dx * dx + dy * dy) / w;
if (w!=0.0f) {
float fac;
@@ -927,7 +927,7 @@ static void static_particle_strand(Render *re, ObjectRen *obr, Material *ma, Par
w= vec[2]*re->winmat[2][3] + re->winmat[3][3];
dx= re->winx*dvec[0]*re->winmat[0][0]/w;
dy= re->winy*dvec[1]*re->winmat[1][1]/w;
- w= sqrt(dx*dx + dy*dy);
+ w = sqrtf(dx * dx + dy * dy);
if (dot_v3v3(anor, nor)<sd->adapt_angle && w>sd->adapt_pix) {
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
vlr->flag= flag;
@@ -2635,7 +2635,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
Material **matar;
float *data, *fp, *orco=NULL;
float n[3], mat[4][4], nmat[4][4];
- int nr, startvert, a, b;
+ int nr, startvert, a, b, negative_scale;
bool need_orco = false;
int totmat;
@@ -2649,6 +2649,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
mul_m4_m4m4(mat, re->viewmat, ob->obmat);
invert_m4_m4(ob->imat, mat);
+ negative_scale = is_negative_m4(mat);
/* local object -> world space transform for normals */
copy_m4_m4(nmat, mat);
@@ -2718,7 +2719,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
zero_v3(n);
index= dl->index;
for (a=0; a<dl->parts; a++, index+=3) {
- int v1 = index[0], v2 = index[1], v3 = index[2];
+ int v1 = index[0], v2 = index[2], v3 = index[1];
float *co1 = &dl->verts[v1 * 3],
*co2 = &dl->verts[v2 * 3],
*co3 = &dl->verts[v3 * 3];
@@ -2731,7 +2732,10 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset)
/* to prevent float accuracy issues, we calculate normal in local object space (not world) */
if (area_tri_v3(co3, co2, co1)>FLT_EPSILON) {
- normal_tri_v3(tmp, co3, co2, co1);
+ if (negative_scale)
+ normal_tri_v3(tmp, co1, co2, co3);
+ else
+ normal_tri_v3(tmp, co3, co2, co1);
add_v3_v3(n, tmp);
}
@@ -2926,8 +2930,7 @@ static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort)
/* make sorted table with edges and face indices in it */
for (a= totface, mf= mface; a>0; a--, mf++) {
- if (mf->v4) totedge+=4;
- else if (mf->v3) totedge+=3;
+ totedge += mf->v4 ? 4 : 3;
}
if (totedge==0)
@@ -2942,8 +2945,9 @@ static struct edgesort *make_mesh_edge_lookup(DerivedMesh *dm, int *totedgesort)
to_edgesort(ed++, 2, 3, mf->v3, mf->v4, a);
to_edgesort(ed++, 3, 0, mf->v4, mf->v1, a);
}
- else if (mf->v3)
+ else {
to_edgesort(ed++, 2, 3, mf->v3, mf->v1, a);
+ }
}
qsort(edsort, totedge, sizeof(struct edgesort), vergedgesort);
@@ -3059,36 +3063,21 @@ static void add_volume(Render *re, ObjectRen *obr, Material *ma)
}
#ifdef WITH_FREESTYLE
-static EdgeHash *make_freestyle_edge_mark_hash(Mesh *me, DerivedMesh *dm)
+static EdgeHash *make_freestyle_edge_mark_hash(DerivedMesh *dm)
{
EdgeHash *edge_hash= NULL;
FreestyleEdge *fed;
MEdge *medge;
int totedge, a;
- const int *index;
medge = dm->getEdgeArray(dm);
totedge = dm->getNumEdges(dm);
- index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
- fed = CustomData_get_layer(&me->edata, CD_FREESTYLE_EDGE);
+ fed = dm->getEdgeDataArray(dm, CD_FREESTYLE_EDGE);
if (fed) {
edge_hash = BLI_edgehash_new(__func__);
- if (!index) {
- if (me->totedge == totedge) {
- for (a = 0; a < me->totedge; a++) {
- if (fed[a].flag & FREESTYLE_EDGE_MARK) {
- BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge + a);
- }
- }
- }
- }
- else {
- for (a = 0; a < totedge; a++) {
- if (index[a] == ORIGINDEX_NONE)
- continue;
- if (fed[index[a]].flag & FREESTYLE_EDGE_MARK)
- BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a);
- }
+ for (a = 0; a < totedge; a++) {
+ if (fed[a].flag & FREESTYLE_EDGE_MARK)
+ BLI_edgehash_insert(edge_hash, medge[a].v1, medge[a].v2, medge+a);
}
}
return edge_hash;
@@ -3268,7 +3257,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
EdgeHash *edge_hash;
/* create a hash table of Freestyle edge marks */
- edge_hash = make_freestyle_edge_mark_hash(me, dm);
+ edge_hash = make_freestyle_edge_mark_hash(dm);
#endif
/* store customdata names, because DerivedMesh is freed */
@@ -3661,6 +3650,7 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
mul_m4_m4m4(mat, re->viewmat, ob->obmat);
invert_m4_m4(ob->imat, mat);
+ copy_m4_m4(lar->lampmat, ob->obmat);
copy_m3_m4(lar->mat, mat);
copy_m3_m4(lar->imat, ob->imat);
@@ -3715,8 +3705,8 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
/* Annoying, lamp UI does this, but the UI might not have been used? - add here too.
* make sure this matches buttons_shading.c's logic */
- if (ELEM4(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY))
- if (ELEM3(la->type, LA_SPOT, LA_SUN, LA_LOCAL))
+ if (ELEM(la->type, LA_AREA, LA_SPOT, LA_SUN, LA_LOCAL) && (la->mode & LA_SHAD_RAY))
+ if (ELEM(la->type, LA_SPOT, LA_SUN, LA_LOCAL))
if (la->ray_samp_method == LA_SAMP_CONSTANT) la->ray_samp_method = LA_SAMP_HALTON;
lar->ray_samp_method= la->ray_samp_method;
@@ -3806,8 +3796,8 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
normalize_v3(lar->imat[1]);
normalize_v3(lar->imat[2]);
- xn= saacos(lar->spotsi);
- xn= sin(xn)/cos(xn);
+ xn = saacos(lar->spotsi);
+ xn = sinf(xn) / cosf(xn);
lar->spottexfac= 1.0f/(xn);
if (lar->mode & LA_ONLYSHADOW) {
@@ -3830,7 +3820,7 @@ static GroupObject *add_render_lamp(Render *re, Object *ob)
/* z factor, for a normalized volume */
angle= saacos(lar->spotsi);
xn= lar->spotsi;
- yn= sin(angle);
+ yn = sinf(angle);
lar->sh_zfac= yn/xn;
/* pre-scale */
lar->sh_invcampos[2]*= lar->sh_zfac;
@@ -4557,8 +4547,7 @@ static void set_dupli_tex_mat(Render *re, ObjectInstanceRen *obi, DupliObject *d
obi->duplitexmat= BLI_memarena_alloc(re->memArena, sizeof(float)*4*4);
invert_m4_m4(imat, dob->mat);
- mul_serie_m4(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv,
- NULL, NULL, NULL, NULL);
+ mul_m4_series(obi->duplitexmat, re->viewmat, omat, imat, re->viewinv);
}
copy_v3_v3(obi->dupliorco, dob->orco);
@@ -4802,13 +4791,12 @@ static int allow_render_object(Render *re, Object *ob, int nolamps, int onlysele
{
if (is_object_hidden(re, ob))
return 0;
-
- /* override not showing object when duplis are used with particles */
- if (ob->transflag & OB_DUPLIPARTS) {
- /* pass */ /* let particle system(s) handle showing vs. not showing */
- }
- else if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) {
- return 0;
+
+ /* Only handle dupli-hiding here if there is no particle systems. Else, let those handle show/noshow. */
+ if (!ob->particlesystem.first) {
+ if ((ob->transflag & OB_DUPLI) && !(ob->transflag & OB_DUPLIFRAMES)) {
+ return 0;
+ }
}
/* don't add non-basic meta objects, ends up having renderobjects with no geometry */
@@ -4843,7 +4831,7 @@ static int allow_render_dupli_instance(Render *UNUSED(re), DupliObject *dob, Obj
}
for (psys=obd->particlesystem.first; psys; psys=psys->next)
- if (!ELEM5(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR))
+ if (!ELEM(psys->part->ren_as, PART_DRAW_BB, PART_DRAW_LINE, PART_DRAW_PATH, PART_DRAW_OB, PART_DRAW_GR))
return 0;
/* don't allow lamp, animated duplis, or radio render */
@@ -5000,7 +4988,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_matrix(duplilist);
+ duplilist_apply_data = duplilist_apply(ob, duplilist);
dupli_render_particle_set(re, ob, timeoffset, 0, 0);
for (dob= duplilist->first, i = 0; dob; dob= dob->next, ++i) {
@@ -5095,7 +5083,7 @@ static void database_init_objects(Render *re, unsigned int renderlay, int nolamp
}
if (duplilist_apply_data) {
- duplilist_restore_matrix(duplilist, duplilist_apply_data);
+ duplilist_restore(duplilist, duplilist_apply_data);
duplilist_free_apply_data(duplilist_apply_data);
}
free_object_duplilist(duplilist);
@@ -5157,8 +5145,10 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l
lay &= 0xFF000000;
/* applies changes fully */
- if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0)
+ if ((re->r.scemode & (R_NO_FRAME_UPDATE|R_BUTS_PREVIEW|R_VIEWPORT_PREVIEW))==0) {
BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
+ render_update_anim_renderdata(re, &re->scene->r);
+ }
/* if no camera, viewmat should have been set! */
if (use_camera_view && camera) {
@@ -5448,7 +5438,7 @@ static float *calculate_strandsurface_speedvectors(Render *re, ObjectInstanceRen
{
if (mesh->co && mesh->prevco && mesh->nextco) {
float winsq= (float)re->winx*(float)re->winy; /* int's can wrap on large images */
- float winroot= sqrt(winsq);
+ float winroot= sqrtf(winsq);
float (*winspeed)[4];
float ho[4], prevho[4], nextho[4], winmat[4][4], vec[2];
int a;
@@ -5487,7 +5477,7 @@ static void calculate_speedvectors(Render *re, ObjectInstanceRen *obi, float *ve
StrandSurface *mesh= NULL;
float *speed, (*winspeed)[4]=NULL, ho[4], winmat[4][4];
float *co1, *co2, *co3, *co4, w[4];
- float winsq= (float)re->winx*(float)re->winy, winroot= sqrt(winsq); /* int's can wrap on large images */
+ float winsq = (float)re->winx * (float)re->winy, winroot = sqrtf(winsq); /* int's can wrap on large images */
int a, *face, *index;
if (obi->flag & R_TRANSFORMED)
@@ -5554,7 +5544,7 @@ static int load_fluidsimspeedvectors(Render *re, ObjectInstanceRen *obi, float *
VertRen *ver= NULL;
float *speed, div, zco[2], avgvel[4] = {0.0, 0.0, 0.0, 0.0};
float zmulx= re->winx/2, zmuly= re->winy/2, len;
- float winsq= (float)re->winx*(float)re->winy, winroot= sqrt(winsq); /* int's can wrap on large images */
+ float winsq = (float)re->winx * (float)re->winy, winroot= sqrtf(winsq); /* int's can wrap on large images */
int a, j;
float hoco[4], ho[4], fsvec[4], camco[4];
float mat[4][4], winmat[4][4];
@@ -5843,8 +5833,8 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
Object *camera;
float mat[4][4];
float amb[3];
- const short onlyselected= !ELEM5(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS);
- const short nolamps= ELEM5(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS);
+ const short onlyselected= !ELEM(type, RE_BAKE_LIGHT, RE_BAKE_ALL, RE_BAKE_SHADOW, RE_BAKE_AO, RE_BAKE_VERTEX_COLORS);
+ const short nolamps= ELEM(type, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS);
re->main= bmain;
re->scene= scene;
@@ -5868,7 +5858,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay,
if (type==RE_BAKE_VERTEX_COLORS)
re->flag |= R_NEED_VCOL;
- if (!actob && ELEM6(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) {
+ if (!actob && ELEM(type, RE_BAKE_LIGHT, RE_BAKE_NORMALS, RE_BAKE_TEXTURE, RE_BAKE_DISPLACEMENT, RE_BAKE_DERIVATIVE, RE_BAKE_VERTEX_COLORS)) {
re->r.mode &= ~R_SHADOW;
re->r.mode &= ~R_RAYTRACE;
}
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index 28b29261e4e..06be00a5a5e 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -329,9 +329,9 @@ void env_rotate_scene(Render *re, float mat[4][4], int do_rotate)
/* copy from add_render_lamp */
if (do_rotate == 1)
- mul_m4_m4m4(tmpmat, re->viewmat, go->ob->obmat);
+ mul_m4_m4m4(tmpmat, re->viewmat, lar->lampmat);
else
- mul_m4_m4m4(tmpmat, re->viewmat_orig, go->ob->obmat);
+ mul_m4_m4m4(tmpmat, re->viewmat_orig, lar->lampmat);
invert_m4_m4(go->ob->imat, tmpmat);
copy_m3_m4(lar->mat, tmpmat);
diff --git a/source/blender/render/intern/source/external_engine.c b/source/blender/render/intern/source/external_engine.c
index e8751210540..54f142184e1 100644
--- a/source/blender/render/intern/source/external_engine.c
+++ b/source/blender/render/intern/source/external_engine.c
@@ -60,6 +60,7 @@
#include "RE_bake.h"
#include "initrender.h"
+#include "renderpipeline.h"
#include "render_types.h"
#include "render_result.h"
@@ -411,20 +412,20 @@ void RE_bake_engine_set_engine_parameters(Render *re, Main *bmain, Scene *scene)
re->r = scene->r;
/* prevent crash when freeing the scene
- but it potentially leaves unfreed memory blocks
- not sure how to fix this yet -- dfelinto */
- re->r.layers.first = re->r.layers.last = NULL;
+ * but it potentially leaves unfreed memory blocks
+ * not sure how to fix this yet -- dfelinto */
+ BLI_listbase_clear(&re->r.layers);
}
bool RE_bake_has_engine(Render *re)
{
RenderEngineType *type = RE_engines_find(re->r.engine);
- return (bool)(type->bake);
+ return (type->bake != NULL);
}
bool RE_bake_engine(
Render *re, Object *object, const BakePixel pixel_array[],
- const int num_pixels, const int depth,
+ const size_t num_pixels, const int depth,
const ScenePassType pass_type, float result[])
{
RenderEngineType *type = RE_engines_find(re->r.engine);
@@ -453,8 +454,8 @@ bool RE_bake_engine(
engine->resolution_y = re->winy;
RE_parts_init(re, false);
- engine->tile_x = re->partx;
- engine->tile_y = re->party;
+ engine->tile_x = re->r.tilex;
+ engine->tile_y = re->r.tiley;
/* update is only called so we create the engine.session */
if (type->update)
@@ -481,6 +482,29 @@ bool RE_bake_engine(
return true;
}
+void RE_engine_frame_set(RenderEngine *engine, int frame, float subframe)
+{
+ Render *re = engine->re;
+ Scene *scene = re->scene;
+ double cfra = (double)frame + (double)subframe;
+
+ CLAMP(cfra, MINAFRAME, MAXFRAME);
+ BKE_scene_frame_set(scene, cfra);
+
+#ifdef WITH_PYTHON
+ BPy_BEGIN_ALLOW_THREADS;
+#endif
+
+ /* It's possible that here we're including layers which were never visible before. */
+ BKE_scene_update_for_newframe_ex(re->eval_ctx, re->main, scene, (1 << 20) - 1, true);
+
+#ifdef WITH_PYTHON
+ BPy_END_ALLOW_THREADS;
+#endif
+
+ BKE_scene_camera_switch_update(scene);
+}
+
/* Render */
static bool render_layer_exclude_animated(Scene *scene, SceneRenderLayer *srl)
@@ -551,7 +575,8 @@ int RE_engine_render(Render *re, int do_all)
lay &= non_excluded_lay;
}
- BKE_scene_update_for_newframe(re->eval_ctx, re->main, re->scene, lay);
+ BKE_scene_update_for_newframe_ex(re->eval_ctx, re->main, re->scene, lay, true);
+ render_update_anim_renderdata(re, &re->scene->r);
}
/* create render result */
@@ -599,6 +624,7 @@ int RE_engine_render(Render *re, int do_all)
if (re->r.scemode & R_BUTS_PREVIEW)
engine->flag |= RE_ENGINE_PREVIEW;
engine->camera_override = re->camera_override;
+ engine->layer_override = re->layer_override;
engine->resolution_x = re->winx;
engine->resolution_y = re->winy;
@@ -639,11 +665,22 @@ int RE_engine_render(Render *re, int do_all)
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);
+ }
+
RE_parts_free(re);
if (BKE_reports_contain(re->reports, RPT_ERROR))
G.is_break = true;
+#ifdef WITH_FREESTYLE
+ if (re->r.mode & R_EDGE_FRS)
+ RE_RenderFreestyleExternal(re);
+#endif
+
return 1;
}
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 7d4b70cea15..2787ce99b13 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -791,176 +791,31 @@ static void area_sample(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata
texr->ta = texr->talpha ? texr->ta*xsd : (clip ? cw*xsd : 1.f);
}
-/* table of (exp(ar) - exp(a)) / (1 - exp(a)) for r in range [0, 1] and a = -2
- * used instead of actual gaussian, otherwise at high texture magnifications circular artifacts are visible */
-#define EWA_MAXIDX 255
-static const float EWA_WTS[EWA_MAXIDX + 1] = {
- 1.f, 0.990965f, 0.982f, 0.973105f, 0.96428f, 0.955524f, 0.946836f, 0.938216f, 0.929664f,
- 0.921178f, 0.912759f, 0.904405f, 0.896117f, 0.887893f, 0.879734f, 0.871638f, 0.863605f,
- 0.855636f, 0.847728f, 0.839883f, 0.832098f, 0.824375f, 0.816712f, 0.809108f, 0.801564f,
- 0.794079f, 0.786653f, 0.779284f, 0.771974f, 0.76472f, 0.757523f, 0.750382f, 0.743297f,
- 0.736267f, 0.729292f, 0.722372f, 0.715505f, 0.708693f, 0.701933f, 0.695227f, 0.688572f,
- 0.68197f, 0.67542f, 0.66892f, 0.662471f, 0.656073f, 0.649725f, 0.643426f, 0.637176f,
- 0.630976f, 0.624824f, 0.618719f, 0.612663f, 0.606654f, 0.600691f, 0.594776f, 0.588906f,
- 0.583083f, 0.577305f, 0.571572f, 0.565883f, 0.56024f, 0.55464f, 0.549084f, 0.543572f,
- 0.538102f, 0.532676f, 0.527291f, 0.521949f, 0.516649f, 0.511389f, 0.506171f, 0.500994f,
- 0.495857f, 0.490761f, 0.485704f, 0.480687f, 0.475709f, 0.470769f, 0.465869f, 0.461006f,
- 0.456182f, 0.451395f, 0.446646f, 0.441934f, 0.437258f, 0.432619f, 0.428017f, 0.42345f,
- 0.418919f, 0.414424f, 0.409963f, 0.405538f, 0.401147f, 0.39679f, 0.392467f, 0.388178f,
- 0.383923f, 0.379701f, 0.375511f, 0.371355f, 0.367231f, 0.363139f, 0.359079f, 0.355051f,
- 0.351055f, 0.347089f, 0.343155f, 0.339251f, 0.335378f, 0.331535f, 0.327722f, 0.323939f,
- 0.320186f, 0.316461f, 0.312766f, 0.3091f, 0.305462f, 0.301853f, 0.298272f, 0.294719f,
- 0.291194f, 0.287696f, 0.284226f, 0.280782f, 0.277366f, 0.273976f, 0.270613f, 0.267276f,
- 0.263965f, 0.26068f, 0.257421f, 0.254187f, 0.250979f, 0.247795f, 0.244636f, 0.241502f,
- 0.238393f, 0.235308f, 0.232246f, 0.229209f, 0.226196f, 0.223206f, 0.220239f, 0.217296f,
- 0.214375f, 0.211478f, 0.208603f, 0.20575f, 0.20292f, 0.200112f, 0.197326f, 0.194562f,
- 0.191819f, 0.189097f, 0.186397f, 0.183718f, 0.18106f, 0.178423f, 0.175806f, 0.17321f,
- 0.170634f, 0.168078f, 0.165542f, 0.163026f, 0.16053f, 0.158053f, 0.155595f, 0.153157f,
- 0.150738f, 0.148337f, 0.145955f, 0.143592f, 0.141248f, 0.138921f, 0.136613f, 0.134323f,
- 0.132051f, 0.129797f, 0.12756f, 0.125341f, 0.123139f, 0.120954f, 0.118786f, 0.116635f,
- 0.114501f, 0.112384f, 0.110283f, 0.108199f, 0.106131f, 0.104079f, 0.102043f, 0.100023f,
- 0.0980186f, 0.09603f, 0.094057f, 0.0920994f, 0.0901571f, 0.08823f, 0.0863179f, 0.0844208f,
- 0.0825384f, 0.0806708f, 0.0788178f, 0.0769792f, 0.0751551f, 0.0733451f, 0.0715493f, 0.0697676f,
- 0.0679997f, 0.0662457f, 0.0645054f, 0.0627786f, 0.0610654f, 0.0593655f, 0.0576789f, 0.0560055f,
- 0.0543452f, 0.0526979f, 0.0510634f, 0.0494416f, 0.0478326f, 0.0462361f, 0.0446521f, 0.0430805f,
- 0.0415211f, 0.039974f, 0.0384389f, 0.0369158f, 0.0354046f, 0.0339052f, 0.0324175f, 0.0309415f,
- 0.029477f, 0.0280239f, 0.0265822f, 0.0251517f, 0.0237324f, 0.0223242f, 0.020927f, 0.0195408f,
- 0.0181653f, 0.0168006f, 0.0154466f, 0.0141031f, 0.0127701f, 0.0114476f, 0.0101354f, 0.00883339f,
- 0.00754159f, 0.00625989f, 0.00498819f, 0.00372644f, 0.00247454f, 0.00123242f, 0.f
-};
-
-/* test if a float value is 'nan'
- * there is a C99 function for this: isnan(), but blender seems to use C90 (according to gcc warns),
- * and may not be supported by other compilers either */
-#ifndef ISNAN
-#define ISNAN(x) ((x) != (x))
-#endif
-//static int ISNAN(float x) { return (x != x); }
+typedef struct ReadEWAData {
+ ImBuf *ibuf;
+ afdata_t *AFD;
+} ReadEWAData;
-static void radangle2imp(float a2, float b2, float th, float *A, float *B, float *C, float *F)
+static void ewa_read_pixel_cb(void *userdata, int x, int y, float result[4])
{
- float ct2 = cosf(th);
- const float st2 = 1.0f - ct2 * ct2; /* <- sin(th)^2 */
- ct2 *= ct2;
- *A = a2*st2 + b2*ct2;
- *B = (b2 - a2)*sinf(2.f*th);
- *C = a2*ct2 + b2*st2;
- *F = a2*b2;
-}
-
-/* all tests here are done to make sure possible overflows are hopefully minimized */
-static void imp2radangle(float A, float B, float C, float F, float *a, float *b, float *th, float *ecc)
-{
- if (F <= 1e-5f) { /* use arbitrary major radius, zero minor, infinite eccentricity */
- *a = sqrtf(A > C ? A : C);
- *b = 0.f;
- *ecc = 1e10f;
- *th = 0.5f*(atan2f(B, A - C) + (float)M_PI);
- }
- else {
- const float AmC = A - C, ApC = A + C, F2 = F*2.f;
- const float r = sqrtf(AmC*AmC + B*B);
- float d = ApC - r;
- *a = (d <= 0.f) ? sqrtf(A > C ? A : C) : sqrtf(F2 / d);
- d = ApC + r;
- if (d <= 0.f) {
- *b = 0.f;
- *ecc = 1e10f;
- }
- else {
- *b = sqrtf(F2 / d);
- *ecc = *a / *b;
- }
- /* incr theta by 0.5*pi (angle of major axis) */
- *th = 0.5f*(atan2f(B, AmC) + (float)M_PI);
- }
+ ReadEWAData *data = (ReadEWAData *) userdata;
+ ibuf_get_color_clip(result, data->ibuf, x, y, data->AFD->extflag);
}
static void ewa_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata_t *AFD)
{
- /* scaling dxt/dyt by full resolution can cause overflow because of huge A/B/C and esp. F values,
- * scaling by aspect ratio alone does the opposite, so try something in between instead... */
- const float ff2 = ibuf->x, ff = sqrtf(ff2), q = ibuf->y / ff;
- const float Ux = AFD->dxt[0]*ff, Vx = AFD->dxt[1]*q, Uy = AFD->dyt[0]*ff, Vy = AFD->dyt[1]*q;
- float A = Vx*Vx + Vy*Vy;
- float B = -2.f*(Ux*Vx + Uy*Vy);
- float C = Ux*Ux + Uy*Uy;
- float F = A*C - B*B*0.25f;
- float a, b, th, ecc, a2, b2, ue, ve, U0, V0, DDQ, U, ac1, ac2, BU, d; /* TXF alpha: cw = 0.f; */
- int u, v, u1, u2, v1, v2; /* TXF alpha: clip = 0; */
-
- /* The so-called 'high' quality ewa method simply adds a constant of 1 to both A & C,
- * so the ellipse always covers at least some texels. But since the filter is now always larger,
- * it also means that everywhere else it's also more blurry then ideally should be the case.
- * So instead here the ellipse radii are modified instead whenever either is too low.
- * Use a different radius based on interpolation switch, just enough to anti-alias when interpolation is off,
- * and slightly larger to make result a bit smoother than bilinear interpolation when interpolation is on
- * (minimum values: const float rmin = intpol ? 1.f : 0.5f;) */
- const float rmin = (AFD->intpol ? 1.5625f : 0.765625f)/ff2;
- imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
- if ((b2 = b*b) < rmin) {
- if ((a2 = a*a) < rmin) {
- B = 0.f;
- A = C = rmin;
- F = A*C;
- }
- else {
- b2 = rmin;
- radangle2imp(a2, b2, th, &A, &B, &C, &F);
- }
- }
-
- ue = ff*sqrtf(C);
- ve = ff*sqrtf(A);
- d = (float)(EWA_MAXIDX + 1) / (F*ff2);
- A *= d;
- B *= d;
- C *= d;
-
- U0 = fx*ibuf->x;
- V0 = fy*ibuf->y;
- u1 = (int)(floorf(U0 - ue));
- u2 = (int)(ceilf(U0 + ue));
- v1 = (int)(floorf(V0 - ve));
- v2 = (int)(ceilf(V0 + ve));
- U0 -= 0.5f;
- V0 -= 0.5f;
- DDQ = 2.f*A;
- U = u1 - U0;
- ac1 = A*(2.f*U + 1.f);
- ac2 = A*U*U;
- BU = B*U;
-
- d = texr->tr = texr->tb = texr->tg = texr->ta = 0.f;
- for (v=v1; v<=v2; ++v) {
- const float V = v - V0;
- float DQ = ac1 + B*V;
- float Q = (C*V + BU)*V + ac2;
- for (u=u1; u<=u2; ++u) {
- if (Q < (float)(EWA_MAXIDX + 1)) {
- float tc[4];
- const float wt = EWA_WTS[(Q < 0.f) ? 0 : (unsigned int)Q];
- /*const int out =*/ ibuf_get_color_clip(tc, ibuf, u, v, AFD->extflag);
- /* TXF alpha: clip |= out;
- * TXF alpha: cw += out ? 0.f : wt; */
- texr->tr += tc[0]*wt;
- texr->tg += tc[1]*wt;
- texr->tb += tc[2]*wt;
- texr->ta += texr->talpha ? tc[3]*wt : 0.f;
- d += wt;
- }
- Q += DQ;
- DQ += DDQ;
- }
- }
+ ReadEWAData data;
+ float uv[2] = {fx, fy};
+ data.ibuf = ibuf;
+ data.AFD = AFD;
+ BLI_ewa_filter(ibuf->x, ibuf->y,
+ AFD->intpol != 0,
+ texr->talpha,
+ uv, AFD->dxt, AFD->dyt,
+ ewa_read_pixel_cb,
+ &data,
+ &texr->tr);
- /* d should hopefully never be zero anymore */
- d = 1.f/d;
- texr->tr *= d;
- texr->tg *= d;
- texr->tb *= d;
- /* clipping can be ignored if alpha used, texr->ta already includes filtered edge */
- texr->ta = texr->talpha ? texr->ta*d : 1.f; /* TXF alpha (clip ? cw*d : 1.f); */
}
static void feline_eval(TexResult *texr, ImBuf *ibuf, float fx, float fy, afdata_t *AFD)
@@ -1304,7 +1159,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
const float C = Ux*Ux + Uy*Uy;
const float F = A*C - B*B*0.25f;
float a, b, th, ecc;
- imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
+ BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
if (tex->texfilter == TXF_FELINE) {
float fProbes;
a *= ff;
@@ -1349,7 +1204,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
if (tex->texfilter == TXF_FELINE) AFD.iProbes = 1;
}
else {
- const int lev = ISNAN(levf) ? 0 : (int)levf;
+ const int lev = isnan(levf) ? 0 : (int)levf;
curibuf = mipmaps[lev];
previbuf = mipmaps[lev + 1];
levf -= floorf(levf);
@@ -1408,7 +1263,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
const float C = Ux*Ux + Uy*Uy;
const float F = A*C - B*B*0.25f;
float a, b, th, ecc, fProbes;
- imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
+ BLI_ewa_imp2radangle(A, B, C, F, &a, &b, &th, &ecc);
a *= ff;
b *= ff;
a = max_ff(a, 1.0f);
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index 5fd4747f19b..353ba5d5caa 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -190,7 +190,7 @@ static float calc_weight(Render *re, float *weight, int i, int j)
for (a = 0; a < re->osa; a++) {
x = re->jit[a][0] + i;
y = re->jit[a][1] + j;
- dist = sqrt(x * x + y * y);
+ dist = sqrtf(x * x + y * y);
weight[a] = 0.0;
diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c
index 4ac1593d1bb..6ba85ea5329 100644
--- a/source/blender/render/intern/source/multires_bake.c
+++ b/source/blender/render/intern/source/multires_bake.c
@@ -42,6 +42,7 @@
#include "BLI_threads.h"
#include "BKE_ccg.h"
+#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_multires.h"
@@ -1154,10 +1155,10 @@ static void apply_ao_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, void
/* this gives results identical to the so-called cosine
* weighted distribution relative to the north pole.
*/
- float SiPhi = sqrt(SiSqPhi);
+ float SiPhi = sqrtf(SiSqPhi);
float CoPhi = SiSqPhi < 1.0f ? sqrtf(1.0f - SiSqPhi) : 0;
- float CoThe = cos(Theta);
- float SiThe = sin(Theta);
+ float CoThe = cosf(Theta);
+ float SiThe = sinf(Theta);
const float dx = CoThe * CoPhi;
const float dy = SiThe * CoPhi;
@@ -1297,6 +1298,7 @@ static void finish_images(MultiresBakeRender *bkr, MultiresBakeResult *result)
}
BKE_image_release_ibuf(ima, ibuf, NULL);
+ DAG_id_tag_update(&ima->id, 0);
}
}
diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c
index dd0b1f89da7..0c6341fe9e5 100644
--- a/source/blender/render/intern/source/occlusion.c
+++ b/source/blender/render/intern/source/occlusion.c
@@ -45,6 +45,7 @@
#include "BLF_translation.h"
+#include "BKE_node.h"
#include "BKE_scene.h"
@@ -194,14 +195,19 @@ static void occ_shade(ShadeSample *ssamp, ObjectInstanceRen *obi, VlakRen *vlr,
}
/* init material vars */
- /* note, keep this synced with render_types.h */
- memcpy(&shi->r, &shi->mat->r, 23 * sizeof(float));
- shi->har = shi->mat->har;
-
+ shade_input_init_material(shi);
+
/* render */
shade_input_set_shade_texco(shi);
- shade_material_loop(shi, shr); /* todo: nodes */
-
+
+ if (shi->mat->nodetree && shi->mat->use_nodes) {
+ ntreeShaderExecTree(shi->mat->nodetree, shi, shr);
+ shi->mat = vlr->mat; /* shi->mat is being set in nodetree */
+ }
+ else {
+ shade_material_loop(shi, shr);
+ }
+
copy_v3_v3(rad, shr->combined);
}
@@ -621,7 +627,7 @@ static void occ_build_recursive(OcclusionTree *tree, OccNode *node, int begin, i
static void occ_build_sh_normalize(OccNode *node)
{
/* normalize spherical harmonics to not include area, so
- * we can clamp the dot product and then mutliply by area */
+ * we can clamp the dot product and then multiply by area */
int b;
if (node->area != 0.0f)
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 232f9db1c65..7b43c77537f 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -61,6 +61,7 @@
#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_image.h"
+#include "BKE_library.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "BKE_node.h"
@@ -237,6 +238,17 @@ static int render_scene_needs_vector(Render *re)
return 0;
}
+static bool render_scene_has_layers_to_render(Scene *scene)
+{
+ SceneRenderLayer *srl;
+ for (srl = scene->r.layers.first; srl; srl = srl->next) {
+ if (!(srl->layflag & SCE_LAY_DISABLE)) {
+ return true;
+ }
+ }
+ return false;
+}
+
/* *************************************************** */
Render *RE_GetRender(const char *name)
@@ -375,7 +387,7 @@ Render *RE_NewRender(const char *name)
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->for_render = true;
+ re->eval_ctx->mode = DAG_EVAL_RENDER;
}
RE_InitRenderCB(re);
@@ -500,32 +512,9 @@ static int check_mode_full_sample(RenderData *rd)
return scemode;
}
-/* what doesn't change during entire render sequence */
-/* disprect is optional, if NULL it assumes full window render */
-void RE_InitState(Render *re, Render *source, RenderData *rd, SceneRenderLayer *srl, int winx, int winy, rcti *disprect)
+static void re_init_resolution(Render *re, Render *source,
+ int winx, int winy, rcti *disprect)
{
- bool had_freestyle = (re->r.mode & R_EDGE_FRS) != 0;
-
- re->ok = true; /* maybe flag */
-
- re->i.starttime = PIL_check_seconds_timer();
-
- /* copy render data and render layers for thread safety */
- BLI_freelistN(&re->r.layers);
- re->r = *rd;
- BLI_duplicatelist(&re->r.layers, &rd->layers);
-
- if (source) {
- /* reuse border flags from source renderer */
- re->r.mode &= ~(R_BORDER | R_CROP);
- re->r.mode |= source->r.mode & (R_BORDER | R_CROP);
-
- /* dimensions shall be shared between all renderers */
- re->r.xsch = source->r.xsch;
- re->r.ysch = source->r.ysch;
- re->r.size = source->r.size;
- }
-
re->winx = winx;
re->winy = winy;
if (source && (source->r.mode & R_BORDER)) {
@@ -559,7 +548,41 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, SceneRenderLayer *
re->rectx = winx;
re->recty = winy;
}
+
+ /* we clip faces with a minimum of 2 pixel boundary outside of image border. see zbuf.c */
+ re->clipcrop = 1.0f + 2.0f / (float)(re->winx > re->winy ? re->winy : re->winx);
+}
+
+/* what doesn't change during entire render sequence */
+/* disprect is optional, if NULL it assumes full window render */
+void RE_InitState(Render *re, Render *source, RenderData *rd,
+ SceneRenderLayer *srl,
+ int winx, int winy, rcti *disprect)
+{
+ bool had_freestyle = (re->r.mode & R_EDGE_FRS) != 0;
+
+ re->ok = true; /* maybe flag */
+ re->i.starttime = PIL_check_seconds_timer();
+
+ /* copy render data and render layers for thread safety */
+ BLI_freelistN(&re->r.layers);
+ re->r = *rd;
+ BLI_duplicatelist(&re->r.layers, &rd->layers);
+
+ if (source) {
+ /* reuse border flags from source renderer */
+ re->r.mode &= ~(R_BORDER | R_CROP);
+ re->r.mode |= source->r.mode & (R_BORDER | R_CROP);
+
+ /* dimensions shall be shared between all renderers */
+ re->r.xsch = source->r.xsch;
+ re->r.ysch = source->r.ysch;
+ re->r.size = source->r.size;
+ }
+
+ re_init_resolution(re, source, winx, winy, disprect);
+
if (re->rectx < 1 || re->recty < 1 || (BKE_imtype_is_movie(rd->im_format.imtype) &&
(re->rectx < 16 || re->recty < 16) ))
{
@@ -638,22 +661,101 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, SceneRenderLayer *
re->result->recty = re->recty;
}
+ if (re->r.scemode & R_VIEWPORT_PREVIEW)
+ re->eval_ctx->mode = DAG_EVAL_PREVIEW;
+ else
+ re->eval_ctx->mode = DAG_EVAL_RENDER;
+
/* ensure renderdatabase can use part settings correct */
RE_parts_clamp(re);
BLI_rw_mutex_unlock(&re->resultmutex);
- /* we clip faces with a minimum of 2 pixel boundary outside of image border. see zbuf.c */
- re->clipcrop = 1.0f + 2.0f / (float)(re->winx > re->winy ? re->winy : re->winx);
-
re->mblur_offs = re->field_offs = 0.f;
RE_init_threadcount(re);
}
+static void render_result_rescale(Render *re)
+{
+ RenderResult *result = re->result;
+ int x, y;
+ float scale_x, scale_y;
+ float *src_rectf;
+
+ src_rectf = result->rectf;
+ if (src_rectf == NULL) {
+ RenderLayer *rl = render_get_active_layer(re, re->result);
+ if (rl != NULL) {
+ src_rectf = rl->rectf;
+ }
+ }
+
+ if (src_rectf != NULL) {
+ float *dst_rectf = NULL;
+ re->result = render_result_new(re,
+ &re->disprect,
+ 0,
+ RR_USE_MEM,
+ RR_ALL_LAYERS);
+
+ if (re->result != NULL) {
+ dst_rectf = re->result->rectf;
+ if (dst_rectf == NULL) {
+ RenderLayer *rl;
+ rl = render_get_active_layer(re, re->result);
+ if (rl != NULL) {
+ dst_rectf = rl->rectf;
+ }
+ }
+
+ scale_x = (float) result->rectx / re->result->rectx;
+ scale_y = (float) result->recty / re->result->recty;
+ for (x = 0; x < re->result->rectx; ++x) {
+ for (y = 0; y < re->result->recty; ++y) {
+ int src_x = x * scale_x,
+ src_y = y * scale_y;
+ int dst_index = y * re->result->rectx + x,
+ src_index = src_y * result->rectx + src_x;
+ copy_v4_v4(dst_rectf + dst_index * 4,
+ src_rectf + src_index * 4);
+ }
+ }
+ }
+ }
+
+ render_result_free(result);
+}
+
+void RE_ChangeResolution(Render *re, int winx, int winy, rcti *disprect)
+{
+ re_init_resolution(re, NULL, winx, winy, disprect);
+ RE_parts_clamp(re);
+
+ if (re->result) {
+ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
+ render_result_rescale(re);
+ BLI_rw_mutex_unlock(&re->resultmutex);
+ }
+}
+
+/* TODO(sergey): This is a bit hackish, used to temporary disable freestyle when
+ * doing viewport render. Needs some better integration of BI viewport rendering
+ * into the pipeline.
+ */
+void RE_ChangeModeFlag(Render *re, int flag, bool clear)
+{
+ if (clear) {
+ re->r.mode &= ~flag;
+ }
+ else {
+ re->r.mode |= flag;
+ }
+}
+
/* update some variables that can be animated, and otherwise wouldn't be due to
* RenderData getting copied once at the start of animation render */
-static void render_update_anim_renderdata(Render *re, RenderData *rd)
+void render_update_anim_renderdata(Render *re, RenderData *rd)
{
/* filter */
re->r.gauss = rd->gauss;
@@ -913,8 +1015,8 @@ static bool find_next_pano_slice(Render *re, int *slice, int *minx, rctf *viewpl
/* rotate database according to part coordinates */
project_renderdata(re, projectverto, 1, -R.panodxp * phi, 1);
- R.panosi = sin(R.panodxp * phi);
- R.panoco = cos(R.panodxp * phi);
+ R.panosi = sinf(R.panodxp * phi);
+ R.panoco = cosf(R.panodxp * phi);
}
(*slice)++;
@@ -1152,7 +1254,13 @@ static void threaded_tile_processor(Render *re)
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);
+ }
+
/* unset threadsafety */
g_break = 0;
@@ -1532,6 +1640,10 @@ static void do_render_fields_blur_3d(Render *re)
if (re->r.mode & R_BORDER) {
if ((re->r.mode & R_CROP) == 0) {
RenderResult *rres;
+
+ /* backup */
+ const rcti orig_disprect = re->disprect;
+ const int orig_rectx = re->rectx, orig_recty = re->recty;
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
@@ -1554,6 +1666,11 @@ static void do_render_fields_blur_3d(Render *re)
re->display_init(re->dih, re->result);
re->display_update(re->duh, re->result, NULL);
+
+ /* restore the disprect from border */
+ re->disprect = orig_disprect;
+ re->rectx = orig_rectx;
+ re->recty = orig_recty;
}
else {
/* set offset (again) for use in compositor, disprect was manipulated. */
@@ -1585,7 +1702,10 @@ static void render_scene(Render *re, Scene *sce, int cfra)
/* initial setup */
RE_InitState(resc, re, &sce->r, NULL, winx, winy, &re->disprect);
-
+
+ /* We still want to use 'rendercache' setting from org (main) scene... */
+ resc->r.scemode = (resc->r.scemode & ~R_EXR_CACHE_FILE) | (re->r.scemode & R_EXR_CACHE_FILE);
+
/* still unsure entity this... */
resc->main = re->main;
resc->scene = sce;
@@ -1619,7 +1739,7 @@ static int composite_needs_render(Scene *sce, int this_scene)
if ((sce->r.scemode & R_DOCOMP) == 0) return 1;
for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS)
+ if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0)
if (this_scene == 0 || node->id == NULL || node->id == &sce->id)
return 1;
}
@@ -1736,11 +1856,13 @@ static void tag_scenes_for_render(Render *re)
}
#ifdef WITH_FREESTYLE
- for (sce = re->freestyle_bmain.scene.first; sce; sce = sce->id.next) {
- sce->id.flag &= ~LIB_DOIT;
+ if (re->freestyle_bmain) {
+ for (sce = re->freestyle_bmain->scene.first; sce; sce = sce->id.next) {
+ sce->id.flag &= ~LIB_DOIT;
#ifdef DEPSGRAPH_WORKAROUND_HACK
- tag_dependend_objects_for_render(sce, renderlay);
+ tag_dependend_objects_for_render(sce, renderlay);
#endif
+ }
}
#endif
@@ -1756,7 +1878,7 @@ static void tag_scenes_for_render(Render *re)
/* check for render-layers nodes using other scenes, we tag them LIB_DOIT */
for (node = re->scene->nodetree->nodes.first; node; node = node->next) {
node->flag &= ~NODE_TEST;
- if (node->type == CMP_NODE_R_LAYERS) {
+ if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
if (node->id) {
if (!MAIN_VERSION_ATLEAST(re->main, 265, 5)) {
if (rlayer_node_uses_alpha(re->scene->nodetree, node)) {
@@ -1775,11 +1897,14 @@ static void tag_scenes_for_render(Render *re)
if (node->id != (ID *)re->scene) {
if ((node->id->flag & LIB_DOIT) == 0) {
- node->flag |= NODE_TEST;
- node->id->flag |= LIB_DOIT;
+ Scene *scene = (Scene *) node->id;
+ if (render_scene_has_layers_to_render(scene)) {
+ node->flag |= NODE_TEST;
+ node->id->flag |= LIB_DOIT;
#ifdef DEPSGRAPH_WORKAROUND_HACK
- tag_dependend_objects_for_render((Scene *) node->id, renderlay);
+ tag_dependend_objects_for_render(scene, renderlay);
#endif
+ }
}
}
}
@@ -1792,7 +1917,8 @@ static void ntree_render_scenes(Render *re)
{
bNode *node;
int cfra = re->scene->r.cfra;
- int restore_scene = 0;
+ Scene *restore_scene = re->scene;
+ bool scene_changed = false;
if (re->scene->nodetree == NULL) return;
@@ -1801,23 +1927,23 @@ static void ntree_render_scenes(Render *re)
/* now foreach render-result node tagged we do a full render */
/* results are stored in a way compisitor will find it */
for (node = re->scene->nodetree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS) {
+ if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
if (node->id && node->id != (ID *)re->scene) {
if (node->flag & NODE_TEST) {
Scene *scene = (Scene *)node->id;
+ scene_changed |= scene != restore_scene;
render_scene(re, scene, cfra);
- restore_scene = (scene != re->scene);
node->flag &= ~NODE_TEST;
- nodeUpdate(re->scene->nodetree, node);
+ nodeUpdate(restore_scene->nodetree, node);
}
}
}
}
/* restore scene if we rendered another last */
- if (restore_scene)
+ if (scene_changed)
BKE_scene_set_background(re->main, re->scene);
}
@@ -1835,9 +1961,13 @@ static void add_freestyle(Render *re, int render)
{
SceneRenderLayer *srl, *actsrl;
LinkData *link;
+ Render *r;
+ const bool do_link = (re->r.mode & R_MBLUR) == 0 || re->i.curblur == re->r.mblur_samples;
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
@@ -1845,19 +1975,21 @@ static void add_freestyle(Render *re, int render)
* and that function requires proper window manager
* to present (sergey)
*/
- re->freestyle_bmain.wm = re->main->wm;
+ re->freestyle_bmain->wm = re->main->wm;
FRS_init_stroke_rendering(re);
- for (srl= (SceneRenderLayer *)re->r.layers.first; srl; srl= srl->next) {
-
- link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render");
- BLI_addtail(&re->freestyle_renders, link);
-
+ for (srl = (SceneRenderLayer *)re->r.layers.first; srl; srl = srl->next) {
+ if (do_link) {
+ link = (LinkData *)MEM_callocN(sizeof(LinkData), "LinkData to Freestyle render");
+ BLI_addtail(&re->freestyle_renders, link);
+ }
if ((re->r.scemode & R_SINGLE_LAYER) && srl != actsrl)
continue;
if (FRS_is_freestyle_enabled(srl)) {
- link->data = (void *)FRS_do_stroke_rendering(re, srl, render);
+ r = FRS_do_stroke_rendering(re, srl, render);
+ if (do_link)
+ link->data = (void *)r;
}
}
@@ -1886,7 +2018,7 @@ static void composite_freestyle_renders(Render *re, int sample)
/* may be NULL in case of empty render layer */
if (freestyle_render) {
- render_result_exr_file_read(freestyle_render, sample);
+ 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;
@@ -1910,10 +2042,20 @@ static void free_all_freestyle_renders(void)
if (freestyle_render) {
freestyle_scene = freestyle_render->scene;
RE_FreeRender(freestyle_render);
- BKE_scene_unlink(&re1->freestyle_bmain, freestyle_scene, NULL);
+ BKE_scene_unlink(re1->freestyle_bmain, freestyle_scene, NULL);
}
}
BLI_freelistN(&re1->freestyle_renders);
+
+ if (re1->freestyle_bmain) {
+ /* 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;
+
+ BKE_main_free(re1->freestyle_bmain);
+ re1->freestyle_bmain = NULL;
+ }
}
}
#endif
@@ -1960,7 +2102,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree)
if (re1 && (re1->r.scemode & R_FULL_SAMPLE)) {
if (sample) {
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- render_result_exr_file_read(re1, sample);
+ render_result_exr_file_read_sample(re1, sample);
#ifdef WITH_FREESTYLE
if (re1->r.mode & R_EDGE_FRS)
composite_freestyle_renders(re1, sample);
@@ -2064,12 +2206,14 @@ void RE_MergeFullSample(Render *re, Main *bmain, Scene *sce, bNodeTree *ntree)
scene->id.flag |= LIB_DOIT;
#ifdef WITH_FREESTYLE
- for (scene = re->freestyle_bmain.scene.first; scene; scene = scene->id.next)
- scene->id.flag &= ~LIB_DOIT;
+ if (re->freestyle_bmain) {
+ for (scene = re->freestyle_bmain->scene.first; scene; scene = scene->id.next)
+ scene->id.flag &= ~LIB_DOIT;
+ }
#endif
for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == CMP_NODE_R_LAYERS) {
+ if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
Scene *nodescene = (Scene *)node->id;
if (nodescene == NULL) nodescene = sce;
@@ -2364,7 +2508,7 @@ static bool check_valid_compositing_camera(Scene *scene, Object *camera_override
bNode *node = scene->nodetree->nodes.first;
while (node) {
- if (node->type == CMP_NODE_R_LAYERS) {
+ if (node->type == CMP_NODE_R_LAYERS && (node->flag & NODE_MUTED) == 0) {
Scene *sce = node->id ? (Scene *)node->id : scene;
if (!sce->camera && !BKE_scene_camera_find(sce)) {
@@ -2446,7 +2590,6 @@ static int check_composite_output(Scene *scene)
bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *reports)
{
- SceneRenderLayer *srl;
int scemode = check_mode_full_sample(&scene->r);
if (scene->r.mode & R_BORDER) {
@@ -2513,18 +2656,24 @@ bool RE_is_rendering_allowed(Scene *scene, Object *camera_override, ReportList *
}
#ifdef WITH_FREESTYLE
- if ((scene->r.mode & R_EDGE_FRS) && (!BKE_scene_use_new_shading_nodes(scene))) {
+ if (scene->r.mode & R_EDGE_FRS) {
BKE_report(reports, RPT_ERROR, "Panoramic camera not supported in Freestyle");
return 0;
}
#endif
}
-
+
+#ifdef WITH_FREESTYLE
+ if (scene->r.mode & R_EDGE_FRS) {
+ if (scene->r.mode & R_FIELDS) {
+ BKE_report(reports, RPT_ERROR, "Fields not supported in Freestyle");
+ return false;
+ }
+ }
+#endif
+
/* layer flag tests */
- for (srl = scene->r.layers.first; srl; srl = srl->next)
- if (!(srl->layflag & SCE_LAY_DISABLE))
- break;
- if (srl == NULL) {
+ if (!render_scene_has_layers_to_render(scene)) {
BKE_report(reports, RPT_ERROR, "All render layers are disabled");
return 0;
}
@@ -2565,7 +2714,8 @@ static void update_physics_cache(Render *re, Scene *scene, int UNUSED(anim_init)
BKE_ptcache_bake(&baker);
}
/* evaluating scene options for general Blender render */
-static int render_initialize_from_main(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override, unsigned int lay_override, int anim, int anim_init)
+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)
{
int winx, winy;
rcti disprect;
@@ -2574,16 +2724,16 @@ static int render_initialize_from_main(Render *re, Main *bmain, Scene *scene, Sc
* r.border is the clipping rect */
/* calculate actual render result and display size */
- winx = (scene->r.size * scene->r.xsch) / 100;
- winy = (scene->r.size * scene->r.ysch) / 100;
+ winx = (rd->size * rd->xsch) / 100;
+ winy = (rd->size * rd->ysch) / 100;
/* we always render smaller part, inserting it in larger image is compositor bizz, it uses disprect for it */
if (scene->r.mode & R_BORDER) {
- disprect.xmin = scene->r.border.xmin * winx;
- disprect.xmax = scene->r.border.xmax * winx;
+ disprect.xmin = rd->border.xmin * winx;
+ disprect.xmax = rd->border.xmax * winx;
- disprect.ymin = scene->r.border.ymin * winy;
- disprect.ymax = scene->r.border.ymax * winy;
+ disprect.ymin = rd->border.ymin * winy;
+ disprect.ymax = rd->border.ymax * winy;
}
else {
disprect.xmin = disprect.ymin = 0;
@@ -2596,6 +2746,7 @@ static int render_initialize_from_main(Render *re, Main *bmain, Scene *scene, Sc
re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
re->camera_override = camera_override;
re->lay = lay_override ? lay_override : scene->lay;
+ re->layer_override = lay_override;
re->i.localview = (re->lay & 0xFF000000) != 0;
/* not too nice, but it survives anim-border render */
@@ -2648,12 +2799,14 @@ void RE_SetReports(Render *re, ReportList *reports)
void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *srl, Object *camera_override,
unsigned int lay_override, int frame, const bool write_still)
{
+ BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_INIT);
+
/* ugly global still... is to prevent preview events and signal subsurfs etc to make full resol */
G.is_rendering = true;
scene->r.cfra = frame;
- if (render_initialize_from_main(re, bmain, scene, srl, camera_override, lay_override, 0, 0)) {
+ if (render_initialize_from_main(re, &scene->r, bmain, scene, srl, camera_override, lay_override, 0, 0)) {
MEM_reset_peak_memory();
BLI_callback_exec(re->main, (ID *)scene, BLI_CB_EVT_RENDER_PRE);
@@ -2688,12 +2841,22 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
void RE_RenderFreestyleStrokes(Render *re, Main *bmain, Scene *scene, int render)
{
re->result_ok= 0;
- if (render_initialize_from_main(re, bmain, scene, NULL, NULL, scene->lay, 0, 0)) {
+ if (render_initialize_from_main(re, &scene->r, bmain, scene, NULL, NULL, scene->lay, 0, 0)) {
if (render)
do_render_fields_blur_3d(re);
}
re->result_ok = 1;
}
+
+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);
+ 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)
@@ -2807,12 +2970,15 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
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);
int cfrao = scene->r.cfra;
int nfra, totrendered = 0, totskipped = 0;
+ 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, bmain, scene, NULL, camera_override, lay_override, 0, 1))
+ if (!render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 0, 1))
return;
/* ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol */
@@ -2874,7 +3040,7 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
char name[FILE_MAX];
/* only border now, todo: camera lens. (ton) */
- render_initialize_from_main(re, bmain, scene, NULL, camera_override, lay_override, 1, 0);
+ render_initialize_from_main(re, &rd, bmain, scene, NULL, camera_override, lay_override, 1, 0);
if (nfra != scene->r.cfra) {
/*
@@ -3029,7 +3195,7 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode)
re->scene_color_manage = BKE_scene_check_color_management_enabled(scene);
BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE);
- success = render_result_exr_file_read(re, 0);
+ success = render_result_exr_file_cache_read(re);
BLI_rw_mutex_unlock(&re->resultmutex);
return success;
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
index 09a6a6374be..014df802a78 100644
--- a/source/blender/render/intern/source/pixelshading.c
+++ b/source/blender/render/intern/source/pixelshading.c
@@ -160,7 +160,7 @@ static void render_lighting_halo(HaloRen *har, float col_r[3])
x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
/* 1.0/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
- inpr= 1.0/(sqrt(1.0f+x*x));
+ inpr = 1.0 / (sqrtf(1.0f + x * x));
}
else inpr= 0.0;
}
@@ -206,7 +206,7 @@ static void render_lighting_halo(HaloRen *har, float col_r[3])
/* dot product and reflectivity*/
- inp = 1.0 - fabs(dot_v3v3(vn, lv));
+ inp = 1.0 - fabsf(dot_v3v3(vn, lv));
/* inp= cos(0.5*M_PI-acos(inp)); */
@@ -329,7 +329,7 @@ int shadeHaloFloat(HaloRen *har, float col[4], int zz,
}
}
- radist= sqrt(dist);
+ radist = sqrtf(dist);
/* watch it: not used nicely: flarec is set at zero in pixstruct */
if (flarec) har->pixels+= (int)(har->rad-radist);
@@ -366,17 +366,15 @@ int shadeHaloFloat(HaloRen *har, float col[4], int zz,
else dist= dist/har->radsq;
if (har->type & HA_FLARECIRC) {
-
- dist= 0.5+fabs(dist-0.5f);
-
+ dist = 0.5 + fabsf(dist - 0.5f);
}
if (har->hard>=30) {
- dist= sqrt(dist);
+ dist = sqrtf(dist);
if (har->hard>=40) {
- dist= sinf(dist*(float)M_PI_2);
+ dist = sinf(dist*(float)M_PI_2);
if (har->hard>=50) {
- dist= sqrt(dist);
+ dist = sqrtf(dist);
}
}
}
@@ -399,7 +397,7 @@ int shadeHaloFloat(HaloRen *har, float col[4], int zz,
rc= hashvectf + (ofs % 768);
- fac= fabs( (xn)*rc[0]+(yn)*rc[1]);
+ fac = fabsf((xn) * rc[0] + (yn) * rc[1]);
if (fac< 1.0f )
linef+= (1.0f-fac);
@@ -411,15 +409,15 @@ int shadeHaloFloat(HaloRen *har, float col[4], int zz,
if (har->starpoints) {
float ster, angle;
/* rotation */
- angle= atan2(yn, xn);
- angle*= (1.0f+0.25f*har->starpoints);
+ angle = atan2f(yn, xn);
+ angle *= (1.0f+0.25f*har->starpoints);
co= cosf(angle);
si= sinf(angle);
angle= (co*xn+si*yn)*(co*yn-si*xn);
- ster= fabs(angle);
+ ster = fabsf(angle);
if (ster>1.0f) {
ster= (har->rad)/(ster);
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index 799f7fa2f2e..ac2e85a33b3 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -384,7 +384,7 @@ static void accum_density(void *userdata, int index, float squared_dist)
else if (pdr->falloff_type == TEX_PD_FALLOFF_CONSTANT)
density = pdr->squared_radius;
else if (pdr->falloff_type == TEX_PD_FALLOFF_ROOT)
- density = sqrt(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);
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 7e56d93f23b..ff1f502cc1a 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -651,7 +651,7 @@ static float shade_by_transmission(Isect *is, ShadeInput *shi, ShadeResult *shr)
const float dx= shi->co[0] - is->start[0];
const float dy= shi->co[1] - is->start[1];
const float dz= shi->co[2] - is->start[2];
- d= sqrt(dx*dx+dy*dy+dz*dz);
+ d = sqrtf(dx * dx + dy * dy + dz * dz);
if (d > shi->mat->tx_limit)
d= shi->mat->tx_limit;
@@ -1117,7 +1117,7 @@ static void QMC_samplePhong(float vec[3], QMCSampler *qsa, int thread, int num,
phi = s[0]*2*M_PI;
pz = pow(s[1], blur);
- sqr = sqrt(1.0f-pz*pz);
+ sqr = sqrtf(1.0f - pz * pz);
vec[0] = (float)(cosf(phi)*sqr);
vec[1] = (float)(sinf(phi)*sqr);
@@ -1281,7 +1281,7 @@ static float get_avg_speed(ShadeInput *shi)
post_x = (shi->winspeed[2] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[2];
post_y = (shi->winspeed[3] == PASS_VECTOR_MAX)?0.0f:shi->winspeed[3];
- speedavg = (sqrt(pre_x*pre_x + pre_y*pre_y) + sqrt(post_x*post_x + post_y*post_y)) / 2.0;
+ speedavg = (sqrtf(pre_x * pre_x + pre_y * pre_y) + sqrtf(post_x * post_x + post_y * post_y)) / 2.0;
return speedavg;
}
@@ -1786,10 +1786,10 @@ static float *sphere_sampler(int type, int resol, int thread, int xs, int ys, in
sphere= threadsafe_table_sphere(0, thread, xs, ys, tot);
/* random rotation */
- ang= BLI_thread_frand(thread);
- sinfi= sin(ang); cosfi= cos(ang);
- ang= BLI_thread_frand(thread);
- sint= sin(ang); cost= cos(ang);
+ ang = BLI_thread_frand(thread);
+ sinfi = sinf(ang); cosfi = cosf(ang);
+ ang = BLI_thread_frand(thread);
+ sint = sinf(ang); cost = cosf(ang);
vec= R.wrld.aosphere;
vec1= sphere;
@@ -2371,9 +2371,9 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, const float lampco[
mul_m3_v3(lar->mat, vec);
/* set start and vec */
- isec->dir[0] = vec[0]+lampco[0]-isec->start[0];
- isec->dir[1] = vec[1]+lampco[1]-isec->start[1];
- isec->dir[2] = vec[2]+lampco[2]-isec->start[2];
+ isec->dir[0] = vec[0]+lampco[0]-shi->co[0];
+ isec->dir[1] = vec[1]+lampco[1]-shi->co[1];
+ isec->dir[2] = vec[2]+lampco[2]-shi->co[2];
RE_instance_rotate_ray_dir(shi->obi, isec);
@@ -2406,9 +2406,9 @@ static void ray_shadow_jitter(ShadeInput *shi, LampRen *lar, const float lampco[
else {
/* sqrt makes nice umbra effect */
if (lar->ray_samp_type & LA_SAMP_UMBRA)
- shadfac[3]= sqrt(1.0f-fac/div);
+ shadfac[3] = sqrtf(1.0f - fac / div);
else
- shadfac[3]= 1.0f-fac/div;
+ shadfac[3] = 1.0f - fac / div;
}
}
/* extern call from shade_lamp_loop */
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index 40de1080634..24797521435 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -37,17 +37,20 @@
#include "BLI_utildefines.h"
#include "BLI_listbase.h"
+#include "BLI_md5.h"
#include "BLI_path_util.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_system.h"
-#include BLI_SYSTEM_PID_H
#include "BLI_threads.h"
#include "BKE_image.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
+#ifdef WITH_CYCLES_DEBUG
+# include "BKE_scene.h"
+#endif
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@@ -402,7 +405,7 @@ static int passtype_from_name(const char *str)
/********************************** New **************************************/
-static void 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 *typestr = get_pass_name(passtype, 0);
RenderPass *rpass = MEM_callocN(sizeof(RenderPass), typestr);
@@ -438,8 +441,34 @@ static void render_layer_add_pass(RenderResult *rr, RenderLayer *rl, int channel
rect[x] = 10e10;
}
}
+ return rpass;
}
+#ifdef WITH_CYCLES_DEBUG
+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";
+ }
+ return "Unknown";
+}
+
+static RenderPass *render_layer_add_debug_pass(RenderResult *rr,
+ RenderLayer *rl,
+ int channels,
+ int pass_type,
+ int debug_type)
+{
+ RenderPass *rpass = render_layer_add_pass(rr, rl, channels, pass_type);
+ rpass->debug_type = debug_type;
+ BLI_strncpy(rpass->name,
+ debug_pass_type_name_get(debug_type),
+ sizeof(rpass->name));
+ return rpass;
+}
+#endif
+
/* called by main render as well for parts */
/* will read info from Render *re to define layers */
/* called in threads */
@@ -578,6 +607,13 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
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);
+
+#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);
+ }
+#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])) {
@@ -1013,7 +1049,7 @@ void render_result_exr_file_end(Render *re)
render_result_free_list(&re->fullresult, re->result);
re->result = NULL;
- render_result_exr_file_read(re, 0);
+ render_result_exr_file_read_sample(re, 0);
}
/* save part into exr file */
@@ -1030,35 +1066,32 @@ void render_result_exr_file_path(Scene *scene, const char *layname, int sample,
BLI_split_file_part(G.main->name, fi, sizeof(fi));
if (sample == 0) {
- BLI_snprintf(name, sizeof(name), "%s_%s_%s_%d.exr", fi, scene->id.name + 2, layname, abs(getpid()));
+ BLI_snprintf(name, sizeof(name), "%s_%s_%s.exr", fi, scene->id.name + 2, layname);
}
else {
- BLI_snprintf(name, sizeof(name), "%s_%s_%s%d_%d.exr", fi, scene->id.name + 2, layname, sample,
- abs(getpid()));
+ BLI_snprintf(name, sizeof(name), "%s_%s_%s%d.exr", fi, scene->id.name + 2, layname, sample);
}
- BLI_make_file_string("/", filepath, BLI_temporary_dir(), name);
+ BLI_make_file_string("/", filepath, BLI_temp_dir_session(), name);
}
-/* only for temp buffer files, makes exact copy of render result */
-int render_result_exr_file_read(Render *re, int sample)
+/* only for temp buffer, makes exact copy of render result */
+int render_result_exr_file_read_sample(Render *re, int sample)
{
RenderLayer *rl;
- char str[FILE_MAX];
+ char str[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100] = "";
bool success = true;
RE_FreeRenderResult(re->result);
re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
for (rl = re->result->layers.first; rl; rl = rl->next) {
-
render_result_exr_file_path(re->scene, rl->name, sample, str);
printf("read exr tmp file: %s\n", str);
if (!render_result_exr_file_read_path(re->result, rl, str)) {
printf("cannot read: %s\n", str);
success = false;
-
}
}
@@ -1117,6 +1150,65 @@ int render_result_exr_file_read_path(RenderResult *rr, RenderLayer *rl_single, c
return 1;
}
+static void render_result_exr_file_cache_path(Scene *sce, const char *root, char *r_path)
+{
+ char filename_full[FILE_MAX + MAX_ID_NAME + 100], filename[FILE_MAXFILE], dirname[FILE_MAXDIR];
+ char path_digest[16] = {0};
+ char path_hexdigest[33];
+
+ /* If root is relative, use either current .blend file dir, or temp one if not saved. */
+ if (G.main->name[0]) {
+ BLI_split_dirfile(G.main->name, dirname, filename, sizeof(dirname), sizeof(filename));
+ BLI_replace_extension(filename, sizeof(filename), ""); /* strip '.blend' */
+ md5_buffer(G.main->name, strlen(G.main->name), path_digest);
+ }
+ else {
+ BLI_strncpy(dirname, BLI_temp_dir_base(), sizeof(dirname));
+ BLI_strncpy(filename, "UNSAVED", sizeof(filename));
+ }
+ md5_to_hexdigest(path_digest, path_hexdigest);
+
+ /* Default to *non-volatile* tmp dir. */
+ if (*root == '\0') {
+ root = BLI_temp_dir_base();
+ }
+
+ BLI_snprintf(filename_full, sizeof(filename_full), "cached_RR_%s_%s_%s.exr",
+ filename, sce->id.name + 2, path_hexdigest);
+ BLI_make_file_string(dirname, r_path, root, filename_full);
+}
+
+void render_result_exr_file_cache_write(Render *re)
+{
+ RenderResult *rr = re->result;
+ char str[FILE_MAXFILE + FILE_MAXFILE + MAX_ID_NAME + 100];
+ char *root = U.render_cachedir;
+
+ 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);
+}
+
+/* For cache, makes exact copy of render result */
+bool render_result_exr_file_cache_read(Render *re)
+{
+ char str[FILE_MAXFILE + MAX_ID_NAME + MAX_ID_NAME + 100] = "";
+ char *root = U.render_cachedir;
+
+ RE_FreeRenderResult(re->result);
+ re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS);
+
+ /* First try cache. */
+ render_result_exr_file_cache_path(re->scene, root, str);
+
+ printf("read exr cache file: %s\n", str);
+ if (!render_result_exr_file_read_path(re->result, NULL, str)) {
+ printf("cannot read: %s\n", str);
+ return false;
+ }
+ return true;
+}
+
/*************************** Combined Pixel Rect *****************************/
ImBuf *render_result_rect_to_ibuf(RenderResult *rr, RenderData *rd)
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index 597f93a2659..1a8ab60d4d0 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -85,8 +85,19 @@
extern struct Render R;
/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
+static RNG_THREAD_ARRAY *random_tex_array;
+void RE_init_texture_rng(void)
+{
+ random_tex_array = BLI_rng_threaded_new();
+}
+
+void RE_exit_texture_rng(void)
+{
+ BLI_rng_threaded_free(random_tex_array);
+}
+
static void init_render_texture(Render *re, Tex *tex)
{
@@ -212,10 +223,10 @@ static int blend(Tex *tex, const float texvec[3], TexResult *texres)
texres->tin= (2.0f+x+y)/4.0f;
}
else if (tex->stype==TEX_RAD) { /* radial */
- texres->tin= (atan2(y, x) / (2*M_PI) + 0.5);
+ texres->tin = (atan2f(y, x) / (2 * M_PI) + 0.5f);
}
else { /* sphere TEX_SPHERE */
- texres->tin= 1.0-sqrt(x*x+ y*y+texvec[2]*texvec[2]);
+ texres->tin = 1.0 - sqrtf(x * x + y * y + texvec[2] * texvec[2]);
if (texres->tin<0.0f) texres->tin= 0.0f;
if (tex->stype==TEX_HALO) texres->tin*= texres->tin; /* halo */
}
@@ -266,8 +277,8 @@ static int clouds(Tex *tex, const float texvec[3], TexResult *texres)
/* creates a sine wave */
static float tex_sin(float a)
{
- a = 0.5 + 0.5*sin(a);
-
+ a = 0.5 + 0.5 * sinf(a);
+
return a;
}
@@ -366,10 +377,10 @@ static float marble_int(Tex *tex, float x, float y, float z)
if (mt>=TEX_SOFT) { /* TEX_SOFT always true */
mi = waveform[wf](mi);
if (mt==TEX_SHARP) {
- mi = sqrt(mi);
+ mi = sqrtf(mi);
}
else if (mt==TEX_SHARPER) {
- mi = sqrt(sqrt(mi));
+ mi = sqrtf(sqrtf(mi));
}
}
@@ -408,41 +419,41 @@ static int magic(Tex *tex, const float texvec[3], TexResult *texres)
n= tex->noisedepth;
turb= tex->turbul/5.0f;
- x= sin( ( texvec[0]+texvec[1]+texvec[2])*5.0f );
- y= cos( (-texvec[0]+texvec[1]-texvec[2])*5.0f );
- z= -cos( (-texvec[0]-texvec[1]+texvec[2])*5.0f );
+ x = sinf(( texvec[0] + texvec[1] + texvec[2]) * 5.0f);
+ y = cosf((-texvec[0] + texvec[1] - texvec[2]) * 5.0f);
+ z = -cosf((-texvec[0] - texvec[1] + texvec[2]) * 5.0f);
if (n>0) {
x*= turb;
y*= turb;
z*= turb;
- y= -cos(x-y+z);
+ y= -cosf(x-y+z);
y*= turb;
if (n>1) {
- x= cos(x-y-z);
+ x= cosf(x-y-z);
x*= turb;
if (n>2) {
- z= sin(-x-y-z);
+ z= sinf(-x-y-z);
z*= turb;
if (n>3) {
- x= -cos(-x+y-z);
+ x= -cosf(-x+y-z);
x*= turb;
if (n>4) {
- y= -sin(-x+y+z);
+ y= -sinf(-x+y+z);
y*= turb;
if (n>5) {
- y= -cos(-x+y+z);
+ y= -cosf(-x+y+z);
y*= turb;
if (n>6) {
- x= cos(x+y+z);
+ x= cosf(x+y+z);
x*= turb;
if (n>7) {
- z= sin(x+y-z);
+ z= sinf(x+y-z);
z*= turb;
if (n>8) {
- x= -cos(-x-y+z);
+ x= -cosf(-x-y+z);
x*= turb;
if (n>9) {
- y= -sin(x-y+z);
+ y= -sinf(x-y+z);
y*= turb;
}
}
@@ -709,19 +720,22 @@ static float voronoiTex(Tex *tex, const float texvec[3], TexResult *texres)
/* ------------------------------------------------------------------------- */
-static int texnoise(Tex *tex, TexResult *texres)
+static int texnoise(Tex *tex, TexResult *texres, int thread)
{
float div=3.0;
- int val, ran, loop;
+ int val, ran, loop, shift = 29;
- ran= BLI_rand();
- val= (ran & 3);
+ ran= BLI_rng_thread_rand(random_tex_array, thread);
loop= tex->noisedepth;
+
+ /* start from top bits since they have more variance */
+ val= ((ran >> shift) & 3);
+
while (loop--) {
- ran= (ran>>2);
- val*= (ran & 3);
- div*= 3.0f;
+ shift -= 2;
+ val *= ((ran >> shift) & 3);
+ div *= 3.0f;
}
texres->tin= ((float)val)/div;
@@ -1127,12 +1141,14 @@ static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int o
retval = stucci(tex, texvec, texres);
break;
case TEX_NOISE:
- retval = texnoise(tex, texres);
+ retval = texnoise(tex, texres, thread);
break;
case TEX_IMAGE:
if (osatex) retval = imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres, pool);
else retval = imagewrap(tex, tex->ima, NULL, texvec, texres, pool);
- BKE_image_tag_time(tex->ima); /* tag image as having being used */
+ if (tex->ima) {
+ BKE_image_tag_time(tex->ima);
+ }
break;
case TEX_ENVMAP:
retval = envmaptex(tex, texvec, dxt, dyt, osatex, texres, pool);
@@ -2346,8 +2362,8 @@ void do_material_tex(ShadeInput *shi, Render *re)
copy_v3_v3(texres.nor, &texres.tr);
}
else {
- float co_nor= 0.5*cos(texres.tin-0.5f);
- float si= 0.5*sin(texres.tin-0.5f);
+ float co_nor= 0.5f * cosf(texres.tin - 0.5f);
+ float si = 0.5f * sinf(texres.tin - 0.5f);
float f1, f2;
f1= shi->vn[0];
@@ -3394,8 +3410,11 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
col[0]= texres.tr*la->energy;
col[1]= texres.tg*la->energy;
col[2]= texres.tb*la->energy;
-
- texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->colfac, mtex->blendtype);
+
+ if (effect & LA_SHAD_TEX)
+ texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->shadowfac, mtex->blendtype);
+ else
+ texture_rgb_blend(col_r, col, col_r, texres.tin, mtex->colfac, mtex->blendtype);
}
}
}
@@ -3562,7 +3581,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene)
/* depending of material type, strip non-compatible mapping modes */
if (mat->material_type == MA_TYPE_SURFACE) {
- if (!ELEM4(mtex->texco, TEXCO_ORCO, TEXCO_OBJECT, TEXCO_GLOB, TEXCO_UV)) {
+ if (!ELEM(mtex->texco, TEXCO_ORCO, TEXCO_OBJECT, TEXCO_GLOB, TEXCO_UV)) {
/* ignore this texture */
mtex->texco = 0;
continue;
@@ -3571,7 +3590,7 @@ Material *RE_init_sample_material(Material *orig_mat, Scene *scene)
mtex->mapto = (mtex->mapto & MAP_COL) | (mtex->mapto & MAP_ALPHA);
}
else if (mat->material_type == MA_TYPE_VOLUME) {
- if (!ELEM3(mtex->texco, TEXCO_OBJECT, TEXCO_ORCO, TEXCO_GLOB)) {
+ if (!ELEM(mtex->texco, TEXCO_OBJECT, TEXCO_ORCO, TEXCO_GLOB)) {
/* ignore */
mtex->texco = 0;
continue;
diff --git a/source/blender/render/intern/source/rendercore.c b/source/blender/render/intern/source/rendercore.c
index 27bc449dce3..a67140c6334 100644
--- a/source/blender/render/intern/source/rendercore.c
+++ b/source/blender/render/intern/source/rendercore.c
@@ -1906,9 +1906,9 @@ static void renderflare(RenderResult *rr, float *rectf, HaloRen *har)
fla.hard= 20.0f + fabsf(70.0f*rc[7]);
fla.tex= 0;
- type= (int)(fabs(3.9f*rc[6]));
+ type= (int)(fabsf(3.9f*rc[6]));
- fla.rad= ma->subsize*sqrtf(fabs(2.0f*har->rad*rc[4]));
+ fla.rad = ma->subsize * sqrtf(fabsf(2.0f * har->rad * rc[4]));
if (type==3) {
fla.rad*= 3.0f;
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index 6a3787289d8..46c504aaabf 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -992,10 +992,10 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0f;
- else zn= atan2(yn, xn);
+ else zn = atan2f(yn, xn);
- har->sin= sin(zn);
- har->cos= cos(zn);
+ har->sin = sinf(zn);
+ har->cos = cosf(zn);
zn= len_v3v3(vec1, vec);
har->hasize= vectsize*zn + (1.0f-vectsize)*hasize;
@@ -1112,10 +1112,10 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
xn= har->xs - 0.5f*re->winx*(hoco1[0]/hoco1[3]);
yn= har->ys - 0.5f*re->winy*(hoco1[1]/hoco1[3]);
if (xn==0.0f || (xn==0.0f && yn==0.0f)) zn= 0.0;
- else zn= atan2(yn, xn);
+ else zn = atan2f(yn, xn);
- har->sin= sin(zn);
- har->cos= cos(zn);
+ har->sin = sinf(zn);
+ har->cos = cosf(zn);
zn= len_v3v3(vec1, vec)*0.5f;
har->hasize= vectsize*zn + (1.0f-vectsize)*hasize;
@@ -1284,8 +1284,8 @@ void project_renderdata(Render *re,
if (do_pano) {
float panophi= xoffs;
- re->panosi= sin(panophi);
- re->panoco= cos(panophi);
+ re->panosi = sinf(panophi);
+ re->panoco = cosf(panophi);
}
for (obr=re->objecttable.first; obr; obr=obr->next) {
diff --git a/source/blender/render/intern/source/shadbuf.c b/source/blender/render/intern/source/shadbuf.c
index 9d337e542a1..9d83ff1d7e8 100644
--- a/source/blender/render/intern/source/shadbuf.c
+++ b/source/blender/render/intern/source/shadbuf.c
@@ -536,7 +536,7 @@ static void compress_shadowbuf(ShadBuf *shb, int *rectz, int square)
if (x< a) minx= x+15-a;
else minx= x-a;
- dist= sqrt( (float)(minx*minx+miny*miny) );
+ dist = sqrtf((float)(minx * minx + miny * miny));
if (square==0 && dist>(float)(a+12)) { /* 12, tested with a onlyshadow lamp */
a= 256; verg= 0; /* 0x80000000; */ /* 0x7FFFFFFF; */
@@ -784,7 +784,7 @@ void makeshadowbuf(Render *re, LampRen *lar)
perspective_m4(shb->winmat, -wsize, wsize, -wsize, wsize, shb->d, shb->clipend);
mul_m4_m4m4(shb->persmat, shb->winmat, shb->viewmat);
- if (ELEM3(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) {
+ if (ELEM(lar->buftype, LA_SHADBUF_REGULAR, LA_SHADBUF_HALFWAY, LA_SHADBUF_DEEP)) {
shb->totbuf= lar->buffers;
/* jitter, weights - not threadsafe! */
@@ -1685,7 +1685,7 @@ static int point_behind_strand(const float p[3], BSPFace *face)
if (face->len==0.0f) {
rc[0]= p[0]-face->vec1[0];
rc[1]= p[1]-face->vec1[1];
- dist= (float)(sqrt(rc[0]*rc[0]+ rc[1]*rc[1]));
+ dist = len_v2(rc);
if (dist < face->radline)
return 1;
@@ -1699,10 +1699,10 @@ static int point_behind_strand(const float p[3], BSPFace *face)
pt[0]= lambda*face->rc[0]+face->vec1[0];
pt[1]= lambda*face->rc[1]+face->vec1[1];
-
+
rc[0]= pt[0]-p[0];
rc[1]= pt[1]-p[1];
- dist= sqrtf(rc[0]*rc[0]+ rc[1]*rc[1]);
+ dist = len_v2(rc);
if (dist < face->radline) {
float zval= face->vec1[2] + lambda*face->rc[2];
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index cc781c863a0..f909c585561 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -144,7 +144,7 @@ float mistfactor(float zcor, float const co[3])
/* pass */
}
else {
- fac = sqrt(fac);
+ fac = sqrtf(fac);
}
}
else {
@@ -338,9 +338,9 @@ static void spothalo(struct LampRen *lar, ShadeInput *shi, float *intens)
/* now we have 2 points, make three lengths with it */
- a= sqrt(p1[0]*p1[0]+p1[1]*p1[1]+p1[2]*p1[2]);
- b= sqrt(p2[0]*p2[0]+p2[1]*p2[1]+p2[2]*p2[2]);
- c= len_v3v3(p1, p2);
+ a = len_v3(p1);
+ b = len_v3(p2);
+ c = len_v3v3(p1, p2);
a/= ladist;
a= sqrt(a);
@@ -640,7 +640,7 @@ static float Blinn_Spec(const float n[3], const float l[3], const float v[3], fl
/* conversion from 'hardness' (1-255) to 'spec_power' (50 maps at 0.1) */
if (spec_power<100.0f)
- spec_power= sqrt(1.0f/spec_power);
+ spec_power = sqrtf(1.0f / spec_power);
else spec_power= 10.0f/spec_power;
h[0]= v[0]+l[0];
@@ -731,7 +731,7 @@ static float WardIso_Spec(const float n[3], const float l[3], const float v[3],
if (tangent) nl = sasqrt(1.0f - nl*nl);
if (nl<=0.0f) nl = 0.001f;
- angle = tan(saacos(nh));
+ angle = tanf(saacos(nh));
alpha = MAX2(rms, 0.001f);
i= nl * (1.0f/(4.0f*(float)M_PI*alpha*alpha)) * (expf( -(angle*angle)/(alpha*alpha))/(sqrtf(nv*nl)));
@@ -746,7 +746,7 @@ static float Toon_Diff(const float n[3], const float l[3], const float UNUSED(v[
rslt = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
- ang = saacos( (double)(rslt) );
+ ang = saacos(rslt);
if ( ang < size ) rslt = 1.0f;
else if ( ang >= (size + smooth) || smooth == 0.0f ) rslt = 0.0f;
@@ -1257,7 +1257,7 @@ float lamp_get_visibility(LampRen *lar, const float co[3], float lv[3], float *d
x = max_ff(fabsf(lvrot[0]/lvrot[2]), fabsf(lvrot[1]/lvrot[2]));
/* 1.0f/(sqrt(1+x*x)) is equivalent to cos(atan(x)) */
- inpr= 1.0f/(sqrt(1.0f+x*x));
+ inpr = 1.0f / (sqrtf(1.0f + x * x));
}
else inpr= 0.0f;
}
@@ -1466,9 +1466,11 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
shr->shad[1] -= shadfac[3]*shi->g*(1.0f-lashdw[1]);
shr->shad[2] -= shadfac[3]*shi->b*(1.0f-lashdw[2]);
- shr->spec[0] -= shadfac[3]*shi->specr*(1.0f-lashdw[0]);
- shr->spec[1] -= shadfac[3]*shi->specg*(1.0f-lashdw[1]);
- shr->spec[2] -= shadfac[3]*shi->specb*(1.0f-lashdw[2]);
+ if (!(lar->mode & LA_NO_SPEC)) {
+ shr->spec[0] -= shadfac[3]*shi->specr*(1.0f-lashdw[0]);
+ shr->spec[1] -= shadfac[3]*shi->specg*(1.0f-lashdw[1]);
+ shr->spec[2] -= shadfac[3]*shi->specb*(1.0f-lashdw[2]);
+ }
return;
}
@@ -1492,11 +1494,14 @@ static void shade_one_light(LampRen *lar, ShadeInput *shi, ShadeResult *shr, int
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]);
}
if (i_noshad>0.0f) {
- if (passflag & (SCE_PASS_DIFFUSE|SCE_PASS_SHADOW)) {
+ 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]);
}
- else
+ else {
copy_v3_v3(shr->diff, shr->shad);
+ }
}
}
@@ -1646,7 +1651,8 @@ static void shade_lamp_loop_only_shadow(ShadeInput *shi, ShadeResult *shr)
else { /* shadowonly_flag == MA_SO_SHADED */
/* Use shaded value */
accum = 1.0f - shaded;
- }}
+ }
+ }
shr->alpha= (shi->alpha)*(accum);
if (shr->alpha<0.0f) shr->alpha=0.0f;
@@ -1704,9 +1710,19 @@ static void wrld_exposure_correct(float diff[3])
void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
{
+ /* Passes which might need to know material color.
+ *
+ * It seems to be faster to just calculate material color
+ * even if the pass doesn't really need it than trying to
+ * figure out whether color is really needed or not.
+ */
+ const int color_passes =
+ SCE_PASS_COMBINED | SCE_PASS_RGBA | SCE_PASS_DIFFUSE | SCE_PASS_SPEC |
+ SCE_PASS_REFLECT | SCE_PASS_NORMAL | SCE_PASS_REFRACT | SCE_PASS_EMIT | SCE_PASS_SHADOW;
+
Material *ma= shi->mat;
int passflag= shi->passflag;
-
+
memset(shr, 0, sizeof(ShadeResult));
if (!(shi->mode & MA_TRANSP)) shi->alpha = 1.0f;
@@ -1721,7 +1737,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
shi->refcol[0]= shi->refcol[1]= shi->refcol[2]= shi->refcol[3]= 0.0f;
/* material color itself */
- if (passflag & (SCE_PASS_COMBINED|SCE_PASS_RGBA)) {
+ if (passflag & color_passes) {
if (ma->mode & (MA_FACETEXTURE)) {
shi->r= shi->vcol[0];
shi->g= shi->vcol[1];
@@ -1877,7 +1893,7 @@ void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)
}
if (shi->combinedflag & SCE_PASS_SHADOW)
- copy_v3_v3(shr->diffshad, shr->shad); /* note, no ';' ! */
+ copy_v3_v3(shr->diffshad, shr->shad);
else
copy_v3_v3(shr->diffshad, shr->diff);
diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c
index 52d3815c4ad..7e9003aaee7 100644
--- a/source/blender/render/intern/source/sss.c
+++ b/source/blender/render/intern/source/sss.c
@@ -165,7 +165,7 @@ static float f_Rd(float alpha_, float A, float ro)
{
float sq;
- sq= sqrt(3.0f*(1.0f - alpha_));
+ sq = sqrtf(3.0f * (1.0f - alpha_));
return (alpha_/2.0f)*(1.0f + expf((-4.0f/3.0f)*A*sq))*expf(-sq) - ro;
}
@@ -212,8 +212,8 @@ static float Rd_rsquare(ScatterSettings *ss, float rr)
{
float sr, sv, Rdr, Rdv;
- sr= sqrt(rr + ss->zr*ss->zr);
- sv= sqrt(rr + ss->zv*ss->zv);
+ sr = sqrtf(rr + ss->zr * ss->zr);
+ sv = sqrtf(rr + ss->zv * ss->zv);
Rdr= ss->zr*(1.0f + ss->sigma*sr)*expf(-ss->sigma*sr)/(sr*sr*sr);
Rdv= ss->zv*(1.0f + ss->sigma*sv)*expf(-ss->sigma*sv)/(sv*sv*sv);
@@ -241,7 +241,7 @@ static void approximate_Rd_rgb(ScatterSettings **ss, float rr, float *rd)
/* pass */
}
else if (rr > RD_TABLE_RANGE) {
- rr= sqrt(rr);
+ rr = sqrtf(rr);
indexf= rr*(RD_TABLE_SIZE/RD_TABLE_RANGE_2);
index= (int)indexf;
idxf= (float)index;
@@ -286,7 +286,7 @@ static void build_Rd_table(ScatterSettings *ss)
r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE);
/*if (r < ss->invsigma_t_*ss->invsigma_t_)
r= ss->invsigma_t_*ss->invsigma_t_;*/
- ss->tableRd[i]= Rd(ss, sqrt(r));
+ ss->tableRd[i]= Rd(ss, sqrtf(r));
r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE);
/*if (r < ss->invsigma_t_)
diff --git a/source/blender/render/intern/source/strand.c b/source/blender/render/intern/source/strand.c
index 50343cfaa0b..485680da76f 100644
--- a/source/blender/render/intern/source/strand.c
+++ b/source/blender/render/intern/source/strand.c
@@ -145,7 +145,7 @@ void strand_eval_point(StrandSegment *sseg, StrandPoint *spoint)
w= spoint->co[2]*strandbuf->winmat[2][3] + strandbuf->winmat[3][3];
dx= strandbuf->winx*cross[0]*strandbuf->winmat[0][0]/w;
dy= strandbuf->winy*cross[1]*strandbuf->winmat[1][1]/w;
- w= sqrt(dx*dx + dy*dy);
+ w = sqrtf(dx * dx + dy * dy);
if (w > 0.0f) {
if (strandbuf->flag & R_STRAND_B_UNITS) {
diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c
index 71ef5b8f62f..1836b3f48a7 100644
--- a/source/blender/render/intern/source/sunsky.c
+++ b/source/blender/render/intern/source/sunsky.c
@@ -89,14 +89,14 @@ void ClipColor(float c[3])
* */
static float AngleBetween(float thetav, float phiv, float theta, float phi)
{
- float cospsi = sin(thetav) * sin(theta) * cos(phi - phiv) + cos(thetav) * cos(theta);
+ float cospsi = sinf(thetav) * sinf(theta) * cosf(phi - phiv) + cosf(thetav) * cosf(theta);
if (cospsi > 1.0f)
return 0;
if (cospsi < -1.0f)
return M_PI;
- return acos(cospsi);
+ return acosf(cospsi);
}
/**
@@ -112,7 +112,7 @@ static void DirectionToThetaPhi(float *toSun, float *theta, float *phi)
if (fabsf(*theta) < 1e-5f)
*phi = 0;
else
- *phi = atan2(toSun[1], toSun[0]);
+ *phi = atan2f(toSun[1], toSun[0]);
}
/**
diff --git a/source/blender/render/intern/source/texture_ocean.c b/source/blender/render/intern/source/texture_ocean.c
index bfd155eba62..55f4bf3794d 100644
--- a/source/blender/render/intern/source/texture_ocean.c
+++ b/source/blender/render/intern/source/texture_ocean.c
@@ -23,7 +23,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/blenkernel/intern/texture_ocean.c
+/** \file blender/render/intern/source/texture_ocean.c
* \ingroup bke
*/
diff --git a/source/blender/render/intern/source/volumetric.c b/source/blender/render/intern/source/volumetric.c
index fe3af5b840e..d5c4c407bf6 100644
--- a/source/blender/render/intern/source/volumetric.c
+++ b/source/blender/render/intern/source/volumetric.c
@@ -499,7 +499,7 @@ static void vol_shade_one_lamp(struct ShadeInput *shi, const float co[3], const
if (shi->mat->vol.shade_type == MA_VOL_SHADE_SHADOWED) {
mul_v3_fl(lacol, vol_get_shadow(shi, lar, co));
}
- else if (ELEM3(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
+ else if (ELEM(shi->mat->vol.shade_type, MA_VOL_SHADE_SHADED, MA_VOL_SHADE_MULTIPLE, MA_VOL_SHADE_SHADEDPLUSMULTIPLE)) {
Isect is;
if (shi->mat->vol.shadeflag & MA_VOL_RECV_EXT_SHADOW) {
diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c
index 28849ed7686..87e546ef24e 100644
--- a/source/blender/render/intern/source/zbuf.c
+++ b/source/blender/render/intern/source/zbuf.c
@@ -2951,7 +2951,7 @@ void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *
dvec2[1]= 0.0f;
}
else {
- speedsq= 1.0f - minspeed/sqrt(speedsq);
+ speedsq = 1.0f - minspeed / sqrtf(speedsq);
dvec2[0]= speedsq*dvec1[0];
dvec2[1]= speedsq*dvec1[1];
}
@@ -3027,7 +3027,7 @@ void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *
if (maxspeed) {
float speedsq= dvz[0]*dvz[0] + dvz[1]*dvz[1];
if (speedsq > maxspeedsq) {
- speedsq= (float)maxspeed/sqrt(speedsq);
+ speedsq = (float)maxspeed / sqrtf(speedsq);
dvz[0]*= speedsq;
dvz[1]*= speedsq;
}
@@ -3386,7 +3386,7 @@ static int zbuffer_abuf(Render *re, RenderPart *pa, APixstr *APixbuf, ListBase *
projectverto(vec, obwinmat, hoco);
fval= mul*(1.0f+hoco[2]/hoco[3]);
- polygon_offset= (int) fabs(zval - fval );
+ polygon_offset= (int)fabsf(zval - fval);
}
else polygon_offset= 0;
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 5f993297840..088bddc8a76 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -40,12 +40,12 @@ set(INC
../../gameengine/BlenderRoutines
../../../intern/ghost
../../../intern/guardedalloc
+ ../../../intern/glew-mx
../../../intern/memutil
)
set(INC_SYS
${ZLIB_INCLUDE_DIRS}
- ${OPENGL_INCLUDE_DIR}
${GLEW_INCLUDE_PATH}
)
@@ -78,7 +78,7 @@ set(SRC
wm_window.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
@@ -107,6 +107,8 @@ endif()
if(WITH_HEADLESS)
add_definitions(-DWITH_HEADLESS)
+elseif(WITH_X11)
+ add_definitions(-DWITH_X11)
endif()
if(WITH_PYTHON)
diff --git a/source/blender/windowmanager/SConscript b/source/blender/windowmanager/SConscript
index 00d363e1539..b93192d5067 100644
--- a/source/blender/windowmanager/SConscript
+++ b/source/blender/windowmanager/SConscript
@@ -36,7 +36,8 @@ incs = [
'#/intern/guardedalloc',
'#/intern/memutil',
'#/source/gameengine/BlenderRoutines',
- '#/extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'../blenfont',
'../blenkernel',
'../blenlib',
@@ -54,7 +55,7 @@ incs = [
]
incs = ' '.join(incs)
-defs = [ 'GLEW_STATIC' ]
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_PYTHON']:
defs.append('WITH_PYTHON')
@@ -78,4 +79,7 @@ if env['WITH_BF_COMPOSITOR']:
if env['WITH_BF_PYTHON_SECURITY']:
defs.append("WITH_PYTHON_SECURITY")
+if env['OURPLATFORM'] in ('linux', 'openbsd3', 'sunos5', 'freebsd7', 'freebsd8', 'freebsd9', 'aix4', 'aix5'):
+ defs.append("WITH_X11")
+
env.BlenderLib ( 'bf_windowmanager', sources, Split(incs), defines=defs, libtype=['core'], priority=[5] )
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 64cada9f005..e1cd334637a 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -118,7 +118,7 @@ void WM_cursor_modal_set(struct wmWindow *win, int curs);
void WM_cursor_modal_restore(struct wmWindow *win);
void WM_cursor_wait (bool val);
void WM_cursor_grab_enable(struct wmWindow *win, bool wrap, bool hide, int bounds[4]);
-void WM_cursor_grab_disable(struct wmWindow *win, int mouse_ungrab_xy[2]);
+void WM_cursor_grab_disable(struct wmWindow *win, const int mouse_ungrab_xy[2]);
void WM_cursor_time (struct wmWindow *win, int nr);
void *WM_paint_cursor_activate(struct wmWindowManager *wm,
@@ -145,19 +145,22 @@ struct wmEventHandler *WM_event_add_keymap_handler_priority(ListBase *handlers,
void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap);
+typedef int (*wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata);
+typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata);
+
struct wmEventHandler *WM_event_add_ui_handler(
const struct bContext *C, ListBase *handlers,
- int (*func)(struct bContext *C, const struct wmEvent *event, void *userdata),
- void (*remove)(struct bContext *C, void *userdata), void *userdata);
-
-void WM_event_remove_ui_handler(ListBase *handlers,
- int (*func)(struct bContext *C, const struct wmEvent *event, void *userdata),
- void (*remove)(struct bContext *C, void *userdata),
- void *userdata, const bool postpone);
-void WM_event_remove_area_handler(struct ListBase *handlers, void *area);
-void WM_event_free_ui_handler_all(struct bContext *C, ListBase *handlers,
- int (*func)(struct bContext *C, const struct wmEvent *event, void *userdata),
- void (*remove)(struct bContext *C, void *userdata));
+ wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
+ void *userdata, const bool accept_dbl_click);
+void WM_event_remove_ui_handler(
+ ListBase *handlers,
+ wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
+ void *userdata, const bool postpone);
+void WM_event_remove_area_handler(
+ struct ListBase *handlers, void *area);
+void WM_event_free_ui_handler_all(
+ struct bContext *C, ListBase *handlers,
+ wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove);
struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op);
void WM_event_remove_handlers(struct bContext *C, ListBase *handlers);
@@ -238,7 +241,8 @@ int WM_operator_call (struct bContext *C, struct wmOperator *op);
int WM_operator_call_notest(struct bContext *C, struct wmOperator *op);
int WM_operator_repeat (struct bContext *C, struct wmOperator *op);
bool WM_operator_repeat_check(const struct bContext *C, struct wmOperator *op);
-int WM_operator_name_call (struct bContext *C, const char *opstring, short context, struct PointerRNA *properties);
+int WM_operator_name_call_ptr(struct bContext *C, struct wmOperatorType *ot, short context, struct PointerRNA *properties);
+int WM_operator_name_call(struct bContext *C, const char *opstring, short context, struct PointerRNA *properties);
int WM_operator_call_py(struct bContext *C, struct wmOperatorType *ot, short context, struct PointerRNA *properties, struct ReportList *reports, const bool is_undo);
void WM_operator_properties_alloc(struct PointerRNA **ptr, struct IDProperty **properties, const char *opstring); /* used for keymap and macro items */
@@ -340,8 +344,10 @@ void WM_event_print(const struct wmEvent *event);
void WM_operator_region_active_win_set(struct bContext *C);
/* drag and drop */
-struct wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value);
+struct wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags);
void WM_event_drag_image(struct wmDrag *, struct ImBuf *, float scale, int sx, int sy);
+void WM_drag_free(struct wmDrag *drag);
+void WM_drag_free_list(struct ListBase *lb);
struct wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, int (*poll)(struct bContext *, struct wmDrag *, const struct wmEvent *event),
void (*copy)(struct wmDrag *, struct wmDropBox *));
@@ -355,6 +361,10 @@ void wmSubWindowScissorSet (struct wmWindow *win, int swinid, const struct rcti
void wmFrustum (float x1, float x2, float y1, float y2, float n, float f);
void wmOrtho (float x1, float x2, float y1, float y2, float n, float f);
void wmOrtho2 (float x1, float x2, float y1, float y2);
+ /* use for conventions (avoid hard-coded offsets all over) */
+void wmOrtho2_region_pixelspace(const struct ARegion *ar);
+void wmOrtho2_region_ui(const struct ARegion *ar);
+void wmOrtho2_pixelspace(const float x, const float y);
/* utilities */
void WM_framebuffer_index_set(int index);
@@ -445,6 +455,9 @@ void WM_event_ndof_rotate_get(const struct wmNDOFMotionData *ndof, float
float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axis[3]);
void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]);
+float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]);
+bool WM_event_is_tablet(const struct wmEvent *event);
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h
index 9645c95f62b..c6c7314e963 100644
--- a/source/blender/windowmanager/WM_keymap.h
+++ b/source/blender/windowmanager/WM_keymap.h
@@ -64,6 +64,8 @@ wmKeyMapItem *WM_keymap_add_item(struct wmKeyMap *keymap, const char *idname, in
int val, int modifier, int keymodifier);
wmKeyMapItem *WM_keymap_add_menu(struct wmKeyMap *keymap, const char *idname, int type,
int val, int modifier, int keymodifier);
+wmKeyMapItem *WM_keymap_add_menu_pie(struct wmKeyMap *keymap, const char *idname, int type,
+ int val, int modifier, int keymodifier);
bool WM_keymap_remove_item(struct wmKeyMap *keymap, struct wmKeyMapItem *kmi);
int WM_keymap_item_to_string(wmKeyMapItem *kmi, char *str, const int len);
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index e73d599a643..ff252f0fc20 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -128,7 +128,7 @@ struct ImBuf;
#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 /* */
+#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
@@ -190,9 +190,6 @@ enum {
#define WM_UI_HANDLER_CONTINUE 0
#define WM_UI_HANDLER_BREAK 1
-typedef int (*wmUIHandlerFunc)(struct bContext *C, const struct wmEvent *event, void *userdata);
-typedef void (*wmUIHandlerRemoveFunc)(struct bContext *C, void *userdata);
-
/* ************** Notifiers ****************** */
typedef struct wmNotifier {
@@ -252,6 +249,7 @@ typedef struct wmNotifier {
#define ND_DATACHANGED (3<<16)
#define ND_HISTORY (4<<16)
#define ND_JOB (5<<16)
+#define ND_UNDO (6<<16)
/* NC_SCREEN screen */
#define ND_SCREENBROWSE (1<<16)
@@ -600,6 +598,12 @@ typedef struct wmReport {
#define WM_DRAG_PATH 2
#define WM_DRAG_NAME 3
#define WM_DRAG_VALUE 4
+#define WM_DRAG_COLOR 5
+
+typedef enum wmDragFlags {
+ WM_DRAG_NOP = 0,
+ WM_DRAG_FREE_DATA = 1,
+} wmDragFlags;
/* note: structs need not exported? */
@@ -616,6 +620,7 @@ typedef struct wmDrag {
int sx, sy;
char opname[200]; /* if set, draws operator name*/
+ unsigned int flags;
} wmDrag;
/* dropboxes are like keymaps, part of the screen/area/region definition */
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 28bddb47778..d05cc572c45 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -462,7 +462,8 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
BLI_freelistN(&wm->queue);
BLI_freelistN(&wm->paintcursors);
- BLI_freelistN(&wm->drags);
+
+ WM_drag_free_list(&wm->drags);
wm_reports_free(wm);
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 6fd3b426142..68fd32cb450 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -230,7 +230,7 @@ void WM_cursor_grab_enable(wmWindow *win, bool wrap, bool hide, int bounds[4])
}
}
-void WM_cursor_grab_disable(wmWindow *win, int mouse_ungrab_xy[2])
+void WM_cursor_grab_disable(wmWindow *win, const int mouse_ungrab_xy[2])
{
if ((G.debug & G_DEBUG) == 0) {
if (win && win->ghostwin) {
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 2aa177602cb..e5bba9285b4 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -143,7 +143,7 @@ void wm_dropbox_free(void)
/* *********************************** */
/* note that the pointer should be valid allocated and not on stack */
-wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value)
+wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmDrag *drag = MEM_callocN(sizeof(struct wmDrag), "new drag");
@@ -152,6 +152,7 @@ wmDrag *WM_event_start_drag(struct bContext *C, int icon, int type, void *poin,
/* if multiple drags are added, they're drawn as list */
BLI_addtail(&wm->drags, drag);
+ drag->flags = flags;
drag->icon = icon;
drag->type = type;
if (type == WM_DRAG_PATH)
@@ -171,6 +172,22 @@ void WM_event_drag_image(wmDrag *drag, ImBuf *imb, float scale, int sx, int sy)
drag->sy = sy;
}
+void WM_drag_free(wmDrag *drag)
+{
+ if ((drag->flags & WM_DRAG_FREE_DATA) && drag->poin) {
+ MEM_freeN(drag->poin);
+ }
+
+ MEM_freeN(drag);
+}
+
+void WM_drag_free_list(struct ListBase *lb)
+{
+ wmDrag *drag;
+ while ((drag = BLI_pophead(lb))) {
+ WM_drag_free(drag);
+ }
+}
static const char *dropbox_active(bContext *C, ListBase *handlers, wmDrag *drag, wmEvent *event)
{
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index 96824eca578..7440570f4a0 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -32,7 +32,6 @@
#include <stdlib.h>
#include <string.h>
-#include <GL/glew.h>
#include "DNA_listBase.h"
#include "DNA_screen_types.h"
@@ -57,6 +56,7 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_glew.h"
#include "RE_engine.h"
@@ -592,7 +592,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
bScreen *screen = win->screen;
ScrArea *sa;
ARegion *ar;
- int copytex = 0, paintcursor = 1;
+ int copytex = 0;
if (win->drawdata) {
glClearColor(0, 0, 0, 0);
@@ -639,7 +639,7 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
wm_triple_copy_textures(win, triple);
}
- if (paintcursor && wm->paintcursors.first) {
+ 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) {
@@ -685,8 +685,6 @@ static void wm_method_draw_triple(bContext *C, wmWindow *win)
CTX_wm_menu_set(C, ar);
ED_region_do_draw(C, ar);
CTX_wm_menu_set(C, NULL);
- /* when a menu is being drawn, don't do the paint cursors */
- paintcursor = 0;
}
}
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 55f18661712..793908ec44b 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -111,10 +111,13 @@ void wm_event_free(wmEvent *event)
if (event->customdata) {
if (event->customdatafree) {
/* note: pointer to listbase struct elsewhere */
- if (event->custom == EVT_DATA_LISTBASE)
- BLI_freelistN(event->customdata);
- else
+ if (event->custom == EVT_DATA_DRAGDROP) {
+ ListBase *lb = event->customdata;
+ WM_drag_free_list(lb);
+ }
+ else {
MEM_freeN(event->customdata);
+ }
}
}
@@ -289,7 +292,7 @@ void wm_event_do_notifiers(bContext *C)
do_anim = true;
}
}
- if (ELEM5(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
+ if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_SCENE, NC_WM)) {
ED_info_stats_clear(win->screen->scene);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
}
@@ -393,13 +396,17 @@ static int wm_handler_ui_call(bContext *C, wmEventHandler *handler, wmEvent *eve
ARegion *region = CTX_wm_region(C);
ARegion *menu = CTX_wm_menu(C);
static bool do_wheel_ui = true;
- const bool is_wheel = ELEM3(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN);
+ const bool is_wheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE, MOUSEPAN);
int retval;
/* UI code doesn't handle return values - it just always returns break.
* to make the DBL_CLICK conversion work, we just don't send this to UI, except mouse clicks */
- if (event->type != LEFTMOUSE && event->val == KM_DBL_CLICK)
+ if (((handler->flag & WM_HANDLER_ACCEPT_DBL_CLICK) == 0) &&
+ (event->type != LEFTMOUSE) &&
+ (event->val == KM_DBL_CLICK))
+ {
return WM_HANDLER_CONTINUE;
+ }
/* UI is quite aggressive with swallowing events, like scrollwheel */
/* I realize this is not extremely nice code... when UI gets keymaps it can be maybe smarter */
@@ -759,7 +766,7 @@ static int wm_operator_exec_notest(bContext *C, wmOperator *op)
/**
* for running operators with frozen context (modal handlers, menus)
*
- * \param store, Store settings for re-use.
+ * \param store Store settings for re-use.
*
* warning: do not use this within an operator to call its self! [#29537] */
int WM_operator_call_ex(bContext *C, wmOperator *op,
@@ -1261,11 +1268,17 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA
/* invokes operator in context */
+int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, short context, PointerRNA *properties)
+{
+ BLI_assert(ot == WM_operatortype_find(ot->idname, true));
+ return wm_operator_call_internal(C, ot, properties, NULL, context, false);
+}
int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties)
{
wmOperatorType *ot = WM_operatortype_find(opstring, 0);
- if (ot)
- return wm_operator_call_internal(C, ot, properties, NULL, context, false);
+ if (ot) {
+ return WM_operator_name_call_ptr(C, ot, context, properties);
+ }
return 0;
}
@@ -1544,7 +1557,7 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
wmOperatorType *ot = op->type;
if (!wm_operator_check_locked_interface(C, ot)) {
- /* Interface is locked and pperator is not allowed to run,
+ /* Interface is locked and operator is not allowed to run,
* nothing to do in this case.
*/
}
@@ -1721,10 +1734,6 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
if (handler->op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
wm->op_undo_depth--;
- if (retval & OPERATOR_FINISHED)
- if (G.debug & G_DEBUG_WM)
- wm_operator_print(C, handler->op);
-
/* XXX check this carefully, CTX_wm_manager(C) == wm is a bit hackish */
if (CTX_wm_manager(C) == wm && wm->op_undo_depth == 0)
if (handler->op->type->flag & OPTYPE_UNDO)
@@ -1754,6 +1763,9 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
CTX_wm_region_set(C, ar_prev);
}
+ /* for WM_operator_pystring only, custom report handling is done above */
+ wm_operator_reports(C, handler->op, retval, true);
+
if (retval & OPERATOR_FINISHED) {
WM_operator_last_properties_store(handler->op);
}
@@ -1929,17 +1941,17 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
wmDropBox *drop = handler->dropboxes->first;
for (; drop; drop = drop->next) {
/* other drop custom types allowed */
- if (event->custom == EVT_DATA_LISTBASE) {
+ if (event->custom == EVT_DATA_DRAGDROP) {
ListBase *lb = (ListBase *)event->customdata;
wmDrag *drag;
for (drag = lb->first; drag; drag = drag->next) {
if (drop->poll(C, drag, event)) {
-
drop->copy(drag, drop);
/* free the drags before calling operator */
- BLI_freelistN(event->customdata);
+ WM_drag_free_list(lb);
+
event->customdata = NULL;
event->custom = 0;
@@ -2005,7 +2017,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
if (CTX_wm_window(C) == NULL)
return action;
- if (!ELEM3(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) {
+ if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE, EVENT_NONE) && !ISTIMER(event->type)) {
/* test for CLICK events */
if (wm_action_not_handled(action)) {
@@ -2141,10 +2153,12 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
return;
}
- if (event->type == MOUSEMOVE)
+ if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
win->screen->do_draw_drag = true;
+ }
else if (event->type == ESCKEY) {
- BLI_freelistN(&wm->drags);
+ WM_drag_free_list(&wm->drags);
+
win->screen->do_draw_drag = true;
}
else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
@@ -2156,7 +2170,7 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
MEM_freeN(event->customdata);
}
- event->custom = EVT_DATA_LISTBASE;
+ event->custom = EVT_DATA_DRAGDROP;
event->customdata = &wm->drags;
event->customdatafree = 1;
@@ -2174,6 +2188,23 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
}
+/* filter out all events of the pie that spawned the last pie unless it's a release event */
+static bool wm_event_pie_filter(wmWindow *win, wmEvent *event)
+{
+ if (win->lock_pie_event && win->lock_pie_event == event->type) {
+ if (event->val == KM_RELEASE) {
+ win->lock_pie_event = EVENT_NONE;
+ return false;
+ }
+ else {
+ return true;
+ }
+ }
+ else {
+ return false;
+ }
+}
+
/* called in main loop */
/* goes over entire hierarchy: events -> window -> screen -> area -> region */
void wm_event_do_handlers(bContext *C)
@@ -2237,9 +2268,21 @@ void wm_event_do_handlers(bContext *C)
WM_event_print(event);
}
#endif
-
+
+ /* take care of pie event filter */
+ if (wm_event_pie_filter(win, event)) {
+#ifndef NDEBUG
+ if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
+ printf("\n%s: event filtered due to pie button pressed\n", __func__);
+ }
+#endif
+ BLI_remlink(&win->queue, event);
+ wm_event_free(event);
+ continue;
+ }
+
CTX_wm_window_set(C, win);
-
+
/* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
CTX_wm_area_set(C, area_event_inside(C, &event->x));
CTX_wm_region_set(C, region_event_inside(C, &event->x));
@@ -2249,6 +2292,7 @@ void wm_event_do_handlers(bContext *C)
wm_region_mouse_co(C, event);
+
/* first we do priority handlers, modal + some limited keymaps */
action |= wm_handlers_do(C, event, &win->modalhandlers);
@@ -2290,10 +2334,12 @@ void wm_event_do_handlers(bContext *C)
/* call even on non mouse events, since the */
wm_region_mouse_co(C, event);
- /* does polls for drop regions and checks uibuts */
- /* need to be here to make sure region context is true */
- if (ELEM(event->type, MOUSEMOVE, EVT_DROP)) {
- wm_drags_check_ops(C, event);
+ if (!BLI_listbase_is_empty(&wm->drags)) {
+ /* does polls for drop regions and checks uibuts */
+ /* need to be here to make sure region context is true */
+ if (ELEM(event->type, MOUSEMOVE, EVT_DROP) || ISKEYMODIFIER(event->type)) {
+ wm_drags_check_ops(C, event);
+ }
}
action |= wm_handlers_do(C, event, &ar->handlers);
@@ -2548,12 +2594,14 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
}
}
-wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers,
- wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata)
+wmEventHandler *WM_event_add_ui_handler(
+ const bContext *C, ListBase *handlers,
+ wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
+ void *userdata, const bool accept_dbl_click)
{
wmEventHandler *handler = MEM_callocN(sizeof(wmEventHandler), "event ui handler");
- handler->ui_handle = func;
- handler->ui_remove = remove;
+ handler->ui_handle = ui_handle;
+ handler->ui_remove = ui_remove;
handler->ui_userdata = userdata;
if (C) {
handler->ui_area = CTX_wm_area(C);
@@ -2566,6 +2614,9 @@ wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers,
handler->ui_menu = NULL;
}
+ if (accept_dbl_click) {
+ handler->flag |= WM_HANDLER_ACCEPT_DBL_CLICK;
+ }
BLI_addhead(handlers, handler);
@@ -2573,13 +2624,18 @@ wmEventHandler *WM_event_add_ui_handler(const bContext *C, ListBase *handlers,
}
/* set "postpone" for win->modalhandlers, this is in a running for () loop in wm_handlers_do() */
-void WM_event_remove_ui_handler(ListBase *handlers,
- wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove, void *userdata, const bool postpone)
+void WM_event_remove_ui_handler(
+ ListBase *handlers,
+ wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
+ void *userdata, const bool postpone)
{
wmEventHandler *handler;
for (handler = handlers->first; handler; handler = handler->next) {
- if (handler->ui_handle == func && handler->ui_remove == remove && handler->ui_userdata == userdata) {
+ if ((handler->ui_handle == ui_handle) &&
+ (handler->ui_remove == ui_remove) &&
+ (handler->ui_userdata == userdata))
+ {
/* handlers will be freed in wm_handlers_do() */
if (postpone) {
handler->flag |= WM_HANDLER_DO_FREE;
@@ -2593,15 +2649,18 @@ void WM_event_remove_ui_handler(ListBase *handlers,
}
}
-void WM_event_free_ui_handler_all(bContext *C, ListBase *handlers,
- wmUIHandlerFunc func, wmUIHandlerRemoveFunc remove)
+void WM_event_free_ui_handler_all(
+ bContext *C, ListBase *handlers,
+ wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove)
{
wmEventHandler *handler, *handler_next;
for (handler = handlers->first; handler; handler = handler_next) {
handler_next = handler->next;
- if (handler->ui_handle == func && handler->ui_remove == remove) {
- remove(C, handler->ui_userdata);
+ if ((handler->ui_handle == ui_handle) &&
+ (handler->ui_remove == ui_remove))
+ {
+ ui_remove(C, handler->ui_userdata);
BLI_remlink(handlers, handler);
wm_event_free_handler(handler);
}
@@ -2677,7 +2736,7 @@ bool WM_modal_tweak_exit(const wmEvent *event, int tweak_event)
else {
/* if the initial event wasn't a tweak event then
* ignore USER_RELEASECONFIRM setting: see [#26756] */
- if (ELEM3(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
+ if (ELEM(tweak_event, EVT_TWEAK_L, EVT_TWEAK_M, EVT_TWEAK_R) == 0) {
return 1;
}
}
@@ -3338,7 +3397,7 @@ void WM_set_locked_interface(wmWindowManager *wm, bool lock)
*
* TODO(sergey): Make it different locked states, so different jobs
* could lock different areas of blender and allow
- * interation with others?
+ * interaction with others?
*/
BKE_spacedata_draw_locks(lock);
}
@@ -3387,4 +3446,39 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
axis_angle_to_quat(q, axis, angle);
}
+/* if this is a tablet event, return tablet pressure and set *pen_flip
+ * to 1 if the eraser tool is being used, 0 otherwise */
+float WM_event_tablet_data(const wmEvent *event, int *pen_flip, float tilt[2])
+{
+ int erasor = 0;
+ float pressure = 1;
+
+ if (tilt)
+ zero_v2(tilt);
+
+ if (event->tablet_data) {
+ wmTabletData *wmtab = event->tablet_data;
+
+ erasor = (wmtab->Active == EVT_TABLET_ERASER);
+ if (wmtab->Active != EVT_TABLET_NONE) {
+ pressure = wmtab->Pressure;
+ if (tilt) {
+ tilt[0] = wmtab->Xtilt;
+ tilt[1] = wmtab->Ytilt;
+ }
+ }
+ }
+
+ if (pen_flip)
+ (*pen_flip) = erasor;
+
+ return pressure;
+}
+
+bool WM_event_is_tablet(const struct wmEvent *event)
+{
+ return (event->tablet_data) ? true : false;
+}
+
+
/** \} */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 1ec2e6a3ee0..7865e09cbe2 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -171,6 +171,28 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
#endif
}
+static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
+{
+ win->ghostwin = oldwin->ghostwin;
+ win->active = oldwin->active;
+ if (win->active)
+ wm->winactive = win;
+
+ if (!G.background) /* file loading in background mode still calls this */
+ GHOST_SetWindowUserData(win->ghostwin, win); /* pointer back */
+
+ oldwin->ghostwin = NULL;
+
+ win->eventstate = oldwin->eventstate;
+ oldwin->eventstate = NULL;
+
+ /* ensure proper screen rescaling */
+ win->sizex = oldwin->sizex;
+ win->sizey = oldwin->sizey;
+ win->posx = oldwin->posx;
+ win->posy = oldwin->posy;
+}
+
/* match old WM with new, 4 cases:
* 1- no current wm, no read wm: make new default
* 2- no current wm, but read wm: that's OK, do nothing
@@ -224,6 +246,8 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
ED_screens_initialize(G.main->wm.first);
}
else {
+ bool has_match = false;
+
/* what if old was 3, and loaded 1? */
/* this code could move to setup_appdata */
oldwm = oldwmlist->first;
@@ -243,33 +267,27 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
/* ensure making new keymaps and set space types */
wm->initialized = 0;
wm->winactive = NULL;
-
+
/* only first wm in list has ghostwins */
for (win = wm->windows.first; win; win = win->next) {
for (oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
-
- if (oldwin->winid == win->winid) {
- win->ghostwin = oldwin->ghostwin;
- win->active = oldwin->active;
- if (win->active)
- wm->winactive = win;
- if (!G.background) /* file loading in background mode still calls this */
- GHOST_SetWindowUserData(win->ghostwin, win); /* pointer back */
+ if (oldwin->winid == win->winid) {
+ has_match = true;
- oldwin->ghostwin = NULL;
-
- win->eventstate = oldwin->eventstate;
- oldwin->eventstate = NULL;
-
- /* ensure proper screen rescaling */
- win->sizex = oldwin->sizex;
- win->sizey = oldwin->sizey;
- win->posx = oldwin->posx;
- win->posy = oldwin->posy;
+ wm_window_substitute_old(wm, oldwin, win);
}
}
}
+
+ /* make sure at least one window is kept open so we don't lose the context, check T42303 */
+ if (!has_match) {
+ oldwin = oldwm->windows.first;
+ win = wm->windows.first;
+
+ wm_window_substitute_old(wm, oldwin, win);
+ }
+
wm_close_and_free_all(C, oldwmlist);
}
}
@@ -278,11 +296,13 @@ static void wm_window_match_do(bContext *C, ListBase *oldwmlist)
/* in case UserDef was read, we re-initialize all, and do versioning */
static void wm_init_userdef(bContext *C, const bool from_memory)
{
+ Main *bmain = CTX_data_main(C);
+
/* versioning is here */
UI_init_userdef();
MEM_CacheLimiter_set_maximum(((size_t)U.memcachelimit) * 1024 * 1024);
- sound_init(CTX_data_main(C));
+ 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);
@@ -295,11 +315,11 @@ static void wm_init_userdef(bContext *C, const bool from_memory)
/* avoid re-saving for every small change to our prefs, allow overrides */
if (from_memory) {
- UI_init_userdef_factory();
+ BLO_update_defaults_userpref_blend();
}
/* update tempdir from user preferences */
- BLI_init_temporary_dir(U.tempdir);
+ BLI_temp_dir_init(U.tempdir);
BKE_userdef_state();
}
@@ -457,6 +477,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
#endif
/* important to do before NULL'ing the context */
+ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
if (!G.background) {
@@ -591,7 +612,7 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
if (BLI_listbase_is_empty(&wmbase)) {
wm_clear_default_size(C);
}
- BLI_init_temporary_dir(U.tempdir);
+ BLI_temp_dir_init(U.tempdir);
#ifdef WITH_PYTHON_SECURITY
/* use alternative setting for security nuts
@@ -648,6 +669,7 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
#endif
/* important to do before NULL'ing the context */
+ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
@@ -1058,14 +1080,14 @@ void wm_autosave_location(char *filepath)
* BLI_make_file_string will create string that has it most likely on C:\
* through get_default_root().
* If there is no C:\tmp autosave fails. */
- if (!BLI_exists(BLI_temporary_dir())) {
+ if (!BLI_exists(BLI_temp_dir_base())) {
savedir = BLI_get_folder_create(BLENDER_USER_AUTOSAVE, NULL);
BLI_make_file_string("/", filepath, savedir, pidstr);
return;
}
#endif
- BLI_make_file_string("/", filepath, BLI_temporary_dir(), pidstr);
+ BLI_make_file_string("/", filepath, BLI_temp_dir_base(), pidstr);
}
void WM_autosave_init(wmWindowManager *wm)
@@ -1129,7 +1151,7 @@ void wm_autosave_delete(void)
if (BLI_exists(filename)) {
char str[FILE_MAX];
- BLI_make_file_string("/", str, BLI_temporary_dir(), BLENDER_QUIT_FILE);
+ BLI_make_file_string("/", str, BLI_temp_dir_base(), BLENDER_QUIT_FILE);
/* if global undo; remove tempsave, otherwise rename */
if (U.uiflag & USER_GLOBALUNDO) BLI_delete(filename, false, false);
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index c9ef473a442..3e287a3907b 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -74,7 +74,7 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
- if (ELEM5(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK,
+ if (ELEM(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK,
WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE))
{
rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new");
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 5dafadc5a47..f762e19c969 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -54,6 +54,8 @@
#include "BLI_threads.h"
#include "BLI_utildefines.h"
+#include "BLO_writefile.h"
+
#include "BKE_blender.h"
#include "BKE_context.h"
#include "BKE_screen.h"
@@ -110,6 +112,7 @@
#include "GPU_buffers.h"
#include "GPU_extensions.h"
#include "GPU_draw.h"
+#include "GPU_init_exit.h"
#include "BKE_depsgraph.h"
#include "BKE_sound.h"
@@ -117,11 +120,17 @@
static void wm_init_reports(bContext *C)
{
- BKE_reports_init(CTX_wm_reports(C), RPT_STORE);
+ ReportList *reports = CTX_wm_reports(C);
+
+ BLI_assert(!reports || BLI_listbase_is_empty(&reports->list));
+
+ BKE_reports_init(reports, RPT_STORE);
}
static void wm_free_reports(bContext *C)
{
- BKE_reports_clear(CTX_wm_reports(C));
+ ReportList *reports = CTX_wm_reports(C);
+
+ BKE_reports_clear(reports);
}
bool wm_start_with_console = false; /* used in creator.c */
@@ -181,13 +190,16 @@ void WM_init(bContext *C, int argc, const char **argv)
(void)argv; /* unused */
#endif
+ ED_spacemacros_init();
+
if (!G.background && !wm_start_with_console)
GHOST_toggleConsole(3);
wm_init_reports(C); /* reports cant be initialized before the wm */
if (!G.background) {
- GPU_extensions_init();
+ GPU_init();
+
GPU_set_mipmap(!(U.gameflags & USER_DISABLE_MIPMAP));
GPU_set_anisotropic(U.anisotropic_filter);
GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
@@ -230,6 +242,7 @@ void WM_init(bContext *C, int argc, const char **argv)
*
* unlikely any handlers are set but its possible,
* note that recovering the last session does its own callbacks. */
+ BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST);
}
}
@@ -295,7 +308,7 @@ bool WM_init_game(bContext *C)
/* full screen the area */
if (!sa->full) {
- ED_screen_full_toggle(C, win, sa);
+ ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
}
/* Fullscreen */
@@ -398,11 +411,18 @@ void WM_exit_ext(bContext *C, const bool do_python)
if ((U.uiflag2 & USER_KEEP_SESSION) || BKE_undo_valid(NULL)) {
/* save the undo state as quit.blend */
char filename[FILE_MAX];
-
- BLI_make_file_string("/", filename, BLI_temporary_dir(), BLENDER_QUIT_FILE);
+ bool has_edited;
+ int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_LOCK | G_FILE_SIGN | G_FILE_HISTORY);
+
+ BLI_make_file_string("/", filename, BLI_temp_dir_base(), BLENDER_QUIT_FILE);
- if (BKE_undo_save_file(filename))
+ has_edited = ED_editors_flush_edits(C, false);
+
+ if ((has_edited && BLO_write_file(CTX_data_main(C), filename, fileflags, NULL, NULL)) ||
+ BKE_undo_save_file(filename))
+ {
printf("Saved session recovery to '%s'\n", filename);
+ }
}
}
@@ -490,9 +510,12 @@ void WM_exit_ext(bContext *C, const bool do_python)
(void)do_python;
#endif
- GPU_global_buffer_pool_free();
- GPU_free_unused_buffers();
- GPU_extensions_exit();
+ if (!G.background) {
+ GPU_global_buffer_pool_free();
+ GPU_free_unused_buffers();
+
+ GPU_exit();
+ }
BKE_reset_undo();
@@ -519,6 +542,8 @@ void WM_exit_ext(bContext *C, const bool do_python)
MEM_printmemlist();
}
wm_autosave_delete();
+
+ BLI_temp_dir_session_purge();
}
void WM_exit(bContext *C)
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 0163517545f..ff90de4b3c6 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -464,6 +464,13 @@ wmKeyMapItem *WM_keymap_add_menu(wmKeyMap *keymap, const char *idname, int type,
return kmi;
}
+wmKeyMapItem *WM_keymap_add_menu_pie(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
+{
+ wmKeyMapItem *kmi = WM_keymap_add_item(keymap, "WM_OT_call_menu_pie", type, val, modifier, keymodifier);
+ RNA_string_set(kmi->ptr, "name", idname);
+ return kmi;
+}
+
bool WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
{
if (BLI_findindex(&keymap->items, kmi) != -1) {
@@ -582,8 +589,11 @@ static void wm_keymap_patch(wmKeyMap *km, wmKeyMap *diff_km)
/* add item */
if (kmdi->add_item) {
+ /* Do not re-add an already existing keymap item! See T42088. */
+ /* We seek only for exact copy here! See T42137. */
+ kmi_add = wm_keymap_find_item_equals(km, kmdi->add_item);
/* only if nothing to remove or item to remove found */
- if (!kmdi->remove_item || kmi_remove) {
+ if (!kmi_add && (!kmdi->remove_item || kmi_remove)) {
kmi_add = wm_keymap_item_copy(kmdi->add_item);
kmi_add->flag |= KMI_USER_MODIFIED;
@@ -1108,9 +1118,9 @@ int WM_keymap_item_compare(wmKeyMapItem *k1, wmKeyMapItem *k2)
if (k1->val != KM_ANY && k2->val != KM_ANY) {
/* take click, press, release conflict into account */
- if (k1->val == KM_CLICK && ELEM3(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0)
+ if (k1->val == KM_CLICK && ELEM(k2->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0)
return 0;
- if (k2->val == KM_CLICK && ELEM3(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0)
+ if (k2->val == KM_CLICK && ELEM(k1->val, KM_PRESS, KM_RELEASE, KM_CLICK) == 0)
return 0;
if (k1->val != k2->val)
return 0;
@@ -1414,46 +1424,73 @@ wmKeyMapItem *WM_keymap_item_find_id(wmKeyMap *keymap, int id)
/* Needs to be kept up to date with Keymap and Operator naming */
wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
{
+ /* Op types purposely skipped for now:
+ * BRUSH_OT
+ * BOID_OT
+ * BUTTONS_OT
+ * CONSTRAINT_OT
+ * PAINT_OT
+ * ED_OT
+ * FLUID_OT
+ * TEXTURE_OT
+ * UI_OT
+ * VIEW2D_OT
+ * WORLD_OT
+ */
+
wmKeyMap *km = NULL;
SpaceLink *sl = CTX_wm_space_data(C);
/* Window */
- if (strstr(opname, "WM_OT")) {
+ if (STRPREFIX(opname, "WM_OT")) {
km = WM_keymap_find_all(C, "Window", 0, 0);
}
- /* Screen */
- else if (strstr(opname, "SCREEN_OT")) {
+ /* Screen & Render */
+ else if (STRPREFIX(opname, "SCREEN_OT") ||
+ STRPREFIX(opname, "RENDER_OT") ||
+ STRPREFIX(opname, "SOUND_OT") ||
+ STRPREFIX(opname, "SCENE_OT"))
+ {
km = WM_keymap_find_all(C, "Screen", 0, 0);
}
/* Grease Pencil */
- else if (strstr(opname, "GPENCIL_OT")) {
+ else if (STRPREFIX(opname, "GPENCIL_OT")) {
km = WM_keymap_find_all(C, "Grease Pencil", 0, 0);
}
/* Markers */
- else if (strstr(opname, "MARKER_OT")) {
+ else if (STRPREFIX(opname, "MARKER_OT")) {
km = WM_keymap_find_all(C, "Markers", 0, 0);
}
/* Import/Export*/
- else if (strstr(opname, "IMPORT_") || strstr(opname, "EXPORT_")) {
+ else if (STRPREFIX(opname, "IMPORT_") ||
+ STRPREFIX(opname, "EXPORT_"))
+ {
km = WM_keymap_find_all(C, "Window", 0, 0);
}
/* 3D View */
- else if (strstr(opname, "VIEW3D_OT")) {
+ else if (STRPREFIX(opname, "VIEW3D_OT")) {
km = WM_keymap_find_all(C, "3D View", sl->spacetype, 0);
}
- else if (strstr(opname, "OBJECT_OT")) {
+ else if (STRPREFIX(opname, "OBJECT_OT")) {
/* exception, this needs to work outside object mode too */
- if (strstr(opname, "OBJECT_OT_mode_set"))
+ if (STRPREFIX(opname, "OBJECT_OT_mode_set"))
km = WM_keymap_find_all(C, "Object Non-modal", 0, 0);
else
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
}
-
+ /* Object mode related */
+ else if (STRPREFIX(opname, "GROUP_OT") ||
+ STRPREFIX(opname, "MATERIAL_OT") ||
+ STRPREFIX(opname, "PTCACHE_OT") ||
+ STRPREFIX(opname, "RIGIDBODY_OT"))
+ {
+ km = WM_keymap_find_all(C, "Object Mode", 0, 0);
+ }
/* Editing Modes */
- else if (strstr(opname, "MESH_OT")) {
+ else if (STRPREFIX(opname, "MESH_OT")) {
km = WM_keymap_find_all(C, "Mesh", 0, 0);
/* some mesh operators are active in object mode too, like add-prim */
@@ -1461,7 +1498,9 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
}
}
- else if (strstr(opname, "CURVE_OT")) {
+ else if (STRPREFIX(opname, "CURVE_OT") ||
+ STRPREFIX(opname, "SURFACE_OT"))
+ {
km = WM_keymap_find_all(C, "Curve", 0, 0);
/* some curve operators are active in object mode too, like add-prim */
@@ -1469,13 +1508,17 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
}
}
- else if (strstr(opname, "ARMATURE_OT")) {
+ else if (STRPREFIX(opname, "ARMATURE_OT") ||
+ STRPREFIX(opname, "SKETCH_OT"))
+ {
km = WM_keymap_find_all(C, "Armature", 0, 0);
}
- else if (strstr(opname, "POSE_OT")) {
+ else if (STRPREFIX(opname, "POSE_OT") ||
+ STRPREFIX(opname, "POSELIB_OT"))
+ {
km = WM_keymap_find_all(C, "Pose", 0, 0);
}
- else if (strstr(opname, "SCULPT_OT")) {
+ else if (STRPREFIX(opname, "SCULPT_OT")) {
switch (CTX_data_mode_enum(C)) {
case OB_MODE_SCULPT:
km = WM_keymap_find_all(C, "Sculpt", 0, 0);
@@ -1485,7 +1528,7 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
- else if (strstr(opname, "MBALL_OT")) {
+ else if (STRPREFIX(opname, "MBALL_OT")) {
km = WM_keymap_find_all(C, "Metaball", 0, 0);
/* some mball operators are active in object mode too, like add-prim */
@@ -1493,17 +1536,20 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
km = WM_keymap_find_all(C, "Object Mode", 0, 0);
}
}
- else if (strstr(opname, "LATTICE_OT")) {
+ else if (STRPREFIX(opname, "LATTICE_OT")) {
km = WM_keymap_find_all(C, "Lattice", 0, 0);
}
- else if (strstr(opname, "PARTICLE_OT")) {
+ else if (STRPREFIX(opname, "PARTICLE_OT")) {
km = WM_keymap_find_all(C, "Particle", 0, 0);
}
- else if (strstr(opname, "FONT_OT")) {
+ else if (STRPREFIX(opname, "FONT_OT")) {
km = WM_keymap_find_all(C, "Font", 0, 0);
}
- else if (strstr(opname, "PAINT_OT")) {
-
+ /* Paint Face Mask */
+ else if (STRPREFIX(opname, "PAINT_OT_face_select")) {
+ km = WM_keymap_find_all(C, "Face Mask", 0, 0);
+ }
+ else if (STRPREFIX(opname, "PAINT_OT")) {
/* check for relevant mode */
switch (CTX_data_mode_enum(C)) {
case OB_MODE_WEIGHT_PAINT:
@@ -1517,70 +1563,83 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
- /* Paint Face Mask */
- else if (strstr(opname, "PAINT_OT_face_select")) {
- km = WM_keymap_find_all(C, "Face Mask", sl->spacetype, 0);
- }
/* Timeline */
- else if (strstr(opname, "TIME_OT")) {
+ else if (STRPREFIX(opname, "TIME_OT")) {
km = WM_keymap_find_all(C, "Timeline", sl->spacetype, 0);
}
/* Image Editor */
- else if (strstr(opname, "IMAGE_OT")) {
+ else if (STRPREFIX(opname, "IMAGE_OT")) {
km = WM_keymap_find_all(C, "Image", sl->spacetype, 0);
}
+ /* Clip Editor */
+ else if (STRPREFIX(opname, "CLIP_OT")) {
+ km = WM_keymap_find_all(C, "Clip", sl->spacetype, 0);
+ }
+ else if (STRPREFIX(opname, "MASK_OT")) {
+ km = WM_keymap_find_all(C, "Mask Editing", 0, 0);
+ }
/* UV Editor */
- else if (strstr(opname, "UV_OT")) {
+ else if (STRPREFIX(opname, "UV_OT")) {
km = WM_keymap_find_all(C, "UV Editor", sl->spacetype, 0);
}
/* Node Editor */
- else if (strstr(opname, "NODE_OT")) {
+ else if (STRPREFIX(opname, "NODE_OT")) {
km = WM_keymap_find_all(C, "Node Editor", sl->spacetype, 0);
}
/* Animation Editor Channels */
- else if (strstr(opname, "ANIM_OT_channels")) {
+ else if (STRPREFIX(opname, "ANIM_OT_channels")) {
km = WM_keymap_find_all(C, "Animation Channels", sl->spacetype, 0);
}
/* Animation Generic - after channels */
- else if (strstr(opname, "ANIM_OT")) {
+ else if (STRPREFIX(opname, "ANIM_OT")) {
km = WM_keymap_find_all(C, "Animation", 0, 0);
}
/* Graph Editor */
- else if (strstr(opname, "GRAPH_OT")) {
+ else if (STRPREFIX(opname, "GRAPH_OT")) {
km = WM_keymap_find_all(C, "Graph Editor", sl->spacetype, 0);
}
/* Dopesheet Editor */
- else if (strstr(opname, "ACTION_OT")) {
+ else if (STRPREFIX(opname, "ACTION_OT")) {
km = WM_keymap_find_all(C, "Dopesheet", sl->spacetype, 0);
}
/* NLA Editor */
- else if (strstr(opname, "NLA_OT")) {
+ else if (STRPREFIX(opname, "NLA_OT")) {
km = WM_keymap_find_all(C, "NLA Editor", sl->spacetype, 0);
}
/* Script */
- else if (strstr(opname, "SCRIPT_OT")) {
+ else if (STRPREFIX(opname, "SCRIPT_OT")) {
km = WM_keymap_find_all(C, "Script", sl->spacetype, 0);
}
/* Text */
- else if (strstr(opname, "TEXT_OT")) {
+ else if (STRPREFIX(opname, "TEXT_OT")) {
km = WM_keymap_find_all(C, "Text", sl->spacetype, 0);
}
/* Sequencer */
- else if (strstr(opname, "SEQUENCER_OT")) {
+ else if (STRPREFIX(opname, "SEQUENCER_OT")) {
km = WM_keymap_find_all(C, "Sequencer", sl->spacetype, 0);
}
/* Console */
- else if (strstr(opname, "CONSOLE_OT")) {
+ else if (STRPREFIX(opname, "CONSOLE_OT")) {
km = WM_keymap_find_all(C, "Console", sl->spacetype, 0);
}
/* Console */
- else if (strstr(opname, "INFO_OT")) {
+ else if (STRPREFIX(opname, "INFO_OT")) {
km = WM_keymap_find_all(C, "Info", sl->spacetype, 0);
}
-
+ /* File browser */
+ else if (STRPREFIX(opname, "FILE_OT")) {
+ km = WM_keymap_find_all(C, "File Browser", sl->spacetype, 0);
+ }
+ /* Logic Editor */
+ else if (STRPREFIX(opname, "LOGIC_OT")) {
+ km = WM_keymap_find_all(C, "Logic Editor", sl->spacetype, 0);
+ }
+ /* Outliner */
+ else if (STRPREFIX(opname, "OUTLINER_OT")) {
+ km = WM_keymap_find_all(C, "Outliner", sl->spacetype, 0);
+ }
/* Transform */
- else if (strstr(opname, "TRANSFORM_OT")) {
-
+ else if (STRPREFIX(opname, "TRANSFORM_OT")) {
/* check for relevant editor */
switch (sl->spacetype) {
case SPACE_VIEW3D:
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index a73532680c5..68aad2dbda6 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -56,6 +56,7 @@
#include "PIL_time.h"
#include "BLI_blenlib.h"
+#include "BLI_dial.h"
#include "BLI_dynstr.h" /*for WM_operator_pystring */
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -501,7 +502,7 @@ void WM_operator_py_idname(char *to, const char *from)
int ofs = (sep - from);
/* note, we use ascii tolower instead of system tolower, because the
- * latter depends on the locale, and can lead to idname mistmatch */
+ * latter depends on the locale, and can lead to idname mismatch */
memcpy(to, from, sizeof(char) * ofs);
BLI_ascii_strtolower(to, ofs);
@@ -1086,7 +1087,6 @@ static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxHeight(), uiSearchBoxWidth(), uiSearchBoxHeight(), NULL, 0, 0, 0, 0, NULL);
uiPopupBoundsBlock(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
- uiEndBlock(C, block);
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_OPEN;
@@ -1313,9 +1313,14 @@ void WM_operator_properties_gesture_border(wmOperatorType *ot, bool extend)
void WM_operator_properties_mouse_select(wmOperatorType *ot)
{
- RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
- RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from selection");
- RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Selection", "Toggle the selection");
+ PropertyRNA *prop;
+
+ prop = RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend selection instead of deselecting everything first");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Remove from selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle Selection", "Toggle the selection");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
void WM_operator_properties_gesture_straightline(wmOperatorType *ot, int cursor)
@@ -1427,7 +1432,6 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
}
uiPopupBoundsBlock(block, 4, 0, 0);
- uiEndBlock(C, block);
return block;
}
@@ -1462,7 +1466,11 @@ static void dialog_check_cb(bContext *C, void *op_ptr, void *UNUSED(arg))
wmOperator *op = op_ptr;
if (op->type->check) {
if (op->type->check(C, op)) {
- /* refresh */
+ /* check for popup and re-layout buttons */
+ ARegion *ar_menu = CTX_wm_menu(C);
+ if (ar_menu) {
+ ED_region_tag_refresh_ui(ar_menu);
+ }
}
}
}
@@ -1507,7 +1515,6 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
/* center around the mouse */
uiPopupBoundsBlock(block, 4, data->width / -2, data->height / 2);
- uiEndBlock(C, block);
return block;
}
@@ -1530,7 +1537,6 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
uiLayoutOperatorButs(C, layout, op, NULL, 'V', 0);
uiPopupBoundsBlock(block, 4, 0, 0);
- uiEndBlock(C, block);
return block;
}
@@ -1774,6 +1780,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
int i;
MenuType *mt = WM_menutype_find("USERPREF_MT_splash", true);
char url[96];
+ const char *version_suffix = NULL;
#ifndef WITH_HEADLESS
extern char datatoc_splash_png[];
@@ -1828,15 +1835,19 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
/* label for 'a' bugfix releases, or 'Release Candidate 1'...
* avoids recreating splash for version updates */
- if (0) {
+ if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
+ version_suffix = "Release Candidate";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
+ version_suffix = STRINGIFY(BLENDER_VERSION_CHAR);
+ }
+ if (version_suffix != NULL && version_suffix[0]) {
/* placed after the version number in the image,
* placing y is tricky to match baseline */
int x = 260 - (2 * UI_DPI_WINDOW_FAC);
int y = 242 + (4 * UI_DPI_WINDOW_FAC);
int w = 240;
- const char *version_suffix = "Release Candidate";
-
/* hack to have text draw 'text_sel' */
uiBlockSetEmboss(block, UI_EMBOSSN);
but = uiDefBut(block, LABEL, 0, version_suffix, x * U.pixelsize, y * U.pixelsize, w * U.pixelsize, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
@@ -1882,13 +1893,14 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
col = uiLayoutColumn(split, false);
uiItemL(col, IFACE_("Links"), ICON_NONE);
uiItemStringO(col, IFACE_("Support an Open Animation Movie"), ICON_URL, "WM_OT_url_open", "url",
- "http://cloud.blender.org/gooseberry");
+ "https://cloud.blender.org/join");
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",
"http://www.blender.org/about/credits/");
- uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url",
- "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.70");
+ BLI_snprintf(url, sizeof(url), "http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/%d.%d",
+ BLENDER_VERSION / 100, BLENDER_VERSION % 100);
+ uiItemStringO(col, IFACE_("Release Log"), ICON_URL, "WM_OT_url_open", "url", url);
uiItemStringO(col, IFACE_("Manual"), ICON_URL, "WM_OT_url_open", "url",
"http://wiki.blender.org/index.php/Doc:2.6/Manual");
uiItemStringO(col, IFACE_("Blender Website"), ICON_URL, "WM_OT_url_open", "url", "http://www.blender.org");
@@ -1924,7 +1936,6 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
uiItemL(col, "", ICON_NONE);
uiCenteredBoundsBlock(block, 0);
- uiEndBlock(C, block);
return block;
}
@@ -1966,7 +1977,6 @@ static uiBlock *wm_block_search_menu(bContext *C, ARegion *ar, void *UNUSED(arg_
uiDefBut(block, LABEL, 0, "", 10, 10 - uiSearchBoxHeight(), uiSearchBoxWidth(), uiSearchBoxHeight(), NULL, 0, 0, 0, 0, NULL);
uiPopupBoundsBlock(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
- uiEndBlock(C, block);
wm_event_init_from_window(win, &event);
event.type = EVT_BUT_OPEN;
@@ -2045,6 +2055,41 @@ static void WM_OT_call_menu(wmOperatorType *ot)
RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
}
+static int wm_call_pie_menu_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ char idname[BKE_ST_MAXNAME];
+ RNA_string_get(op->ptr, "name", idname);
+
+ uiPieMenuInvoke(C, idname, event);
+
+ return OPERATOR_CANCELLED;
+}
+
+static int wm_call_pie_menu_exec(bContext *C, wmOperator *op)
+{
+ char idname[BKE_ST_MAXNAME];
+ RNA_string_get(op->ptr, "name", idname);
+
+ uiPieMenuInvoke(C, idname, CTX_wm_window(C)->eventstate);
+
+ return OPERATOR_CANCELLED;
+}
+
+static void WM_OT_call_menu_pie(wmOperatorType *ot)
+{
+ ot->name = "Call Pie Menu";
+ ot->idname = "WM_OT_call_menu_pie";
+ ot->description = "Call (draw) a pre-defined pie menu";
+
+ ot->invoke = wm_call_pie_menu_invoke;
+ ot->exec = wm_call_pie_menu_exec;
+ ot->poll = WM_operator_winactive;
+
+ ot->flag = OPTYPE_INTERNAL;
+
+ RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
+}
+
/* ************ window / screen operator definitions ************** */
/* this poll functions is needed in place of WM_operator_winactive
@@ -2053,7 +2098,7 @@ static int wm_operator_winactive_normal(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
- if (win == NULL || win->screen == NULL || win->screen->full != SCREENNORMAL)
+ if (win == NULL || win->screen == NULL || win->screen->state != SCREENNORMAL)
return 0;
return 1;
@@ -2163,7 +2208,7 @@ static void WM_OT_read_homefile(wmOperatorType *ot)
"Load user interface setup from the .blend file");
RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
- /* ommit poll to run in background mode */
+ /* omit poll to run in background mode */
}
static void WM_OT_read_factory_settings(wmOperatorType *ot)
@@ -2174,7 +2219,7 @@ static void WM_OT_read_factory_settings(wmOperatorType *ot)
ot->invoke = WM_operator_confirm;
ot->exec = wm_homefile_read_exec;
- /* ommit poll to run in background mode */
+ /* omit poll to run in background mode */
}
/* *************** open file **************** */
@@ -2327,13 +2372,13 @@ static void WM_OT_open_mainfile(wmOperatorType *ot)
ot->exec = wm_open_mainfile_exec;
ot->check = wm_open_mainfile_check;
ot->ui = wm_open_mainfile_ui;
- /* ommit window poll so this can work in background mode */
+ /* omit window poll so this can work in background mode */
WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_OPENFILE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
- RNA_def_boolean(ot->srna, "load_ui", 1, "Load UI", "Load user interface setup in the .blend file");
- RNA_def_boolean(ot->srna, "use_scripts", 1, "Trusted Source",
+ RNA_def_boolean(ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file");
+ RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
"Allow .blend file to execute scripts automatically, default available from system preferences");
}
@@ -2344,7 +2389,14 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op)
{
bool success;
- success = wm_file_read_opwrap(C, G.main->name, op->reports, true);
+ wm_open_init_use_scripts(op, false);
+
+ if (RNA_boolean_get(op->ptr, "use_scripts"))
+ G.f |= G_SCRIPT_AUTOEXEC;
+ else
+ G.f &= ~G_SCRIPT_AUTOEXEC;
+
+ success = wm_file_read_opwrap(C, G.main->name, op->reports, !(G.f & G_SCRIPT_AUTOEXEC));
if (success) {
return OPERATOR_FINISHED;
@@ -2366,6 +2418,9 @@ static void WM_OT_revert_mainfile(wmOperatorType *ot)
ot->description = "Reload the saved file";
ot->invoke = WM_operator_confirm;
+ RNA_def_boolean(ot->srna, "use_scripts", true, "Trusted Source",
+ "Allow .blend file to execute scripts automatically, default available from system preferences");
+
ot->exec = wm_revert_mainfile_exec;
ot->poll = wm_revert_mainfile_poll;
}
@@ -2415,7 +2470,7 @@ static short wm_link_append_flag(wmOperator *op)
if (RNA_boolean_get(op->ptr, "autoselect")) flag |= FILE_AUTOSELECT;
if (RNA_boolean_get(op->ptr, "active_layer")) flag |= FILE_ACTIVELAY;
- if (RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH;
+ if (RNA_struct_find_property(op->ptr, "relative_path") && RNA_boolean_get(op->ptr, "relative_path")) flag |= FILE_RELPATH;
if (RNA_boolean_get(op->ptr, "link")) flag |= FILE_LINK;
if (RNA_boolean_get(op->ptr, "instance_groups")) flag |= FILE_GROUP_INSTANCE;
@@ -2546,13 +2601,31 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-static void WM_OT_link_append(wmOperatorType *ot)
+static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
{
PropertyRNA *prop;
- ot->name = "Link/Append from Library";
- ot->idname = "WM_OT_link_append";
- ot->description = "Link or Append from a Library .blend file";
+ /* better not save _any_ settings for this operator */
+ /* properties */
+ prop = RNA_def_boolean(ot->srna, "link", is_link,
+ "Link", "Link the objects or datablocks rather than appending");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
+ prop = RNA_def_boolean(ot->srna, "autoselect", true,
+ "Select", "Select new objects");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "active_layer", true,
+ "Active Layer", "Put new objects on the active layer");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "instance_groups", is_link,
+ "Instance Groups", "Create Dupli-Group instances for each group");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
+static void WM_OT_link(wmOperatorType *ot)
+{
+ ot->name = "Link from Library";
+ ot->idname = "WM_OT_link";
+ ot->description = "Link from a Library .blend file";
ot->invoke = wm_link_append_invoke;
ot->exec = wm_link_append_exec;
@@ -2565,16 +2638,27 @@ static void WM_OT_link_append(wmOperatorType *ot)
WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH | WM_FILESEL_FILES,
FILE_DEFAULTDISPLAY);
- /* better not save _any_ settings for this operator */
- /* properties */
- prop = RNA_def_boolean(ot->srna, "link", 1, "Link", "Link the objects or datablocks rather than appending");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN);
- prop = RNA_def_boolean(ot->srna, "autoselect", 1, "Select", "Select the linked objects");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "active_layer", 1, "Active Layer", "Put the linked objects on the active layer");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "instance_groups", 1, "Instance Groups", "Create instances for each group as a DupliGroup");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ wm_link_append_properties_common(ot, true);
+}
+
+static void WM_OT_append(wmOperatorType *ot)
+{
+ ot->name = "Append from Library";
+ ot->idname = "WM_OT_append";
+ ot->description = "Append from a Library .blend file";
+
+ ot->invoke = wm_link_append_invoke;
+ ot->exec = wm_link_append_exec;
+ ot->poll = wm_link_append_poll;
+
+ ot->flag |= OPTYPE_UNDO;
+
+ WM_operator_properties_filesel(
+ ot, FOLDERFILE | BLENDERFILE, FILE_LOADLIB, FILE_OPENFILE,
+ WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES,
+ FILE_DEFAULTDISPLAY);
+
+ wm_link_append_properties_common(ot, false);
}
/* *************** recover last session **************** */
@@ -2583,7 +2667,7 @@ void WM_recover_last_session(bContext *C, ReportList *reports)
{
char filepath[FILE_MAX];
- BLI_make_file_string("/", filepath, BLI_temporary_dir(), BLENDER_QUIT_FILE);
+ BLI_make_file_string("/", filepath, BLI_temp_dir_base(), BLENDER_QUIT_FILE);
/* if reports==NULL, it's called directly without operator, we add a quick check here */
if (reports || BLI_exists(filepath)) {
G.fileflags |= G_FILE_RECOVER;
@@ -2776,7 +2860,7 @@ static void WM_OT_save_as_mainfile(wmOperatorType *ot)
ot->invoke = wm_save_as_mainfile_invoke;
ot->exec = wm_save_as_mainfile_exec;
ot->check = blend_save_check;
- /* ommit window poll so this can work in background mode */
+ /* omit window poll so this can work in background mode */
WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_SAVE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
@@ -2852,7 +2936,7 @@ static void WM_OT_save_mainfile(wmOperatorType *ot)
ot->invoke = wm_save_mainfile_invoke;
ot->exec = wm_save_as_mainfile_exec;
ot->check = blend_save_check;
- /* ommit window poll so this can work in background mode */
+ /* omit window poll so this can work in background mode */
WM_operator_properties_filesel(ot, FOLDERFILE | BLENDERFILE, FILE_BLENDER, FILE_SAVE,
WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY);
@@ -2862,7 +2946,7 @@ static void WM_OT_save_mainfile(wmOperatorType *ot)
static void WM_OT_window_fullscreen_toggle(wmOperatorType *ot)
{
- ot->name = "Toggle Fullscreen";
+ ot->name = "Toggle Window Fullscreen";
ot->idname = "WM_OT_window_fullscreen_toggle";
ot->description = "Toggle the current window fullscreen";
@@ -3241,6 +3325,9 @@ static void tweak_gesture_modal(bContext *C, const wmEvent *event)
wmEvent tevent;
wm_event_init_from_window(window, &tevent);
+ /* We want to get coord from start of drag, not from point where it becomes a tweak event, see T40549 */
+ tevent.x = rect->xmin + sx;
+ tevent.y = rect->ymin + sy;
if (gesture->event_type == LEFTMOUSE)
tevent.type = EVT_TWEAK_L;
else if (gesture->event_type == RIGHTMOUSE)
@@ -3284,7 +3371,7 @@ void wm_tweakevent_test(bContext *C, wmEvent *event, int action)
if (win->tweak == NULL) {
if (CTX_wm_region(C)) {
if (event->val == KM_PRESS) {
- if (ELEM3(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
+ if (ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) {
win->tweak = WM_gesture_new(C, event, WM_GESTURE_TWEAK);
}
}
@@ -3635,6 +3722,9 @@ typedef struct {
StructRNA *image_id_srna;
float initial_value, current_value, min_value, max_value;
int initial_mouse[2];
+ int slow_mouse[2];
+ bool slow_mode;
+ Dial *dial;
unsigned int gltex;
ListBase orig_paintcursors;
bool use_secondary_tex;
@@ -3659,8 +3749,8 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
break;
case PROP_ANGLE:
- d[0] = WM_RADIAL_CONTROL_DISPLAY_SIZE * cos(rc->initial_value);
- d[1] = WM_RADIAL_CONTROL_DISPLAY_SIZE * sin(rc->initial_value);
+ d[0] = WM_RADIAL_CONTROL_DISPLAY_SIZE * cosf(rc->initial_value);
+ d[1] = WM_RADIAL_CONTROL_DISPLAY_SIZE * sinf(rc->initial_value);
break;
default:
return;
@@ -4025,7 +4115,7 @@ static int radial_control_invoke(bContext *C, wmOperator *op, const wmEvent *eve
/* get subtype of property */
rc->subtype = RNA_property_subtype(rc->prop);
- if (!ELEM5(rc->subtype, PROP_NONE, PROP_DISTANCE, PROP_FACTOR, PROP_ANGLE, PROP_PIXEL)) {
+ if (!ELEM(rc->subtype, PROP_NONE, PROP_DISTANCE, PROP_FACTOR, PROP_ANGLE, PROP_PIXEL)) {
BKE_report(op->reports, RPT_ERROR, "Property must be a none, distance, a factor, or an angle");
MEM_freeN(rc);
return OPERATOR_CANCELLED;
@@ -4068,6 +4158,11 @@ static void radial_control_cancel(bContext *C, wmOperator *op)
RadialControl *rc = op->customdata;
wmWindowManager *wm = CTX_wm_manager(C);
+ if (rc->dial) {
+ MEM_freeN(rc->dial);
+ rc->dial = NULL;
+ }
+
WM_paint_cursor_end(wm, rc->cursor);
/* restore original paint cursors */
@@ -4087,24 +4182,61 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
{
RadialControl *rc = op->customdata;
float new_value, dist, zoom[2];
- float delta[2], snap, ret = OPERATOR_RUNNING_MODAL;
-
+ float delta[2], ret = OPERATOR_RUNNING_MODAL;
+ bool snap;
+ float angle_precision = 0.0f;
/* TODO: fix hardcoded events */
- snap = event->ctrl;
+ snap = event->ctrl != 0;
switch (event->type) {
case MOUSEMOVE:
- delta[0] = rc->initial_mouse[0] - event->x;
- delta[1] = rc->initial_mouse[1] - event->y;
-
- if (rc->zoom_prop) {
- RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
- delta[0] /= zoom[0];
- delta[1] /= zoom[1];
+ if (rc->slow_mode) {
+ if (rc->subtype == PROP_ANGLE) {
+ float position[2] = {event->x, event->y};
+
+ /* calculate the initial angle here first */
+ delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0];
+ delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1];
+
+ /* precision angle gets calculated from dial and gets added later */
+ angle_precision = -0.1f * BLI_dial_angle(rc->dial, position);
+ }
+ else {
+ delta[0] = rc->initial_mouse[0] - rc->slow_mouse[0];
+ delta[1] = rc->initial_mouse[1] - rc->slow_mouse[1];
+
+ if (rc->zoom_prop) {
+ RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
+ delta[0] /= zoom[0];
+ delta[1] /= zoom[1];
+ }
+
+ dist = len_v2(delta);
+
+ delta[0] = event->x - rc->slow_mouse[0];
+ delta[1] = event->y - rc->slow_mouse[1];
+
+ if (rc->zoom_prop) {
+ delta[0] /= zoom[0];
+ delta[1] /= zoom[1];
+ }
+
+ dist = dist + 0.1f * (delta[0] + delta[1]);
+ }
}
+ else {
+ delta[0] = rc->initial_mouse[0] - event->x;
+ delta[1] = rc->initial_mouse[1] - event->y;
- dist = len_v2(delta);
+ if (rc->zoom_prop) {
+ RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
+ delta[0] /= zoom[0];
+ delta[1] /= zoom[1];
+ }
+
+ dist = len_v2(delta);
+ }
/* calculate new value and apply snapping */
switch (rc->subtype) {
@@ -4119,7 +4251,10 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f;
break;
case PROP_ANGLE:
- new_value = atan2(delta[1], delta[0]) + M_PI;
+ new_value = atan2f(delta[1], delta[0]) + M_PI + angle_precision;
+ new_value = fmod(new_value, 2.0f * (float)M_PI);
+ if (new_value < 0.0f)
+ new_value += 2.0f * (float)M_PI;
if (snap) new_value = DEG2RADF(((int)RAD2DEGF(new_value) + 5) / 10 * 10);
break;
default:
@@ -4146,6 +4281,29 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
RNA_property_update(C, &rc->ptr, rc->prop);
ret = OPERATOR_FINISHED;
break;
+
+ case LEFTSHIFTKEY:
+ case RIGHTSHIFTKEY:
+ if (event->val == KM_PRESS) {
+ rc->slow_mouse[0] = event->x;
+ rc->slow_mouse[1] = event->y;
+ rc->slow_mode = true;
+ if (rc->subtype == PROP_ANGLE) {
+ float initial_position[2] = {UNPACK2(rc->initial_mouse)};
+ float current_position[2] = {UNPACK2(rc->slow_mouse)};
+ rc->dial = BLI_dial_initialize(initial_position, 0.0f);
+ /* immediately set the position to get a an initial direction */
+ BLI_dial_angle(rc->dial, current_position);
+ }
+ }
+ if (event->val == KM_RELEASE) {
+ rc->slow_mode = false;
+ if (rc->dial) {
+ MEM_freeN(rc->dial);
+ rc->dial = NULL;
+ }
+ }
+ break;
}
ED_region_tag_redraw(CTX_wm_region(C));
@@ -4158,8 +4316,6 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
static void WM_OT_radial_control(wmOperatorType *ot)
{
- PropertyRNA *prop;
-
ot->name = "Radial Control";
ot->idname = "WM_OT_radial_control";
ot->description = "Set some size property (like e.g. brush size) with mouse wheel";
@@ -4171,32 +4327,23 @@ static void WM_OT_radial_control(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
/* all paths relative to the context */
- prop = RNA_def_string(ot->srna, "data_path_primary", NULL, 0, "Primary Data Path", "Primary path of property to be set by the radial control");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "data_path_primary", NULL, 0, "Primary Data Path", "Primary path of property to be set by the radial control");
- prop = RNA_def_string(ot->srna, "data_path_secondary", NULL, 0, "Secondary Data Path", "Secondary path of property to be set by the radial control");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "data_path_secondary", NULL, 0, "Secondary Data Path", "Secondary path of property to be set by the radial control");
- prop = RNA_def_string(ot->srna, "use_secondary", NULL, 0, "Use Secondary", "Path of property to select between the primary and secondary data paths");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "use_secondary", NULL, 0, "Use Secondary", "Path of property to select between the primary and secondary data paths");
- prop = RNA_def_string(ot->srna, "rotation_path", NULL, 0, "Rotation Path", "Path of property used to rotate the texture display");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "rotation_path", NULL, 0, "Rotation Path", "Path of property used to rotate the texture display");
- prop = RNA_def_string(ot->srna, "color_path", NULL, 0, "Color Path", "Path of property used to set the color of the control");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "color_path", NULL, 0, "Color Path", "Path of property used to set the color of the control");
- prop = RNA_def_string(ot->srna, "fill_color_path", NULL, 0, "Fill Color Path", "Path of property used to set the fill color of the control");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "fill_color_path", NULL, 0, "Fill Color Path", "Path of property used to set the fill color of the control");
- prop = RNA_def_string(ot->srna, "zoom_path", NULL, 0, "Zoom Path", "Path of property used to set the zoom level for the control");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "zoom_path", NULL, 0, "Zoom Path", "Path of property used to set the zoom level for the control");
- prop = RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_string(ot->srna, "image_id", NULL, 0, "Image ID", "Path of ID that is used to generate an image for the control");
- prop = RNA_def_boolean(ot->srna, "secondary_tex", 0, "Secondary Texture", "Tweak brush secondary/mask texture");
- RNA_def_property_flag(prop, PROP_HIDDEN);
+ RNA_def_boolean(ot->srna, "secondary_tex", 0, "Secondary Texture", "Tweak brush secondary/mask texture");
}
/* ************************** timer for testing ***************** */
@@ -4207,6 +4354,7 @@ static void redraw_timer_window_swap(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *sa;
+ CTX_wm_menu_set(C, NULL);
for (sa = CTX_wm_screen(C)->areabase.first; sa; sa = sa->next)
ED_area_tag_redraw(sa);
@@ -4245,7 +4393,8 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
}
else if (type == 1) {
wmWindow *win = CTX_wm_window(C);
-
+ CTX_wm_menu_set(C, NULL);
+
ED_region_tag_redraw(ar);
wm_draw_update(C);
@@ -4258,6 +4407,8 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
ScrArea *sa_back = CTX_wm_area(C);
ARegion *ar_back = CTX_wm_region(C);
+ CTX_wm_menu_set(C, NULL);
+
for (sa = CTX_wm_screen(C)->areabase.first; sa; sa = sa->next) {
ARegion *ar_iter;
CTX_wm_area_set(C, sa);
@@ -4418,7 +4569,8 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_quit_blender);
WM_operatortype_append(WM_OT_open_mainfile);
WM_operatortype_append(WM_OT_revert_mainfile);
- WM_operatortype_append(WM_OT_link_append);
+ WM_operatortype_append(WM_OT_link);
+ WM_operatortype_append(WM_OT_append);
WM_operatortype_append(WM_OT_recover_last_session);
WM_operatortype_append(WM_OT_recover_auto_save);
WM_operatortype_append(WM_OT_save_as_mainfile);
@@ -4431,6 +4583,7 @@ void wm_operatortype_init(void)
WM_operatortype_append(WM_OT_splash);
WM_operatortype_append(WM_OT_search_menu);
WM_operatortype_append(WM_OT_call_menu);
+ WM_operatortype_append(WM_OT_call_menu_pie);
WM_operatortype_append(WM_OT_radial_control);
#if defined(WIN32)
WM_operatortype_append(WM_OT_console_toggle);
@@ -4587,6 +4740,7 @@ static void gesture_border_modal_keymap(wmKeyConfig *keyconf)
WM_modalkeymap_assign(keymap, "VIEW3D_OT_render_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_select_border");
WM_modalkeymap_assign(keymap, "VIEW3D_OT_zoom_border"); /* XXX TODO: zoom border should perhaps map rightmouse to zoom out instead of in+cancel */
+ WM_modalkeymap_assign(keymap, "IMAGE_OT_render_border");
}
/* zoom to border modal operators */
@@ -4644,10 +4798,8 @@ void wm_window_keymap(wmKeyConfig *keyconf)
WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "WM_OT_open_mainfile", F1KEY, KM_PRESS, 0, 0);
- WM_keymap_add_item(keymap, "WM_OT_link_append", OKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
- kmi = WM_keymap_add_item(keymap, "WM_OT_link_append", F1KEY, KM_PRESS, KM_SHIFT, 0);
- RNA_boolean_set(kmi->ptr, "link", false);
- RNA_boolean_set(kmi->ptr, "instance_groups", false);
+ WM_keymap_add_item(keymap, "WM_OT_link", OKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+ WM_keymap_add_item(keymap, "WM_OT_append", F1KEY, KM_PRESS, KM_SHIFT, 0);
WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_CTRL, 0);
WM_keymap_add_item(keymap, "WM_OT_save_mainfile", WKEY, KM_PRESS, KM_CTRL, 0);
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index b7452206b27..76add2f9aac 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -98,6 +98,8 @@ typedef struct PlayState {
bool go;
/* waiting for images to load */
bool loading;
+ /* x/y image flip */
+ bool draw_flip[2];
int fstep;
@@ -168,6 +170,15 @@ static void playanim_window_get_size(int *width_r, int *height_r)
GHOST_DisposeRectangle(bounds);
}
+static void playanim_gl_matrix(void)
+{
+ /* unified matrix, note it affects offset for drawing */
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
+ glMatrixMode(GL_MODELVIEW);
+}
+
/* implementation */
static void playanim_event_qual_update(void)
{
@@ -245,7 +256,8 @@ static int pupdate_time(void)
static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf *ibuf, int fontid, int fstep)
{
- float offsx, offsy;
+ float offs_x, offs_y;
+ float span_x, span_y;
if (ibuf == NULL) {
printf("%s: no ibuf for picture '%s'\n", __func__, picture ? picture->name : "<NIL>");
@@ -260,13 +272,17 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
+ /* size within window */
+ span_x = (ps->zoom * ibuf->x) / (float)ps->win_x;
+ span_y = (ps->zoom * ibuf->y) / (float)ps->win_y;
+
/* offset within window */
- offsx = 0.5f * (((float)ps->win_x - ps->zoom * ibuf->x) / (float)ps->win_x);
- offsy = 0.5f * (((float)ps->win_y - ps->zoom * ibuf->y) / (float)ps->win_y);
+ offs_x = 0.5f * (1.0f - span_x);
+ offs_y = 0.5f * (1.0f - span_y);
- CLAMP(offsx, 0.0f, 1.0f);
- CLAMP(offsy, 0.0f, 1.0f);
- glRasterPos2f(offsx, offsy);
+ CLAMP(offs_x, 0.0f, 1.0f);
+ CLAMP(offs_y, 0.0f, 1.0f);
+ glRasterPos2f(offs_x, offs_y);
glClearColor(0.1, 0.1, 0.1, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
@@ -276,9 +292,15 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- fdrawcheckerboard(offsx, offsy, offsx + (ps->zoom * ibuf->x) / (float)ps->win_x, offsy + (ps->zoom * ibuf->y) / (float)ps->win_y);
+ fdrawcheckerboard(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
}
-
+
+ glRasterPos2f(offs_x + (ps->draw_flip[0] ? span_x : 0.0f),
+ offs_y + (ps->draw_flip[1] ? span_y : 0.0f));
+
+ glPixelZoom(ps->zoom * ps->draw_flip[0] ? -1.0f : 1.0f,
+ ps->zoom * ps->draw_flip[1] ? -1.0f : 1.0f);
+
glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
glDisable(GL_BLEND);
@@ -363,7 +385,7 @@ static void build_pict_list_ex(PlayState *ps, const char *first, int totframes,
size_t size;
int file;
- file = open(filepath, O_BINARY | O_RDONLY, 0);
+ file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
if (file < 0) {
/* print errno? */
return;
@@ -518,6 +540,14 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
case GHOST_kKeyP:
if (val) ps->pingpong = !ps->pingpong;
break;
+ case GHOST_kKeyF:
+ {
+ if (val) {
+ int axis = (g_WS.qual & WS_QUAL_SHIFT) ? 1 : 0;
+ ps->draw_flip[axis] = !ps->draw_flip[axis];
+ }
+ break;
+ }
case GHOST_kKey1:
case GHOST_kKeyNumpad1:
if (val) swaptime = ps->fstep / 60.0;
@@ -780,13 +810,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr ps_void)
glViewport(0, 0, ps->win_x, ps->win_y);
glScissor(0, 0, ps->win_x, ps->win_y);
- /* unified matrix, note it affects offset for drawing */
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
- glMatrixMode(GL_MODELVIEW);
+ playanim_gl_matrix();
- glPixelZoom(ps->zoom, ps->zoom);
ptottime = 0.0;
playanim_toscreen(ps, ps->picture, ps->curframe_ibuf, ps->fontid, ps->fstep);
@@ -891,6 +916,8 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
ps.dropped_file[0] = 0;
ps.zoom = 1.0f;
/* resetmap = false */
+ ps.draw_flip[0] = false;
+ ps.draw_flip[1] = false;
ps.fstep = 1;
@@ -1008,11 +1035,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
playanim_window_open("Blender:Anim", start_x, start_y, ibuf->x, ibuf->y);
- /* unified matrix, note it affects offset for drawing */
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
- glMatrixMode(GL_MODELVIEW);
+ playanim_gl_matrix();
}
GHOST_GetMainDisplayDimensions(g_WS.ghost_system, &maxwinx, &maxwiny);
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 1792ea40a1a..e26bcac9b1a 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -215,7 +215,7 @@ int wm_subwindow_open(wmWindow *win, const rcti *winrct)
/* extra service */
wm_swin_size_get(swin, &width, &height);
- wmOrtho2(-GLA_PIXEL_OFS, (float)width - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, (float)height - GLA_PIXEL_OFS);
+ wmOrtho2_pixelspace(width, height);
glLoadIdentity();
return swin->swinid;
@@ -272,7 +272,7 @@ void wm_subwindow_position(wmWindow *win, int swinid, const rcti *winrct)
/* extra service */
wmSubWindowSet(win, swinid);
wm_swin_size_get(swin, &width, &height);
- wmOrtho2(-GLA_PIXEL_OFS, (float)width - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, (float)height - GLA_PIXEL_OFS);
+ wmOrtho2_pixelspace(width, height);
}
else {
printf("%s: Internal error, bad winid: %d\n", __func__, swinid);
@@ -308,7 +308,7 @@ void wmSubWindowScissorSet(wmWindow *win, int swinid, const rcti *srct, bool src
int scissor_height = BLI_rcti_size_y(srct);
/* typically a single pixel doesn't matter,
- * but one pixel offset is noticable with viewport border render */
+ * but one pixel offset is noticeable with viewport border render */
if (srct_pad) {
scissor_width += 1;
scissor_height += 1;
@@ -319,7 +319,7 @@ void wmSubWindowScissorSet(wmWindow *win, int swinid, const rcti *srct, bool src
else
glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
- wmOrtho2(-GLA_PIXEL_OFS, (float)width - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, (float)height - GLA_PIXEL_OFS);
+ wmOrtho2_pixelspace(width, height);
glLoadIdentity();
glFlush();
@@ -358,6 +358,35 @@ void wmOrtho2(float x1, float x2, float y1, float y2)
wmOrtho(x1, x2, y1, y2, -100, 100);
}
+static void wmOrtho2_offset(const float x, const float y, const float ofs)
+{
+ wmOrtho2(ofs, x + ofs, ofs, y + ofs);
+}
+
+/**
+ * default pixel alignment.
+ */
+void wmOrtho2_region_pixelspace(const struct ARegion *ar)
+{
+ wmOrtho2_offset(ar->winx + 1, ar->winy + 1, -GLA_PIXEL_OFS);
+}
+
+void wmOrtho2_pixelspace(const float x, const float y)
+{
+ wmOrtho2_offset(x, y, -GLA_PIXEL_OFS);
+}
+
+/**
+ * use for drawing uiBlock, any UI elements and text.
+ * \note prevents blurry text with multi-sample (FSAA), see T41749
+ */
+void wmOrtho2_region_ui(const ARegion *ar)
+{
+ /* note, intentionally no '+ 1',
+ * as with wmOrtho2_region_pixelspace */
+ wmOrtho2_offset(ar->winx, ar->winy, -0.01f);
+}
+
/* *************************** Framebuffer color depth, for selection codes ********************** */
#ifdef __APPLE__
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 44e31f46167..46a20d3bf88 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -55,7 +55,6 @@
#include "BKE_global.h"
#include "BKE_main.h"
-#include "BIF_gl.h"
#include "RNA_access.h"
@@ -74,6 +73,8 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_init_exit.h"
+#include "GPU_glew.h"
#include "UI_interface.h"
@@ -319,8 +320,7 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
/* nothing to do for 'temp' windows,
* because WM_window_open_temp always sets window title */
}
- else {
-
+ else if (win->ghostwin) {
/* this is set to 1 if you don't have startup.blend open */
if (G.save_over && G.main->name[0]) {
char str[sizeof(G.main->name) + 24];
@@ -339,8 +339,21 @@ void wm_window_title(wmWindowManager *wm, wmWindow *win)
}
}
+float wm_window_pixelsize(wmWindow *win)
+{
+ float pixelsize = GHOST_GetNativePixelSize(win->ghostwin);
+
+ switch (U.virtual_pixel) {
+ default:
+ case VIRTUAL_PIXEL_NATIVE:
+ return pixelsize;
+ case VIRTUAL_PIXEL_DOUBLE:
+ return 2.0f * pixelsize;
+ }
+}
+
/* belongs to below */
-static void wm_window_add_ghostwindow(const char *title, wmWindow *win)
+static void wm_window_add_ghostwindow(wmWindowManager *wm, const char *title, wmWindow *win)
{
GHOST_WindowHandle ghostwin;
static int multisamples = -1;
@@ -364,8 +377,11 @@ static void wm_window_add_ghostwindow(const char *title, wmWindow *win)
if (ghostwin) {
GHOST_RectangleHandle bounds;
+ /* the new window has already been made drawable upon creation */
+ wm->windrawable = win;
+
/* needed so we can detect the graphics card below */
- GPU_extensions_init();
+ GPU_init();
win->ghostwin = ghostwin;
GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
@@ -397,7 +413,7 @@ static void wm_window_add_ghostwindow(const char *title, wmWindow *win)
/* displays with larger native pixels, like Macbook. Used to scale dpi with */
/* needed here, because it's used before it reads userdef */
- U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin);
+ U.pixelsize = wm_window_pixelsize(win);
BKE_userdef_state();
wm_window_swap_buffers(win);
@@ -431,8 +447,7 @@ void wm_window_add_ghostwindows(wmWindowManager *wm)
wm_init_state.start_x = 0;
wm_init_state.start_y = 0;
-
-#if !defined(__APPLE__) && !defined(WIN32) /* X11 */
+#ifdef WITH_X11 /* X11 */
/* X11, start maximized but use default sane size */
wm_init_state.size_x = min_ii(wm_init_state.size_x, WM_WIN_INIT_SIZE_X);
wm_init_state.size_y = min_ii(wm_init_state.size_y, WM_WIN_INIT_SIZE_Y);
@@ -461,7 +476,7 @@ void wm_window_add_ghostwindows(wmWindowManager *wm)
wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE;
}
- wm_window_add_ghostwindow("Blender", win);
+ wm_window_add_ghostwindow(wm, "Blender", win);
}
/* happens after fileread */
if (win->eventstate == NULL)
@@ -686,7 +701,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
GHOST_ActivateWindowDrawingContext(win->ghostwin);
/* this can change per window */
- U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin);
+ U.pixelsize = wm_window_pixelsize(win);
BKE_userdef_state();
}
}
@@ -747,7 +762,16 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
GHOST_TEventKeyData kdata;
wmEvent event;
int wx, wy;
-
+ const int keymodifier = ((query_qual(SHIFT) ? KM_SHIFT : 0) |
+ (query_qual(CONTROL) ? KM_CTRL : 0) |
+ (query_qual(ALT) ? KM_ALT : 0) |
+ (query_qual(OS) ? KM_OSKEY : 0));
+
+ /* Win23/GHOST modifier bug, see T40317 */
+#ifndef WIN32
+//# define USE_WIN_ACTIVATE
+#endif
+
wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
win->active = 1;
@@ -756,25 +780,69 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* bad ghost support for modifier keys... so on activate we set the modifiers again */
/* TODO: This is not correct since a modifier may be held when a window is activated...
- * better solve this at ghost level. attempted fix r54450 but it caused bug [#34255] */
+ * better solve this at ghost level. attempted fix r54450 but it caused bug [#34255]
+ *
+ * For now don't send GHOST_kEventKeyDown events, just set the 'eventstate'.
+ */
kdata.ascii = '\0';
kdata.utf8_buf[0] = '\0';
- if (win->eventstate->shift && !query_qual(SHIFT)) {
- kdata.key = GHOST_kKeyLeftShift;
- wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
+
+ if (win->eventstate->shift) {
+ if ((keymodifier & KM_SHIFT) == 0) {
+ kdata.key = GHOST_kKeyLeftShift;
+ wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
+ }
+ }
+#ifdef USE_WIN_ACTIVATE
+ else {
+ if (keymodifier & KM_SHIFT) {
+ win->eventstate->shift = KM_MOD_FIRST;
+ }
+ }
+#endif
+ if (win->eventstate->ctrl) {
+ if ((keymodifier & KM_CTRL) == 0) {
+ kdata.key = GHOST_kKeyLeftControl;
+ wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
+ }
+ }
+#ifdef USE_WIN_ACTIVATE
+ else {
+ if (keymodifier & KM_CTRL) {
+ win->eventstate->ctrl = KM_MOD_FIRST;
+ }
+ }
+#endif
+ if (win->eventstate->alt) {
+ if ((keymodifier & KM_ALT) == 0) {
+ kdata.key = GHOST_kKeyLeftAlt;
+ wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
+ }
}
- if (win->eventstate->ctrl && !query_qual(CONTROL)) {
- kdata.key = GHOST_kKeyLeftControl;
- wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
+#ifdef USE_WIN_ACTIVATE
+ else {
+ if (keymodifier & KM_ALT) {
+ win->eventstate->alt = KM_MOD_FIRST;
+ }
}
- if (win->eventstate->alt && !query_qual(ALT)) {
- kdata.key = GHOST_kKeyLeftAlt;
- wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
+#endif
+ if (win->eventstate->oskey) {
+ if ((keymodifier & KM_OSKEY) == 0) {
+ kdata.key = GHOST_kKeyOS;
+ wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
+ }
}
- if (win->eventstate->oskey && !query_qual(OS)) {
- kdata.key = GHOST_kKeyOS;
- wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
+#ifdef USE_WIN_ACTIVATE
+ else {
+ if (keymodifier & KM_OSKEY) {
+ win->eventstate->oskey = KM_MOD_FIRST;
+ }
}
+#endif
+
+#undef USE_WIN_ACTIVATE
+
+
/* keymodifier zero, it hangs on hotkeys that open windows otherwise */
win->eventstate->keymodifier = 0;
@@ -921,14 +989,15 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
const char *path = GHOST_GetEventData(evt);
if (path) {
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_open_mainfile", false);
/* operator needs a valid window in context, ensures
* it is correctly set */
oldWindow = CTX_wm_window(C);
CTX_wm_window_set(C, win);
- WM_operator_properties_create(&props_ptr, "WM_OT_open_mainfile");
+ WM_operator_properties_create_ptr(&props_ptr, ot);
RNA_string_set(&props_ptr, "filepath", path);
- WM_operator_name_call(C, "WM_OT_open_mainfile", WM_OP_EXEC_DEFAULT, &props_ptr);
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr);
WM_operator_properties_free(&props_ptr);
CTX_wm_window_set(C, oldWindow);
@@ -962,7 +1031,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* make blender drop event with custom data pointing to wm drags */
event.type = EVT_DROP;
event.val = KM_RELEASE;
- event.custom = EVT_DATA_LISTBASE;
+ event.custom = EVT_DATA_DRAGDROP;
event.customdata = &wm->drags;
event.customdatafree = 1;
@@ -981,7 +1050,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* try to get icon type from extension */
icon = ED_file_extension_icon((char *)stra->strings[a]);
- WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0);
+ WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0, WM_DRAG_NOP);
/* void poin should point to string, it makes a copy */
break; /* only one drop element supported now */
}
@@ -992,7 +1061,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
case GHOST_kEventNativeResolutionChange:
// printf("change, pixel size %f\n", GHOST_GetNativePixelSize(win->ghostwin));
- U.pixelsize = GHOST_GetNativePixelSize(win->ghostwin);
+ U.pixelsize = wm_window_pixelsize(win);
BKE_userdef_state();
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
@@ -1359,9 +1428,9 @@ void wm_window_set_swap_interval (wmWindow *win, int interval)
GHOST_SetSwapInterval(win->ghostwin, interval);
}
-int wm_window_get_swap_interval (wmWindow *win)
+bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut)
{
- return GHOST_GetSwapInterval(win->ghostwin);
+ return GHOST_GetSwapInterval(win->ghostwin, intervalOut);
}
@@ -1412,6 +1481,9 @@ void WM_cursor_warp(wmWindow *win, int x, int y)
win->eventstate->prevx = oldx;
win->eventstate->prevy = oldy;
+
+ win->eventstate->x = oldx;
+ win->eventstate->y = oldy;
}
}
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index df084554c54..d1a94194108 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -81,8 +81,9 @@ enum {
/* handler flag */
enum {
- WM_HANDLER_BLOCKING = 1, /* after this handler all others are ignored */
- WM_HANDLER_DO_FREE = 2 /* handler tagged to be freed in wm_handlers_do() */
+ 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 */
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 4a274d25170..7dfc2b52c33 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -36,92 +36,230 @@
#define __WM_EVENT_TYPES_H__
/* customdata type */
-#define EVT_DATA_GESTURE 1
-#define EVT_DATA_TIMER 2
-#define EVT_DATA_LISTBASE 3
-#define EVT_DATA_NDOF_MOTION 4
+enum {
+ EVT_DATA_GESTURE = 1,
+ EVT_DATA_TIMER = 2,
+ EVT_DATA_DRAGDROP = 3,
+ EVT_DATA_NDOF_MOTION = 4,
+};
/* tablet active, matches GHOST_TTabletMode */
-#define EVT_TABLET_NONE 0
-#define EVT_TABLET_STYLUS 1
-#define EVT_TABLET_ERASER 2
-
-
-/* *** wmEvent.type *** */
-
-/* non-event, for example disabled timer */
-#define EVENT_NONE 0
-/* MOUSE : 0x00x */
-#define LEFTMOUSE 1
-#define MIDDLEMOUSE 2
-#define RIGHTMOUSE 3
-#define MOUSEMOVE 4
- /* only use if you want user option switch possible */
-#define ACTIONMOUSE 5
-#define SELECTMOUSE 6
- /* Extra mouse buttons */
-#define BUTTON4MOUSE 7
-#define BUTTON5MOUSE 8
- /* More mouse buttons - can't use 9 and 10 here (wheel) */
-#define BUTTON6MOUSE 18
-#define BUTTON7MOUSE 19
- /* Extra trackpad gestures */
-#define MOUSEPAN 14
-#define MOUSEZOOM 15
-#define MOUSEROTATE 16
- /* defaults from ghost */
-#define WHEELUPMOUSE 10
-#define WHEELDOWNMOUSE 11
- /* mapped with userdef */
-#define WHEELINMOUSE 12
-#define WHEELOUTMOUSE 13
- /* Successive MOUSEMOVE's are converted to this, so we can easily
- * ignore all but the most recent MOUSEMOVE (for better performance),
- * paint and drawing tools however will want to handle these. */
-#define INBETWEEN_MOUSEMOVE 17
-
-
-/* NDOF (from SpaceNavigator & friends)
- * These should be kept in sync with GHOST_NDOFManager.h
- * Ordering matters, exact values do not. */
-
-#define NDOF_MOTION 400
+enum {
+ EVT_TABLET_NONE = 0,
+ EVT_TABLET_STYLUS = 1,
+ EVT_TABLET_ERASER = 2,
+};
+/* ********** wmEvent.type ********** */
enum {
- // used internally, never sent
+ /* non-event, for example disabled timer */
+ EVENT_NONE = 0x0000,
+
+ /* ********** Start of Input devices. ********** */
+
+ /* MOUSE : 0x000x, 0x001x */
+ LEFTMOUSE = 0x0001,
+ MIDDLEMOUSE = 0x0002,
+ RIGHTMOUSE = 0x0003,
+ MOUSEMOVE = 0x0004,
+ /* only use if you want user option switch possible */
+ ACTIONMOUSE = 0x0005,
+ SELECTMOUSE = 0x0006,
+ /* Extra mouse buttons */
+ BUTTON4MOUSE = 0x0007,
+ BUTTON5MOUSE = 0x0008,
+ /* More mouse buttons - can't use 9 and 10 here (wheel) */
+ BUTTON6MOUSE = 0x0012,
+ BUTTON7MOUSE = 0x0013,
+ /* Extra trackpad gestures */
+ MOUSEPAN = 0x000e,
+ MOUSEZOOM = 0x000f,
+ MOUSEROTATE = 0x0010,
+ /* defaults from ghost */
+ WHEELUPMOUSE = 0x000a,
+ WHEELDOWNMOUSE = 0x000b,
+ /* mapped with userdef */
+ WHEELINMOUSE = 0x000c,
+ WHEELOUTMOUSE = 0x000d,
+ /* Successive MOUSEMOVE's are converted to this, so we can easily
+ * ignore all but the most recent MOUSEMOVE (for better performance),
+ * paint and drawing tools however will want to handle these. */
+ INBETWEEN_MOUSEMOVE = 0x0011,
+
+ /* *** Start of keyboard codes. *** */
+
+ /* standard keyboard.
+ * XXX from 0x0020 to 0x00ff, and 0x012c to 0x013f for function keys! */
+ AKEY = 0x0061, /* 'a' */
+ BKEY = 0x0062, /* 'b' */
+ CKEY = 0x0063, /* 'c' */
+ DKEY = 0x0064, /* 'd' */
+ EKEY = 0x0065, /* 'e' */
+ FKEY = 0x0066, /* 'f' */
+ GKEY = 0x0067, /* 'g' */
+#ifndef WIN32
+ HKEY = 0x0068, /* 'h' */
+#else
+#define HKEY 0x0068
+#endif
+ IKEY = 0x0069, /* 'i' */
+ JKEY = 0x006a, /* 'j' */
+ KKEY = 0x006b, /* 'k' */
+ LKEY = 0x006c, /* 'l' */
+ MKEY = 0x006d, /* 'm' */
+ NKEY = 0x006e, /* 'n' */
+ OKEY = 0x006f, /* 'o' */
+ PKEY = 0x0070, /* 'p' */
+ QKEY = 0x0071, /* 'q' */
+ RKEY = 0x0072, /* 'r' */
+ SKEY = 0x0073, /* 's' */
+ TKEY = 0x0074, /* 't' */
+ UKEY = 0x0075, /* 'u' */
+ VKEY = 0x0076, /* 'v' */
+ WKEY = 0x0077, /* 'w' */
+ XKEY = 0x0078, /* 'x' */
+ YKEY = 0x0079, /* 'y' */
+ ZKEY = 0x007a, /* 'z' */
+
+ ZEROKEY = 0x0030, /* '0' */
+ ONEKEY = 0x0031, /* '1' */
+ TWOKEY = 0x0032, /* '2' */
+ THREEKEY = 0x0033, /* '3' */
+ FOURKEY = 0x0034, /* '4' */
+ FIVEKEY = 0x0035, /* '5' */
+ SIXKEY = 0x0036, /* '6' */
+ SEVENKEY = 0x0037, /* '7' */
+ EIGHTKEY = 0x0038, /* '8' */
+ NINEKEY = 0x0039, /* '9' */
+
+ CAPSLOCKKEY = 0x00d3, /* 211 */
+
+ LEFTCTRLKEY = 0x00d4, /* 212 */
+ LEFTALTKEY = 0x00d5, /* 213 */
+ RIGHTALTKEY = 0x00d6, /* 214 */
+ RIGHTCTRLKEY = 0x00d7, /* 215 */
+ RIGHTSHIFTKEY = 0x00d8, /* 216 */
+ LEFTSHIFTKEY = 0x00d9, /* 217 */
+
+ ESCKEY = 0x00da, /* 218 */
+ TABKEY = 0x00db, /* 219 */
+ RETKEY = 0x00dc, /* 220 */
+ SPACEKEY = 0x00dd, /* 221 */
+ LINEFEEDKEY = 0x00de, /* 222 */
+ BACKSPACEKEY = 0x00df, /* 223 */
+ DELKEY = 0x00e0, /* 224 */
+ SEMICOLONKEY = 0x00e1, /* 225 */
+ PERIODKEY = 0x00e2, /* 226 */
+ COMMAKEY = 0x00e3, /* 227 */
+ QUOTEKEY = 0x00e4, /* 228 */
+ ACCENTGRAVEKEY = 0x00e5, /* 229 */
+ MINUSKEY = 0x00e6, /* 230 */
+ SLASHKEY = 0x00e8, /* 232 */
+ BACKSLASHKEY = 0x00e9, /* 233 */
+ EQUALKEY = 0x00ea, /* 234 */
+ LEFTBRACKETKEY = 0x00eb, /* 235 */
+ RIGHTBRACKETKEY = 0x00ec, /* 236 */
+
+ LEFTARROWKEY = 0x0089, /* 137 */
+ DOWNARROWKEY = 0x008a, /* 138 */
+ RIGHTARROWKEY = 0x008b, /* 139 */
+ UPARROWKEY = 0x008c, /* 140 */
+
+ PAD0 = 0x0096, /* 150 */
+ PAD1 = 0x0097, /* 151 */
+ PAD2 = 0x0098, /* 152 */
+ PAD3 = 0x0099, /* 153 */
+ PAD4 = 0x009a, /* 154 */
+ PAD5 = 0x009b, /* 155 */
+ PAD6 = 0x009c, /* 156 */
+ PAD7 = 0x009d, /* 157 */
+ PAD8 = 0x009e, /* 158 */
+ PAD9 = 0x009f, /* 159 */
+
+ PADPERIOD = 0x00c7, /* 199 */
+ PADASTERKEY = 0x00a0, /* 160 */
+ PADSLASHKEY = 0x00a1, /* 161 */
+ PADMINUS = 0x00a2, /* 162 */
+ PADENTER = 0x00a3, /* 163 */
+ PADPLUSKEY = 0x00a4, /* 164 */
+
+ PAUSEKEY = 0x00a5, /* 165 */
+ INSERTKEY = 0x00a6, /* 166 */
+ HOMEKEY = 0x00a7, /* 167 */
+ PAGEUPKEY = 0x00a8, /* 168 */
+ PAGEDOWNKEY = 0x00a9, /* 169 */
+ ENDKEY = 0x00aa, /* 170 */
+
+ UNKNOWNKEY = 0x00ab, /* 171 */
+ OSKEY = 0x00ac, /* 172 */
+ GRLESSKEY = 0x00ad, /* 173 */
+
+ /* XXX: are these codes ok? */
+ MEDIAPLAY = 0x00ae, /* 174 */
+ MEDIASTOP = 0x00af, /* 175 */
+ MEDIAFIRST = 0x00b0, /* 176 */
+ MEDIALAST = 0x00b1, /* 177 */
+
+ F1KEY = 0x012c, /* 300 */
+ F2KEY = 0x012d, /* 301 */
+ F3KEY = 0x012e, /* 302 */
+ F4KEY = 0x012f, /* 303 */
+ F5KEY = 0x0130, /* 304 */
+ F6KEY = 0x0131, /* 305 */
+ F7KEY = 0x0132, /* 306 */
+ F8KEY = 0x0133, /* 307 */
+ F9KEY = 0x0134, /* 308 */
+ F10KEY = 0x0135, /* 309 */
+ F11KEY = 0x0136, /* 310 */
+ F12KEY = 0x0137, /* 311 */
+ F13KEY = 0x0138, /* 312 */
+ F14KEY = 0x0139, /* 313 */
+ F15KEY = 0x013a, /* 314 */
+ F16KEY = 0x013b, /* 315 */
+ F17KEY = 0x013c, /* 316 */
+ F18KEY = 0x013d, /* 317 */
+ F19KEY = 0x013e, /* 318 */
+
+ /* *** End of keyboard codes. *** */
+
+ /* NDOF (from SpaceNavigator & friends)
+ * These should be kept in sync with GHOST_NDOFManager.h
+ * Ordering matters, exact values do not. */
+ NDOF_MOTION = 0x0190,
+ /* used internally, never sent */
NDOF_BUTTON_NONE = NDOF_MOTION,
- // these two are available from any 3Dconnexion device
+ /* these two are available from any 3Dconnexion device */
NDOF_BUTTON_MENU,
NDOF_BUTTON_FIT,
- // standard views
+ /* standard views */
NDOF_BUTTON_TOP,
NDOF_BUTTON_BOTTOM,
NDOF_BUTTON_LEFT,
NDOF_BUTTON_RIGHT,
NDOF_BUTTON_FRONT,
NDOF_BUTTON_BACK,
- // more views
+ /* more views */
NDOF_BUTTON_ISO1,
NDOF_BUTTON_ISO2,
- // 90 degree rotations
+ /* 90 degree rotations */
NDOF_BUTTON_ROLL_CW,
NDOF_BUTTON_ROLL_CCW,
NDOF_BUTTON_SPIN_CW,
NDOF_BUTTON_SPIN_CCW,
NDOF_BUTTON_TILT_CW,
NDOF_BUTTON_TILT_CCW,
- // device control
+ /* device control */
NDOF_BUTTON_ROTATE,
NDOF_BUTTON_PANZOOM,
NDOF_BUTTON_DOMINANT,
NDOF_BUTTON_PLUS,
NDOF_BUTTON_MINUS,
- // keyboard emulation
+ /* keyboard emulation */
NDOF_BUTTON_ESC,
NDOF_BUTTON_ALT,
NDOF_BUTTON_SHIFT,
NDOF_BUTTON_CTRL,
- // general-purpose buttons
+ /* general-purpose buttons */
NDOF_BUTTON_1,
NDOF_BUTTON_2,
NDOF_BUTTON_3,
@@ -132,180 +270,82 @@ enum {
NDOF_BUTTON_8,
NDOF_BUTTON_9,
NDOF_BUTTON_10,
- // more general-purpose buttons
+ /* more general-purpose buttons */
NDOF_BUTTON_A,
NDOF_BUTTON_B,
NDOF_BUTTON_C,
- // the end
- NDOF_LAST
+ /* the end */
+ NDOF_LAST,
+
+ /* ********** End of Input devices. ********** */
+
+ /* ********** Start of Blender internal events. ********** */
+
+ /* XXX Those are mixed inside keyboard 'area'! */
+ /* System: 0x010x */
+ INPUTCHANGE = 0x0103, /* input connected or disconnected */
+ WINDEACTIVATE = 0x0104, /* window is deactivated, focus lost */
+ /* Timer: 0x011x */
+ TIMER = 0x0110, /* timer event, passed on to all queues */
+ TIMER0 = 0x0111, /* timer event, slot for internal use */
+ TIMER1 = 0x0112, /* timer event, slot for internal use */
+ TIMER2 = 0x0113, /* timer event, slot for internal use */
+ TIMERJOBS = 0x0114, /* timer event, jobs system */
+ TIMERAUTOSAVE = 0x0115, /* timer event, autosave */
+ TIMERREPORT = 0x0116, /* timer event, reports */
+ TIMERREGION = 0x0117, /* timer event, region slide in/out */
+ TIMERF = 0x011F, /* last timer */
+
+ /* Tweak, gestures: 0x500x, 0x501x */
+ EVT_ACTIONZONE_AREA = 0x5000,
+ EVT_ACTIONZONE_REGION = 0x5001,
+ EVT_ACTIONZONE_FULLSCREEN = 0x5002,
+ /* tweak events, for L M R mousebuttons */
+ EVT_TWEAK_L = 0x5003,
+ EVT_TWEAK_M = 0x5004,
+ EVT_TWEAK_R = 0x5005,
+ /* tweak events for action or select mousebutton */
+ EVT_TWEAK_A = 0x5006,
+ EVT_TWEAK_S = 0x5007,
+ EVT_GESTURE = 0x5010,
+
+ /* Misc Blender internals: 0x502x */
+ EVT_FILESELECT = 0x5020,
+ EVT_BUT_OPEN = 0x5021,
+ EVT_MODAL_MAP = 0x5022,
+ EVT_DROP = 0x5023,
+ EVT_BUT_CANCEL = 0x5024,
+
+ /* ********** End of Blender internal events. ********** */
};
-/* SYSTEM : 0x01xx */
-#define INPUTCHANGE 0x0103 /* input connected or disconnected */
-#define WINDEACTIVATE 0x0104 /* window is deactivated, focus lost */
-
-#define TIMER 0x0110 /* timer event, passed on to all queues */
-#define TIMER0 0x0111 /* timer event, slot for internal use */
-#define TIMER1 0x0112 /* timer event, slot for internal use */
-#define TIMER2 0x0113 /* timer event, slot for internal use */
-#define TIMERJOBS 0x0114 /* timer event, jobs system */
-#define TIMERAUTOSAVE 0x0115 /* timer event, autosave */
-#define TIMERREPORT 0x0116 /* timer event, reports */
-#define TIMERREGION 0x0117 /* timer event, region slide in/out */
-#define TIMERF 0x011F /* last timer */
+/* *********** wmEvent.type helpers. ********** */
/* test whether the event is timer event */
#define ISTIMER(event_type) (event_type >= TIMER && event_type <= TIMERF)
-/* standard keyboard */
-#define AKEY 'a'
-#define BKEY 'b'
-#define CKEY 'c'
-#define DKEY 'd'
-#define EKEY 'e'
-#define FKEY 'f'
-#define GKEY 'g'
-#define HKEY 'h'
-#define IKEY 'i'
-#define JKEY 'j'
-#define KKEY 'k'
-#define LKEY 'l'
-#define MKEY 'm'
-#define NKEY 'n'
-#define OKEY 'o'
-#define PKEY 'p'
-#define QKEY 'q'
-#define RKEY 'r'
-#define SKEY 's'
-#define TKEY 't'
-#define UKEY 'u'
-#define VKEY 'v'
-#define WKEY 'w'
-#define XKEY 'x'
-#define YKEY 'y'
-#define ZKEY 'z'
-
-#define ZEROKEY '0'
-#define ONEKEY '1'
-#define TWOKEY '2'
-#define THREEKEY '3'
-#define FOURKEY '4'
-#define FIVEKEY '5'
-#define SIXKEY '6'
-#define SEVENKEY '7'
-#define EIGHTKEY '8'
-#define NINEKEY '9'
-
-#define CAPSLOCKKEY 211
-
-#define LEFTCTRLKEY 212
-#define LEFTALTKEY 213
-#define RIGHTALTKEY 214
-#define RIGHTCTRLKEY 215
-#define RIGHTSHIFTKEY 216
-#define LEFTSHIFTKEY 217
-
-#define ESCKEY 218
-#define TABKEY 219
-#define RETKEY 220
-#define SPACEKEY 221
-#define LINEFEEDKEY 222
-#define BACKSPACEKEY 223
-#define DELKEY 224
-#define SEMICOLONKEY 225
-#define PERIODKEY 226
-#define COMMAKEY 227
-#define QUOTEKEY 228
-#define ACCENTGRAVEKEY 229
-#define MINUSKEY 230
-#define SLASHKEY 232
-#define BACKSLASHKEY 233
-#define EQUALKEY 234
-#define LEFTBRACKETKEY 235
-#define RIGHTBRACKETKEY 236
-
-#define LEFTARROWKEY 137
-#define DOWNARROWKEY 138
-#define RIGHTARROWKEY 139
-#define UPARROWKEY 140
-
-#define PAD0 150
-#define PAD1 151
-#define PAD2 152
-#define PAD3 153
-#define PAD4 154
-#define PAD5 155
-#define PAD6 156
-#define PAD7 157
-#define PAD8 158
-#define PAD9 159
-
-
-#define PADPERIOD 199
-#define PADSLASHKEY 161
-#define PADASTERKEY 160
-
-#define PADMINUS 162
-#define PADENTER 163
-#define PADPLUSKEY 164
-
-#define F1KEY 300
-#define F2KEY 301
-#define F3KEY 302
-#define F4KEY 303
-#define F5KEY 304
-#define F6KEY 305
-#define F7KEY 306
-#define F8KEY 307
-#define F9KEY 308
-#define F10KEY 309
-#define F11KEY 310
-#define F12KEY 311
-#define F13KEY 312
-#define F14KEY 313
-#define F15KEY 314
-#define F16KEY 315
-#define F17KEY 316
-#define F18KEY 317
-#define F19KEY 318
-
-#define PAUSEKEY 165
-#define INSERTKEY 166
-#define HOMEKEY 167
-#define PAGEUPKEY 168
-#define PAGEDOWNKEY 169
-#define ENDKEY 170
-
-#define UNKNOWNKEY 171
-#define OSKEY 172
-#define GRLESSKEY 173
-
-// XXX: are these codes ok?
-#define MEDIAPLAY 174
-#define MEDIASTOP 175
-#define MEDIAFIRST 176
-#define MEDIALAST 177
-
/* for event checks */
- /* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */
- /* UNUSED - see wm_eventmatch - BUG [#30479] */
-// #define ISTEXTINPUT(event_type) (event_type >= ' ' && event_type <= 255)
+/* only used for KM_TEXTINPUT, so assume that we want all user-inputtable ascii codes included */
+/* UNUSED - see wm_eventmatch - BUG [#30479] */
+/* #define ISTEXTINPUT(event_type) (event_type >= ' ' && event_type <= 255) */
/* note, an alternative could be to check 'event->utf8_buf' */
- /* test whether the event is a key on the keyboard */
-#define ISKEYBOARD(event_type) (event_type >= ' ' && event_type <= 320)
+/* test whether the event is a key on the keyboard */
+#define ISKEYBOARD(event_type) \
+ ((event_type >= 0x0020 && event_type <= 0x00ff) || \
+ (event_type >= 0x012c && event_type <= 0x013f))
- /* test whether the event is a modifier key */
+/* test whether the event is a modifier key */
#define ISKEYMODIFIER(event_type) ((event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) || event_type == OSKEY)
- /* test whether the event is a mouse button */
+/* test whether the event is a mouse button */
#define ISMOUSE(event_type) (event_type >= LEFTMOUSE && event_type <= BUTTON7MOUSE)
- /* test whether the event is tweak event */
+/* test whether the event is tweak event */
#define ISTWEAK(event_type) (event_type >= EVT_TWEAK_L && event_type <= EVT_GESTURE)
- /* test whether the event is a NDOF event */
+/* test whether the event is a NDOF event */
#define ISNDOF(event_type) (event_type >= NDOF_MOTION && event_type < NDOF_LAST)
/* test whether event type is acceptable as hotkey, excluding modifiers */
@@ -315,76 +355,61 @@ enum {
(event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == false && \
(event_type >= UNKNOWNKEY && event_type <= GRLESSKEY) == false)
-/* **************** BLENDER GESTURE EVENTS (0x5000) **************** */
-
-#define EVT_ACTIONZONE_AREA 20480
-#define EVT_ACTIONZONE_REGION 20481
-
- /* tweak events, for L M R mousebuttons */
-#define EVT_TWEAK_L 20482
-#define EVT_TWEAK_M 20483
-#define EVT_TWEAK_R 20484
- /* tweak events for action or select mousebutton */
-#define EVT_TWEAK_A 20485
-#define EVT_TWEAK_S 20486
-
-#define EVT_GESTURE 20496
-
-/* value of tweaks and line gestures, note, KM_ANY (-1) works for this case too */
-#define EVT_GESTURE_N 1
-#define EVT_GESTURE_NE 2
-#define EVT_GESTURE_E 3
-#define EVT_GESTURE_SE 4
-#define EVT_GESTURE_S 5
-#define EVT_GESTURE_SW 6
-#define EVT_GESTURE_W 7
-#define EVT_GESTURE_NW 8
-/* value of corner gestures */
-#define EVT_GESTURE_N_E 9
-#define EVT_GESTURE_N_W 10
-#define EVT_GESTURE_E_N 11
-#define EVT_GESTURE_E_S 12
-#define EVT_GESTURE_S_E 13
-#define EVT_GESTURE_S_W 14
-#define EVT_GESTURE_W_S 15
-#define EVT_GESTURE_W_N 16
-
-/* **************** OTHER BLENDER EVENTS ********************* */
-
-/* event->type */
-#define EVT_FILESELECT 0x5020
-
-/* event->val */
-#define EVT_FILESELECT_OPEN 1
-#define EVT_FILESELECT_FULL_OPEN 2
-#define EVT_FILESELECT_EXEC 3
-#define EVT_FILESELECT_CANCEL 4
-#define EVT_FILESELECT_EXTERNAL_CANCEL 5
-
-/* event->type */
-#define EVT_BUT_OPEN 0x5021
-#define EVT_MODAL_MAP 0x5022
-#define EVT_DROP 0x5023
-#define EVT_BUT_CANCEL 0x5024
-
-/* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
-#define GESTURE_MODAL_CANCEL 1
-#define GESTURE_MODAL_CONFIRM 2
-
-#define GESTURE_MODAL_SELECT 3
-#define GESTURE_MODAL_DESELECT 4
-
-#define GESTURE_MODAL_NOP 5 /* circle select when no mouse button is pressed */
-
-#define GESTURE_MODAL_CIRCLE_ADD 6 /* circle sel: larger brush */
-#define GESTURE_MODAL_CIRCLE_SUB 7 /* circle sel: smaller brush */
-
-#define GESTURE_MODAL_BEGIN 8 /* border select/straight line, activate, use release to detect which button */
-
-#define GESTURE_MODAL_IN 9
-#define GESTURE_MODAL_OUT 10
-
-#define GESTURE_MODAL_CIRCLE_SIZE 11 /* circle sel: size brush (for trackpad event) */
+
+/* ********** wmEvent.val ********** */
+
+/* Gestures */
+enum {
+ /* value of tweaks and line gestures, note, KM_ANY (-1) works for this case too */
+ EVT_GESTURE_N = 1,
+ EVT_GESTURE_NE = 2,
+ EVT_GESTURE_E = 3,
+ EVT_GESTURE_SE = 4,
+ EVT_GESTURE_S = 5,
+ EVT_GESTURE_SW = 6,
+ EVT_GESTURE_W = 7,
+ EVT_GESTURE_NW = 8,
+ /* value of corner gestures */
+ EVT_GESTURE_N_E = 9,
+ EVT_GESTURE_N_W = 10,
+ EVT_GESTURE_E_N = 11,
+ EVT_GESTURE_E_S = 12,
+ EVT_GESTURE_S_E = 13,
+ EVT_GESTURE_S_W = 14,
+ EVT_GESTURE_W_S = 15,
+ EVT_GESTURE_W_N = 16,
+};
+
+/* File select */
+enum {
+ EVT_FILESELECT_OPEN = 1,
+ EVT_FILESELECT_FULL_OPEN = 2,
+ EVT_FILESELECT_EXEC = 3,
+ EVT_FILESELECT_CANCEL = 4,
+ EVT_FILESELECT_EXTERNAL_CANCEL = 5,
+};
+
+/* Gesture */
+/* NOTE: these values are saved in keymap files, do not change them but just add new ones */
+enum {
+ GESTURE_MODAL_CANCEL = 1,
+ GESTURE_MODAL_CONFIRM = 2,
+
+ GESTURE_MODAL_SELECT = 3,
+ GESTURE_MODAL_DESELECT = 4,
+
+ GESTURE_MODAL_NOP = 5, /* circle select when no mouse button is pressed */
+
+ GESTURE_MODAL_CIRCLE_ADD = 6, /* circle sel: larger brush */
+ GESTURE_MODAL_CIRCLE_SUB = 7, /* circle sel: smaller brush */
+
+ GESTURE_MODAL_BEGIN = 8, /* border select/straight line, activate, use release to detect which button */
+
+ GESTURE_MODAL_IN = 9,
+ GESTURE_MODAL_OUT = 10,
+
+ GESTURE_MODAL_CIRCLE_SIZE = 11, /* circle sel: size brush (for trackpad event) */
+};
#endif /* __WM_EVENT_TYPES_H__ */
diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h
index e0639b098a8..9c9c79d2f54 100644
--- a/source/blender/windowmanager/wm_window.h
+++ b/source/blender/windowmanager/wm_window.h
@@ -58,8 +58,10 @@ 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_swap_buffers (wmWindow *win);
-void wm_window_set_swap_interval (wmWindow *win, int interval);
-int wm_window_get_swap_interval (wmWindow *win);
+void wm_window_set_swap_interval(wmWindow *win, int interval);
+bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut);
+
+float wm_window_pixelsize(wmWindow *win);
void wm_get_cursor_position (wmWindow *win, int *x, int *y);
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index c952c56485c..9cd5763847a 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -152,9 +152,11 @@ endif()
bf_intern_raskter
bf_intern_opencolorio
bf_intern_opennl
+ bf_intern_glew_mx
extern_rangetree
extern_wcwidth
extern_libmv
+ extern_glog
)
if(WITH_MOD_CLOTH_ELTOPO)
@@ -162,7 +164,7 @@ endif()
endif()
if(NOT WITH_SYSTEM_GLEW)
- list(APPEND BLENDER_SORTED_LIBS extern_glew)
+ list(APPEND BLENDER_SORTED_LIBS ${BLENDER_GLEW_LIBRARIES})
endif()
if(WITH_LZMA)
@@ -228,3 +230,9 @@ if(WITH_PLAYER)
endif()
setup_liblinks(blenderplayer)
+
+# We put CLEW and CUEW here because OPENSUBDIV_LIBRARIES dpeends on them..
+if(WITH_CYCLES OR WITH_COMPOSITOR OR WITH_OPENSUBDIV)
+ target_link_libraries(blenderplayer "extern_clew")
+ target_link_libraries(blenderplayer "extern_cuew")
+endif()
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index af6541e9008..0846e37178d 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -45,6 +45,7 @@ struct ARegion;
struct ARegionType;
struct BMEditMesh;
struct Base;
+struct BoundBox;
struct Brush;
struct CSG_FaceIteratorDescriptor;
struct CSG_VertexIteratorDescriptor;
@@ -141,6 +142,7 @@ struct wmWindowManager;
#include "../../intern/dualcon/dualcon.h"
#include "../../intern/elbeem/extern/elbeem.h"
#include "../blender/blenkernel/BKE_modifier.h"
+#include "../blender/blenkernel/BKE_paint.h"
#include "../blender/collada/collada.h"
#include "../blender/compositor/COM_compositor.h"
#include "../blender/editors/include/ED_armature.h"
@@ -167,6 +169,7 @@ struct wmWindowManager;
#include "../blender/editors/include/UI_interface_icons.h"
#include "../blender/editors/include/UI_resources.h"
#include "../blender/editors/include/UI_view2d.h"
+#include "../blender/freestyle/FRS_freestyle.h"
#include "../blender/python/BPY_extern.h"
#include "../blender/render/extern/include/RE_engine.h"
#include "../blender/render/extern/include/RE_pipeline.h"
@@ -218,6 +221,8 @@ void *g_system;
float *RE_RenderLayerGetPass(struct RenderLayer *rl, int passtype) RET_NULL
float RE_filter_value(int type, float x) RET_ZERO
struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name) RET_NULL
+void RE_init_texture_rng() RET_NONE
+void RE_exit_texture_rng() RET_NONE
/* zbuf.c stub */
void antialias_tagbuf(int xsize, int ysize, char *rectmove) RET_NONE
@@ -228,6 +233,7 @@ void ibuf_sample(struct ImBuf *ibuf, float fx, float fy, float dx, float dy, flo
/* Freestyle */
bool ED_texture_context_check_linestyle(const struct bContext *C) RET_ZERO
+void FRS_free_view_map_cache(void) RET_NONE
/* texture.c */
int multitex_ext(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage) RET_ZERO
@@ -244,6 +250,9 @@ struct Render *RE_GetRender(const char *name) RET_NULL
float RE_lamp_get_data(struct ShadeInput *shi, struct Object *lamp_obj, float col[4], float lv[3], float *dist, float shadow[4]) RET_ZERO
/* blenkernel */
+bool BKE_paint_proj_mesh_data_check(struct Scene *scene, struct Object *ob, bool *uvs, bool *mat, bool *tex, bool *stencil) RET_ZERO
+
+/* render */
void RE_FreeRenderResult(struct RenderResult *res) RET_NONE
void RE_FreeAllRenderResults(void) RET_NONE
struct RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty) RET_NULL
@@ -300,6 +309,8 @@ void ED_armature_transform(struct bArmature *arm, float mat[4][4]) RET_NONE
struct wmEventHandler *WM_event_add_modal_handler(struct bContext *C, struct wmOperator *op) RET_NULL
struct wmTimer *WM_event_add_timer(struct wmWindowManager *wm, struct wmWindow *win, int event_type, double timestep) RET_NULL
void WM_event_remove_timer(struct wmWindowManager *wm, struct wmWindow *win, struct wmTimer *timer) RET_NONE
+float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]) RET_ZERO
+bool WM_event_is_tablet(const struct wmEvent *event) RET_ZERO
void ED_armature_edit_bone_remove(struct bArmature *arm, struct EditBone *exBone) RET_NONE
void object_test_constraints(struct Object *owner) RET_NONE
void ED_armature_ebone_to_mat4(struct EditBone *ebone, float mat[4][4]) RET_NONE
@@ -384,7 +395,6 @@ void ED_area_tag_redraw(struct ScrArea *sa) RET_NONE
void ED_area_tag_refresh(struct ScrArea *sa) RET_NONE
void ED_area_newspace(struct bContext *C, struct ScrArea *sa, int type) RET_NONE
void ED_region_tag_redraw(struct ARegion *ar) RET_NONE
-void ED_curve_transform(struct Curve *cv, float mat[4][4]) RET_NONE
void WM_event_add_fileselect(struct bContext *C, struct wmOperator *op) RET_NONE
void WM_cursor_wait(bool val) RET_NONE
void ED_node_texture_default(const struct bContext *C, struct Tex *tex) RET_NONE
@@ -410,7 +420,7 @@ void ED_view3D_background_image_remove(struct View3D *v3d, struct BGpic *bgpic)
void ED_view3D_background_image_clear(struct View3D *v3d) RET_NONE
void ED_view3d_update_viewmat(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, float viewmat[4][4], float winmat[4][4]) RET_NONE
float ED_view3d_grid_scale(struct Scene *scene, struct View3D *v3d, const char **grid_unit) RET_ZERO
-void ED_view3d_shade_update(struct Main *bmain, struct View3D *v3d, struct ScrArea *sa) RET_NONE
+void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View3D *v3d, struct ScrArea *sa) RET_NONE
void ED_node_shader_default(const struct bContext *C, struct ID *id) RET_NONE
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh) RET_NONE
struct bScreen *ED_screen_animation_playing(const struct wmWindowManager *wm) RET_NULL
@@ -436,7 +446,6 @@ void uiLayoutSetScaleX(struct uiLayout *layout, float scale) RET_NONE
void uiLayoutSetScaleY(struct uiLayout *layout, float scale) RET_NONE
void uiTemplateIconView(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname) RET_NONE
void ED_base_object_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Base *base) RET_NONE
-void ED_mesh_transform(struct Mesh *me, float mat[4][4]) RET_NONE
void ED_mesh_update(struct Mesh *mesh, struct bContext *C, int calc_edges, int calc_tessface) RET_NONE
void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count) RET_NONE
void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count) RET_NONE
@@ -472,8 +481,6 @@ bool ED_texture_context_check_lamp(const struct bContext *C) RET_ZERO
bool ED_texture_context_check_particles(const struct bContext *C) RET_ZERO
bool ED_texture_context_check_others(const struct bContext *C) RET_ZERO
-void ED_mball_transform(struct MetaBall *mb, float mat[4][4]) RET_NONE
-
bool snapObjectsRayEx(struct Scene *scene, struct Base *base_act, struct View3D *v3d, struct ARegion *ar, struct Object *obedit, short snap_mode,
struct Object **r_ob, float r_obmat[4][4],
const float ray_start[3], const float ray_normal[3], float *r_ray_dist,
@@ -481,7 +488,6 @@ bool snapObjectsRayEx(struct Scene *scene, struct Base *base_act, struct View3D
void make_editLatt(struct Object *obedit) RET_NONE
void load_editLatt(struct Object *obedit) RET_NONE
-void ED_lattice_transform(struct Lattice *lt, float mat[4][4]) RET_NONE
void load_editNurb(struct Object *obedit) RET_NONE
void make_editNurb(struct Object *obedit) RET_NONE
@@ -529,7 +535,7 @@ struct uiLayout *uiTemplateConstraint(struct uiLayout *layout, struct PointerRNA
void uiTemplatePreview(struct uiLayout *layout, struct bContext *C, struct ID *id, int show_buttons, struct ID *parent,
struct MTex *slot, const char *preview_id) RET_NONE
void uiTemplateIDPreview(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, const char *newop, const char *openop, const char *unlinkop, int rows, int cols) RET_NONE
-void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, int levels, int brush) RET_NONE
+void uiTemplateCurveMapping(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int type, int levels, int brush, int neg_slope) RET_NONE
void uiTemplateColorRamp(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int expand) RET_NONE
void uiTemplateLayers(uiLayout *layout, struct PointerRNA *ptr, const char *propname, PointerRNA *used_ptr, const char *used_propname, int active_layer) RET_NONE
void uiTemplateImageLayers(struct uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser) RET_NONE
@@ -560,6 +566,7 @@ void uiTemplateColorspaceSettings(struct uiLayout *layout, struct PointerRNA *pt
void uiTemplateColormanagedViewSettings(struct uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname) RET_NONE
void uiTemplateComponentMenu(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, const char *name) RET_NONE
void uiTemplateNodeSocket(struct uiLayout *layout, struct bContext *C, float *color) RET_NONE
+void uiTemplatePalette(struct uiLayout *layout, struct PointerRNA *ptr, const char *propname, int color) RET_NONE
/* rna render */
struct RenderResult *RE_engine_begin_result(RenderEngine *engine, int x, int y, int w, int h, const char *layername) RET_NULL
@@ -585,6 +592,7 @@ void RE_engine_free(struct RenderEngine *engine) RET_NONE
struct RenderEngineType *RE_engines_find(const char *idname) RET_NULL
void RE_engine_update_memory_stats(struct RenderEngine *engine, float mem_used, float mem_peak) RET_NONE
struct RenderEngine *RE_engine_create(struct RenderEngineType *type) RET_NULL
+void RE_engine_frame_set(struct RenderEngine *engine, int frame, float subframe) RET_NONE
void RE_FreePersistentData(void) RET_NONE
/* python */
@@ -617,6 +625,13 @@ struct wmKeyMap *WM_modalkeymap_add(struct wmKeyConfig *keyconf, const char *idn
struct uiPopupMenu *uiPupMenuBegin(struct bContext *C, const char *title, int icon) RET_NULL
void uiPupMenuEnd(struct bContext *C, struct uiPopupMenu *head) RET_NONE
struct uiLayout *uiPupMenuLayout(struct uiPopupMenu *head) RET_NULL
+struct uiLayout *uiPieMenuLayout(struct uiPieMenu *pie) RET_NULL
+void uiPieMenuInvoke(struct bContext *C, const char *idname, const struct wmEvent *event) RET_NONE
+struct uiPieMenu *uiPieMenuBegin(struct bContext *C, const char *title, int icon, const struct wmEvent *event) RET_NULL
+void uiPieMenuEnd(struct bContext *C, uiPieMenu *pie) RET_NONE
+struct uiLayout *uiLayoutRadial(struct uiLayout *layout) RET_NULL
+void uiPieOperatorEnumInvoke(struct bContext *C, const char *title, const char *opname,
+ const char *propname, const struct wmEvent *event) RET_NONE
/* RNA COLLADA dependency */
int collada_export(struct Scene *sce,
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index efd678cd86d..c2f6ec55030 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -27,6 +27,7 @@ setup_libdirs()
blender_include_dirs(
../../intern/guardedalloc
+ ../../intern/glew-mx
../blender/blenlib
../blender/blenkernel
../blender/blenloader
@@ -39,6 +40,9 @@ blender_include_dirs(
../blender/windowmanager
)
+add_definitions(${GL_DEFINITIONS})
+blender_include_dirs("${GLEW_INCLUDE_PATH}")
+
if(WIN32)
blender_include_dirs(../../intern/utfconv)
endif()
@@ -48,6 +52,11 @@ if(WITH_LIBMV)
add_definitions(-DWITH_LIBMV)
endif()
+if(WITH_CYCLES AND WITH_CYCLES_LOGGING)
+ blender_include_dirs(../../intern/cycles/blender)
+ add_definitions(-DWITH_CYCLES_LOGGING)
+endif()
+
if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
endif()
@@ -174,6 +183,10 @@ if(WITH_BUILDINFO)
list(APPEND SRC
buildinfo.c
)
+
+ # make an object library so can load with it in tests
+ add_library(buildinfoobj OBJECT buildinfo.c)
+ add_dependencies(buildinfoobj buildinfo)
endif()
# message(STATUS "Configuring blender")
@@ -270,7 +283,7 @@ elseif(APPLE)
if(WITH_PYTHON_MODULE)
set(TARGETDIR_VER ${TARGETDIR}/${BLENDER_VERSION})
else()
- set(TARGETDIR_VER ${TARGETDIR}/blender.app/Contents/MacOS/${BLENDER_VERSION})
+ set(TARGETDIR_VER ${TARGETDIR}/blender.app/Contents/Resources/${BLENDER_VERSION})
endif()
endif()
@@ -387,13 +400,29 @@ endif()
if(UNIX AND NOT APPLE)
+ if(NOT WITH_PYTHON_MODULE)
+ install(
+ CODE
+ "
+ execute_process(COMMAND
+ ${CMAKE_SOURCE_DIR}/doc/manpage/blender.1.py
+ ${TARGETDIR}/blender
+ ${TARGETDIR}/blender.1)
+ "
+ )
+ endif()
+
# there are a few differences between portable and system install
if(WITH_INSTALL_PORTABLE)
install(
+ FILES ${TARGETDIR}/blender.1
+ DESTINATION ${TARGETDIR}
+ )
+
+ install(
FILES
${CMAKE_SOURCE_DIR}/release/freedesktop/blender.desktop
${CMAKE_SOURCE_DIR}/release/freedesktop/icons/scalable/apps/blender.svg
- ${CMAKE_SOURCE_DIR}/doc/manpage/blender.1
DESTINATION ${TARGETDIR}
)
@@ -421,6 +450,11 @@ if(UNIX AND NOT APPLE)
PROGRAMS ${TARGETDIR}/blender
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
)
+ # manpage only with 'blender' binary
+ install(
+ FILES ${TARGETDIR}/blender.1
+ DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1
+ )
endif()
@@ -456,10 +490,6 @@ if(UNIX AND NOT APPLE)
DESTINATION ${CMAKE_INSTALL_PREFIX}/bin
)
install(
- FILES ${CMAKE_SOURCE_DIR}/doc/manpage/blender.1
- DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man1
- )
- install(
FILES ${BLENDER_TEXT_FILES}
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/doc/blender
)
@@ -498,16 +528,22 @@ if(UNIX AND NOT APPLE)
PATTERN "idlelib" EXCLUDE # ./idlelib
PATTERN "test" EXCLUDE # ./test
PATTERN "turtledemo" EXCLUDE # ./turtledemo
- PATTERN "turtle.py" EXCLUDE # ./turtle.py
+ PATTERN "turtle.py" EXCLUDE # ./turtle.py
)
# # doesnt work, todo
# install(CODE "execute_process(COMMAND find ${TARGETDIR}/${BLENDER_VERSION}/python/lib/ -name '*.so' -exec strip -s {} '\;')")
-
+
if(WITH_PYTHON_INSTALL_NUMPY)
+ # Install to the same directory as the source, so debian-like
+ # distros are happy with their policy.
+ set(_suffix "site-packages")
+ if(${PYTHON_NUMPY_PATH} MATCHES "dist-packages")
+ set(_suffix "dist-packages")
+ endif()
install(
DIRECTORY ${PYTHON_NUMPY_PATH}/numpy
- DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/site-packages
+ DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix}
PATTERN ".svn" EXCLUDE
PATTERN "__pycache__" EXCLUDE # * any cache *
PATTERN "*.pyc" EXCLUDE # * any cache *
@@ -521,19 +557,47 @@ if(UNIX AND NOT APPLE)
PATTERN "*.h" EXCLUDE # some includes are not in include dirs
PATTERN "*.a" EXCLUDE # ./core/lib/libnpymath.a - for linking, we dont need.
)
+ unset(_suffix)
endif()
# Copy requests, we need to generalize site-packages
if(WITH_PYTHON_INSTALL_REQUESTS)
+ set(_suffix "site-packages")
+ if(${PYTHON_REQUESTS_PATH} MATCHES "dist-packages")
+ set(_suffix "dist-packages")
+ endif()
install(
- DIRECTORY ${PYTHON_LIBPATH}/python${PYTHON_VERSION}/site-packages/requests
- DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/site-packages
+ DIRECTORY ${PYTHON_REQUESTS_PATH}/requests
+ DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix}
PATTERN ".svn" EXCLUDE
PATTERN "__pycache__" EXCLUDE # * any cache *
PATTERN "*.pyc" EXCLUDE # * any cache *
PATTERN "*.pyo" EXCLUDE # * any cache *
PATTERN "cacert.pem" EXCLUDE # for now we don't deal with security
)
+ # On some platforms requests does have extra dependencies.
+ set(_requests_deps "chardet" "urllib3")
+ foreach(_requests_dep ${_requests_deps})
+ if(EXISTS ${PYTHON_REQUESTS_PATH}/${_requests_dep})
+ install(
+ DIRECTORY ${PYTHON_REQUESTS_PATH}/${_requests_dep}
+ DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix}
+ PATTERN ".svn" EXCLUDE
+ PATTERN "__pycache__" EXCLUDE # * any cache *
+ PATTERN "*.pyc" EXCLUDE # * any cache *
+ PATTERN "*.pyo" EXCLUDE # * any cache *
+ )
+ endif()
+ endforeach()
+ if(EXISTS ${PYTHON_REQUESTS_PATH}/six.py)
+ install(
+ FILES ${PYTHON_REQUESTS_PATH}/six.py
+ DESTINATION ${TARGETDIR_VER}/python/${_target_LIB}/python${PYTHON_VERSION}/${_suffix}
+ )
+ endif()
+ unset(_requests_dep)
+ unset(_requests_deps)
+ unset(_suffix)
endif()
unset(_target_LIB)
@@ -550,13 +614,13 @@ elseif(WIN32)
string(REPLACE "." "" _PYTHON_VERSION_NO_DOTS ${PYTHON_VERSION})
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll
+ FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}.dll ${LIBDIR}/python/lib/sqlite3.dll
DESTINATION ${TARGETDIR}
CONFIGURATIONS Release;RelWithDebInfo;MinSizeRel
)
install(
- FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll
+ FILES ${LIBDIR}/python/lib/python${_PYTHON_VERSION_NO_DOTS}_d.dll ${LIBDIR}/python/lib/sqlite3_d.dll
DESTINATION ${TARGETDIR}
CONFIGURATIONS Debug
)
@@ -616,6 +680,18 @@ elseif(WIN32)
unset(_PYTHON_VERSION_NO_DOTS)
endif()
+ # EGL Runtime Components
+ if(WITH_GL_EGL)
+ if(WIN32)
+ install(FILES "${OPENGLES_DLL}" DESTINATION ${TARGETDIR})
+ install(FILES "${OPENGLES_EGL_DLL}" DESTINATION ${TARGETDIR})
+
+ if(WITH_GL_ANGLE)
+ install(FILES "${D3DCOMPILER_DLL}" DESTINATION ${TARGETDIR})
+ endif()
+ endif()
+ endif()
+
if(MSVC)
install(
FILES ${LIBDIR}/pthreads/lib/pthreadVC2.dll
@@ -648,19 +724,7 @@ elseif(WIN32)
endif()
if(WITH_CODEC_FFMPEG)
- if(MSVC11)
- install(
- FILES
- ${LIBDIR}/ffmpeg/lib/avcodec-54.dll
- ${LIBDIR}/ffmpeg/lib/avformat-54.dll
- ${LIBDIR}/ffmpeg/lib/avdevice-54.dll
- ${LIBDIR}/ffmpeg/lib/avutil-52.dll
- ${LIBDIR}/ffmpeg/lib/avfilter-3.dll
- ${LIBDIR}/ffmpeg/lib/swresample-0.dll
- ${LIBDIR}/ffmpeg/lib/swscale-2.dll
- DESTINATION ${TARGETDIR}
- )
- elseif(WITH_MINGW64)
+ if(WITH_MINGW64)
install(
FILES
${LIBDIR}/ffmpeg/lib/avcodec-53.dll
@@ -693,45 +757,19 @@ elseif(WIN32)
endif()
if(WITH_OPENAL)
- if(MSVC11)
- install(
- FILES
- ${LIBDIR}/openal/lib/OpenAL32.dll
- DESTINATION ${TARGETDIR}
- )
- else()
- install(
- FILES
- ${LIBDIR}/openal/lib/OpenAL32.dll
- ${LIBDIR}/openal/lib/wrap_oal.dll
- DESTINATION ${TARGETDIR}
- )
- endif()
+ install(
+ FILES
+ ${LIBDIR}/openal/lib/OpenAL32.dll
+ ${LIBDIR}/openal/lib/wrap_oal.dll
+ DESTINATION ${TARGETDIR}
+ )
endif()
-# if(WITH_JACK AND MSVC11)
-# if(CMAKE_CL_64)
-# install(
-# FILES
-# ${LIBDIR}/jack/lib/libjack64.dll
-# DESTINATION ${TARGETDIR}
-# )
-# else()
-# install(
-# FILES
-# ${LIBDIR}/jack/lib/libjack.dll
-# DESTINATION ${TARGETDIR}
-# )
-# endif()
-# endif()
-
if(WITH_SDL)
- if(NOT CMAKE_CL_64)
- install(
- FILES ${LIBDIR}/sdl/lib/SDL.dll
- DESTINATION ${TARGETDIR}
- )
- endif()
+ install(
+ FILES ${LIBDIR}/sdl/lib/SDL.dll
+ DESTINATION ${TARGETDIR}
+ )
endif()
if(NOT CMAKE_CL_64)
@@ -817,6 +855,13 @@ elseif(APPLE)
)
endif()
+ if(WITH_LLVM AND NOT LLVM_STATIC)
+ install(
+ FILES ${LIBDIR}/llvm/lib/libLLVM-3.4.dylib
+ DESTINATION ${TARGETDIR}/blender.app/Contents/MacOS
+ )
+ endif()
+
# python
if(WITH_PYTHON AND NOT WITH_PYTHON_MODULE AND NOT WITH_PYTHON_FRAMEWORK)
# the python zip is first extract as part of the build process,
@@ -856,7 +901,7 @@ elseif(APPLE)
if(WITH_GAMEENGINE AND WITH_PLAYER)
set(OSX_APP_PLAYER_SOURCEDIR ${CMAKE_SOURCE_DIR}/release/darwin/blenderplayer.app)
set(PLAYER_SOURCEINFO ${OSX_APP_PLAYER_SOURCEDIR}/Contents/Info.plist)
- set(PLAYER_TARGETDIR_VER ${TARGETDIR}/blenderplayer.app/Contents/MacOS/${BLENDER_VERSION})
+ set(PLAYER_TARGETDIR_VER ${TARGETDIR}/blenderplayer.app/Contents/Resources/${BLENDER_VERSION})
# important to make a clean install each time else old scripts get loaded.
@@ -911,257 +956,23 @@ unset(BLENDER_TEXT_FILES)
add_dependencies(blender makesdna)
-get_property(BLENDER_LINK_LIBS GLOBAL PROPERTY BLENDER_LINK_LIBS)
+setup_blender_sorted_libs()
-list(APPEND BLENDER_LINK_LIBS
- bf_windowmanager
- bf_render
-)
+target_link_libraries(blender ${BLENDER_SORTED_LIBS})
-if(WITH_MOD_FLUID)
- list(APPEND BLENDER_LINK_LIBS bf_intern_elbeem)
-endif()
+setup_liblinks(blender)
-if(WITH_CYCLES)
- list(APPEND BLENDER_LINK_LIBS
- cycles_render
- cycles_bvh
- cycles_device
- cycles_kernel
- cycles_util
- cycles_subd)
- if(WITH_CYCLES_OSL)
- list(APPEND BLENDER_LINK_LIBS cycles_kernel_osl)
- endif()
-endif()
+# -----------------------------------------------------------------------------
+# Setup launcher
-#if(UNIX)
- # Sort libraries
- set(BLENDER_SORTED_LIBS
- bf_windowmanager
-
- bf_editor_space_api
- bf_editor_space_action
- bf_editor_space_buttons
- bf_editor_space_console
- bf_editor_space_file
- bf_editor_space_graph
- bf_editor_space_image
- bf_editor_space_info
- bf_editor_space_logic
- bf_editor_space_nla
- bf_editor_space_node
- bf_editor_space_outliner
- bf_editor_space_script
- bf_editor_space_sequencer
- bf_editor_space_text
- bf_editor_space_time
- bf_editor_space_userpref
- bf_editor_space_view3d
- bf_editor_space_clip
-
- bf_editor_transform
- bf_editor_util
- bf_editor_uvedit
- bf_editor_curve
- bf_editor_gpencil
- bf_editor_interface
- bf_editor_mesh
- bf_editor_metaball
- bf_editor_object
- bf_editor_armature
- bf_editor_physics
- bf_editor_render
- bf_editor_screen
- bf_editor_sculpt_paint
- bf_editor_sound
- bf_editor_animation
- bf_editor_datafiles
- bf_editor_mask
- bf_editor_io
-
- bf_render
- bf_python
- bf_python_ext
-# bf_python_manta #requres additional link flags
- bf_python_mathutils
- bf_python_bmesh
- bf_freestyle
- bf_ikplugin
- bf_modifiers
- bf_bmesh
- bf_blenkernel
- bf_nodes
- bf_gpu
- bf_blenloader
- bf_imbuf
- bf_blenlib
- bf_intern_ghost
- bf_intern_string
- bf_avi
- bf_imbuf_cineon
- bf_imbuf_openexr
- bf_imbuf_openimageio
- bf_imbuf_dds
- bf_collada
- bf_intern_elbeem
- bf_intern_memutil
- bf_intern_guardedalloc
- bf_intern_ctr
- bf_intern_utfconv
- ge_blen_routines
- ge_converter
- ge_phys_dummy
- ge_phys_bullet
- bf_intern_smoke
- extern_minilzo
- extern_lzma
- extern_colamd
- ge_logic_ketsji
- extern_recastnavigation
- ge_logic
- ge_rasterizer
- ge_oglrasterizer
- ge_logic_expressions
- ge_scenegraph
- ge_logic_network
- ge_logic_ngnetwork
- ge_logic_loopbacknetwork
- bf_intern_moto
- extern_openjpeg
- extern_redcode
- ge_videotex
- bf_rna
- bf_dna
- bf_blenfont
- bf_intern_audaspace
- bf_intern_mikktspace
- bf_intern_dualcon
- bf_intern_cycles
- cycles_render
- cycles_bvh
- cycles_device
- cycles_kernel
- cycles_util
- cycles_subd
- bf_intern_raskter
- bf_intern_opencolorio
- extern_rangetree
- extern_wcwidth
- extern_libmv
-# extern_manta
+if(WIN32 AND NOT WITH_PYTHON_MODULE)
+ set(LAUNCHER_SRC
+ creator_launch_win.c
+ ../icons/winblender.rc
)
+ add_executable(blender-launcher ${LAUNCHER_SRC})
+ target_link_libraries(blender-launcher bf_intern_utfconv ${PLATFORM_LINKLIBS})
- if(WITH_COMPOSITOR)
- # added for opencl compositor
- list_insert_before(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_compositor")
- list_insert_after(BLENDER_SORTED_LIBS "bf_compositor" "bf_intern_opencl")
- endif()
-
- if(WITH_LIBMV)
- list(APPEND BLENDER_SORTED_LIBS extern_ceres)
- endif()
-
- if(WITH_MOD_CLOTH_ELTOPO)
- list(APPEND BLENDER_SORTED_LIBS extern_eltopo)
- endif()
-
- if(NOT WITH_SYSTEM_GLEW)
- list(APPEND BLENDER_SORTED_LIBS extern_glew)
- endif()
-
- if(WITH_BINRELOC)
- list(APPEND BLENDER_SORTED_LIBS extern_binreloc)
- endif()
-
- if(WITH_CXX_GUARDEDALLOC)
- list(APPEND BLENDER_SORTED_LIBS bf_intern_guardedalloc_cpp)
- endif()
-
- if(WITH_IK_SOLVER)
- list_insert_after(BLENDER_SORTED_LIBS "bf_intern_elbeem" "bf_intern_iksolver")
- endif()
-
- if(WITH_IK_ITASC)
- list(APPEND BLENDER_SORTED_LIBS bf_intern_itasc)
- endif()
-
- if(WITH_CODEC_QUICKTIME)
- list(APPEND BLENDER_SORTED_LIBS bf_quicktime)
- endif()
-
- if(WITH_INPUT_NDOF)
- list(APPEND BLENDER_SORTED_LIBS bf_intern_ghostndof3dconnexion)
- endif()
-
- if(WITH_MOD_BOOLEAN)
- list(APPEND BLENDER_SORTED_LIBS extern_carve)
- endif()
-
- if(WITH_GHOST_XDND)
- list(APPEND BLENDER_SORTED_LIBS extern_xdnd)
- endif()
-
- if(WITH_CYCLES_OSL)
- list_insert_after(BLENDER_SORTED_LIBS "cycles_kernel" "cycles_kernel_osl")
- endif()
-
- if(WITH_INTERNATIONAL)
- list(APPEND BLENDER_SORTED_LIBS bf_intern_locale)
- endif()
-
- if(WITH_OPENNL)
- list_insert_after(BLENDER_SORTED_LIBS "bf_render" "bf_intern_opennl")
- endif()
-
- if(WITH_BULLET)
- list_insert_after(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_intern_rigidbody")
- endif()
-
- if(WITH_BULLET AND NOT WITH_SYSTEM_BULLET)
- list_insert_after(BLENDER_SORTED_LIBS "ge_logic_ngnetwork" "extern_bullet")
- endif()
-
-# if(WITH_MOD_MANTA)
-# list(APPEND BLENDER_SORTED_LIBS extern_manta)
-# #list(APPEND BLENDER_LINK_LIBS extern_manta)
-# endif()
-
- foreach(SORTLIB ${BLENDER_SORTED_LIBS})
- set(REMLIB ${SORTLIB})
- foreach(SEARCHLIB ${BLENDER_LINK_LIBS})
- if(${SEARCHLIB} STREQUAL ${SORTLIB})
- set(REMLIB "")
- endif()
- endforeach()
- if(REMLIB)
- # message(STATUS "Removing library ${REMLIB} from blender linking because: not configured")
- list(APPEND REM_MSG ${REMLIB})
- list(REMOVE_ITEM BLENDER_SORTED_LIBS ${REMLIB})
- endif()
- endforeach()
- if(REM_MSG)
- list(SORT REM_MSG)
- message(STATUS "Blender Skipping: (${REM_MSG})")
- endif()
- target_link_libraries(blender ${BLENDER_SORTED_LIBS})
-
- #linking manta library
- if(APPLE)
- SET(MANTA_LINK_LIBRARIES -force_load bf_python_manta )
- else()
- SET(MANTA_LINK_LIBRARIES -Wl,--whole-archive bf_python_manta -Wl,--no-whole-archive )
- endif()
- #-Wl,--whole-archive bf_python_manta -Wl,--no-whole-archive)
- TARGET_LINK_LIBRARIES(blender ${MANTA_LINK_LIBRARIES})
-
- unset(SEARCHLIB)
- unset(SORTLIB)
- unset(REMLIB)
- unset(REM_MSG)
-
-#else()
-# target_link_libraries(blender ${BLENDER_LINK_LIBS})
-#endif()
-
-setup_liblinks(blender)
+ set_target_properties(blender PROPERTIES OUTPUT_NAME blender-app)
+ set_target_properties(blender-launcher PROPERTIES OUTPUT_NAME blender)
+endif()
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 0dad2fd6b75..d779095c1ee 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -41,6 +41,9 @@
#endif
#ifdef WIN32
+# if defined(_MSC_VER) && _MSC_VER >= 1800 && defined(_M_X64)
+# include <math.h> /* needed for _set_FMA3_enable */
+# endif
# include <windows.h>
# include "utfconv.h"
#endif
@@ -104,6 +107,7 @@
#include "RE_engine.h"
#include "RE_pipeline.h"
+#include "RE_render_ext.h"
#include "ED_datafiles.h"
#include "ED_util.h"
@@ -146,6 +150,10 @@
# include "libmv-capi.h"
#endif
+#ifdef WITH_CYCLES_LOGGING
+# include "CCL_api.h"
+#endif
+
/* from buildinfo.c */
#ifdef BUILD_DATE
extern char build_date[];
@@ -306,6 +314,9 @@ static int print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)
#ifdef WITH_LIBMV
BLI_argsPrintArgDoc(ba, "--debug-libmv");
#endif
+#ifdef WITH_CYCLES_LOGGING
+ BLI_argsPrintArgDoc(ba, "--debug-cycles");
+#endif
BLI_argsPrintArgDoc(ba, "--debug-memory");
BLI_argsPrintArgDoc(ba, "--debug-jobs");
BLI_argsPrintArgDoc(ba, "--debug-python");
@@ -447,6 +458,15 @@ static int debug_mode_libmv(int UNUSED(argc), const char **UNUSED(argv), void *U
}
#endif
+#ifdef WITH_CYCLES_LOGGING
+static int debug_mode_cycles(int UNUSED(argc), const char **UNUSED(argv),
+ void *UNUSED(data))
+{
+ CCL_start_debug_logging();
+ return 0;
+}
+#endif
+
static int debug_mode_memory(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
{
MEM_set_memory_debug();
@@ -535,7 +555,7 @@ static void blender_crash_handler_backtrace(FILE *fp)
SymInitialize(process, NULL, true);
nframes = CaptureStackBackTrace(0, SIZE, stack, NULL);
- symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + MAXSYMBOL * sizeof( char ), "crash Symbol table");
+ symbolinfo = MEM_callocN(sizeof(SYMBOL_INFO) + MAXSYMBOL * sizeof(char), "crash Symbol table");
symbolinfo->MaxNameLen = MAXSYMBOL - 1;
symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO);
@@ -566,7 +586,7 @@ static void blender_crash_handler(int signum)
char fname[FILE_MAX];
if (!G.main->name[0]) {
- BLI_make_file_string("/", fname, BLI_temporary_dir(), "crash.blend");
+ BLI_make_file_string("/", fname, BLI_temp_dir_base(), "crash.blend");
}
else {
BLI_strncpy(fname, G.main->name, sizeof(fname));
@@ -587,10 +607,10 @@ static void blender_crash_handler(int signum)
char fname[FILE_MAX];
if (!G.main->name[0]) {
- BLI_join_dirfile(fname, sizeof(fname), BLI_temporary_dir(), "blender.crash.txt");
+ BLI_join_dirfile(fname, sizeof(fname), BLI_temp_dir_base(), "blender.crash.txt");
}
else {
- BLI_join_dirfile(fname, sizeof(fname), BLI_temporary_dir(), BLI_path_basename(G.main->name));
+ BLI_join_dirfile(fname, sizeof(fname), BLI_temp_dir_base(), BLI_path_basename(G.main->name));
BLI_replace_extension(fname, sizeof(fname), ".crash.txt");
}
@@ -621,6 +641,8 @@ static void blender_crash_handler(int signum)
fclose(fp);
}
+ /* Delete content of temp dir! */
+ BLI_temp_dir_session_purge();
/* really crash */
signal(signum, SIG_DFL);
@@ -812,6 +834,9 @@ static int set_engine(int argc, const char **argv, void *data)
if (BLI_findstring(&R_engines, argv[1], offsetof(RenderEngineType, idname))) {
BLI_strncpy_utf8(rd->engine, argv[1], sizeof(rd->engine));
}
+ else {
+ printf("\nError: engine not found '%s'\n", argv[1]);
+ }
}
else {
printf("\nError: no blend loaded. order the arguments so '-E / --engine ' is after a blend is loaded.\n");
@@ -879,6 +904,8 @@ static int set_verbosity(int argc, const char **argv, void *UNUSED(data))
#ifdef WITH_LIBMV
libmv_setLoggingVerbosity(level);
+#elif defined(WITH_CYCLES_LOGGING)
+ CCL_logging_verbosity_set(level);
#else
(void)level;
#endif
@@ -999,6 +1026,7 @@ static int render_frame(int argc, const char **argv, void *data)
break;
}
+ BLI_begin_threaded_malloc();
BKE_reports_init(&reports, RPT_PRINT);
frame = CLAMPIS(frame, MINAFRAME, MAXFRAME);
@@ -1006,6 +1034,7 @@ static int render_frame(int argc, const char **argv, void *data)
RE_SetReports(re, &reports);
RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, frame, frame, scene->r.frame_step);
RE_SetReports(re, NULL);
+ BLI_end_threaded_malloc();
return 1;
}
else {
@@ -1027,10 +1056,12 @@ static int render_animation(int UNUSED(argc), const char **UNUSED(argv), void *d
Main *bmain = CTX_data_main(C);
Render *re = RE_NewRender(scene->id.name);
ReportList reports;
+ BLI_begin_threaded_malloc();
BKE_reports_init(&reports, RPT_PRINT);
RE_SetReports(re, &reports);
RE_BlenderAnim(re, bmain, scene, NULL, scene->lay, scene->r.sfra, scene->r.efra, scene->r.frame_step);
RE_SetReports(re, NULL);
+ BLI_end_threaded_malloc();
}
else {
printf("\nError: no blend loaded. cannot use '-a'.\n");
@@ -1407,6 +1438,9 @@ static void setupArguments(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
#ifdef WITH_LIBMV
BLI_argsAdd(ba, 1, NULL, "--debug-libmv", "\n\tEnable debug messages from libmv library", debug_mode_libmv, NULL);
#endif
+#ifdef WITH_CYCLES_LOGGING
+ BLI_argsAdd(ba, 1, NULL, "--debug-cycles", "\n\tEnable debug messages from Cycles", debug_mode_cycles, NULL);
+#endif
BLI_argsAdd(ba, 1, NULL, "--debug-memory", "\n\tEnable fully guarded memory allocation and debugging", debug_mode_memory, NULL);
BLI_argsAdd(ba, 1, NULL, "--debug-value", "<value>\n\tSet debug value of <value> on startup\n", set_debug_value, NULL);
@@ -1495,7 +1529,13 @@ int main(
bArgs *ba;
#endif
-#ifdef WIN32 /* Win32 Unicode Args */
+#ifdef WIN32
+ /* FMA3 support in the 2013 CRT is broken on Vista and Windows 7 RTM (fixed in SP1). Just disable it. */
+# if defined(_MSC_VER) && _MSC_VER >= 1800 && defined(_M_X64)
+ _set_FMA3_enable(0);
+# endif
+
+ /* Win32 Unicode Args */
/* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized
* (it depends on the args passed in, which is what we're getting here!)
*/
@@ -1565,24 +1605,11 @@ int main(
#ifdef WITH_LIBMV
libmv_initLogging(argv[0]);
+#elif defined(WITH_CYCLES_LOGGING)
+ CCL_init_logging(argv[0]);
#endif
setCallbacks();
-#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE)
- /* patch to ignore argument finder gives us (pid?) */
- if (argc == 2 && strncmp(argv[1], "-psn_", 5) == 0) {
- extern int GHOST_HACK_getFirstFile(char buf[]);
- static char firstfilebuf[512];
-
- argc = 1;
-
- if (GHOST_HACK_getFirstFile(firstfilebuf)) {
- argc = 2;
- argv[1] = firstfilebuf;
- }
- }
-
-#endif
#ifdef __FreeBSD__
fpsetmask(0);
@@ -1601,6 +1628,8 @@ int main(
DAG_init();
BKE_brush_system_init();
+ RE_init_texture_rng();
+
BLI_callback_global_init();
@@ -1666,7 +1695,7 @@ int main(
/* this is properly initialized with user defs, but this is default */
/* call after loading the startup.blend so we can read U.tempdir */
- BLI_init_temporary_dir(U.tempdir);
+ BLI_temp_dir_init(U.tempdir);
}
else {
#ifndef WITH_PYTHON_MODULE
@@ -1676,7 +1705,7 @@ int main(
WM_init(C, argc, (const char **)argv);
/* don't use user preferences temp dir */
- BLI_init_temporary_dir(NULL);
+ BLI_temp_dir_init(NULL);
}
#ifdef WITH_PYTHON
/**
diff --git a/source/creator/creator_launch_win.c b/source/creator/creator_launch_win.c
new file mode 100644
index 00000000000..03f28cd4034
--- /dev/null
+++ b/source/creator/creator_launch_win.c
@@ -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) 2014 by Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* Binary name to launch. */
+#define BLENDER_BINARY L"blender-app.exe"
+
+#define WIN32_LEAN_AND_MEAN
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <windows.h>
+#include <Shellapi.h>
+
+#include "utfconv.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_winstuff.h"
+
+static void local_hacks_do(void)
+{
+ _putenv_s("OMP_WAIT_POLICY", "PASSIVE");
+}
+
+int main(int argc, const char **UNUSED(argv_c))
+{
+ PROCESS_INFORMATION processInformation = {0};
+ STARTUPINFOW startupInfo = {0};
+ BOOL result;
+ wchar_t command[65536];
+ int i, len = sizeof(command) / sizeof(wchar_t);
+ wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc);
+ int argci = 0;
+
+ local_hacks_do();
+
+ wcsncpy(command, BLENDER_BINARY, len - 1);
+ len -= wcslen(BLENDER_BINARY);
+ for (i = 1; i < argc; ++i) {
+ size_t argument_len = wcslen(argv_16[i]);
+ wcsncat(command, L" \"", len - 2);
+ wcsncat(command, argv_16[i], len - 3);
+ len -= argument_len + 1;
+ if (argv_16[i][argument_len - 1] == '\\') {
+ wcsncat(command, L"\\", len - 1);
+ len--;
+ }
+ wcsncat(command, L"\"", len - 1);
+ }
+
+ LocalFree(argv_16);
+
+ startupInfo.cb = sizeof(startupInfo);
+ result = CreateProcessW(NULL, command, NULL, NULL, TRUE,
+ 0, NULL, NULL,
+ &startupInfo, &processInformation);
+
+ if (!result) {
+ fprintf(stderr, "%S\n", L"Error launching " BLENDER_BINARY);
+ return EXIT_FAILURE;
+ }
+
+ WaitForSingleObject(processInformation.hProcess, INFINITE);
+
+ CloseHandle(processInformation.hProcess);
+ CloseHandle(processInformation.hThread);
+
+ return EXIT_SUCCESS;
+}
diff --git a/source/creator/osx_locals.map b/source/creator/osx_locals.map
index c3dd8b62792..8405be74ab7 100644
--- a/source/creator/osx_locals.map
+++ b/source/creator/osx_locals.map
@@ -1,3 +1,8 @@
## The symbols will be treated as if they were marked as __private_extern__
## (aka visibility=hidden) and will not be global in the output file
*boost*
+*__ZNSt6vector*
+*llvm*
+*LLVM*
+*OSL*
+
diff --git a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
index 03401f0e8b8..2a7e631637e 100644
--- a/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
+++ b/source/gameengine/BlenderRoutines/BL_KetsjiEmbedStart.cpp
@@ -40,7 +40,7 @@
# pragma warning (disable:4786)
#endif
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "KX_BlenderCanvas.h"
#include "KX_BlenderKeyboardDevice.h"
@@ -67,6 +67,7 @@
extern "C" {
+ #include "DNA_object_types.h"
#include "DNA_view3d_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
@@ -91,6 +92,11 @@ extern "C" {
#include "../../blender/windowmanager/WM_types.h"
#include "../../blender/windowmanager/wm_window.h"
+
+/* avoid more includes (not used by BGE) */
+typedef void * wmUIHandlerFunc;
+typedef void * wmUIHandlerRemoveFunc;
+
#include "../../blender/windowmanager/wm_event_system.h"
}
@@ -181,6 +187,8 @@ static int BL_KetsjiNextFrame(KX_KetsjiEngine *ketsjiengine, bContext *C, wmWind
return exitrequested;
}
+
+#ifdef WITH_PYTHON
static struct BL_KetsjiNextFrameState {
class KX_KetsjiEngine* ketsjiengine;
struct bContext *C;
@@ -205,6 +213,8 @@ static int BL_KetsjiPyNextFrame(void *state0)
state->mousedevice,
state->draw_letterbox);
}
+#endif
+
extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *cam_frame, int always_use_expand_framing)
{
@@ -273,6 +283,10 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
bool mouse_state = startscene->gm.flag & GAME_SHOW_MOUSE;
bool restrictAnimFPS = startscene->gm.flag & GAME_RESTRICT_ANIM_UPDATES;
+ short drawtype = v3d->drawtype;
+
+ /* we do not support material mode in game engine, force change to texture mode */
+ if (drawtype == OB_MATERIAL) drawtype = OB_TEXTURE;
if (animation_record) usefixed= false; /* override since you don't want to run full-speed for sim recording */
// create the canvas and rasterizer
@@ -285,7 +299,8 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
// Setup vsync
- int previous_vsync = canvas->GetSwapInterval();
+ int previous_vsync = 0;
+ canvas->GetSwapInterval(previous_vsync);
if (startscene->gm.vsync == VSYNC_ADAPTIVE)
canvas->SetSwapInterval(-1);
else
@@ -361,7 +376,7 @@ extern "C" void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *c
camzoom = 2.0;
}
- rasterizer->SetDrawingMode(v3d->drawtype);
+ rasterizer->SetDrawingMode(drawtype);
ketsjiengine->SetCameraZoom(camzoom);
// if we got an exitcode 3 (KX_EXIT_REQUEST_START_OTHER_GAME) load a different file
diff --git a/source/gameengine/BlenderRoutines/CMakeLists.txt b/source/gameengine/BlenderRoutines/CMakeLists.txt
index 73dbe005518..1a2809cc8ab 100644
--- a/source/gameengine/BlenderRoutines/CMakeLists.txt
+++ b/source/gameengine/BlenderRoutines/CMakeLists.txt
@@ -24,6 +24,7 @@ set(INC
../../blender/makesrna
../../blender/windowmanager
../../../intern/container
+ ../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/string
)
@@ -52,7 +53,7 @@ set(SRC
KX_BlenderSystem.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_AUDASPACE)
list(APPEND INC
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
index b3e0b4c3ea6..31f3b1b2047 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -29,7 +29,7 @@
* \ingroup blroutines
*/
-#include <GL/glew.h>
+#include "glew-mx.h"
#include "MEM_guardedalloc.h"
@@ -91,9 +91,9 @@ void KX_BlenderCanvas::SetSwapInterval(int interval)
wm_window_set_swap_interval(m_win, interval);
}
-int KX_BlenderCanvas::GetSwapInterval()
+bool KX_BlenderCanvas::GetSwapInterval(int &intervalOut)
{
- return wm_window_get_swap_interval(m_win);
+ return wm_window_get_swap_interval(m_win, &intervalOut);
}
void KX_BlenderCanvas::ResizeWindow(int width, int height)
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
index 9ad80cb1737..917e0136cb1 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.h
@@ -82,8 +82,9 @@ public:
int interval
);
- int
+ bool
GetSwapInterval(
+ int &intervalOut
);
void
diff --git a/source/gameengine/BlenderRoutines/SConscript b/source/gameengine/BlenderRoutines/SConscript
index 62d657189c5..def0bc32697 100644
--- a/source/gameengine/BlenderRoutines/SConscript
+++ b/source/gameengine/BlenderRoutines/SConscript
@@ -29,9 +29,7 @@ Import ('env')
sources = env.Glob('*.cpp')
-defs = [
- 'GLEW_STATIC',
- ]
+defs = env['BF_GL_DEFINITIONS']
incs = [
'.',
@@ -39,7 +37,8 @@ incs = [
'#intern/guardedalloc',
'#intern/string',
'#source/blender',
- '#extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#intern/audaspace/intern',
'#intern/ghost/include',
'#intern/moto/include',
diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp
index 0392280444d..e01130a8970 100644
--- a/source/gameengine/Converter/BL_ArmatureObject.cpp
+++ b/source/gameengine/Converter/BL_ArmatureObject.cpp
@@ -101,7 +101,7 @@ static void game_copy_pose(bPose **dst, bPose *src, int copy_constraint)
out->chanhash = NULL;
out->agroups.first= out->agroups.last= NULL;
out->ikdata = NULL;
- out->ikparam = MEM_dupallocN(out->ikparam);
+ out->ikparam = MEM_dupallocN(src->ikparam);
out->flag |= POSE_GAME_ENGINE;
BLI_duplicatelist(&out->chanbase, &src->chanbase);
@@ -231,6 +231,8 @@ BL_ArmatureObject::BL_ArmatureObject(
m_objArma = BKE_object_copy(armature);
m_objArma->data = BKE_armature_copy((bArmature *)armature->data);
m_pose = m_objArma->pose;
+ // need this to get iTaSC working ok in the BGE
+ m_pose->flag |= POSE_GAME_ENGINE;
memcpy(m_obmat, m_objArma->obmat, sizeof(m_obmat));
}
@@ -319,6 +321,10 @@ void BL_ArmatureObject::LoadConstraints(KX_BlenderSceneConverter* converter)
}
}
}
+
+ // If we have constraints, make sure we get treated as an "animated" object
+ if (m_constraintNumber > 0)
+ GetActionManager();
}
BL_ArmatureConstraint* BL_ArmatureObject::GetConstraint(const char* posechannel, const char* constraintname)
diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
index e511f01e9c6..87b64582e11 100644
--- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp
+++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp
@@ -876,7 +876,7 @@ static bool ConvertMaterial(
material->alphablend = GEMAT_ALPHA;
// always zsort alpha + add
- if ((ELEM3(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP )) {
+ if ((ELEM(material->alphablend, GEMAT_ALPHA, GEMAT_ALPHA_SORT, GEMAT_ADD) || texalpha) && (material->alphablend != GEMAT_CLIP )) {
material->ras_mode |= ALPHA;
material->ras_mode |= (mat && (mat->game.alpha_blend & GEMAT_ALPHA_SORT))? ZSORT: 0;
}
diff --git a/source/gameengine/Converter/BL_ShapeActionActuator.h b/source/gameengine/Converter/BL_ShapeActionActuator.h
index f72275b79cf..e96d0e0ebb4 100644
--- a/source/gameengine/Converter/BL_ShapeActionActuator.h
+++ b/source/gameengine/Converter/BL_ShapeActionActuator.h
@@ -59,7 +59,7 @@ public:
virtual void ProcessReplica();
void SetBlendTime (float newtime);
- void BlendShape(struct Key* key, float weigth);
+ void BlendShape(struct Key* key, float weight);
bAction* GetAction() { return m_action; }
void SetAction(bAction* act) { m_action= act; }
diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
index 5930d5e90d2..a20ebb3a081 100644
--- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
+++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp
@@ -1237,6 +1237,16 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
gameobj->RemoveMeshes(); /* XXX - slack, should only remove meshes that are library items but mostly objects only have 1 mesh */
break;
}
+ else {
+ /* also free the mesh if it's using a tagged material */
+ int mat_index = mesh->NumMaterials();
+ while (mat_index--) {
+ if (IS_TAGGED(mesh->GetMeshMaterial(mat_index)->m_bucket->GetPolyMaterial()->GetBlenderMaterial())) {
+ gameobj->RemoveMeshes(); /* XXX - slack, same as above */
+ break;
+ }
+ }
+ }
}
/* make sure action actuators are not referencing tagged actions */
@@ -1372,10 +1382,42 @@ bool KX_BlenderSceneConverter::FreeBlendFile(struct Main *maggie)
}
vector<pair<KX_Scene*,RAS_MeshObject*> >::iterator meshit;
+ RAS_BucketManager::BucketList::iterator bit;
+ list<RAS_MeshSlot>::iterator msit;
+ RAS_BucketManager::BucketList buckets;
+
size = m_meshobjects.size();
for (i=0, meshit=m_meshobjects.begin(); i<size; ) {
RAS_MeshObject *me= (*meshit).second;
if (IS_TAGGED(me->GetMesh())) {
+ // Before deleting the mesh object, make sure the rasterizer is
+ // no longer referencing it.
+ buckets = meshit->first->GetBucketManager()->GetSolidBuckets();
+ for (bit=buckets.begin(); bit!=buckets.end(); bit++) {
+ msit = (*bit)->msBegin();
+
+ while (msit != (*bit)->msEnd()) {
+ if (msit->m_mesh == meshit->second)
+ (*bit)->RemoveMesh(&(*msit++));
+ else
+ msit++;
+ }
+ }
+
+ // And now the alpha buckets
+ buckets = meshit->first->GetBucketManager()->GetAlphaBuckets();
+ for (bit=buckets.begin(); bit!=buckets.end(); bit++) {
+ msit = (*bit)->msBegin();
+
+ while (msit != (*bit)->msEnd()) {
+ if (msit->m_mesh == meshit->second)
+ (*bit)->RemoveMesh(&(*msit++));
+ else
+ msit++;
+ }
+ }
+
+ // Now it should be safe to delete
delete (*meshit).second;
*meshit = m_meshobjects.back();
m_meshobjects.pop_back();
@@ -1480,7 +1522,9 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene* kx_scene,
/* Watch this!, if its used in the original scene can cause big troubles */
if (me->us > 0) {
+#ifdef DEBUG
printf("Mesh has a user \"%s\"\n", name);
+#endif
me = (ID*)BKE_mesh_copy_ex(from_maggie, (Mesh*)me);
me->us--;
}
@@ -1526,7 +1570,8 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene* kx_scene,
}
}
}
-
+
+ m_currentScene = kx_scene; // This needs to be set in case we LibLoaded earlier
RAS_MeshObject *meshobj = BL_ConvertMesh((Mesh *)me, NULL, kx_scene, this, false);
kx_scene->GetLogicManager()->RegisterMeshName(meshobj->GetName(),meshobj);
m_map_mesh_to_gamemesh.clear(); /* This is at runtime so no need to keep this, BL_ConvertMesh adds */
diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp
index b59c26ab90b..f6ed3366625 100644
--- a/source/gameengine/Converter/KX_ConvertActuators.cpp
+++ b/source/gameengine/Converter/KX_ConvertActuators.cpp
@@ -70,6 +70,7 @@
#include "KX_ParentActuator.h"
#include "KX_SCA_DynamicActuator.h"
#include "KX_SteeringActuator.h"
+#include "KX_MouseActuator.h"
#include "KX_Scene.h"
#include "KX_KetsjiEngine.h"
@@ -514,15 +515,7 @@ void BL_ConvertActuators(const char* maggiename,
break;
case ACT_EDOB_REPLACE_MESH:
{
- RAS_MeshObject *tmpmesh = NULL;
- if (editobact->me)
- tmpmesh = BL_ConvertMesh(
- editobact->me,
- blenderobject,
- scene,
- converter,
- false
- );
+ RAS_MeshObject *tmpmesh = converter->FindGameMesh(editobact->me);
KX_SCA_ReplaceMeshActuator* tmpreplaceact = new KX_SCA_ReplaceMeshActuator(
gameobj,
@@ -545,8 +538,8 @@ void BL_ConvertActuators(const char* maggiename,
originalval,
editobact->time,
editobact->flag,
- blenderobject->trackflag,
- blenderobject->upflag);
+ editobact->trackflag,
+ editobact->upflag);
baseact = tmptrackact;
break;
}
@@ -1102,6 +1095,50 @@ void BL_ConvertActuators(const char* maggiename,
baseact = tmpstact;
break;
}
+ case ACT_MOUSE:
+ {
+ bMouseActuator* mouAct = (bMouseActuator*) bact->data;
+ int mode = KX_MouseActuator::KX_ACT_MOUSE_NODEF;
+
+ switch (mouAct->type) {
+ case ACT_MOUSE_VISIBILITY:
+ {
+ mode = KX_MouseActuator::KX_ACT_MOUSE_VISIBILITY;
+ break;
+ }
+ case ACT_MOUSE_LOOK:
+ {
+ mode = KX_MouseActuator::KX_ACT_MOUSE_LOOK;
+ break;
+ }
+ }
+
+ bool visible = (mouAct->flag & ACT_MOUSE_VISIBLE) != 0;
+ bool use_axis[2] = {(mouAct->flag & ACT_MOUSE_USE_AXIS_X) != 0, (mouAct->flag & ACT_MOUSE_USE_AXIS_Y) != 0};
+ bool reset[2] = {(mouAct->flag & ACT_MOUSE_RESET_X) != 0, (mouAct->flag & ACT_MOUSE_RESET_Y) != 0};
+ bool local[2] = {(mouAct->flag & ACT_MOUSE_LOCAL_X) != 0, (mouAct->flag & ACT_MOUSE_LOCAL_Y) != 0};
+
+ SCA_MouseManager* eventmgr = (SCA_MouseManager*) logicmgr->FindEventManager(SCA_EventManager::MOUSE_EVENTMGR);
+ if (eventmgr) {
+ KX_MouseActuator* tmpbaseact = new KX_MouseActuator(gameobj,
+ ketsjiEngine,
+ eventmgr,
+ mode,
+ visible,
+ use_axis,
+ mouAct->threshold,
+ reset,
+ mouAct->object_axis,
+ local,
+ mouAct->sensitivity,
+ mouAct->limit_x,
+ mouAct->limit_y);
+ baseact = tmpbaseact;
+ } else {
+ //cout << "\n Couldn't find mouse event manager..."; - should throw an error here...
+ }
+ break;
+ }
default:
; /* generate some error */
}
diff --git a/source/gameengine/Converter/KX_ConvertSensors.cpp b/source/gameengine/Converter/KX_ConvertSensors.cpp
index b3c6f6ddd24..0d706fcd924 100644
--- a/source/gameengine/Converter/KX_ConvertSensors.cpp
+++ b/source/gameengine/Converter/KX_ConvertSensors.cpp
@@ -329,12 +329,19 @@ void BL_ConvertSensors(struct Object* blenderobject,
gameobj);
} else {
/* give us a focus-aware sensor */
+ bool bFindMaterial = (bmouse->mode & SENS_COLLISION_MATERIAL);
+ bool bXRay = (bmouse->flag & SENS_RAY_XRAY);
+ STR_String checkname = (bFindMaterial? bmouse->matname : bmouse->propname);
+
gamesensor = new KX_MouseFocusSensor(eventmgr,
startx,
starty,
keytype,
trackfocus,
(bmouse->flag & SENS_MOUSE_FOCUS_PULSE) ? true:false,
+ checkname,
+ bFindMaterial,
+ bXRay,
kxscene,
kxengine,
gameobj);
@@ -377,6 +384,12 @@ void BL_ConvertSensors(struct Object* blenderobject,
propchecktype = SCA_PropertySensor::KX_PROPSENSOR_EXPRESSION;
/* error */
break;
+ case SENS_PROP_LESSTHAN:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_LESSTHAN;
+ break;
+ case SENS_PROP_GREATERTHAN:
+ propchecktype = SCA_PropertySensor::KX_PROPSENSOR_GREATERTHAN;
+ break;
default:
; /* error */
}
diff --git a/source/gameengine/Expressions/BoolValue.cpp b/source/gameengine/Expressions/BoolValue.cpp
index ee913877c96..9ff53395056 100644
--- a/source/gameengine/Expressions/BoolValue.cpp
+++ b/source/gameengine/Expressions/BoolValue.cpp
@@ -186,6 +186,13 @@ double CBoolValue::GetNumber()
+int CBoolValue::GetValueType()
+{
+ return VALUE_BOOL_TYPE;
+}
+
+
+
const STR_String& CBoolValue::GetText()
{
return m_bool ? sTrueString : sFalseString;
diff --git a/source/gameengine/Expressions/BoolValue.h b/source/gameengine/Expressions/BoolValue.h
index b88c839a58e..161d6112f68 100644
--- a/source/gameengine/Expressions/BoolValue.h
+++ b/source/gameengine/Expressions/BoolValue.h
@@ -41,6 +41,7 @@ public:
virtual const STR_String& GetText();
virtual double GetNumber();
+ virtual int GetValueType();
bool GetBool();
virtual void SetValue(CValue* newval);
diff --git a/source/gameengine/Expressions/EmptyValue.cpp b/source/gameengine/Expressions/EmptyValue.cpp
index 7f3af9f649d..f8e72181ed7 100644
--- a/source/gameengine/Expressions/EmptyValue.cpp
+++ b/source/gameengine/Expressions/EmptyValue.cpp
@@ -82,6 +82,13 @@ double CEmptyValue::GetNumber()
+int CEmptyValue::GetValueType()
+{
+ return VALUE_EMPTY_TYPE;
+}
+
+
+
CListValue* CEmptyValue::GetPolySoup()
{
CListValue* soup = new CListValue();
diff --git a/source/gameengine/Expressions/EmptyValue.h b/source/gameengine/Expressions/EmptyValue.h
index 8eccb97e0f5..88ef206f0f0 100644
--- a/source/gameengine/Expressions/EmptyValue.h
+++ b/source/gameengine/Expressions/EmptyValue.h
@@ -32,6 +32,7 @@ public:
virtual const STR_String & GetText();
virtual double GetNumber();
+ virtual int GetValueType();
CListValue* GetPolySoup();
virtual double* GetVector3(bool bGetTransformedVec=false);
bool IsInside(CValue* testpoint,bool bBorderInclude=true);
diff --git a/source/gameengine/Expressions/ErrorValue.cpp b/source/gameengine/Expressions/ErrorValue.cpp
index ba9c52be6c7..46e09b9073f 100644
--- a/source/gameengine/Expressions/ErrorValue.cpp
+++ b/source/gameengine/Expressions/ErrorValue.cpp
@@ -107,6 +107,13 @@ double CErrorValue::GetNumber()
+int CErrorValue::GetValueType()
+{
+ return VALUE_ERROR_TYPE;
+}
+
+
+
const STR_String & CErrorValue::GetText()
{
return m_strErrorText;
diff --git a/source/gameengine/Expressions/ErrorValue.h b/source/gameengine/Expressions/ErrorValue.h
index 0095528254e..61c72151f40 100644
--- a/source/gameengine/Expressions/ErrorValue.h
+++ b/source/gameengine/Expressions/ErrorValue.h
@@ -27,6 +27,7 @@ class CErrorValue : public CPropValue
public:
virtual const STR_String & GetText();
virtual double GetNumber();
+ virtual int GetValueType();
CErrorValue();
CErrorValue(const char *errmsg);
virtual ~CErrorValue();
diff --git a/source/gameengine/Expressions/Expression.cpp b/source/gameengine/Expressions/Expression.cpp
index c1146aaa65c..2428df977d3 100644
--- a/source/gameengine/Expressions/Expression.cpp
+++ b/source/gameengine/Expressions/Expression.cpp
@@ -21,13 +21,13 @@
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
-#ifdef _DEBUG
+#ifdef DEBUG
//int gRefCountExpr;
#endif
CExpression::CExpression()// : m_cached_calculate(NULL)
{
m_refcount = 1;
-#ifdef _DEBUG
+#ifdef DEBUG
//gRefCountExpr++;
#endif
}
diff --git a/source/gameengine/Expressions/Expression.h b/source/gameengine/Expressions/Expression.h
index d1b7eda43f0..9a4f1f93284 100644
--- a/source/gameengine/Expressions/Expression.h
+++ b/source/gameengine/Expressions/Expression.h
@@ -116,7 +116,7 @@ public:
virtual CExpression * AddRef() { // please leave multiline, for debugger !!!
-#ifdef _DEBUG
+#ifdef DEBUG
//gRefCountExpr++;
assertd(m_refcount < 255);
#endif
@@ -124,7 +124,7 @@ public:
return this;
};
virtual CExpression* Release(CExpression* complicatedtrick=NULL) {
-#ifdef _DEBUG
+#ifdef DEBUG
//gRefCountExpr--;
#endif
if (--m_refcount < 1)
diff --git a/source/gameengine/Expressions/FloatValue.cpp b/source/gameengine/Expressions/FloatValue.cpp
index 0f468e328ed..4d6f3f467eb 100644
--- a/source/gameengine/Expressions/FloatValue.cpp
+++ b/source/gameengine/Expressions/FloatValue.cpp
@@ -285,6 +285,13 @@ double CFloatValue::GetNumber()
+int CFloatValue::GetValueType()
+{
+ return VALUE_FLOAT_TYPE;
+}
+
+
+
void CFloatValue::SetValue(CValue* newval)
{
m_float = (float)newval->GetNumber();
diff --git a/source/gameengine/Expressions/FloatValue.h b/source/gameengine/Expressions/FloatValue.h
index bc6a2d052d4..379c3e951bc 100644
--- a/source/gameengine/Expressions/FloatValue.h
+++ b/source/gameengine/Expressions/FloatValue.h
@@ -33,6 +33,7 @@ public:
void Configure(CValue* menuvalue);
virtual double GetNumber();
+ virtual int GetValueType();
virtual void SetValue(CValue* newval);
float GetFloat();
void SetFloat(float fl);
diff --git a/source/gameengine/Expressions/IntValue.cpp b/source/gameengine/Expressions/IntValue.cpp
index fa4c9ad8ac9..82d2e94dbb0 100644
--- a/source/gameengine/Expressions/IntValue.cpp
+++ b/source/gameengine/Expressions/IntValue.cpp
@@ -15,6 +15,8 @@
*
*/
+#include <stdio.h>
+
#include "IntValue.h"
#include "ErrorValue.h"
#include "FloatValue.h"
@@ -33,7 +35,7 @@ effect: constructs a new CIntValue
*/
{
-#ifdef _DEBUG_
+#ifdef DEBUG_
m_textval = "Int illegal constructor";
#endif
m_pstrRep=NULL;
@@ -298,6 +300,13 @@ double CIntValue::GetNumber()
+int CIntValue::GetValueType()
+{
+ return VALUE_INT_TYPE;
+}
+
+
+
const STR_String & CIntValue::GetText()
{
if (!m_pstrRep)
diff --git a/source/gameengine/Expressions/IntValue.h b/source/gameengine/Expressions/IntValue.h
index 8411b09693c..6da975f4f7f 100644
--- a/source/gameengine/Expressions/IntValue.h
+++ b/source/gameengine/Expressions/IntValue.h
@@ -31,6 +31,7 @@ class CIntValue : public CPropValue
public:
virtual const STR_String& GetText();
virtual double GetNumber();
+ virtual int GetValueType();
cInt GetInt();
CIntValue();
diff --git a/source/gameengine/Expressions/ListValue.cpp b/source/gameengine/Expressions/ListValue.cpp
index 1f12a9b78e1..75e3b490505 100644
--- a/source/gameengine/Expressions/ListValue.cpp
+++ b/source/gameengine/Expressions/ListValue.cpp
@@ -250,6 +250,13 @@ double CListValue::GetNumber()
+int CListValue::GetValueType()
+{
+ return VALUE_LIST_TYPE;
+}
+
+
+
void CListValue::SetModified(bool bModified)
{
CValue::SetModified(bModified);
diff --git a/source/gameengine/Expressions/ListValue.h b/source/gameengine/Expressions/ListValue.h
index 5240c54ae4e..bb188179836 100644
--- a/source/gameengine/Expressions/ListValue.h
+++ b/source/gameengine/Expressions/ListValue.h
@@ -40,6 +40,7 @@ public:
VALUE_OPERATOR op,
CValue* val);
virtual double GetNumber();
+ virtual int GetValueType();
virtual CValue* GetReplica();
public:
diff --git a/source/gameengine/Expressions/StringValue.cpp b/source/gameengine/Expressions/StringValue.cpp
index 166125bc906..098949c9d7b 100644
--- a/source/gameengine/Expressions/StringValue.cpp
+++ b/source/gameengine/Expressions/StringValue.cpp
@@ -120,6 +120,13 @@ double CStringValue::GetNumber()
+int CStringValue::GetValueType()
+{
+ return VALUE_STRING_TYPE;
+}
+
+
+
const STR_String & CStringValue::GetText()
{
return m_strString;
diff --git a/source/gameengine/Expressions/StringValue.h b/source/gameengine/Expressions/StringValue.h
index 22d433455ec..cb60600ad88 100644
--- a/source/gameengine/Expressions/StringValue.h
+++ b/source/gameengine/Expressions/StringValue.h
@@ -36,6 +36,7 @@ public:
virtual bool IsEqual(const STR_String & other);
virtual const STR_String & GetText();
virtual double GetNumber();
+ virtual int GetValueType();
virtual CValue* Calc(VALUE_OPERATOR op, CValue *val);
virtual CValue* CalcFinal(VALUE_DATA_TYPE dtype, VALUE_OPERATOR op, CValue *val);
diff --git a/source/gameengine/Expressions/Value.cpp b/source/gameengine/Expressions/Value.cpp
index e5c4001de4c..bdef2dbd5b0 100644
--- a/source/gameengine/Expressions/Value.cpp
+++ b/source/gameengine/Expressions/Value.cpp
@@ -86,7 +86,7 @@ struct SmartCValueRef
std::vector<SmartCValueRef> gRefList;
#endif
-#ifdef _DEBUG
+#ifdef DEBUG
//int gRefCountValue;
#endif
@@ -101,7 +101,7 @@ effect: constucts a CValue
*/
{
//debug(gRefCountValue++) // debugging
-#ifdef _DEBUG
+#ifdef DEBUG
//gRefCountValue++;
#ifdef CVALUE_DEBUG
gRefList.push_back(SmartCValueRef(this));
@@ -460,7 +460,7 @@ void CValue::DisableRefCount()
m_refcount--;
//debug(gRefCountValue--);
-#ifdef _DEBUG
+#ifdef DEBUG
//gRefCountValue--;
#endif
m_ValFlags.RefCountDisabled=true;
@@ -472,7 +472,7 @@ void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */
{
m_refcount = 1;
-#ifdef _DEBUG
+#ifdef DEBUG
//gRefCountValue++;
#endif
PyObjectPlus::ProcessReplica();
@@ -494,6 +494,15 @@ void CValue::ProcessReplica() /* was AddDataToReplica in 2.48 */
}
}
+
+
+int CValue::GetValueType()
+{
+ return VALUE_NO_TYPE;
+}
+
+
+
CValue* CValue::FindIdentifier(const STR_String& identifiername)
{
diff --git a/source/gameengine/Expressions/Value.h b/source/gameengine/Expressions/Value.h
index db7d69a638f..c7e9a40a059 100644
--- a/source/gameengine/Expressions/Value.h
+++ b/source/gameengine/Expressions/Value.h
@@ -82,17 +82,15 @@ enum VALUE_DATA_TYPE {
VALUE_BOOL_TYPE,
VALUE_ERROR_TYPE,
VALUE_EMPTY_TYPE,
- VALUE_SOLID_TYPE,
- VALUE_COMBISOLID_TYPE,
+ VALUE_LIST_TYPE,
+ VALUE_VOID_TYPE,
VALUE_VECTOR_TYPE,
- VALUE_MENU_TYPE,
- VALUE_ACTOR_TYPE,
VALUE_MAX_TYPE //only here to provide number of types
};
-#ifdef _DEBUG
+#ifdef DEBUG
//extern int gRefCountValue; // debugonly variable to check if all CValue Refences are Dereferenced at programexit
#endif
@@ -253,7 +251,7 @@ public:
// Increase global reference count, used to see at the end of the program
// if all CValue-derived classes have been dereferenced to 0
//debug(gRefCountValue++);
-#ifdef _DEBUG
+#ifdef DEBUG
//gRefCountValue++;
#endif
m_refcount++;
@@ -266,7 +264,7 @@ public:
// Decrease global reference count, used to see at the end of the program
// if all CValue-derived classes have been dereferenced to 0
//debug(gRefCountValue--);
-#ifdef _DEBUG
+#ifdef DEBUG
//gRefCountValue--;
#endif
// Decrease local reference count, if it reaches 0 the object should be freed
@@ -311,6 +309,7 @@ public:
virtual const STR_String & GetText() = 0;
virtual double GetNumber() = 0;
+ virtual int GetValueType(); // Get Prop value type
double* ZeroVector() { return m_sZeroVec; }
virtual double* GetVector3(bool bGetTransformedVec = false);
@@ -323,7 +322,6 @@ public:
virtual void ProcessReplica();
//virtual CValue* Copy() = 0;
-
STR_String op2str(VALUE_OPERATOR op);
// setting / getting flags
diff --git a/source/gameengine/Expressions/VectorValue.cpp b/source/gameengine/Expressions/VectorValue.cpp
index a0e1b616d5e..6931ba2aa76 100644
--- a/source/gameengine/Expressions/VectorValue.cpp
+++ b/source/gameengine/Expressions/VectorValue.cpp
@@ -162,6 +162,14 @@ double CVectorValue::GetNumber()
}
+
+int CVectorValue::GetValueType()
+{
+ return VALUE_VECTOR_TYPE;
+}
+
+
+
double* CVectorValue::GetVector3(bool bGetTransformedVec)
{
if (bGetTransformedVec)
diff --git a/source/gameengine/Expressions/VectorValue.h b/source/gameengine/Expressions/VectorValue.h
index 69f2d4b54ae..717fa68f6dc 100644
--- a/source/gameengine/Expressions/VectorValue.h
+++ b/source/gameengine/Expressions/VectorValue.h
@@ -37,6 +37,7 @@ public:
void Configure(CValue* menuvalue);
virtual double* GetVector3(bool bGetTransformedVec=false);
virtual double GetNumber();
+ virtual int GetValueType();
CValue* Calc(VALUE_OPERATOR op, CValue *val) {
return val->CalcFinal(VALUE_VECTOR_TYPE, op, this);
diff --git a/source/gameengine/Expressions/VoidValue.h b/source/gameengine/Expressions/VoidValue.h
index 832f75c9c9f..4f74910dd8a 100644
--- a/source/gameengine/Expressions/VoidValue.h
+++ b/source/gameengine/Expressions/VoidValue.h
@@ -59,6 +59,7 @@ public:
/// Value -> String or number
virtual const STR_String & GetText(); /* Get string description of void value (unimplemented) */
virtual double GetNumber() { return -1; }
+ virtual int GetValueType() { return VALUE_VOID_TYPE; }
/// Value calculation
virtual CValue* Calc(VALUE_OPERATOR op, CValue *val);
diff --git a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h
index 37c867ef7d6..566e5567507 100644
--- a/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h
+++ b/source/gameengine/GameLogic/Joystick/SCA_JoystickDefines.h
@@ -36,7 +36,7 @@
#undef main
#endif
-#ifndef _DEBUG
+#ifndef DEBUG
# define JOYSTICK_ECHO(x)
#else
# include <iostream>
diff --git a/source/gameengine/GameLogic/SCA_IActuator.h b/source/gameengine/GameLogic/SCA_IActuator.h
index aed49bc1822..8c22fb39c80 100644
--- a/source/gameengine/GameLogic/SCA_IActuator.h
+++ b/source/gameengine/GameLogic/SCA_IActuator.h
@@ -89,6 +89,7 @@ public:
KX_ACT_STATE,
KX_ACT_ARMATURE,
KX_ACT_STEERING,
+ KX_ACT_MOUSE,
};
SCA_IActuator(SCA_IObject* gameobj, KX_ACTUATOR_TYPE type);
diff --git a/source/gameengine/GameLogic/SCA_IScene.cpp b/source/gameengine/GameLogic/SCA_IScene.cpp
index c98c86639d3..3ca4b6607b3 100644
--- a/source/gameengine/GameLogic/SCA_IScene.cpp
+++ b/source/gameengine/GameLogic/SCA_IScene.cpp
@@ -70,6 +70,32 @@ std::vector<SCA_DebugProp*>& SCA_IScene::GetDebugProperties()
}
+bool SCA_IScene::PropertyInDebugList( class CValue *gameobj, const STR_String &name )
+{
+ for (std::vector<SCA_DebugProp*>::iterator it = m_debugList.begin();
+ !(it==m_debugList.end());++it) {
+ STR_String debugname = (*it)->m_name;
+ CValue *debugobj = (*it)->m_obj;
+
+ if (debugobj == gameobj && debugname == name)
+ return true;
+ }
+ return false;
+}
+
+
+bool SCA_IScene::ObjectInDebugList( class CValue *gameobj )
+{
+ for (std::vector<SCA_DebugProp*>::iterator it = m_debugList.begin();
+ !(it==m_debugList.end());++it) {
+ CValue* debugobj = (*it)->m_obj;
+
+ if (debugobj == gameobj)
+ return true;
+ }
+ return false;
+}
+
void SCA_IScene::AddDebugProperty(class CValue* debugprop,
const STR_String &name)
@@ -84,6 +110,24 @@ void SCA_IScene::AddDebugProperty(class CValue* debugprop,
}
+void SCA_IScene::RemoveDebugProperty(class CValue *gameobj,
+ const STR_String &name)
+{
+ vector<SCA_DebugProp*>::iterator it = m_debugList.begin();
+ while(it != m_debugList.end()) {
+ STR_String debugname = (*it)->m_name;
+ CValue *debugobj = (*it)->m_obj;
+
+ if (debugobj == gameobj && debugname == name) {
+ delete (*it);
+ m_debugList.erase(it);
+ break;
+ }
+ ++it;
+ }
+}
+
+
void SCA_IScene::RemoveObjectDebugProperties(class CValue* gameobj)
{
vector<SCA_DebugProp*>::iterator it = m_debugList.begin();
diff --git a/source/gameengine/GameLogic/SCA_IScene.h b/source/gameengine/GameLogic/SCA_IScene.h
index e2e1edd4354..b76b5636b13 100644
--- a/source/gameengine/GameLogic/SCA_IScene.h
+++ b/source/gameengine/GameLogic/SCA_IScene.h
@@ -67,9 +67,11 @@ public:
virtual void ReplaceMesh(class CValue* gameobj,
void* meshobj, bool use_gfx, bool use_phys)=0;
std::vector<SCA_DebugProp*>& GetDebugProperties();
+ bool PropertyInDebugList(class CValue *gameobj, const STR_String &name);
+ bool ObjectInDebugList(class CValue *gameobj);
void RemoveAllDebugProperties();
- void AddDebugProperty(class CValue* debugprop,
- const STR_String &name);
+ void AddDebugProperty(class CValue* debugprop, const STR_String &name);
+ void RemoveDebugProperty(class CValue *gameobj, const STR_String &name);
void RemoveObjectDebugProperties(class CValue* gameobj);
virtual void Update2DFilter(std::vector<STR_String>& propNames, void* gameObj,
diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp
index 0eab6187d07..ea1b2a2bce3 100644
--- a/source/gameengine/GameLogic/SCA_PropertyActuator.cpp
+++ b/source/gameengine/GameLogic/SCA_PropertyActuator.cpp
@@ -69,13 +69,24 @@ bool SCA_PropertyActuator::Update()
bool bNegativeEvent = IsNegativeEvent();
RemoveAllEvents();
-
+ CValue* propowner = GetParent();
if (bNegativeEvent)
- return false; // do nothing on negative events
+ {
+ if (m_type==KX_ACT_PROP_LEVEL)
+ {
+ CValue* newval = new CBoolValue(false);
+ CValue* oldprop = propowner->GetProperty(m_propname);
+ if (oldprop)
+ {
+ oldprop->SetValue(newval);
+ }
+ newval->Release();
+ }
+ return false;
+ }
- CValue* propowner = GetParent();
CParser parser;
parser.SetContext( propowner->AddRef());
@@ -97,6 +108,19 @@ bool SCA_PropertyActuator::Update()
}
newval->Release();
}
+ else if (m_type==KX_ACT_PROP_LEVEL)
+ {
+ CValue* newval = new CBoolValue(true);
+ CValue* oldprop = propowner->GetProperty(m_propname);
+ if (oldprop)
+ {
+ oldprop->SetValue(newval);
+ } else
+ {
+ propowner->SetProperty(m_propname,newval);
+ }
+ newval->Release();
+ }
else if ((userexpr = parser.ProcessText(m_exprtxt))) {
switch (m_type)
{
diff --git a/source/gameengine/GameLogic/SCA_PropertyActuator.h b/source/gameengine/GameLogic/SCA_PropertyActuator.h
index 83a6d05df1b..228ecf94bc4 100644
--- a/source/gameengine/GameLogic/SCA_PropertyActuator.h
+++ b/source/gameengine/GameLogic/SCA_PropertyActuator.h
@@ -44,6 +44,7 @@ class SCA_PropertyActuator : public SCA_IActuator
KX_ACT_PROP_ADD,
KX_ACT_PROP_COPY,
KX_ACT_PROP_TOGGLE,
+ KX_ACT_PROP_LEVEL,
KX_ACT_PROP_MAX
};
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
index ad57e529297..6f34f8710c1 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp
@@ -133,6 +133,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
{
case KX_PROPSENSOR_NOTEQUAL:
reverse = true;
+ /* fall-through */
case KX_PROPSENSOR_EQUAL:
{
CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
@@ -150,7 +151,7 @@ bool SCA_PropertySensor::CheckPropertyCondition()
/* Patch: floating point values cant use strings usefully since you can have "0.0" == "0.0000"
* this could be made into a generic Value class function for comparing values with a string.
*/
- if (result==false && dynamic_cast<CFloatValue *>(orgprop) != NULL) {
+ if (result==false && (orgprop->GetValueType() == VALUE_FLOAT_TYPE)) {
float f;
if (sscanf(m_checkpropval.ReadPtr(), "%f", &f) == 1) {
result = (f == ((CFloatValue *)orgprop)->GetFloat());
@@ -198,11 +199,11 @@ bool SCA_PropertySensor::CheckPropertyCondition()
const float max = m_checkpropmaxval.ToFloat();
float val;
- if (dynamic_cast<CStringValue *>(orgprop) == NULL) {
- val = orgprop->GetNumber();
+ if (orgprop->GetValueType() == VALUE_STRING_TYPE){
+ val = orgprop->GetText().ToFloat();
}
else {
- val = orgprop->GetText().ToFloat();
+ val = orgprop->GetNumber();
}
result = (min <= val) && (val <= max);
@@ -228,6 +229,36 @@ bool SCA_PropertySensor::CheckPropertyCondition()
//cout << " \nSens:Prop:changed!"; /* need implementation here!!! */
break;
}
+ case KX_PROPSENSOR_LESSTHAN:
+ reverse = true;
+ /* fall-through */
+ case KX_PROPSENSOR_GREATERTHAN:
+ {
+ CValue* orgprop = GetParent()->FindIdentifier(m_checkpropname);
+ if (!orgprop->IsError())
+ {
+ const float ref = m_checkpropval.ToFloat();
+ float val;
+
+ if (orgprop->GetValueType() == VALUE_STRING_TYPE){
+ val = orgprop->GetText().ToFloat();
+ }
+ else {
+ val = orgprop->GetNumber();
+ }
+
+ if (reverse) {
+ result = val < ref;
+ }
+ else {
+ result = val > ref;
+ }
+
+ }
+ orgprop->Release();
+
+ break;
+ }
default:
; /* error */
}
diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.h b/source/gameengine/GameLogic/SCA_PropertySensor.h
index fee03dcf4c0..f9cfb5fb1d2 100644
--- a/source/gameengine/GameLogic/SCA_PropertySensor.h
+++ b/source/gameengine/GameLogic/SCA_PropertySensor.h
@@ -57,6 +57,8 @@ public:
KX_PROPSENSOR_INTERVAL,
KX_PROPSENSOR_CHANGED,
KX_PROPSENSOR_EXPRESSION,
+ KX_PROPSENSOR_LESSTHAN,
+ KX_PROPSENSOR_GREATERTHAN,
KX_PROPSENSOR_MAX
};
diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp
index 3a9e8ff0bbc..8c3ce38276e 100644
--- a/source/gameengine/GameLogic/SCA_PythonController.cpp
+++ b/source/gameengine/GameLogic/SCA_PythonController.cpp
@@ -263,7 +263,18 @@ PyAttributeDef SCA_PythonController::Attributes[] = {
void SCA_PythonController::ErrorPrint(const char *error_msg)
{
- printf("%s - object '%s', controller '%s':\n", error_msg, GetParent()->GetName().Ptr(), GetName().Ptr());
+ // If GetParent() is NULL, then most likely the object this controller
+ // was attached to is gone (e.g., removed by LibFree()). Also, GetName()
+ // can be a bad pointer if GetParent() is NULL, so better be safe and
+ // flag it as unavailable as well
+ const char *obj_name, *ctr_name;
+ if (GetParent()) {
+ obj_name = GetParent()->GetName().ReadPtr();
+ ctr_name = GetName().ReadPtr();
+ } else {
+ obj_name = ctr_name = "Unavailable";
+ }
+ printf("%s - object '%s', controller '%s':\n", error_msg, obj_name, ctr_name);
PyErr_Print();
/* Added in 2.48a, the last_traceback can reference Objects for example, increasing
diff --git a/source/gameengine/GamePlayer/common/CMakeLists.txt b/source/gameengine/GamePlayer/common/CMakeLists.txt
index 2fc4df86332..e6c980de566 100644
--- a/source/gameengine/GamePlayer/common/CMakeLists.txt
+++ b/source/gameengine/GamePlayer/common/CMakeLists.txt
@@ -47,6 +47,7 @@ set(INC
../../../blender/makesdna
../../../../intern/container
../../../../intern/ghost
+ ../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../intern/string
)
@@ -55,7 +56,7 @@ set(INC_SYS
../../../../intern/moto/include
${GLEW_INCLUDE_PATH}
${PYTHON_INCLUDE_DIRS}
- ${PNG_INCLUDE_DIR}
+ ${PNG_INCLUDE_DIRS}
${ZLIB_INCLUDE_DIRS}
)
@@ -69,6 +70,6 @@ set(SRC
GPC_MouseDevice.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
blender_add_lib_nolist(ge_player_common "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.h b/source/gameengine/GamePlayer/common/GPC_Canvas.h
index bd50066a212..338f9647b3e 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.h
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.h
@@ -40,7 +40,7 @@
# include <windows.h>
#endif /* WIN32 */
-#include "GL/glew.h"
+#include "glew-mx.h"
#include <map>
diff --git a/source/gameengine/GamePlayer/common/SConscript b/source/gameengine/GamePlayer/common/SConscript
index e30c2eb5859..b8fb9cbd2e2 100644
--- a/source/gameengine/GamePlayer/common/SConscript
+++ b/source/gameengine/GamePlayer/common/SConscript
@@ -64,12 +64,11 @@ incs = [
'#source/blender/misc',
'#source/blender/blenloader',
'#source/blender/gpu',
- '#extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
]
-defs = [
- 'GLEW_STATIC',
- ]
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_PYTHON']:
incs.extend(Split(env['BF_PYTHON_INC']))
diff --git a/source/gameengine/GamePlayer/ghost/CMakeLists.txt b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
index df752799c2c..8ab090eac02 100644
--- a/source/gameengine/GamePlayer/ghost/CMakeLists.txt
+++ b/source/gameengine/GamePlayer/ghost/CMakeLists.txt
@@ -48,6 +48,7 @@ set(INC
../../../blender/makesrna
../../../../intern/container
../../../../intern/ghost
+ ../../../../intern/glew-mx
../../../../intern/guardedalloc
../../../../intern/string
../../../../intern/memutil
@@ -73,7 +74,7 @@ set(SRC
GPG_System.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_CODEC_FFMPEG)
add_definitions(-DWITH_FFMPEG)
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
index b85d4b40ca8..d7a63c28da3 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp
@@ -36,8 +36,9 @@
# include <windows.h>
#endif
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "GPU_extensions.h"
+#include "GPU_init_exit.h"
#include "GPG_Application.h"
#include "BL_BlenderDataConversion.h"
@@ -545,7 +546,7 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode)
{
if (!m_engineInitialized)
{
- GPU_extensions_init();
+ GPU_init();
bgl::InitExtensions(true);
// get and set the preferences
@@ -867,7 +868,7 @@ void GPG_Application::exitEngine()
m_canvas = 0;
}
- GPU_extensions_exit();
+ GPU_exit();
#ifdef WITH_PYTHON
// Call this after we're sure nothing needs Python anymore (e.g., destructors)
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp b/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp
index 35c7c62a67d..556f85804ea 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_Canvas.cpp
@@ -113,12 +113,12 @@ void GPG_Canvas::SetSwapInterval(int interval)
m_window->setSwapInterval(interval);
}
-int GPG_Canvas::GetSwapInterval()
+bool GPG_Canvas::GetSwapInterval(int& intervalOut)
{
if (m_window)
- return m_window->getSwapInterval();
+ return (bool)m_window->getSwapInterval(intervalOut);
- return 0;
+ return false;
}
void GPG_Canvas::ResizeWindow(int width, int height)
diff --git a/source/gameengine/GamePlayer/ghost/GPG_Canvas.h b/source/gameengine/GamePlayer/ghost/GPG_Canvas.h
index 6e1f86cac0e..337c2cedf55 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_Canvas.h
+++ b/source/gameengine/GamePlayer/ghost/GPG_Canvas.h
@@ -56,7 +56,7 @@ public:
virtual void SetMouseState(RAS_MouseState mousestate);
virtual void SwapBuffers();
virtual void SetSwapInterval(int interval);
- virtual int GetSwapInterval();
+ virtual bool GetSwapInterval(int& intervalOut);
virtual int GetMouseX(int x) { return x; }
virtual int GetMouseY(int y) { return y; }
diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
index 31fafd86db7..3bb5f17841d 100644
--- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
+++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp
@@ -79,8 +79,6 @@ extern "C"
#include "IMB_imbuf.h"
#include "IMB_moviecache.h"
- int GHOST_HACK_getFirstFile(char buf[]);
-
// For BLF
#include "BLF_api.h"
#include "BLF_translation.h"
@@ -294,12 +292,6 @@ static void get_filename(int argc, char **argv, char *filename)
if (BLI_exists(argv[argc-1])) {
BLI_strncpy(filename, argv[argc-1], FILE_MAX);
}
- if (::strncmp(argv[argc-1], "-psn_", 5)==0) {
- static char firstfilebuf[512];
- if (GHOST_HACK_getFirstFile(firstfilebuf)) {
- BLI_strncpy(filename, firstfilebuf, FILE_MAX);
- }
- }
}
srclen -= ::strlen("MacOS/blenderplayer");
@@ -430,7 +422,7 @@ int main(int argc, char** argv)
#endif /* __alpha__ */
#endif /* __linux__ */
BLI_init_program_path(argv[0]);
- BLI_init_temporary_dir(NULL);
+ BLI_temp_dir_init(NULL);
// We don't use threads directly in the BGE, but we need to call this so things like
// freeing up GPU_Textures works correctly.
@@ -811,14 +803,6 @@ int main(int argc, char** argv)
if (scr_saver_mode != SCREEN_SAVER_MODE_CONFIGURATION)
#endif
{
-
- if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) {
- GPU_set_mipmap(0);
- }
-
- GPU_set_anisotropic(U.anisotropic_filter);
- GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
-
// Create the system
if (GHOST_ISystem::createSystem() == GHOST_kSuccess) {
GHOST_ISystem* system = GHOST_ISystem::getSystem();
@@ -1041,6 +1025,13 @@ int main(int argc, char** argv)
else
app.startWindow(title, windowLeft, windowTop, windowWidth, windowHeight,
stereoWindow, stereomode, aasamples);
+
+ if (SYS_GetCommandLineInt(syshandle, "nomipmap", 0)) {
+ GPU_set_mipmap(0);
+ }
+
+ GPU_set_anisotropic(U.anisotropic_filter);
+ GPU_set_gpu_mipmapping(U.use_gpu_mipmap);
}
}
}
@@ -1142,5 +1133,7 @@ int main(int argc, char** argv)
MEM_printmemlist();
}
+ BLI_temp_dir_session_purge();
+
return error ? -1 : 0;
}
diff --git a/source/gameengine/GamePlayer/ghost/SConscript b/source/gameengine/GamePlayer/ghost/SConscript
index 3e8ab3d0dd7..d4c31889a5e 100644
--- a/source/gameengine/GamePlayer/ghost/SConscript
+++ b/source/gameengine/GamePlayer/ghost/SConscript
@@ -68,15 +68,14 @@ incs = [
'#source/blender/misc',
'#source/blender/blenloader',
'#source/blender/gpu',
- '#extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
]
incs.append(env['BF_PTHREADS_INC'])
incs.append(env['BF_BOOST_INC'])
-defs = [
- 'GLEW_STATIC',
- ]
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_PYTHON']:
incs += Split(env['BF_PYTHON_INC'])
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp
index 6f6925dcf76..bcdef85bc8a 100644
--- a/source/gameengine/Ketsji/BL_BlenderShader.cpp
+++ b/source/gameengine/Ketsji/BL_BlenderShader.cpp
@@ -77,7 +77,7 @@ void BL_BlenderShader::SetProg(bool enable, double time, RAS_IRasterizer* rasty)
view.getValue((float*)viewmat);
viewinv.getValue((float*)viewinvmat);
- GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time, 1, viewmat, viewinvmat);
+ GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time, 1, viewmat, viewinvmat, false);
}
else
GPU_material_unbind(mGPUMat);
diff --git a/source/gameengine/Ketsji/BL_Shader.cpp b/source/gameengine/Ketsji/BL_Shader.cpp
index 872ac19351d..a59c3686a18 100644
--- a/source/gameengine/Ketsji/BL_Shader.cpp
+++ b/source/gameengine/Ketsji/BL_Shader.cpp
@@ -22,7 +22,7 @@
* \ingroup ketsji
*/
-#include "GL/glew.h"
+#include "glew-mx.h"
#include <iostream>
#include "BL_Shader.h"
diff --git a/source/gameengine/Ketsji/BL_Texture.cpp b/source/gameengine/Ketsji/BL_Texture.cpp
index 1578c745b9f..1a78efb3c18 100644
--- a/source/gameengine/Ketsji/BL_Texture.cpp
+++ b/source/gameengine/Ketsji/BL_Texture.cpp
@@ -22,7 +22,7 @@
* \ingroup ketsji
*/
-#include "GL/glew.h"
+#include "glew-mx.h"
#include <iostream>
#include <map>
diff --git a/source/gameengine/Ketsji/CMakeLists.txt b/source/gameengine/Ketsji/CMakeLists.txt
index 09ef1677d7c..44532e5d737 100644
--- a/source/gameengine/Ketsji/CMakeLists.txt
+++ b/source/gameengine/Ketsji/CMakeLists.txt
@@ -49,6 +49,7 @@ set(INC
../../blender/python/generic
../../blender/python/mathutils
../../../intern/container
+ ../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/string
)
@@ -91,6 +92,7 @@ set(SRC
KX_MaterialIpoController.cpp
KX_MeshProxy.cpp
KX_MotionState.cpp
+ KX_MouseActuator.cpp
KX_MouseFocusSensor.cpp
KX_NavMeshObject.cpp
KX_NearSensor.cpp
@@ -169,6 +171,7 @@ set(SRC
KX_MaterialIpoController.h
KX_MeshProxy.h
KX_MotionState.h
+ KX_MouseActuator.h
KX_MouseFocusSensor.h
KX_NavMeshObject.h
KX_NearSensor.h
@@ -227,7 +230,7 @@ set(SRC
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
if(WITH_IMAGE_DDS)
add_definitions(-DWITH_DDS)
diff --git a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
index 68a71218b8c..9f0b582045f 100644
--- a/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
+++ b/source/gameengine/Ketsji/KX_BlenderMaterial.cpp
@@ -22,7 +22,7 @@
* \ingroup ketsji
*/
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "KX_BlenderMaterial.h"
#include "BL_Material.h"
@@ -616,7 +616,7 @@ void KX_BlenderMaterial::ActivateMeshSlot(const RAS_MeshSlot & ms, RAS_IRasteriz
/* we do blend modes here, because they can change per object
* with the same material due to obcolor/obalpha */
alphablend = mBlenderShader->GetAlphaBlend();
- if (ELEM3(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID)
+ if (ELEM(alphablend, GEMAT_SOLID, GEMAT_ALPHA, GEMAT_ALPHA_SORT) && mMaterial->alphablend != GEMAT_SOLID)
alphablend = mMaterial->alphablend;
rasty->SetAlphaBlend(alphablend);
diff --git a/source/gameengine/Ketsji/KX_Camera.cpp b/source/gameengine/Ketsji/KX_Camera.cpp
index 4ab768e4240..e0761154ed2 100644
--- a/source/gameengine/Ketsji/KX_Camera.cpp
+++ b/source/gameengine/Ketsji/KX_Camera.cpp
@@ -31,7 +31,7 @@
*/
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "KX_Camera.h"
#include "KX_Scene.h"
#include "KX_PythonInit.h"
diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp
index 793324fab75..29d92762285 100644
--- a/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.cpp
@@ -114,6 +114,7 @@ PyMethodDef KX_ConstraintWrapper::Methods[] = {
PyAttributeDef KX_ConstraintWrapper::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("constraint_id", KX_ConstraintWrapper, pyattr_get_constraintId),
+ KX_PYATTRIBUTE_RO_FUNCTION("constraint_type", KX_ConstraintWrapper, pyattr_get_constraintType),
{ NULL } //Sentinel
};
@@ -123,4 +124,10 @@ PyObject *KX_ConstraintWrapper::pyattr_get_constraintId(void *self_v, const KX_P
return self->PyGetConstraintId();
}
+PyObject *KX_ConstraintWrapper::pyattr_get_constraintType(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_ConstraintWrapper* self = static_cast<KX_ConstraintWrapper*>(self_v);
+ return PyLong_FromLong(self->m_constraintType);
+}
+
#endif // WITH_PYTHON
diff --git a/source/gameengine/Ketsji/KX_ConstraintWrapper.h b/source/gameengine/Ketsji/KX_ConstraintWrapper.h
index eafc45b5a70..b7124c76439 100644
--- a/source/gameengine/Ketsji/KX_ConstraintWrapper.h
+++ b/source/gameengine/Ketsji/KX_ConstraintWrapper.h
@@ -49,6 +49,7 @@ public:
KX_PYMETHOD(KX_ConstraintWrapper,GetParam);
static PyObject *pyattr_get_constraintId(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static PyObject *pyattr_get_constraintType(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
#endif
private:
diff --git a/source/gameengine/Ketsji/KX_Dome.cpp b/source/gameengine/Ketsji/KX_Dome.cpp
index 71d7257a907..a77269c116d 100644
--- a/source/gameengine/Ketsji/KX_Dome.cpp
+++ b/source/gameengine/Ketsji/KX_Dome.cpp
@@ -41,7 +41,7 @@
#include "RAS_CameraData.h"
#include "BLI_math.h"
-#include "GL/glew.h"
+#include "glew-mx.h"
// constructor
KX_Dome::KX_Dome (
@@ -2044,9 +2044,7 @@ void KX_Dome::RenderDomeFrame(KX_Scene* scene, KX_Camera* cam, int i)
cam->NodeUpdateGS(0.f);
scene->CalculateVisibleMeshes(m_rasterizer,cam);
+ scene->UpdateAnimations(m_engine->GetFrameTime());
scene->RenderBuckets(camtrans, m_rasterizer);
-
- // update levels of detail
- scene->UpdateObjectLods();
}
diff --git a/source/gameengine/Ketsji/KX_Dome.h b/source/gameengine/Ketsji/KX_Dome.h
index a7e798a3944..420565e62f6 100644
--- a/source/gameengine/Ketsji/KX_Dome.h
+++ b/source/gameengine/Ketsji/KX_Dome.h
@@ -38,7 +38,7 @@
#include "RAS_IRasterizer.h"
#include "KX_KetsjiEngine.h"
-#include "GL/glew.h"
+#include "glew-mx.h"
#include <vector>
#include "MEM_guardedalloc.h"
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index 9ea76980c20..dc246406a88 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -51,6 +51,7 @@ typedef unsigned long uint_ptr;
#include "KX_Light.h" // only for their ::Type
#include "KX_FontObject.h" // only for their ::Type
#include "RAS_MeshObject.h"
+#include "KX_NavMeshObject.h"
#include "KX_MeshProxy.h"
#include "KX_PolyProxy.h"
#include <stdio.h> // printf
@@ -68,6 +69,7 @@ typedef unsigned long uint_ptr;
#include "SCA_IController.h"
#include "NG_NetworkScene.h" //Needed for sendMessage()
#include "KX_ObstacleSimulation.h"
+#include "KX_Scene.h"
#include "BKE_object.h"
@@ -928,6 +930,27 @@ KX_GameObject::SetVisible(
}
}
+bool KX_GameObject::GetCulled()
+{
+ // If we're set to not cull, double-check with
+ // the mesh slots first. This is kind of nasty, but
+ // it allows us to get proper culling information.
+ if (!m_bCulled)
+ {
+ SG_QList::iterator<RAS_MeshSlot> mit(m_meshSlots);
+ for (mit.begin(); !mit.end(); ++mit)
+ {
+ if ((*mit)->m_bCulled)
+ {
+ m_bCulled = true;
+ break;
+ }
+ }
+ }
+
+ return m_bCulled;
+}
+
static void setOccluder_recursive(SG_Node* node, bool v)
{
NodeList& children = node->GetSGChildren();
@@ -958,6 +981,44 @@ KX_GameObject::SetOccluder(
}
}
+static void setDebug_recursive(SG_Node *node, bool debug)
+{
+ NodeList& children = node->GetSGChildren();
+ KX_Scene *scene = KX_GetActiveScene();
+
+ for (NodeList::iterator childit = children.begin();!(childit==children.end());++childit) {
+ SG_Node *childnode = (*childit);
+ KX_GameObject *clientgameobj = static_cast<KX_GameObject*>( (*childit)->GetSGClientObject());
+ if (clientgameobj != NULL) {
+ if (debug) {
+ if (!scene->ObjectInDebugList(clientgameobj))
+ scene->AddObjectDebugProperties(clientgameobj);
+ }
+ else
+ scene->RemoveObjectDebugProperties(clientgameobj);
+ }
+
+ /* if the childobj is NULL then this may be an inverse parent link
+ * so a non recursive search should still look down this node. */
+ setDebug_recursive(childnode, debug);
+ }
+}
+
+void KX_GameObject::SetUseDebugProperties( bool debug, bool recursive )
+{
+ KX_Scene *scene = KX_GetActiveScene();
+
+ if (debug) {
+ if (!scene->ObjectInDebugList(this))
+ scene->AddObjectDebugProperties(this);
+ }
+ else
+ scene->RemoveObjectDebugProperties(this);
+
+ if (recursive)
+ setDebug_recursive(GetSGNode(), debug);
+}
+
void
KX_GameObject::SetLayer(
int l
@@ -1526,9 +1587,10 @@ CListValue* KX_GameObject::GetChildrenRecursive()
KX_Scene* KX_GameObject::GetScene()
{
SG_Node* node = this->GetSGNode();
- KX_Scene* scene = static_cast<KX_Scene*>(node->GetSGClientInfo());
-
- return scene;
+ if (node == NULL)
+ // this happens for object in non active layers, rely on static scene then
+ return KX_GetActiveScene();
+ return static_cast<KX_Scene*>(node->GetSGClientInfo());
}
/* ---------------------------------------------------------------------
@@ -1807,6 +1869,7 @@ PyMethodDef KX_GameObject::Methods[] = {
KX_PYMETHODTABLE_O(KX_GameObject, getDistanceTo),
KX_PYMETHODTABLE_O(KX_GameObject, getVectTo),
KX_PYMETHODTABLE(KX_GameObject, sendMessage),
+ KX_PYMETHODTABLE(KX_GameObject, addDebugProperty),
KX_PYMETHODTABLE_KEYWORDS(KX_GameObject, playAction),
KX_PYMETHODTABLE(KX_GameObject, stopAction),
@@ -1859,6 +1922,8 @@ PyAttributeDef KX_GameObject::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("childrenRecursive", KX_GameObject, pyattr_get_children_recursive),
KX_PYATTRIBUTE_RO_FUNCTION("attrDict", KX_GameObject, pyattr_get_attrDict),
KX_PYATTRIBUTE_RW_FUNCTION("color", KX_GameObject, pyattr_get_obcolor, pyattr_set_obcolor),
+ KX_PYATTRIBUTE_RW_FUNCTION("debug", KX_GameObject, pyattr_get_debug, pyattr_set_debug),
+ KX_PYATTRIBUTE_RW_FUNCTION("debugRecursive", KX_GameObject, pyattr_get_debugRecursive, pyattr_set_debugRecursive),
/* experimental, don't rely on these yet */
KX_PYATTRIBUTE_RO_FUNCTION("sensors", KX_GameObject, pyattr_get_sensors),
@@ -2167,9 +2232,15 @@ int KX_GameObject::pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIB
return PY_SET_ATTR_FAIL;
}
- Py_XDECREF(self->m_collisionCallbacks);
+ if (self->m_collisionCallbacks == NULL) {
+ self->RegisterCollisionCallbacks();
+ } else {
+ Py_DECREF(self->m_collisionCallbacks);
+ }
+
Py_INCREF(value);
+
self->m_collisionCallbacks = value;
return PY_SET_ATTR_SUCCESS;
@@ -2769,6 +2840,52 @@ PyObject *KX_GameObject::pyattr_get_attrDict(void *self_v, const KX_PYATTRIBUTE_
return self->m_attr_dict;
}
+PyObject *KX_GameObject::pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_Scene *scene = KX_GetActiveScene();
+ KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
+
+ return PyBool_FromLong(scene->ObjectInDebugList(self));
+}
+
+int KX_GameObject::pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
+ int param = PyObject_IsTrue(value);
+
+ if (param == -1) {
+ PyErr_SetString(PyExc_AttributeError, "gameOb.debug = bool: KX_GameObject, expected True or False");
+ return PY_SET_ATTR_FAIL;
+ }
+
+ self->SetUseDebugProperties(param, false);
+
+ return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject *KX_GameObject::pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_Scene *scene = KX_GetActiveScene();
+ KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
+
+ return PyBool_FromLong(scene->ObjectInDebugList(self));
+}
+
+int KX_GameObject::pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ KX_GameObject *self = static_cast<KX_GameObject*>(self_v);
+ int param = PyObject_IsTrue(value);
+
+ if (param == -1) {
+ PyErr_SetString(PyExc_AttributeError, "gameOb.debugRecursive = bool: KX_GameObject, expected True or False");
+ return PY_SET_ATTR_FAIL;
+ }
+
+ self->SetUseDebugProperties(param, true);
+
+ return PY_SET_ATTR_SUCCESS;
+}
+
PyObject *KX_GameObject::PyApplyForce(PyObject *args)
{
int local = 0;
@@ -3007,19 +3124,20 @@ PyObject *KX_GameObject::PyApplyImpulse(PyObject *args)
{
PyObject *pyattach;
PyObject *pyimpulse;
+ int local = 0;
if (!m_pPhysicsController) {
PyErr_SetString(PyExc_RuntimeError, "This object has no physics controller");
return NULL;
}
- if (PyArg_ParseTuple(args, "OO:applyImpulse", &pyattach, &pyimpulse))
+ if (PyArg_ParseTuple(args, "OO|i:applyImpulse", &pyattach, &pyimpulse, &local))
{
MT_Point3 attach;
MT_Vector3 impulse;
if (PyVecTo(pyattach, attach) && PyVecTo(pyimpulse, impulse))
{
- m_pPhysicsController->ApplyImpulse(attach, impulse);
+ m_pPhysicsController->ApplyImpulse(attach, impulse, (local!=0));
Py_RETURN_NONE;
}
@@ -3253,8 +3371,6 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCastTo,
KX_GameObject *parent = GetParent();
if (!spc && parent)
spc = parent->GetPhysicsController();
- if (parent)
- parent->Release();
m_pHitObject = NULL;
if (propName)
@@ -3399,8 +3515,6 @@ KX_PYMETHODDEF_DOC(KX_GameObject, rayCast,
KX_GameObject *parent = GetParent();
if (!spc && parent)
spc = parent->GetPhysicsController();
- if (parent)
- parent->Release();
m_pHitObject = NULL;
if (propName)
@@ -3593,6 +3707,29 @@ KX_PYMETHODDEF_DOC(KX_GameObject, isPlayingAction,
}
+KX_PYMETHODDEF_DOC(KX_GameObject, addDebugProperty,
+"addDebugProperty(name, visible=1)\n"
+"Added or remove a debug property to the debug list.\n")
+{
+ KX_Scene *scene = KX_GetActiveScene();
+ char *name;
+ int visible = 1;
+
+ if (!PyArg_ParseTuple(args,"s|i:debugProperty", &name , &visible))
+ return NULL;
+
+ if (visible) {
+ if (!scene->PropertyInDebugList(this, name))
+ scene->AddDebugProperty(this, name);
+ }
+ else {
+ scene->RemoveDebugProperty(this, name);
+ }
+
+ Py_RETURN_NONE;
+}
+
+
/* dict style access */
@@ -3660,7 +3797,8 @@ bool ConvertPythonToGameObject(PyObject *value, KX_GameObject **object, bool py_
if ( PyObject_TypeCheck(value, &KX_GameObject::Type) ||
PyObject_TypeCheck(value, &KX_LightObject::Type) ||
PyObject_TypeCheck(value, &KX_Camera::Type) ||
- PyObject_TypeCheck(value, &KX_FontObject::Type))
+ PyObject_TypeCheck(value, &KX_FontObject::Type) ||
+ PyObject_TypeCheck(value, &KX_NavMeshObject::Type))
{
*object = static_cast<KX_GameObject*>BGE_PROXY_REF(value);
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index 7450be4fdef..d4fa4851696 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -852,10 +852,10 @@ public:
/**
* Was this object culled?
*/
- inline bool
+ bool
GetCulled(
void
- ) { return m_bCulled; }
+ );
/**
* Set culled flag of this object
@@ -934,6 +934,11 @@ public:
m_pObstacleSimulation = NULL;
}
+ /**
+ * add debug object to the debuglist.
+ */
+ void SetUseDebugProperties(bool debug, bool recursive);
+
KX_ClientObjectInfo* getClientInfo() { return m_pClient_info; }
CListValue* GetChildren();
@@ -993,6 +998,7 @@ public:
KX_PYMETHOD_DOC_O(KX_GameObject,getVectTo);
KX_PYMETHOD_DOC_VARARGS(KX_GameObject, sendMessage);
KX_PYMETHOD_VARARGS(KX_GameObject, ReinstancePhysicsMesh);
+ KX_PYMETHOD_DOC(KX_GameObject, addDebugProperty);
KX_PYMETHOD_DOC(KX_GameObject, playAction);
KX_PYMETHOD_DOC(KX_GameObject, stopAction);
@@ -1060,7 +1066,11 @@ public:
static int pyattr_set_obcolor(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
static PyObject* pyattr_get_collisionCallbacks(void *selv_v, const KX_PYATTRIBUTE_DEF *attrdef);
static int pyattr_set_collisionCallbacks(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
-
+ static PyObject* pyattr_get_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_debug(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+ static PyObject* pyattr_get_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_debugRecursive(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+
/* Experimental! */
static PyObject* pyattr_get_sensors(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
static PyObject* pyattr_get_controllers(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
index 96a3845a439..f76580cd44d 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.cpp
@@ -140,7 +140,6 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_frameTime(0.f),
m_clockTime(0.f),
m_previousClockTime(0.f),
- m_previousAnimTime(0.f),
m_exitcode(KX_EXIT_REQUEST_NO_REQUEST),
@@ -164,6 +163,7 @@ KX_KetsjiEngine::KX_KetsjiEngine(KX_ISystem* system)
m_showProperties(false),
m_showBackground(false),
m_show_debug_properties(false),
+ m_autoAddDebugProperties(true),
m_animation_record(false),
@@ -514,13 +514,13 @@ void KX_KetsjiEngine::EndFrame()
RenderDebugProperties();
}
- double tottime = m_logger->GetAverage(), time;
+ double tottime = m_logger->GetAverage();
if (tottime < 1e-6)
tottime = 1e-6;
#ifdef WITH_PYTHON
for (int i = tc_first; i < tc_numCategories; ++i) {
- time = m_logger->GetAverage((KX_TimeCategory)i);
+ double time = m_logger->GetAverage((KX_TimeCategory)i);
PyObject *val = PyTuple_New(2);
PyTuple_SetItem(val, 0, PyFloat_FromDouble(time*1000.f));
PyTuple_SetItem(val, 1, PyFloat_FromDouble(time/tottime * 100.f));
@@ -686,13 +686,6 @@ bool KX_KetsjiEngine::NextFrame()
SG_SetActiveStage(SG_STAGE_ACTUATOR_UPDATE);
scene->UpdateParents(m_frameTime);
- if (!GetRestrictAnimationFPS())
- {
- m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true);
- SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE);
- scene->UpdateAnimations(m_frameTime);
- }
-
m_logger->StartLog(tc_physics, m_kxsystem->GetTimeInSeconds(), true);
SG_SetActiveStage(SG_STAGE_PHYSICS2);
scene->GetPhysicsEnvironment()->BeginFrame();
@@ -794,27 +787,6 @@ bool KX_KetsjiEngine::NextFrame()
m_logger->StartLog(tc_services, m_kxsystem->GetTimeInSeconds(), true);
}
}
-
-
- // Handle the animations independently of the logic time step
- if (GetRestrictAnimationFPS())
- {
- double clocktime = m_kxsystem->GetTimeInSeconds();
- m_logger->StartLog(tc_animations, clocktime, true);
- SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE);
-
- double anim_timestep = 1.0/KX_GetActiveScene()->GetAnimationFPS();
- if (clocktime - m_previousAnimTime > anim_timestep)
- {
- // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep)
- // printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime));
- m_previousAnimTime = clocktime;
- for (sceneit = m_scenes.begin();sceneit != m_scenes.end(); ++sceneit)
- {
- (*sceneit)->UpdateAnimations(clocktime);
- }
- }
- }
// Start logging time spend outside main loop
m_logger->StartLog(tc_outside, m_kxsystem->GetTimeInSeconds(), true);
@@ -1183,8 +1155,15 @@ void KX_KetsjiEngine::RenderShadowBuffers(KX_Scene *scene)
raslight->BindShadowBuffer(m_canvas, cam, camtrans);
/* update scene */
+ m_logger->StartLog(tc_scenegraph, m_kxsystem->GetTimeInSeconds(), true);
scene->CalculateVisibleMeshes(m_rasterizer, cam, raslight->GetShadowLayer());
+ m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true);
+ scene->UpdateAnimations(GetFrameTime());
+
+ m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
+
+
/* render */
m_rasterizer->ClearDepthBuffer();
m_rasterizer->ClearColorBuffer();
@@ -1316,8 +1295,10 @@ void KX_KetsjiEngine::RenderFrame(KX_Scene* scene, KX_Camera* cam)
scene->CalculateVisibleMeshes(m_rasterizer,cam);
- // update levels of detail
- scene->UpdateObjectLods();
+ m_logger->StartLog(tc_animations, m_kxsystem->GetTimeInSeconds(), true);
+ SG_SetActiveStage(SG_STAGE_ANIMATION_UPDATE);
+
+ scene->UpdateAnimations(GetFrameTime());
m_logger->StartLog(tc_rasterizer, m_kxsystem->GetTimeInSeconds(), true);
SG_SetActiveStage(SG_STAGE_RENDER);
@@ -1751,9 +1732,19 @@ void KX_KetsjiEngine::AddScheduledScenes()
-void KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
+bool KX_KetsjiEngine::ReplaceScene(const STR_String& oldscene,const STR_String& newscene)
{
- m_replace_scenes.push_back(std::make_pair(oldscene,newscene));
+ // Don't allow replacement if the new scene doesn't exists.
+ // Allows smarter game design (used to have no check here).
+ // Note that it creates a small backward compatbility issue
+ // for a game that did a replace followed by a lib load with the
+ // new scene in the lib => it won't work anymore, the lib
+ // must be loaded before doing the replace.
+ if (m_sceneconverter->GetBlenderSceneForName(newscene) != NULL) {
+ m_replace_scenes.push_back(std::make_pair(oldscene,newscene));
+ return true;
+ }
+ return false;
}
// replace scene is not the same as removing and adding because the
@@ -1775,15 +1766,20 @@ void KX_KetsjiEngine::ReplaceScheduledScenes()
int i=0;
/* Scenes are not supposed to be included twice... I think */
KX_SceneList::iterator sceneit;
- for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++)
- {
+ for (sceneit = m_scenes.begin();sceneit != m_scenes.end() ; sceneit++) {
KX_Scene* scene = *sceneit;
- if (scene->GetName() == oldscenename)
- {
- m_sceneconverter->RemoveScene(scene);
- KX_Scene* tmpscene = CreateScene(newscenename);
- m_scenes[i]=tmpscene;
- PostProcessScene(tmpscene);
+ if (scene->GetName() == oldscenename) {
+ // avoid crash if the new scene doesn't exist, just do nothing
+ Scene *blScene = m_sceneconverter->GetBlenderSceneForName(newscenename);
+ if (blScene) {
+ m_sceneconverter->RemoveScene(scene);
+ KX_Scene* tmpscene = CreateScene(blScene);
+ m_scenes[i]=tmpscene;
+ PostProcessScene(tmpscene);
+ }
+ else {
+ printf("warning: scene %s could not be found, not replaced!\n",newscenename.ReadPtr());
+ }
}
i++;
}
@@ -1917,6 +1913,46 @@ short KX_KetsjiEngine::GetExitKey()
return m_exitkey;
}
+void KX_KetsjiEngine::SetShowFramerate(bool frameRate)
+{
+ m_show_framerate = frameRate;
+}
+
+bool KX_KetsjiEngine::GetShowFramerate()
+{
+ return m_show_framerate;
+}
+
+void KX_KetsjiEngine::SetShowProfile(bool profile)
+{
+ m_show_profile = profile;
+}
+
+bool KX_KetsjiEngine::GetShowProfile()
+{
+ return m_show_profile;
+}
+
+void KX_KetsjiEngine::SetShowProperties(bool properties)
+{
+ m_show_debug_properties = properties;
+}
+
+bool KX_KetsjiEngine::GetShowProperties()
+{
+ return m_show_debug_properties;
+}
+
+void KX_KetsjiEngine::SetAutoAddDebugProperties(bool add)
+{
+ m_autoAddDebugProperties = add;
+}
+
+bool KX_KetsjiEngine::GetAutoAddDebugProperties()
+{
+ return m_autoAddDebugProperties;
+}
+
void KX_KetsjiEngine::SetTimingDisplay(bool frameRate, bool profile, bool properties)
{
m_show_framerate = frameRate;
diff --git a/source/gameengine/Ketsji/KX_KetsjiEngine.h b/source/gameengine/Ketsji/KX_KetsjiEngine.h
index 9e5d1893320..2b80e3bd69a 100644
--- a/source/gameengine/Ketsji/KX_KetsjiEngine.h
+++ b/source/gameengine/Ketsji/KX_KetsjiEngine.h
@@ -111,7 +111,6 @@ private:
double m_frameTime;//discrete timestamp of the 'game logic frame'
double m_clockTime;//current time
double m_previousClockTime;//previous clock time
- double m_previousAnimTime; //the last time animations were updated
double m_remainingTime;
static int m_maxLogicFrame; /* maximum number of consecutive logic frame */
@@ -175,8 +174,10 @@ private:
bool m_showProperties;
/** Show background behind text for readability? */
bool m_showBackground;
-
+ /** Show debug properties on the game display*/
bool m_show_debug_properties;
+ /** Automatic add debug properties to the debug list*/
+ bool m_autoAddDebugProperties;
/** record physics into keyframes */
bool m_animation_record;
@@ -222,6 +223,7 @@ public:
PyObject* GetPyProfileDict();
#endif
void SetSceneConverter(KX_ISceneConverter* sceneconverter);
+ KX_ISceneConverter* GetSceneConverter() { return m_sceneconverter; }
void SetAnimRecordMode(bool animation_record, int startFrame);
RAS_IRasterizer* GetRasterizer() { return m_rasterizer; }
@@ -256,7 +258,7 @@ public:
void ConvertAndAddScene(const STR_String& scenename,bool overlay);
void RemoveScene(const STR_String& scenename);
- void ReplaceScene(const STR_String& oldscene,const STR_String& newscene);
+ bool ReplaceScene(const STR_String& oldscene,const STR_String& newscene);
void SuspendScene(const STR_String& scenename);
void ResumeScene(const STR_String& scenename);
@@ -354,6 +356,46 @@ public:
static short GetExitKey();
/**
+ * \Sets the display for frame rate on or off.
+ */
+ void SetShowFramerate(bool frameRate);
+
+ /**
+ * \Gets the display for frame rate on or off.
+ */
+ bool GetShowFramerate();
+
+ /**
+ * \Sets the display for individual components on or off.
+ */
+ void SetShowProfile(bool profile);
+
+ /**
+ * \Gets the display for individual components on or off.
+ */
+ bool GetShowProfile();
+
+ /**
+ * \Sets the display of scene object debug properties on or off.
+ */
+ void SetShowProperties(bool properties);
+
+ /**
+ * \Gets the display of scene object debug properties on or off.
+ */
+ bool GetShowProperties();
+
+ /**
+ * \Sets if the auto adding of scene object debug properties on or off.
+ */
+ bool GetAutoAddDebugProperties();
+
+ /**
+ * \Sets the auto adding of scene object debug properties on or off.
+ */
+ void SetAutoAddDebugProperties(bool add);
+
+ /**
* Activates or deactivates timing information display.
* \param frameRate Display for frame rate on or off.
* \param profile Display for individual components on or off.
diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp
index 37c36da0db3..33cfec57fc0 100644
--- a/source/gameengine/Ketsji/KX_Light.cpp
+++ b/source/gameengine/Ketsji/KX_Light.cpp
@@ -231,7 +231,7 @@ int KX_LightObject::pyattr_set_distance(void *self_v, const KX_PYATTRIBUTE_DEF *
else if (val > 5000.f)
val = 5000.f;
- self->m_lightobj->m_energy = val;
+ self->m_lightobj->m_distance = val;
return PY_SET_ATTR_SUCCESS;
}
@@ -242,7 +242,7 @@ int KX_LightObject::pyattr_set_distance(void *self_v, const KX_PYATTRIBUTE_DEF *
PyObject *KX_LightObject::pyattr_get_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
{
KX_LightObject* self = static_cast<KX_LightObject*>(self_v);
- return Py_BuildValue("[fff]", self->m_lightobj->m_color[0], self->m_lightobj->m_color[1], self->m_lightobj->m_color[1]);
+ return Py_BuildValue("[fff]", self->m_lightobj->m_color[0], self->m_lightobj->m_color[1], self->m_lightobj->m_color[2]);
}
int KX_LightObject::pyattr_set_color(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
diff --git a/source/gameengine/Ketsji/KX_MouseActuator.cpp b/source/gameengine/Ketsji/KX_MouseActuator.cpp
new file mode 100644
index 00000000000..aae5d18189a
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MouseActuator.cpp
@@ -0,0 +1,531 @@
+/*
+ * ***** 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): Geoffrey Gollmer, Jorge Bernal
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "KX_MouseActuator.h"
+#include "KX_KetsjiEngine.h"
+#include "SCA_MouseManager.h"
+#include "SCA_IInputDevice.h"
+#include "RAS_ICanvas.h"
+#include "KX_GameObject.h"
+#include "MT_Vector3.h"
+#include "MT_Scalar.h"
+#include "MT_assert.h"
+#include "limits.h"
+
+#include "BLI_math.h"
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* ------------------------------------------------------------------------- */
+/* Native functions */
+/* ------------------------------------------------------------------------- */
+
+KX_MouseActuator::KX_MouseActuator(
+ SCA_IObject* gameobj,
+
+ KX_KetsjiEngine* ketsjiEngine,
+ SCA_MouseManager* eventmgr,
+ int acttype,
+ bool visible,
+ bool* use_axis,
+ float* threshold,
+ bool* reset,
+ int* object_axis,
+ bool* local,
+ float* sensitivity,
+ float* limit_x,
+ float* limit_y
+):
+ SCA_IActuator(gameobj, KX_ACT_MOUSE),
+ m_ketsji(ketsjiEngine),
+ m_eventmgr(eventmgr),
+ m_type(acttype),
+ m_visible(visible),
+ m_use_axis_x(use_axis[0]),
+ m_use_axis_y(use_axis[1]),
+ m_reset_x(reset[0]),
+ m_reset_y(reset[1]),
+ m_local_x(local[0]),
+ m_local_y(local[1])
+{
+ m_canvas = m_ketsji->GetCanvas();
+ m_oldposition[0] = m_oldposition[1] = -1.f;
+ m_limit_x[0] = limit_x[0];
+ m_limit_x[1] = limit_x[1];
+ m_limit_y[0] = limit_y[0];
+ m_limit_y[1] = limit_y[1];
+ m_threshold[0] = threshold[0];
+ m_threshold[1] = threshold[1];
+ m_object_axis[0] = object_axis[0];
+ m_object_axis[1] = object_axis[1];
+ m_sensitivity[0] = sensitivity[0];
+ m_sensitivity[1] = sensitivity[1];
+ m_angle[0] = 0.f;
+ m_angle[1] = 0.f;
+}
+
+KX_MouseActuator::~KX_MouseActuator()
+{
+}
+
+bool KX_MouseActuator::Update()
+{
+ bool result = false;
+
+ bool bNegativeEvent = IsNegativeEvent();
+ RemoveAllEvents();
+
+ if (bNegativeEvent)
+ return false; // do nothing on negative events
+
+ KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent());
+
+ m_mouse = ((SCA_MouseManager *)m_eventmgr)->GetInputDevice();
+
+ switch (m_type) {
+ case KX_ACT_MOUSE_VISIBILITY:
+ {
+ if (m_visible) {
+ if (m_canvas) {
+ m_canvas->SetMouseState(RAS_ICanvas::MOUSE_NORMAL);
+ }
+ }
+ else {
+ if (m_canvas) {
+ m_canvas->SetMouseState(RAS_ICanvas::MOUSE_INVISIBLE);
+ }
+ }
+ break;
+ }
+ case KX_ACT_MOUSE_LOOK:
+ {
+ if (m_mouse) {
+
+ float position[2];
+ float movement[2];
+ MT_Vector3 rotation;
+ float setposition[2] = {0.0};
+
+ getMousePosition(position);
+
+ movement[0] = position[0];
+ movement[1] = position[1];
+
+ //preventing initial skipping.
+ if ((m_oldposition[0] <= -0.9) && (m_oldposition[1] <= -0.9)) {
+
+ if (m_reset_x) {
+ m_oldposition[0] = 0.5;
+ }
+ else {
+ m_oldposition[0] = position[0];
+ }
+
+ if (m_reset_y) {
+ m_oldposition[1] = 0.5;
+ }
+ else {
+ m_oldposition[1] = position[1];
+ }
+ setMousePosition(m_oldposition[0], m_oldposition[1]);
+ break;
+ }
+
+ //Calculating X axis.
+ if (m_use_axis_x) {
+
+ if (m_reset_x) {
+ setposition[0] = 0.5;
+ movement[0] -= 0.5;
+ }
+ else {
+ setposition[0] = position[0];
+ movement[0] -= m_oldposition[0];
+ }
+
+ movement[0] *= -1.0;
+
+ /* Don't apply the rotation when width resolution is odd (+ little movement) to
+ avoid undesired drifting or when we are under a certain threshold for mouse
+ movement */
+
+ if (!((m_canvas->GetWidth() % 2 != 0) && MT_abs(movement[0]) < 0.01) &&
+ ((movement[0] > (m_threshold[0] / 10.0)) ||
+ ((movement[0] * (-1.0)) > (m_threshold[0] / 10.0)))) {
+
+ movement[0] *= m_sensitivity[0];
+
+ if ((m_limit_x[0] != 0.0) && ((m_angle[0] + movement[0]) <= m_limit_x[0])) {
+ movement[0] = m_limit_x[0] - m_angle[0];
+ }
+
+ if ((m_limit_x[1] != 0.0) && ((m_angle[0] + movement[0]) >= m_limit_x[1])) {
+ movement[0] = m_limit_x[1] - m_angle[0];
+ }
+
+ m_angle[0] += movement[0];
+
+ switch (m_object_axis[0]) {
+ case KX_ACT_MOUSE_OBJECT_AXIS_X:
+ {
+ rotation = MT_Vector3(movement[0], 0.0, 0.0);
+ break;
+ }
+ case KX_ACT_MOUSE_OBJECT_AXIS_Y:
+ {
+ rotation = MT_Vector3(0.0, movement[0], 0.0);
+ break;
+ }
+ case KX_ACT_MOUSE_OBJECT_AXIS_Z:
+ {
+ rotation = MT_Vector3(0.0, 0.0, movement[0]);
+ break;
+ }
+ default:
+ break;
+ }
+ parent->ApplyRotation(rotation, m_local_x);
+ }
+ }
+ else {
+ setposition[0] = 0.5;
+ }
+
+ //Calculating Y axis.
+ if (m_use_axis_y) {
+
+ if (m_reset_y) {
+ setposition[1] = 0.5;
+ movement[1] -= 0.5;
+ }
+ else {
+ setposition[1] = position[1];
+ movement[1] -= m_oldposition[1];
+ }
+
+ movement[1] *= -1.0;
+
+ /* Don't apply the rotation when height resolution is odd (+ little movement) to
+ avoid undesired drifting or when we are under a certain threshold for mouse
+ movement */
+
+ if (!((m_canvas->GetHeight() % 2 != 0) && MT_abs(movement[1]) < 0.01) &&
+ ((movement[1] > (m_threshold[1] / 10.0)) ||
+ ((movement[1] * (-1.0)) > (m_threshold[1] / 10.0)))) {
+
+ movement[1] *= m_sensitivity[1];
+
+ if ((m_limit_y[0] != 0.0) && ((m_angle[1] + movement[1]) <= m_limit_y[0])) {
+ movement[1] = m_limit_y[0] - m_angle[1];
+ }
+
+ if ((m_limit_y[1] != 0.0) && ((m_angle[1] + movement[1]) >= m_limit_y[1])) {
+ movement[1] = m_limit_y[1] - m_angle[1];
+ }
+
+ m_angle[1] += movement[1];
+
+ switch (m_object_axis[1])
+ {
+ case KX_ACT_MOUSE_OBJECT_AXIS_X:
+ {
+ rotation = MT_Vector3(movement[1], 0.0, 0.0);
+ break;
+ }
+ case KX_ACT_MOUSE_OBJECT_AXIS_Y:
+ {
+ rotation = MT_Vector3(0.0, movement[1], 0.0);
+ break;
+ }
+ case KX_ACT_MOUSE_OBJECT_AXIS_Z:
+ {
+ rotation = MT_Vector3(0.0, 0.0, movement[1]);
+ break;
+ }
+ default:
+ break;
+ }
+ parent->ApplyRotation(rotation, m_local_y);
+ }
+ }
+ else {
+ setposition[1] = 0.5;
+ }
+
+ setMousePosition(setposition[0], setposition[1]);
+
+ m_oldposition[0] = position[0];
+ m_oldposition[1] = position[1];
+
+ }
+ else {
+ //printf("\nNo input device detected for mouse actuator\n");
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return result;
+}
+
+bool KX_MouseActuator::isValid(KX_MouseActuator::KX_ACT_MOUSE_MODE mode)
+{
+ return ((mode > KX_ACT_MOUSE_NODEF) && (mode < KX_ACT_MOUSE_MAX));
+}
+
+
+CValue* KX_MouseActuator::GetReplica()
+{
+ KX_MouseActuator* replica = new KX_MouseActuator(*this);
+
+ replica->ProcessReplica();
+ return replica;
+}
+
+void KX_MouseActuator::ProcessReplica()
+{
+ SCA_IActuator::ProcessReplica();
+}
+
+void KX_MouseActuator::getMousePosition(float* pos)
+{
+ MT_assert(!m_mouse);
+ const SCA_InputEvent & xevent = m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEX);
+ const SCA_InputEvent & yevent = m_mouse->GetEventValue(SCA_IInputDevice::KX_MOUSEY);
+
+ pos[0] = m_canvas->GetMouseNormalizedX(xevent.m_eventval);
+ pos[1] = m_canvas->GetMouseNormalizedY(yevent.m_eventval);
+}
+
+void KX_MouseActuator::setMousePosition(float fx, float fy)
+{
+ int x, y;
+
+ x = (int)(fx * m_canvas->GetWidth());
+ y = (int)(fy * m_canvas->GetHeight());
+
+ m_canvas->SetMousePosition(x, y);
+}
+
+#ifndef DISABLE_PYTHON
+
+/* ------------------------------------------------------------------------- */
+/* Python functions */
+/* ------------------------------------------------------------------------- */
+
+/* Integration hooks ------------------------------------------------------- */
+PyTypeObject KX_MouseActuator::Type = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "KX_MouseActuator",
+ sizeof(PyObjectPlus_Proxy),
+ 0,
+ py_base_dealloc,
+ 0,
+ 0,
+ 0,
+ 0,
+ py_base_repr,
+ 0,0,0,0,0,0,0,0,0,
+ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+ 0,0,0,0,0,0,0,
+ Methods,
+ 0,
+ 0,
+ &SCA_IActuator::Type,
+ 0,0,0,0,0,0,
+ py_base_new
+};
+
+PyMethodDef KX_MouseActuator::Methods[] = {
+ {"reset", (PyCFunction) KX_MouseActuator::sPyReset, METH_NOARGS,"reset() : undo rotation caused by actuator\n"},
+ {NULL,NULL} //Sentinel
+};
+
+
+
+PyAttributeDef KX_MouseActuator::Attributes[] = {
+ KX_PYATTRIBUTE_BOOL_RW("visible", KX_MouseActuator, m_visible),
+ KX_PYATTRIBUTE_BOOL_RW("use_axis_x", KX_MouseActuator, m_use_axis_x),
+ KX_PYATTRIBUTE_BOOL_RW("use_axis_y", KX_MouseActuator, m_use_axis_y),
+ KX_PYATTRIBUTE_FLOAT_ARRAY_RW("threshold", 0.0, 0.5, KX_MouseActuator, m_threshold, 2),
+ KX_PYATTRIBUTE_BOOL_RW("reset_x", KX_MouseActuator, m_reset_x),
+ KX_PYATTRIBUTE_BOOL_RW("reset_y", KX_MouseActuator, m_reset_y),
+ KX_PYATTRIBUTE_INT_ARRAY_RW("object_axis", 0, 2, 1, KX_MouseActuator, m_object_axis, 2),
+ KX_PYATTRIBUTE_BOOL_RW("local_x", KX_MouseActuator, m_local_x),
+ KX_PYATTRIBUTE_BOOL_RW("local_y", KX_MouseActuator, m_local_y),
+ KX_PYATTRIBUTE_FLOAT_ARRAY_RW("sensitivity", -FLT_MAX, FLT_MAX, KX_MouseActuator, m_sensitivity, 2),
+ KX_PYATTRIBUTE_RW_FUNCTION("limit_x", KX_MouseActuator, pyattr_get_limit_x, pyattr_set_limit_x),
+ KX_PYATTRIBUTE_RW_FUNCTION("limit_y", KX_MouseActuator, pyattr_get_limit_y, pyattr_set_limit_y),
+ KX_PYATTRIBUTE_RW_FUNCTION("angle", KX_MouseActuator, pyattr_get_angle, pyattr_set_angle),
+ { NULL } //Sentinel
+};
+
+PyObject* KX_MouseActuator::pyattr_get_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
+ return Py_BuildValue("[f,f]", (self->m_limit_x[0] / M_PI * 180.0), (self->m_limit_x[1] / M_PI * 180.0));
+}
+
+int KX_MouseActuator::pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ PyObject *item1, *item2;
+ KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
+
+ if (!PyList_Check(value))
+ return PY_SET_ATTR_FAIL;
+
+ if (PyList_Size(value) != 2)
+ return PY_SET_ATTR_FAIL;
+
+ item1 = PyList_GetItem(value, 0);
+ item2 = PyList_GetItem(value, 1);
+
+ if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) {
+ return PY_SET_ATTR_FAIL;
+ }
+ else {
+ self->m_limit_x[0] = (PyFloat_AsDouble(item1) * M_PI / 180.0);
+ self->m_limit_x[1] = (PyFloat_AsDouble(item2) * M_PI / 180.0);
+ }
+
+ return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject* KX_MouseActuator::pyattr_get_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
+ return Py_BuildValue("[f,f]", (self->m_limit_y[0] / M_PI * 180.0), (self->m_limit_y[1] / M_PI * 180.0));
+}
+
+int KX_MouseActuator::pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ PyObject *item1, *item2;
+ KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
+
+ if (!PyList_Check(value))
+ return PY_SET_ATTR_FAIL;
+
+ if (PyList_Size(value) != 2)
+ return PY_SET_ATTR_FAIL;
+
+ item1 = PyList_GetItem(value, 0);
+ item2 = PyList_GetItem(value, 1);
+
+ if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) {
+ return PY_SET_ATTR_FAIL;
+ }
+ else {
+ self->m_limit_y[0] = (PyFloat_AsDouble(item1) * M_PI / 180.0);
+ self->m_limit_y[1] = (PyFloat_AsDouble(item2) * M_PI / 180.0);
+ }
+
+ return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject* KX_MouseActuator::pyattr_get_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
+{
+ KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
+ return Py_BuildValue("[f,f]", (self->m_angle[0] / M_PI * 180.0), (self->m_angle[1] / M_PI * 180.0));
+}
+
+int KX_MouseActuator::pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value)
+{
+ PyObject *item1, *item2;
+ KX_MouseActuator* self= static_cast<KX_MouseActuator*>(self_v);
+
+ if (!PyList_Check(value))
+ return PY_SET_ATTR_FAIL;
+
+ if (PyList_Size(value) != 2)
+ return PY_SET_ATTR_FAIL;
+
+ item1 = PyList_GetItem(value, 0);
+ item2 = PyList_GetItem(value, 1);
+
+ if (!(PyFloat_Check(item1)) || !(PyFloat_Check(item2))) {
+ return PY_SET_ATTR_FAIL;
+ }
+ else {
+ self->m_angle[0] = (PyFloat_AsDouble(item1) * M_PI / 180.0);
+ self->m_angle[1] = (PyFloat_AsDouble(item2) * M_PI / 180.0);
+ }
+
+ return PY_SET_ATTR_SUCCESS;
+}
+
+PyObject* KX_MouseActuator::PyReset()
+{
+ MT_Vector3 rotation;
+ KX_GameObject *parent = static_cast<KX_GameObject *>(GetParent());
+
+ switch (m_object_axis[0]) {
+ case KX_ACT_MOUSE_OBJECT_AXIS_X:
+ {
+ rotation = MT_Vector3(-1.0 * m_angle[0], 0.0, 0.0);
+ break;
+ }
+ case KX_ACT_MOUSE_OBJECT_AXIS_Y:
+ {
+ rotation = MT_Vector3(0.0, -1.0 * m_angle[0], 0.0);
+ break;
+ }
+ case KX_ACT_MOUSE_OBJECT_AXIS_Z:
+ {
+ rotation = MT_Vector3(0.0, 0.0, -1.0 * m_angle[0]);
+ break;
+ }
+ default:
+ break;
+ }
+ parent->ApplyRotation(rotation, m_local_x);
+
+ switch (m_object_axis[1]) {
+ case KX_ACT_MOUSE_OBJECT_AXIS_X:
+ {
+ rotation = MT_Vector3(-1.0 * m_angle[1], 0.0, 0.0);
+ break;
+ }
+ case KX_ACT_MOUSE_OBJECT_AXIS_Y:
+ {
+ rotation = MT_Vector3(0.0, -1.0 * m_angle[1], 0.0);
+ break;
+ }
+ case KX_ACT_MOUSE_OBJECT_AXIS_Z:
+ {
+ rotation = MT_Vector3(0.0, 0.0, -1.0 * m_angle[1]);
+ break;
+ }
+ default:
+ break;
+ }
+ parent->ApplyRotation(rotation, m_local_y);
+
+ m_angle[0] = 0.0;
+ m_angle[1] = 0.0;
+
+ Py_RETURN_NONE;
+}
+
+#endif
diff --git a/source/gameengine/Ketsji/KX_MouseActuator.h b/source/gameengine/Ketsji/KX_MouseActuator.h
new file mode 100644
index 00000000000..bf90bd21dac
--- /dev/null
+++ b/source/gameengine/Ketsji/KX_MouseActuator.h
@@ -0,0 +1,127 @@
+/*
+ * ***** 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): Geoffrey Gollmer, Jorge Bernal
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __KX_MOUSEACTUATOR
+#define __KX_MOUSEACTUATOR
+
+#include "SCA_IActuator.h"
+
+class KX_KetsjiEngine;
+class SCA_MouseManager;
+class SCA_IInputDevice;
+class RAS_ICanvas;
+
+class KX_MouseActuator : public SCA_IActuator
+{
+ Py_Header
+
+private:
+
+ KX_KetsjiEngine* m_ketsji;
+ SCA_MouseManager* m_eventmgr;
+ SCA_IInputDevice* m_mouse;
+ RAS_ICanvas* m_canvas;
+ int m_type;
+
+ bool m_visible;
+
+ bool m_use_axis_x; /* 0 for calculate axis, 1 for ignore axis */
+ bool m_use_axis_y;
+ float m_threshold[2];
+ bool m_reset_x; /* 0=reset, 1=free */
+ bool m_reset_y;
+ int m_object_axis[2]; /* 0=x, 1=y, 2=z */
+ bool m_local_x; /* 0=local, 1=global*/
+ bool m_local_y;
+ float m_sensitivity[2];
+ float m_limit_x[2];
+ float m_limit_y[2];
+
+ float m_oldposition[2];
+ float m_angle[2];
+
+public:
+
+ enum KX_ACT_MOUSE_OBJECT_AXIS {
+ KX_ACT_MOUSE_OBJECT_AXIS_X = 0,
+ KX_ACT_MOUSE_OBJECT_AXIS_Y,
+ KX_ACT_MOUSE_OBJECT_AXIS_Z
+ };
+
+ enum KX_ACT_MOUSE_MODE {
+ KX_ACT_MOUSE_NODEF = 0,
+ KX_ACT_MOUSE_VISIBILITY,
+ KX_ACT_MOUSE_LOOK,
+ KX_ACT_MOUSE_MAX
+ };
+
+ KX_MouseActuator(
+ SCA_IObject* gameobj,
+ KX_KetsjiEngine* ketsjiEngine,
+ SCA_MouseManager* eventmgr,
+ int acttype,
+ bool visible,
+ bool* use_axis,
+ float* threshold,
+ bool* reset,
+ int* object_axis,
+ bool* local,
+ float* sensitivity,
+ float* limit_x,
+ float* limit_y
+ );
+
+
+ ~KX_MouseActuator();
+
+ CValue* GetReplica();
+ virtual void ProcessReplica();
+
+ virtual bool Update();
+
+ /* check whether this value is valid */
+ bool isValid(KX_ACT_MOUSE_MODE mode);
+
+ virtual void getMousePosition(float*);
+ virtual void setMousePosition(float, float);
+
+ /* --------------------------------------------------------------------- */
+ /* Python interface ---------------------------------------------------- */
+ /* --------------------------------------------------------------------- */
+
+ /* Methods */
+
+ KX_PYMETHOD_DOC_NOARGS(KX_MouseActuator,Reset);
+
+ /* Attributes */
+
+ static PyObject* pyattr_get_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_limit_x(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+
+ static PyObject* pyattr_get_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_limit_y(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+
+ static PyObject* pyattr_get_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef);
+ static int pyattr_set_angle(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef, PyObject *value);
+};
+
+#endif //__KX_MOUSEACTUATOR_DOC
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
index 2dbafdad3d9..a9f6bb0d2ff 100644
--- a/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.cpp
@@ -60,15 +60,21 @@
KX_MouseFocusSensor::KX_MouseFocusSensor(SCA_MouseManager* eventmgr,
int startx,
int starty,
- short int mousemode,
- int focusmode,
- bool bTouchPulse,
- KX_Scene* kxscene,
- KX_KetsjiEngine *kxengine,
- SCA_IObject* gameobj)
+ short int mousemode,
+ int focusmode,
+ bool bTouchPulse,
+ const STR_String& propname,
+ bool bFindMaterial,
+ bool bXRay,
+ KX_Scene* kxscene,
+ KX_KetsjiEngine *kxengine,
+ SCA_IObject* gameobj)
: SCA_MouseSensor(eventmgr, startx, starty, mousemode, gameobj),
m_focusmode(focusmode),
m_bTouchPulse(bTouchPulse),
+ m_bXRay(bXRay),
+ m_bFindMaterial(bFindMaterial),
+ m_propertyname(propname),
m_kxscene(kxscene),
m_kxengine(kxengine)
{
@@ -146,20 +152,73 @@ bool KX_MouseFocusSensor::RayHit(KX_ClientObjectInfo *client_info, KX_RayCast *r
* self-hits are excluded by setting the correct ignore-object.)
* Hitspots now become valid. */
KX_GameObject* thisObj = (KX_GameObject*) GetParent();
+
+ bool bFound = false;
+
if ((m_focusmode == 2) || hitKXObj == thisObj)
{
- m_hitObject = hitKXObj;
- m_hitPosition = result->m_hitPoint;
- m_hitNormal = result->m_hitNormal;
- m_hitUV = result->m_hitUV;
- return true;
+ if (m_propertyname.Length() == 0)
+ {
+ bFound = true;
+ }
+ else
+ {
+ if (m_bFindMaterial)
+ {
+ if (client_info->m_auxilary_info)
+ {
+ bFound = (m_propertyname== ((char*)client_info->m_auxilary_info));
+ }
+ }
+ else
+ {
+ bFound = hitKXObj->GetProperty(m_propertyname) != NULL;
+ }
+ }
+
+ if (bFound)
+ {
+ m_hitObject = hitKXObj;
+ m_hitPosition = result->m_hitPoint;
+ m_hitNormal = result->m_hitNormal;
+ m_hitUV = result->m_hitUV;
+ return true;
+ }
}
return true; // object must be visible to trigger
//return false; // occluded objects can trigger
}
-
+/* this function is used to pre-filter the object before casting the ray on them.
+ * This is useful for "X-Ray" option when we want to see "through" unwanted object.
+ */
+bool KX_MouseFocusSensor::NeedRayCast(KX_ClientObjectInfo* client)
+{
+ if (client->m_type > KX_ClientObjectInfo::ACTOR)
+ {
+ // Unknown type of object, skip it.
+ // Should not occur as the sensor objects are filtered in RayTest()
+ printf("Invalid client type %d found ray casting\n", client->m_type);
+ return false;
+ }
+ if (m_bXRay && m_propertyname.Length() != 0)
+ {
+ if (m_bFindMaterial)
+ {
+ // not quite correct: an object may have multiple material
+ // should check all the material and not only the first one
+ if (!client->m_auxilary_info || (m_propertyname != ((char*)client->m_auxilary_info)))
+ return false;
+ }
+ else
+ {
+ if (client->m_gameobject->GetProperty(m_propertyname) == NULL)
+ return false;
+ }
+ }
+ return true;
+}
bool KX_MouseFocusSensor::ParentObjectHasFocusCamera(KX_Camera *cam)
{
@@ -384,7 +443,10 @@ PyAttributeDef KX_MouseFocusSensor::Attributes[] = {
KX_PYATTRIBUTE_RO_FUNCTION("hitPosition", KX_MouseFocusSensor, pyattr_get_hit_position),
KX_PYATTRIBUTE_RO_FUNCTION("hitNormal", KX_MouseFocusSensor, pyattr_get_hit_normal),
KX_PYATTRIBUTE_RO_FUNCTION("hitUV", KX_MouseFocusSensor, pyattr_get_hit_uv),
- KX_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor,m_bTouchPulse),
+ KX_PYATTRIBUTE_BOOL_RW("usePulseFocus", KX_MouseFocusSensor, m_bTouchPulse),
+ KX_PYATTRIBUTE_BOOL_RW("useXRay", KX_MouseFocusSensor, m_bXRay),
+ KX_PYATTRIBUTE_BOOL_RW("useMaterial", KX_MouseFocusSensor, m_bFindMaterial),
+ KX_PYATTRIBUTE_STRING_RW("propName", 0, MAX_PROP_NAME, false, KX_MouseFocusSensor, m_propertyname),
{ NULL } //Sentinel
};
diff --git a/source/gameengine/Ketsji/KX_MouseFocusSensor.h b/source/gameengine/Ketsji/KX_MouseFocusSensor.h
index 1f7809831e7..0c7c8ab676a 100644
--- a/source/gameengine/Ketsji/KX_MouseFocusSensor.h
+++ b/source/gameengine/Ketsji/KX_MouseFocusSensor.h
@@ -57,6 +57,9 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
short int mousemode,
int focusmode,
bool bTouchPulse,
+ const STR_String& propname,
+ bool bFindMaterial,
+ bool bXRay,
KX_Scene* kxscene,
KX_KetsjiEngine* kxengine,
SCA_IObject* gameobj);
@@ -88,7 +91,7 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
};
bool RayHit(KX_ClientObjectInfo* client, KX_RayCast* result, void * const data);
- bool NeedRayCast(KX_ClientObjectInfo* client) { return true; }
+ bool NeedRayCast(KX_ClientObjectInfo* client);
const MT_Point3& RaySource() const;
const MT_Point3& RayTarget() const;
@@ -134,6 +137,21 @@ class KX_MouseFocusSensor : public SCA_MouseSensor
bool m_bTouchPulse;
/**
+ * Flags get through other objects
+ */
+ bool m_bXRay;
+
+ /**
+ * Flags material
+ */
+ bool m_bFindMaterial;
+
+ /**
+ * Property or material name
+ */
+ STR_String m_propertyname;
+
+ /**
* Flags whether the previous test evaluated positive.
*/
bool m_positive_event;
diff --git a/source/gameengine/Ketsji/KX_NavMeshObject.cpp b/source/gameengine/Ketsji/KX_NavMeshObject.cpp
index 42f62886ff7..8360681759a 100644
--- a/source/gameengine/Ketsji/KX_NavMeshObject.cpp
+++ b/source/gameengine/Ketsji/KX_NavMeshObject.cpp
@@ -111,7 +111,7 @@ bool KX_NavMeshObject::BuildVertIndArrays(float *&vertices, int& nverts,
float *&dvertices, int &ndvertsuniq, unsigned short *&dtris,
int& ndtris, int &vertsPerPoly)
{
- DerivedMesh* dm = mesh_create_derived_no_virtual(KX_GetActiveScene()->GetBlenderScene(), GetBlenderObject(),
+ DerivedMesh* dm = mesh_create_derived_no_virtual(GetScene()->GetBlenderScene(), GetBlenderObject(),
NULL, CD_MASK_MESH);
CustomData *pdata = dm->getPolyDataLayout(dm);
int* recastData = (int*) CustomData_get_layer(pdata, CD_RECAST);
@@ -304,6 +304,7 @@ bool KX_NavMeshObject::BuildNavMesh()
|| vertsPerPoly<3)
{
printf("Can't build navigation mesh data for object:%s\n", m_name.ReadPtr());
+ if (vertices) delete[] vertices;
return false;
}
@@ -325,7 +326,10 @@ bool KX_NavMeshObject::BuildNavMesh()
float cs = 0.2f;
if (!nverts || !npolys)
+ {
+ if (vertices) delete[] vertices;
return false;
+ }
float bmin[3], bmax[3];
calcMeshBounds(vertices, nverts, bmin, bmax);
@@ -463,9 +467,10 @@ bool KX_NavMeshObject::BuildNavMesh()
if (dtris) MEM_freeN(dtris);
if (dvertices)
- {
delete [] dvertices;
- }
+
+ if (vertsi)
+ delete [] vertsi;
return true;
}
@@ -591,6 +596,8 @@ int KX_NavMeshObject::FindPath(const MT_Point3& from, const MT_Point3& to, float
waypoint.getValue(&path[i*3]);
}
}
+
+ delete[] polys;
}
return pathLen;
diff --git a/source/gameengine/Ketsji/KX_ObjectActuator.cpp b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
index 2f85453dd23..0eec86987be 100644
--- a/source/gameengine/Ketsji/KX_ObjectActuator.cpp
+++ b/source/gameengine/Ketsji/KX_ObjectActuator.cpp
@@ -32,6 +32,7 @@
* \ingroup ketsji
*/
+#include <stdio.h>
#include "KX_ObjectActuator.h"
#include "KX_GameObject.h"
diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
index e9843b0af5b..ebf1b9ec577 100644
--- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
+++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
@@ -740,6 +740,7 @@ PyObject *initPythonConstraintBinding()
KX_MACRO_addTypesToDict(d, ANGULAR_CONSTRAINT, PHY_ANGULAR_CONSTRAINT);
KX_MACRO_addTypesToDict(d, CONETWIST_CONSTRAINT, PHY_CONE_TWIST_CONSTRAINT);
KX_MACRO_addTypesToDict(d, VEHICLE_CONSTRAINT, PHY_VEHICLE_CONSTRAINT);
+ KX_MACRO_addTypesToDict(d, GENERIC_6DOF_CONSTRAINT, PHY_GENERIC_6DOF_CONSTRAINT);
// Check for errors
if (PyErr_Occurred()) {
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index 234d03ab618..fefc64b4bad 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -30,7 +30,7 @@
* \ingroup ketsji
*/
-#include "GL/glew.h"
+#include "glew-mx.h"
#ifdef _MSC_VER
# pragma warning (disable:4786)
@@ -87,6 +87,8 @@ extern "C" {
#include "KX_SCA_DynamicActuator.h"
#include "KX_SteeringActuator.h"
#include "KX_NavMeshObject.h"
+#include "KX_MouseActuator.h"
+#include "KX_TrackToActuator.h"
#include "SCA_IInputDevice.h"
#include "SCA_PropertySensor.h"
@@ -199,7 +201,16 @@ static PyObject *gp_OrigPythonSysModules= NULL;
//#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, PyLong_FromLong(SCA_IInputDevice::KX_##name))
//#define KX_MACRO_addToDict(dict, name) PyDict_SetItemString(dict, #name, item=PyLong_FromLong(name)); Py_DECREF(item)
/* For the defines for types from logic bricks, we do stuff explicitly... */
-#define KX_MACRO_addTypesToDict(dict, name, name2) PyDict_SetItemString(dict, #name, item=PyLong_FromLong(name2)); Py_DECREF(item)
+#define KX_MACRO_addTypesToDict(dict, name, value) KX_MACRO_addTypesToDict_fn(dict, #name, value)
+static void KX_MACRO_addTypesToDict_fn(PyObject *dict, const char *name, long value)
+{
+ PyObject *item;
+
+ item = PyLong_FromLong(value);
+ PyDict_SetItemString(dict, name, item);
+ Py_DECREF(item);
+}
+
// temporarily python stuff, will be put in another place later !
@@ -246,7 +257,7 @@ static PyObject *gPyExpandPath(PyObject *, PyObject *args)
BLI_strncpy(expanded, filename, FILE_MAX);
BLI_path_abs(expanded, gp_GamePythonPath);
- return PyUnicode_DecodeFSDefault(expanded);
+ return PyC_UnicodeFromByte(expanded);
}
static char gPyStartGame_doc[] =
@@ -535,7 +546,7 @@ static PyObject *gPyGetBlendFileList(PyObject *, PyObject *args)
while ((dirp = readdir(dp)) != NULL) {
if (BLI_testextensie(dirp->d_name, ".blend")) {
- value= PyUnicode_DecodeFSDefault(dirp->d_name);
+ value = PyC_UnicodeFromByte(dirp->d_name);
PyList_Append(list, value);
Py_DECREF(value);
}
@@ -1385,9 +1396,76 @@ static PyObject *gPySetVsync(PyObject *, PyObject *args)
static PyObject *gPyGetVsync(PyObject *)
{
- return PyLong_FromLong(gp_Canvas->GetSwapInterval());
+ int interval = 0;
+ gp_Canvas->GetSwapInterval(interval);
+ return PyLong_FromLong(interval);
}
+static PyObject *gPyShowFramerate(PyObject *, PyObject *args)
+{
+ int visible;
+ if (!PyArg_ParseTuple(args,"i:showFramerate",&visible))
+ return NULL;
+
+ if (visible && gp_KetsjiEngine)
+ gp_KetsjiEngine->SetShowFramerate(true);
+ else
+ gp_KetsjiEngine->SetShowFramerate(false);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyShowProfile(PyObject *, PyObject *args)
+{
+ int visible;
+ if (!PyArg_ParseTuple(args,"i:showProfile",&visible))
+ return NULL;
+
+ if (visible && gp_KetsjiEngine)
+ gp_KetsjiEngine->SetShowProfile(true);
+ else
+ gp_KetsjiEngine->SetShowProfile(false);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyShowProperties(PyObject *, PyObject *args)
+{
+ int visible;
+ if (!PyArg_ParseTuple(args,"i:showProperties",&visible))
+ return NULL;
+
+ if (visible && gp_KetsjiEngine)
+ gp_KetsjiEngine->SetShowProperties(true);
+ else
+ gp_KetsjiEngine->SetShowProperties(false);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyAutoDebugList(PyObject *, PyObject *args)
+{
+ int add;
+ if (!PyArg_ParseTuple(args,"i:autoAddProperties",&add))
+ return NULL;
+
+ if (add && gp_KetsjiEngine)
+ gp_KetsjiEngine->SetAutoAddDebugProperties(true);
+ else
+ gp_KetsjiEngine->SetAutoAddDebugProperties(false);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *gPyClearDebugList(PyObject *)
+{
+ if (gp_KetsjiScene)
+ gp_KetsjiScene->RemoveAllDebugProperties();
+
+ Py_RETURN_NONE;
+}
+
+
static struct PyMethodDef rasterizer_methods[] = {
{"getWindowWidth",(PyCFunction) gPyGetWindowWidth,
METH_VARARGS, "getWindowWidth doc"},
@@ -1435,6 +1513,11 @@ static struct PyMethodDef rasterizer_methods[] = {
{"getMipmapping", (PyCFunction) gPyGetMipmapping, METH_NOARGS, ""},
{"setVsync", (PyCFunction) gPySetVsync, METH_VARARGS, ""},
{"getVsync", (PyCFunction) gPyGetVsync, METH_NOARGS, ""},
+ {"showFramerate",(PyCFunction) gPyShowFramerate, METH_VARARGS, "show or hide the framerate"},
+ {"showProfile",(PyCFunction) gPyShowProfile, METH_VARARGS, "show or hide the profile"},
+ {"showProperties",(PyCFunction) gPyShowProperties, METH_VARARGS, "show or hide the debug properties"},
+ {"autoDebugList",(PyCFunction) gPyAutoDebugList, METH_VARARGS, "enable or disable auto adding debug properties to the debug list"},
+ {"clearDebugList",(PyCFunction) gPyClearDebugList, METH_NOARGS, "clears the debug property list"},
{ NULL, (PyCFunction) NULL, 0, NULL }
};
@@ -1538,6 +1621,8 @@ PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack
KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_INTERVAL, SCA_PropertySensor::KX_PROPSENSOR_INTERVAL);
KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_CHANGED, SCA_PropertySensor::KX_PROPSENSOR_CHANGED);
KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_EXPRESSION, SCA_PropertySensor::KX_PROPSENSOR_EXPRESSION);
+ KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_LESSTHAN, SCA_PropertySensor::KX_PROPSENSOR_LESSTHAN);
+ KX_MACRO_addTypesToDict(d, KX_PROPSENSOR_GREATERTHAN, SCA_PropertySensor::KX_PROPSENSOR_GREATERTHAN);
/* 3. Constraint actuator */
KX_MACRO_addTypesToDict(d, KX_CONSTRAINTACT_LOCX, KX_ConstraintActuator::KX_ACT_CONSTRAINT_LOCX);
@@ -1681,6 +1766,17 @@ PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack
KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_Y, KX_RaySensor::KX_RAY_AXIS_NEG_Y);
KX_MACRO_addTypesToDict(d, KX_RAY_AXIS_NEG_Z, KX_RaySensor::KX_RAY_AXIS_NEG_Z);
+ /* TrackTo Actuator */
+ KX_MACRO_addTypesToDict(d, KX_TRACK_UPAXIS_POS_X, KX_TrackToActuator::KX_TRACK_UPAXIS_POS_X);
+ KX_MACRO_addTypesToDict(d, KX_TRACK_UPAXIS_POS_Y, KX_TrackToActuator::KX_TRACK_UPAXIS_POS_Y);
+ KX_MACRO_addTypesToDict(d, KX_TRACK_UPAXIS_POS_Z, KX_TrackToActuator::KX_TRACK_UPAXIS_POS_Z);
+ KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_POS_X, KX_TrackToActuator::KX_TRACK_TRAXIS_POS_X);
+ KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_POS_Y, KX_TrackToActuator::KX_TRACK_TRAXIS_POS_Y);
+ KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_POS_Z, KX_TrackToActuator::KX_TRACK_TRAXIS_POS_Z);
+ KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_NEG_X, KX_TrackToActuator::KX_TRACK_TRAXIS_NEG_X);
+ KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_NEG_Y, KX_TrackToActuator::KX_TRACK_TRAXIS_NEG_Y);
+ KX_MACRO_addTypesToDict(d, KX_TRACK_TRAXIS_NEG_Z, KX_TrackToActuator::KX_TRACK_TRAXIS_NEG_Z);
+
/* Dynamic actuator */
KX_MACRO_addTypesToDict(d, KX_DYN_RESTORE_DYNAMICS, KX_SCA_DynamicActuator::KX_DYN_RESTORE_DYNAMICS);
KX_MACRO_addTypesToDict(d, KX_DYN_DISABLE_DYNAMICS, KX_SCA_DynamicActuator::KX_DYN_DISABLE_DYNAMICS);
@@ -1818,6 +1914,12 @@ PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack
KX_MACRO_addTypesToDict(d, KX_ACTION_BLEND_BLEND, BL_Action::ACT_BLEND_BLEND);
KX_MACRO_addTypesToDict(d, KX_ACTION_BLEND_ADD, BL_Action::ACT_BLEND_ADD);
+ /* Mouse Actuator object axis*/
+ KX_MACRO_addTypesToDict(d, KX_ACT_MOUSE_OBJECT_AXIS_X, KX_MouseActuator::KX_ACT_MOUSE_OBJECT_AXIS_X);
+ KX_MACRO_addTypesToDict(d, KX_ACT_MOUSE_OBJECT_AXIS_Y, KX_MouseActuator::KX_ACT_MOUSE_OBJECT_AXIS_Y);
+ KX_MACRO_addTypesToDict(d, KX_ACT_MOUSE_OBJECT_AXIS_Z, KX_MouseActuator::KX_ACT_MOUSE_OBJECT_AXIS_Z);
+
+
// Check for errors
if (PyErr_Occurred())
{
@@ -1874,7 +1976,7 @@ static void initPySysObjects__append(PyObject *sys_path, const char *filename)
BLI_split_dir_part(filename, expanded, sizeof(expanded)); /* get the dir part of filename only */
BLI_path_abs(expanded, gp_GamePythonPath); /* filename from lib->filename is (always?) absolute, so this may not be needed but it wont hurt */
BLI_cleanup_file(gp_GamePythonPath, expanded); /* Don't use BLI_cleanup_dir because it adds a slash - BREAKS WIN32 ONLY */
- item= PyUnicode_DecodeFSDefault(expanded);
+ item = PyC_UnicodeFromByte(expanded);
// printf("SysPath - '%s', '%s', '%s'\n", expanded, filename, gp_GamePythonPath);
@@ -1949,10 +2051,10 @@ void removeImportMain(struct Main *maggie)
// Copied from bpy_interface.c
static struct _inittab bge_internal_modules[] = {
- {(char *)"mathutils", PyInit_mathutils},
- {(char *)"bgl", BPyInit_bgl},
- {(char *)"blf", BPyInit_blf},
- {(char *)"aud", AUD_initPython},
+ {"mathutils", PyInit_mathutils},
+ {"bgl", BPyInit_bgl},
+ {"blf", BPyInit_blf},
+ {"aud", AUD_initPython},
{NULL, NULL}
};
@@ -2179,7 +2281,6 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas)
PyObject *m;
PyObject *d;
- PyObject *item;
/* Use existing module where possible
* be careful not to init any runtime vars after this */
@@ -2309,7 +2410,6 @@ PyObject *initGameKeys()
{
PyObject *m;
PyObject *d;
- PyObject *item;
/* Use existing module where possible */
m = PyImport_ImportModule( "GameKeys" );
diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
index bacace9199a..7d38ce58eee 100644
--- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
@@ -97,6 +97,7 @@
#include "SCA_RandomActuator.h"
#include "SCA_IController.h"
#include "KX_NavMeshObject.h"
+#include "KX_MouseActuator.h"
static void PyType_Attr_Set(PyGetSetDef *attr_getset, PyAttributeDef *attr)
{
@@ -227,6 +228,7 @@ void initPyTypes(void)
PyType_Ready_Attr(dict, KX_VehicleWrapper, init_getset);
PyType_Ready_Attr(dict, KX_VertexProxy, init_getset);
PyType_Ready_Attr(dict, KX_VisibilityActuator, init_getset);
+ PyType_Ready_Attr(dict, KX_MouseActuator, init_getset);
PyType_Ready_Attr(dict, PyObjectPlus, init_getset);
PyType_Ready_Attr(dict, SCA_2DFilterActuator, init_getset);
PyType_Ready_Attr(dict, SCA_ANDController, init_getset);
diff --git a/source/gameengine/Ketsji/KX_RaySensor.h b/source/gameengine/Ketsji/KX_RaySensor.h
index 09e99fe0013..4604863a233 100644
--- a/source/gameengine/Ketsji/KX_RaySensor.h
+++ b/source/gameengine/Ketsji/KX_RaySensor.h
@@ -83,13 +83,14 @@ public:
}
//Python Interface
+ // odd order, see: SENS_RAY_X_AXIS
enum RayAxis {
- KX_RAY_AXIS_POS_X = 0,
- KX_RAY_AXIS_POS_Y,
- KX_RAY_AXIS_POS_Z,
- KX_RAY_AXIS_NEG_X,
- KX_RAY_AXIS_NEG_Y,
- KX_RAY_AXIS_NEG_Z
+ KX_RAY_AXIS_POS_X = 1,
+ KX_RAY_AXIS_POS_Y = 0,
+ KX_RAY_AXIS_POS_Z = 2,
+ KX_RAY_AXIS_NEG_X = 3,
+ KX_RAY_AXIS_NEG_Y = 4,
+ KX_RAY_AXIS_NEG_Z = 5,
};
#ifdef WITH_PYTHON
diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp
index c826f39517a..d0eab9de1c1 100644
--- a/source/gameengine/Ketsji/KX_Scene.cpp
+++ b/source/gameengine/Ketsji/KX_Scene.cpp
@@ -595,7 +595,9 @@ KX_GameObject* KX_Scene::AddNodeReplicaObject(class SG_IObject* node, class CVal
void KX_Scene::ReplicateLogic(KX_GameObject* newobj)
{
/* add properties to debug list, for added objects and DupliGroups */
- AddObjectDebugProperties(newobj);
+ if (KX_GetActiveEngine()->GetAutoAddDebugProperties()) {
+ AddObjectDebugProperties(newobj);
+ }
// also relink the controller to sensors/actuators
SCA_ControllerList& controllers = newobj->GetControllers();
//SCA_SensorList& sensors = newobj->GetSensors();
@@ -1005,7 +1007,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj)
int ret;
KX_GameObject* newobj = (KX_GameObject*) gameobj;
- /* remove property to debug list */
+ /* remove property from debug list */
RemoveObjectDebugProperties(newobj);
/* Invalidate the python reference, since the object may exist in script lists
@@ -1038,6 +1040,7 @@ int KX_Scene::NewRemoveObject(class CValue* gameobj)
!(itc==controllers.end());itc++)
{
m_logicmgr->RemoveController(*itc);
+ (*itc)->ReParent(NULL);
}
SCA_ActuatorList& actuators = newobj->GetActuators();
@@ -1166,8 +1169,6 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
#ifdef WITH_BULLET
bool bHasSoftBody = (!parentobj && (blendobj->gameflag & OB_SOFT_BODY));
#endif
- bool releaseParent = true;
-
if (oldblendobj==NULL) {
if (bHasModifier || bHasShapeKey || bHasDvert || bHasArmature) {
@@ -1187,9 +1188,8 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
oldblendobj, blendobj,
mesh,
true,
- static_cast<BL_ArmatureObject*>( parentobj )
+ static_cast<BL_ArmatureObject*>( parentobj->AddRef() )
);
- releaseParent= false;
modifierDeformer->LoadShapeDrivers(parentobj);
}
else
@@ -1215,9 +1215,8 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
mesh,
true,
true,
- static_cast<BL_ArmatureObject*>( parentobj )
+ static_cast<BL_ArmatureObject*>( parentobj->AddRef() )
);
- releaseParent= false;
shapeDeformer->LoadShapeDrivers(parentobj);
}
else
@@ -1241,9 +1240,8 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
mesh,
true,
true,
- static_cast<BL_ArmatureObject*>( parentobj )
+ static_cast<BL_ArmatureObject*>( parentobj->AddRef() )
);
- releaseParent= false;
newobj->SetDeformer(skinDeformer);
}
else if (bHasDvert)
@@ -1260,10 +1258,6 @@ void KX_Scene::ReplaceMesh(class CValue* obj,void* meshobj, bool use_gfx, bool u
newobj->SetDeformer(softdeformer);
}
#endif
-
- // release parent reference if its not being used
- if ( releaseParent && parentobj)
- parentobj->Release();
}
}
@@ -1357,17 +1351,6 @@ void KX_Scene::SetCameraOnTop(KX_Camera* cam)
}
}
-
-void KX_Scene::UpdateMeshTransformations()
-{
- // do this incrementally in the future
- for (int i = 0; i < m_objectlist->GetCount(); i++)
- {
- KX_GameObject* gameobj = (KX_GameObject*)m_objectlist->GetValue(i);
- gameobj->GetOpenGLMatrix();
- }
-}
-
void KX_Scene::MarkVisible(SG_Tree *node, RAS_IRasterizer* rasty, KX_Camera* cam, int layer)
{
int intersect = KX_Camera::INTERSECT;
@@ -1548,6 +1531,9 @@ void KX_Scene::CalculateVisibleMeshes(RAS_IRasterizer* rasty,KX_Camera* cam, int
MarkVisible(rasty, static_cast<KX_GameObject*>(m_objectlist->GetValue(i)), cam, layer);
}
}
+
+ // Now that we know visible meshes, update LoDs
+ UpdateObjectLods();
}
// logic stuff
@@ -1591,7 +1577,7 @@ void KX_Scene::AddAnimatedObject(CValue* gameobj)
static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(threadid))
{
- KX_GameObject *gameobj, *child;
+ KX_GameObject *gameobj, *child, *parent;
CListValue *children;
bool needs_update;
double curtime = *(double*)BLI_task_pool_userdata(pool);
@@ -1635,8 +1621,11 @@ static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(t
if (needs_update) {
gameobj->UpdateActionManager(curtime);
children = gameobj->GetChildren();
+ parent = gameobj->GetParent();
- if (gameobj->GetDeformer())
+ // Only do deformers here if they are not parented to an armature, otherwise the armature will
+ // handle updating its children
+ if (gameobj->GetDeformer() && (!parent || (parent && parent->GetGameObjectType() != SCA_IObject::OBJ_ARMATURE)))
gameobj->GetDeformer()->Update();
for (int j=0; j<children->GetCount(); ++j) {
@@ -1653,6 +1642,20 @@ static void update_anim_thread_func(TaskPool *pool, void *taskdata, int UNUSED(t
void KX_Scene::UpdateAnimations(double curtime)
{
+ KX_KetsjiEngine *engine = KX_GetActiveEngine();
+
+ if (engine->GetRestrictAnimationFPS())
+ {
+ // Handle the animations independently of the logic time step
+ double anim_timestep = 1.0 / GetAnimationFPS();
+ if (curtime - m_previousAnimTime < anim_timestep)
+ return;
+
+ // Sanity/debug print to make sure we're actually going at the fps we want (should be close to anim_timestep)
+ // printf("Anim fps: %f\n", 1.0/(m_clockTime - m_previousAnimTime));
+ m_previousAnimTime = curtime;
+ }
+
TaskPool *pool = BLI_task_pool_create(KX_GetActiveEngine()->GetTaskScheduler(), &curtime);
for (int i=0; i<m_animatedlist->GetCount(); ++i) {
@@ -2024,7 +2027,11 @@ bool KX_Scene::MergeScene(KX_Scene *other)
{
KX_GameObject* gameobj = (KX_GameObject*)other->GetObjectList()->GetValue(i);
MergeScene_GameObject(gameobj, this, other);
- AddObjectDebugProperties(gameobj); // add properties to debug list for LibLoad objects
+
+ /* add properties to debug list for LibLoad objects */
+ if (KX_GetActiveEngine()->GetAutoAddDebugProperties()) {
+ AddObjectDebugProperties(gameobj);
+ }
gameobj->UpdateBuckets(false); /* only for active objects */
}
@@ -2497,16 +2504,18 @@ KX_PYMETHODDEF_DOC(KX_Scene, restart,
KX_PYMETHODDEF_DOC(KX_Scene, replace,
"replace(newScene)\n"
- "Replaces this scene with another one.\n")
+ "Replaces this scene with another one.\n"
+ "Return True if the new scene exists and scheduled for replacement, False otherwise.\n")
{
char* name;
if (!PyArg_ParseTuple(args, "s:replace", &name))
return NULL;
- KX_GetActiveEngine()->ReplaceScene(m_sceneName, name);
+ if (KX_GetActiveEngine()->ReplaceScene(m_sceneName, name))
+ Py_RETURN_TRUE;
- Py_RETURN_NONE;
+ Py_RETURN_FALSE;
}
KX_PYMETHODDEF_DOC(KX_Scene, suspend,
diff --git a/source/gameengine/Ketsji/KX_Scene.h b/source/gameengine/Ketsji/KX_Scene.h
index 50fac923fe2..c5840c28041 100644
--- a/source/gameengine/Ketsji/KX_Scene.h
+++ b/source/gameengine/Ketsji/KX_Scene.h
@@ -289,6 +289,8 @@ protected:
double m_suspendedtime;
double m_suspendeddelta;
+ double m_previousAnimTime; //the last time animations were updated
+
struct Scene* m_blenderScene;
RAS_2DFilterManager m_filtermanager;
@@ -524,7 +526,6 @@ public:
void SetWorldInfo(class KX_WorldInfo* wi);
KX_WorldInfo* GetWorldInfo();
void CalculateVisibleMeshes(RAS_IRasterizer* rasty, KX_Camera *cam, int layer=0);
- void UpdateMeshTransformations();
KX_Camera* GetpCamera();
NG_NetworkDeviceInterface* GetNetworkDeviceInterface();
NG_NetworkScene* GetNetworkScene();
diff --git a/source/gameengine/Ketsji/KX_SteeringActuator.cpp b/source/gameengine/Ketsji/KX_SteeringActuator.cpp
index 2fa72c04a20..ff192299702 100644
--- a/source/gameengine/Ketsji/KX_SteeringActuator.cpp
+++ b/source/gameengine/Ketsji/KX_SteeringActuator.cpp
@@ -602,7 +602,7 @@ int KX_SteeringActuator::pyattr_set_navmesh(void *self, const struct KX_PYATTRIB
if (!ConvertPythonToGameObject(value, &gameobj, true, "actuator.object = value: KX_SteeringActuator"))
return PY_SET_ATTR_FAIL; // ConvertPythonToGameObject sets the error
- if (!PyObject_TypeCheck(value, &KX_NavMeshObject::Type))
+ if (dynamic_cast<KX_NavMeshObject *>(gameobj) == NULL)
{
PyErr_Format(PyExc_TypeError, "KX_NavMeshObject is expected");
return PY_SET_ATTR_FAIL;
diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
index d010d3d50a0..7ec379eec26 100644
--- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp
+++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
@@ -85,7 +85,7 @@ bool KX_TouchEventManager::newBroadphaseResponse(void *client_data,
PHY_IPhysicsController* ctrl2 = static_cast<PHY_IPhysicsController*>(object2);
KX_ClientObjectInfo *info1 = (ctrl1) ? static_cast<KX_ClientObjectInfo*>(ctrl1->GetNewClientInfo()) : NULL;
- KX_ClientObjectInfo *info2 = (ctrl1) ? static_cast<KX_ClientObjectInfo*>(ctrl2->GetNewClientInfo()) : NULL;
+ KX_ClientObjectInfo *info2 = (ctrl2) ? static_cast<KX_ClientObjectInfo*>(ctrl2->GetNewClientInfo()) : NULL;
// This call back should only be called for controllers of Near and Radar sensor
if (!info1)
@@ -97,9 +97,14 @@ bool KX_TouchEventManager::newBroadphaseResponse(void *client_data,
bool has_py_callbacks = false;
+#ifdef WITH_PYTHON
// Consider callbacks for broadphase inclusion if it's a sensor object type
if (gobj1 && gobj2)
has_py_callbacks = gobj1->m_collisionCallbacks || gobj2->m_collisionCallbacks;
+#else
+ (void)gobj1;
+ (void)gobj2;
+#endif
switch (info1->m_type)
{
diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
index 90b7850946b..75baf5fac1d 100644
--- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp
+++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp
@@ -31,8 +31,7 @@
* Replace the mesh for this actuator's parent
*/
-/* todo: not all trackflags / upflags are implemented/tested !
- * m_trackflag is used to determine the forward tracking direction
+/* m_trackflag is used to determine the forward tracking direction
* m_upflag for the up direction
* normal situation is +y for forward, +z for up */
@@ -177,7 +176,77 @@ static MT_Matrix3x3 matrix3x3_interpol(MT_Matrix3x3 oldmat, MT_Matrix3x3 mat, in
return EulToMat3(eul);
}
+static float basis_cross(int n, int m)
+{
+ switch (n - m) {
+ case 1:
+ case -2:
+ return 1.0f;
+
+ case -1:
+ case 2:
+ return -1.0f;
+
+ default:
+ return 0.0f;
+ }
+}
+/* vectomat function obtained from constrain.c and modified to work with MOTO library */
+static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short threedimup)
+{
+ MT_Matrix3x3 mat;
+ MT_Vector3 y(MT_Scalar(0.0), MT_Scalar(1.0), MT_Scalar(0.0));
+ MT_Vector3 z(MT_Scalar(0.0), MT_Scalar(0.0), MT_Scalar(1.0)); /* world Z axis is the global up axis */
+ MT_Vector3 proj;
+ MT_Vector3 right;
+ MT_Scalar mul;
+ int right_index;
+
+ /* Normalized Vec vector*/
+ vec = vec.safe_normalized_vec(z);
+
+ /* if 2D doesn't move the up vector */
+ if (!threedimup){
+ vec.setValue(MT_Scalar(vec[0]), MT_Scalar(vec[1]), MT_Scalar(0.0));
+ vec = (vec - z.dot(vec)*z).safe_normalized_vec(z);
+ }
+
+ if (axis > 2)
+ axis -= 3;
+ else
+ vec = -vec;
+
+ /* project the up vector onto the plane specified by vec */
+ /* first z onto vec... */
+ mul = z.dot(vec) / vec.dot(vec);
+ proj = vec * mul;
+ /* then onto the plane */
+ proj = z - proj;
+ /* proj specifies the transformation of the up axis */
+ proj = proj.safe_normalized_vec(y);
+
+ /* Normalized cross product of vec and proj specifies transformation of the right axis */
+ right = proj.cross(vec);
+ right.normalize();
+
+ if (axis != upflag) {
+ right_index = 3 - axis - upflag;
+
+ /* account for up direction, track direction */
+ right = right * basis_cross(axis, upflag);
+ mat.setRow(right_index, right);
+ mat.setRow(upflag, proj);
+ mat.setRow(axis, vec);
+ mat = mat.inverse();
+ }
+ /* identity matrix - don't do anything if the two axes are the same */
+ else {
+ mat.setIdentity();
+ }
+
+ return mat;
+}
KX_TrackToActuator::~KX_TrackToActuator()
{
@@ -247,153 +316,24 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
else if (m_object)
{
KX_GameObject* curobj = (KX_GameObject*) GetParent();
- MT_Vector3 dir = ((KX_GameObject*)m_object)->NodeGetWorldPosition() - curobj->NodeGetWorldPosition();
- if (dir.length2())
- dir.normalize();
- MT_Vector3 up(0,0,1);
-
-
-#ifdef DSADSA
- switch (m_upflag)
- {
- case 0:
- {
- up.setValue(1.0,0,0);
- break;
- }
- case 1:
- {
- up.setValue(0,1.0,0);
- break;
- }
- case 2:
- default:
- {
- up.setValue(0,0,1.0);
- }
- }
-#endif
- if (m_allow3D)
- {
- up = (up - up.dot(dir) * dir).safe_normalized();
-
- }
- else
- {
- dir = (dir - up.dot(dir)*up).safe_normalized();
- }
-
- MT_Vector3 left;
+ MT_Vector3 dir = curobj->NodeGetWorldPosition() - ((KX_GameObject*)m_object)->NodeGetWorldPosition();
MT_Matrix3x3 mat;
-
- switch (m_trackflag)
- {
- case 0: // TRACK X
- {
- // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = dir.safe_normalized();
- dir = up.cross(left).safe_normalized();
- mat.setValue (
- left[0], dir[0],up[0],
- left[1], dir[1],up[1],
- left[2], dir[2],up[2]
- );
-
- break;
- };
- case 1: // TRACK Y
- {
- // (0.0 , 1.0 , 0.0 ) y direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = (dir.cross(up)).safe_normalized();
- mat.setValue (
- left[0], dir[0],up[0],
- left[1], dir[1],up[1],
- left[2], dir[2],up[2]
- );
-
- break;
- }
-
- case 2: // track Z
- {
- left = up.safe_normalized();
- up = dir.safe_normalized();
- dir = left;
- left = (dir.cross(up)).safe_normalized();
- mat.setValue (
- left[0], dir[0],up[0],
- left[1], dir[1],up[1],
- left[2], dir[2],up[2]
- );
- break;
- }
-
- case 3: // TRACK -X
- {
- // (1.0 , 0.0 , 0.0 ) x direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = -dir.safe_normalized();
- dir = up.cross(left).safe_normalized();
- mat.setValue (
- left[0], dir[0],up[0],
- left[1], dir[1],up[1],
- left[2], dir[2],up[2]
- );
-
- break;
- };
- case 4: // TRACK -Y
- {
- // (0.0 , -1.0 , 0.0 ) -y direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = (-dir.cross(up)).safe_normalized();
- mat.setValue (
- left[0], -dir[0],up[0],
- left[1], -dir[1],up[1],
- left[2], -dir[2],up[2]
- );
- break;
- }
- case 5: // track -Z
- {
- left = up.safe_normalized();
- up = -dir.safe_normalized();
- dir = left;
- left = (dir.cross(up)).safe_normalized();
- mat.setValue (
- left[0], dir[0],up[0],
- left[1], dir[1],up[1],
- left[2], dir[2],up[2]
- );
-
- break;
- }
-
- default:
- {
- // (1.0 , 0.0 , 0.0 ) -x direction is forward, z (0.0 , 0.0 , 1.0 ) up
- left = -dir.safe_normalized();
- dir = up.cross(left).safe_normalized();
- mat.setValue (
- left[0], dir[0],up[0],
- left[1], dir[1],up[1],
- left[2], dir[2],up[2]
- );
- }
- }
-
MT_Matrix3x3 oldmat;
- oldmat= curobj->NodeGetWorldOrientation();
+
+ mat = vectomat(dir, m_trackflag, m_upflag, m_allow3D);
+ oldmat = curobj->NodeGetWorldOrientation();
/* erwin should rewrite this! */
- mat= matrix3x3_interpol(oldmat, mat, m_time);
+ mat = matrix3x3_interpol(oldmat, mat, m_time);
-
- if (m_parentobj) { // check if the model is parented and calculate the child transform
+ /* check if the model is parented and calculate the child transform */
+ if (m_parentobj) {
MT_Point3 localpos;
localpos = curobj->GetSGNode()->GetLocalPosition();
// Get the inverse of the parent matrix
MT_Matrix3x3 parentmatinv;
- parentmatinv = m_parentobj->NodeGetWorldOrientation ().inverse ();
+ parentmatinv = m_parentobj->NodeGetWorldOrientation().inverse();
// transform the local coordinate system into the parents system
mat = parentmatinv * mat;
// append the initial parent local rotation matrix
@@ -404,8 +344,7 @@ bool KX_TrackToActuator::Update(double curtime, bool frame)
curobj->NodeSetLocalPosition(localpos);
//curobj->UpdateTransform();
}
- else
- {
+ else {
curobj->NodeSetLocalOrientation(mat);
}
@@ -451,6 +390,8 @@ PyMethodDef KX_TrackToActuator::Methods[] = {
PyAttributeDef KX_TrackToActuator::Attributes[] = {
KX_PYATTRIBUTE_INT_RW("time",0,1000,true,KX_TrackToActuator,m_time),
KX_PYATTRIBUTE_BOOL_RW("use3D",KX_TrackToActuator,m_allow3D),
+ KX_PYATTRIBUTE_INT_RW("upAxis", 0, 2, true, KX_TrackToActuator,m_upflag),
+ KX_PYATTRIBUTE_INT_RW("trackAxis", 0, 5, true, KX_TrackToActuator,m_trackflag),
KX_PYATTRIBUTE_RW_FUNCTION("object", KX_TrackToActuator, pyattr_get_object, pyattr_set_object),
{ NULL } //Sentinel
diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.h b/source/gameengine/Ketsji/KX_TrackToActuator.h
index f5f5c4c2836..124014eede2 100644
--- a/source/gameengine/Ketsji/KX_TrackToActuator.h
+++ b/source/gameengine/Ketsji/KX_TrackToActuator.h
@@ -47,7 +47,6 @@ class KX_TrackToActuator : public SCA_IActuator
bool m_allow3D;
// time field
int m_time;
- int m_trackTime;
int m_trackflag;
int m_upflag;
@@ -69,6 +68,21 @@ class KX_TrackToActuator : public SCA_IActuator
virtual void Relink(CTR_Map<CTR_HashedPtr, void*> *obj_map);
virtual bool Update(double curtime, bool frame);
+ //Python Interface
+ enum UpAxis {
+ KX_TRACK_UPAXIS_POS_X = 0,
+ KX_TRACK_UPAXIS_POS_Y,
+ KX_TRACK_UPAXIS_POS_Z
+ };
+ enum TrackAxis {
+ KX_TRACK_TRAXIS_POS_X = 0,
+ KX_TRACK_TRAXIS_POS_Y,
+ KX_TRACK_TRAXIS_POS_Z,
+ KX_TRACK_TRAXIS_NEG_X,
+ KX_TRACK_TRAXIS_NEG_Y,
+ KX_TRACK_TRAXIS_NEG_Z
+ };
+
#ifdef WITH_PYTHON
/* Python part */
diff --git a/source/gameengine/Ketsji/SConscript b/source/gameengine/Ketsji/SConscript
index db5474cf2d7..8074a4064ff 100644
--- a/source/gameengine/Ketsji/SConscript
+++ b/source/gameengine/Ketsji/SConscript
@@ -30,7 +30,7 @@ import sys
Import ('env')
sources = env.Glob('*.cpp')
-defs = [ 'GLEW_STATIC' ]
+defs = env['BF_GL_DEFINITIONS']
incs = [
'.',
@@ -38,7 +38,8 @@ incs = [
'#intern/guardedalloc',
'#intern/string',
'#source/blender',
- '#extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#intern/audaspace/FX',
'#intern/audaspace/intern',
'#intern/moto/include',
diff --git a/source/gameengine/Physics/Bullet/CMakeLists.txt b/source/gameengine/Physics/Bullet/CMakeLists.txt
index 87d851016dd..e52dc1ba052 100644
--- a/source/gameengine/Physics/Bullet/CMakeLists.txt
+++ b/source/gameengine/Physics/Bullet/CMakeLists.txt
@@ -29,6 +29,7 @@ remove_strict_flags()
set(INC
.
../common
+ ../../Converter
../../Expressions
../../GameLogic
../../Ketsji
@@ -39,6 +40,7 @@ set(INC
../../../blender/makesdna
../../../../intern/container
../../../../intern/guardedalloc
+ ../../../../intern/glew-mx
../../../../intern/string
)
@@ -65,4 +67,6 @@ if(WITH_BULLET)
add_definitions(-DWITH_BULLET)
endif()
+add_definitions(${GL_DEFINITIONS})
+
blender_add_lib(ge_phys_bullet "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
index c98cf212265..72c3b13e301 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.cpp
@@ -1309,8 +1309,9 @@ void CcdPhysicsController::SetLinearVelocity(const MT_Vector3& lin_vel,bool loc
}
}
}
-void CcdPhysicsController::ApplyImpulse(const MT_Point3& attach, const MT_Vector3& impulsein)
+void CcdPhysicsController::ApplyImpulse(const MT_Point3& attach, const MT_Vector3& impulsein, bool local)
{
+ btVector3 pos;
btVector3 impulse(impulsein.x(), impulsein.y(), impulsein.z());
if (m_object && impulse.length2() > (SIMD_EPSILON*SIMD_EPSILON))
@@ -1323,7 +1324,19 @@ void CcdPhysicsController::ApplyImpulse(const MT_Point3& attach, const MT_Vecto
return;
}
- btVector3 pos(attach.x(), attach.y(), attach.z());
+ btTransform xform = m_object->getWorldTransform();
+
+ if (local)
+ {
+ pos = btVector3(attach.x(), attach.y(), attach.z());
+ impulse = xform.getBasis() * impulse;
+ }
+ else {
+ /* If the point of impulse application is not equal to the object position
+ * then an angular momentum is generated in the object*/
+ pos = btVector3(attach.x()-xform.getOrigin().x(), attach.y()-xform.getOrigin().y(), attach.z()-xform.getOrigin().z());
+ }
+
btRigidBody* body = GetRigidBody();
if (body)
body->applyImpulse(impulse,pos);
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
index 25a8f0306bd..4d0d96e07c6 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h
@@ -565,7 +565,7 @@ protected:
virtual void SetMass(MT_Scalar newmass);
// physics methods
- virtual void ApplyImpulse(const MT_Point3& attach, const MT_Vector3& impulsein);
+ virtual void ApplyImpulse(const MT_Point3& attach, const MT_Vector3& impulsein, bool local);
virtual void ApplyTorque(const MT_Vector3& torque,bool local);
virtual void ApplyForce(const MT_Vector3& force,bool local);
virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local);
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
index bbc3968347c..e17d4402556 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
@@ -42,6 +42,7 @@ subject to the following restrictions:
#include "PHY_Pro.h"
#include "KX_GameObject.h"
#include "KX_PythonInit.h" // for KX_RasterizerDrawDebugLine
+#include "KX_BlenderSceneConverter.h"
#include "RAS_MeshObject.h"
#include "RAS_Polygon.h"
#include "RAS_TexVert.h"
@@ -83,7 +84,7 @@ void DrawRasterizerLine(const float* from,const float* to,int color);
// This was copied from the old KX_ConvertPhysicsObjects
#ifdef WIN32
-#if defined(_MSC_VER) && (_MSC_VER >= 1310)
+#ifdef _MSC_VER
//only use SIMD Hull code under Win32
//#define TEST_HULL 1
#ifdef TEST_HULL
@@ -296,6 +297,44 @@ public:
};
+
+class BlenderVehicleRaycaster: public btDefaultVehicleRaycaster
+{
+ btDynamicsWorld* m_dynamicsWorld;
+public:
+ BlenderVehicleRaycaster(btDynamicsWorld* world)
+ :btDefaultVehicleRaycaster(world), m_dynamicsWorld(world)
+ {
+ }
+
+ virtual void* castRay(const btVector3& from,const btVector3& to, btVehicleRaycasterResult& result)
+ {
+ // RayResultCallback& resultCallback;
+
+ btCollisionWorld::ClosestRayResultCallback rayCallback(from,to);
+
+ // We override btDefaultVehicleRaycaster so we can set this flag, otherwise our
+ // vehicles go crazy (http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=9662)
+ rayCallback.m_flags |= btTriangleRaycastCallback::kF_UseSubSimplexConvexCastRaytest;
+
+ m_dynamicsWorld->rayTest(from, to, rayCallback);
+
+ if (rayCallback.hasHit())
+ {
+
+ const btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject);
+ if (body && body->hasContactResponse())
+ {
+ result.m_hitPointInWorld = rayCallback.m_hitPointWorld;
+ result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld;
+ result.m_hitNormalInWorld.normalize();
+ result.m_distFraction = rayCallback.m_closestHitFraction;
+ return (void*)body;
+ }
+ }
+ return 0;
+ }
+};
#endif //NEW_BULLET_VEHICLE_SUPPORT
class CcdOverlapFilterCallBack : public btOverlapFilterCallback
@@ -839,6 +878,14 @@ void CcdPhysicsEnvironment::ProcessFhSprings(double curTime,float interval)
}
}
+int CcdPhysicsEnvironment::GetDebugMode() const
+{
+ if (m_debugDrawer) {
+ return m_debugDrawer->getDebugMode();
+ }
+ return 0;
+}
+
void CcdPhysicsEnvironment::SetDebugMode(int debugMode)
{
if (m_debugDrawer) {
@@ -2047,7 +2094,7 @@ void CcdPhysicsEnvironment::SetConstraintParam(int constraintId,int param,float
case 12: case 13: case 14: case 15: case 16: case 17:
{
- //param 13-17 are for motorized springs on each of the degrees of freedom
+ //param 12-17 are for motorized springs on each of the degrees of freedom
btGeneric6DofSpringConstraint* genCons = (btGeneric6DofSpringConstraint*)typedConstraint;
int springIndex = param-12;
if (value0!=0.f)
@@ -2824,7 +2871,7 @@ int CcdPhysicsEnvironment::CreateConstraint(class PHY_IPhysicsController* ctrl
{
btRaycastVehicle::btVehicleTuning* tuning = new btRaycastVehicle::btVehicleTuning();
btRigidBody* chassis = rb0;
- btDefaultVehicleRaycaster* raycaster = new btDefaultVehicleRaycaster(m_dynamicsWorld);
+ btDefaultVehicleRaycaster* raycaster = new BlenderVehicleRaycaster(m_dynamicsWorld);
btRaycastVehicle* vehicle = new btRaycastVehicle(*tuning,chassis,raycaster);
WrapperVehicle* wrapperVehicle = new WrapperVehicle(vehicle,ctrl0);
m_wrapperVehicles.push_back(wrapperVehicle);
@@ -2998,9 +3045,17 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
CcdConstructionInfo ci;
class CcdShapeConstructionInfo *shapeInfo = new CcdShapeConstructionInfo();
- KX_GameObject *parent = gameobj->GetParent();
- if (parent)
+ // get Root Parent of blenderobject
+ Object *blenderparent = blenderobject->parent;
+ while (blenderparent && blenderparent->parent) {
+ blenderparent = blenderparent->parent;
+ }
+
+ KX_GameObject *parent = NULL;
+ if (blenderparent)
{
+ KX_BlenderSceneConverter *converter = (KX_BlenderSceneConverter*)KX_GetActiveEngine()->GetSceneConverter();
+ parent = converter->FindGameObject(blenderparent);
isbulletdyna = false;
isbulletsoftbody = false;
shapeprops->m_mass = 0.f;
@@ -3041,10 +3096,81 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
if (blenderobject->bsoft)
{
ci.m_margin = blenderobject->bsoft->margin;
+ ci.m_gamesoftFlag = blenderobject->bsoft->flag;
+
+ ci.m_soft_linStiff = blenderobject->bsoft->linStiff;
+ ci.m_soft_angStiff = blenderobject->bsoft->angStiff; /* angular stiffness 0..1 */
+ ci.m_soft_volume = blenderobject->bsoft->volume; /* volume preservation 0..1 */
+
+ ci.m_soft_viterations = blenderobject->bsoft->viterations; /* Velocities solver iterations */
+ ci.m_soft_piterations = blenderobject->bsoft->piterations; /* Positions solver iterations */
+ ci.m_soft_diterations = blenderobject->bsoft->diterations; /* Drift solver iterations */
+ ci.m_soft_citerations = blenderobject->bsoft->citerations; /* Cluster solver iterations */
+
+ ci.m_soft_kSRHR_CL = blenderobject->bsoft->kSRHR_CL; /* Soft vs rigid hardness [0,1] (cluster only) */
+ ci.m_soft_kSKHR_CL = blenderobject->bsoft->kSKHR_CL; /* Soft vs kinetic hardness [0,1] (cluster only) */
+ ci.m_soft_kSSHR_CL = blenderobject->bsoft->kSSHR_CL; /* Soft vs soft hardness [0,1] (cluster only) */
+ ci.m_soft_kSR_SPLT_CL = blenderobject->bsoft->kSR_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
+
+ ci.m_soft_kSK_SPLT_CL = blenderobject->bsoft->kSK_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
+ ci.m_soft_kSS_SPLT_CL = blenderobject->bsoft->kSS_SPLT_CL; /* Soft vs rigid impulse split [0,1] (cluster only) */
+ ci.m_soft_kVCF = blenderobject->bsoft->kVCF; /* Velocities correction factor (Baumgarte) */
+ ci.m_soft_kDP = blenderobject->bsoft->kDP; /* Damping coefficient [0,1] */
+
+ ci.m_soft_kDG = blenderobject->bsoft->kDG; /* Drag coefficient [0,+inf] */
+ ci.m_soft_kLF = blenderobject->bsoft->kLF; /* Lift coefficient [0,+inf] */
+ ci.m_soft_kPR = blenderobject->bsoft->kPR; /* Pressure coefficient [-inf,+inf] */
+ ci.m_soft_kVC = blenderobject->bsoft->kVC; /* Volume conversation coefficient [0,+inf] */
+
+ ci.m_soft_kDF = blenderobject->bsoft->kDF; /* Dynamic friction coefficient [0,1] */
+ ci.m_soft_kMT = blenderobject->bsoft->kMT; /* Pose matching coefficient [0,1] */
+ ci.m_soft_kCHR = blenderobject->bsoft->kCHR; /* Rigid contacts hardness [0,1] */
+ ci.m_soft_kKHR = blenderobject->bsoft->kKHR; /* Kinetic contacts hardness [0,1] */
+
+ ci.m_soft_kSHR = blenderobject->bsoft->kSHR; /* Soft contacts hardness [0,1] */
+ ci.m_soft_kAHR = blenderobject->bsoft->kAHR; /* Anchors hardness [0,1] */
+ ci.m_soft_collisionflags = blenderobject->bsoft->collisionflags; /* Vertex/Face or Signed Distance Field(SDF) or Clusters, Soft versus Soft or Rigid */
+ ci.m_soft_numclusteriterations = blenderobject->bsoft->numclusteriterations; /* number of iterations to refine collision clusters*/
+
}
else
{
ci.m_margin = 0.f;
+ ci.m_gamesoftFlag = OB_BSB_BENDING_CONSTRAINTS | OB_BSB_SHAPE_MATCHING | OB_BSB_AERO_VPOINT;
+
+ ci.m_soft_linStiff = 0.5;
+ ci.m_soft_angStiff = 1.f; /* angular stiffness 0..1 */
+ ci.m_soft_volume = 1.f; /* volume preservation 0..1 */
+
+ ci.m_soft_viterations = 0;
+ ci.m_soft_piterations = 1;
+ ci.m_soft_diterations = 0;
+ ci.m_soft_citerations = 4;
+
+ ci.m_soft_kSRHR_CL = 0.1f;
+ ci.m_soft_kSKHR_CL = 1.f;
+ ci.m_soft_kSSHR_CL = 0.5;
+ ci.m_soft_kSR_SPLT_CL = 0.5f;
+
+ ci.m_soft_kSK_SPLT_CL = 0.5f;
+ ci.m_soft_kSS_SPLT_CL = 0.5f;
+ ci.m_soft_kVCF = 1;
+ ci.m_soft_kDP = 0;
+
+ ci.m_soft_kDG = 0;
+ ci.m_soft_kLF = 0;
+ ci.m_soft_kPR = 0;
+ ci.m_soft_kVC = 0;
+
+ ci.m_soft_kDF = 0.2f;
+ ci.m_soft_kMT = 0.05f;
+ ci.m_soft_kCHR = 1.0f;
+ ci.m_soft_kKHR = 0.1f;
+
+ ci.m_soft_kSHR = 1.f;
+ ci.m_soft_kAHR = 0.7f;
+ ci.m_soft_collisionflags = OB_BSB_COL_SDF_RS + OB_BSB_COL_VF_SS;
+ ci.m_soft_numclusteriterations = 16;
}
}
else
@@ -3056,27 +3182,26 @@ void CcdPhysicsEnvironment::ConvertObject(KX_GameObject *gameobj, RAS_MeshObject
btCollisionShape* bm = 0;
- char bounds;
- if (blenderobject->gameflag & OB_BOUNDS)
- {
- bounds = blenderobject->collision_boundtype;
- }
- else
+ char bounds = isbulletdyna ? OB_BOUND_SPHERE : OB_BOUND_TRIANGLE_MESH;
+ if (!(blenderobject->gameflag & OB_BOUNDS))
{
if (blenderobject->gameflag & OB_SOFT_BODY)
bounds = OB_BOUND_TRIANGLE_MESH;
else if (blenderobject->gameflag & OB_CHARACTER)
bounds = OB_BOUND_SPHERE;
- else if (isbulletdyna)
+ }
+ else
+ {
+ if (ELEM(blenderobject->collision_boundtype, OB_BOUND_CONVEX_HULL, OB_BOUND_TRIANGLE_MESH)
+ && blenderobject->type != OB_MESH)
+ {
+ // Can't use triangle mesh or convex hull on a non-mesh object, fall-back to sphere
bounds = OB_BOUND_SPHERE;
+ }
else
- bounds = OB_BOUND_TRIANGLE_MESH;
+ bounds = blenderobject->collision_boundtype;
}
- // Can't use triangle mesh or convex hull on a non-mesh object, fall-back to sphere
- if (ELEM(bounds, OB_BOUND_TRIANGLE_MESH, OB_BOUND_CONVEX_HULL) && blenderobject->type != OB_MESH)
- bounds = OB_BOUND_SPHERE;
-
// Get bounds information
float bounds_center[3], bounds_extends[3];
BoundBox *bb= BKE_object_boundbox_get(blenderobject);
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
index a94e205b160..ff8a3f4f9f9 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.h
@@ -139,6 +139,7 @@ protected:
virtual float GetFixedTimeStep() { return 0.f; }
virtual void SetDebugMode(int debugMode);
+ virtual int GetDebugMode()const;
virtual void SetGravity(float x,float y,float z);
virtual void GetGravity(MT_Vector3& grav);
diff --git a/source/gameengine/Physics/Bullet/SConscript b/source/gameengine/Physics/Bullet/SConscript
index 2700997ccd4..30287553a10 100644
--- a/source/gameengine/Physics/Bullet/SConscript
+++ b/source/gameengine/Physics/Bullet/SConscript
@@ -34,11 +34,13 @@ incs = [
'#intern/container',
'#intern/guardedalloc',
'#intern/string',
- '#extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#intern/moto/include',
'#source/blender/blenkernel',
'#source/blender/blenlib',
'#source/blender/makesdna',
+ '#source/gameengine/Converter',
'#source/gameengine/Expressions',
'#source/gameengine/GameLogic',
'#source/gameengine/Ketsji',
@@ -50,7 +52,7 @@ incs = ' '.join(incs)
incs += ' ' + env['BF_BULLET_INC']
-defs = []
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_PYTHON']:
incs += ' ' + env['BF_PYTHON_INC']
diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp
index 1bb5431c749..979128370ee 100644
--- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp
+++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.cpp
@@ -78,8 +78,10 @@ float DummyPhysicsEnvironment::GetFixedTimeStep()
return 0.f;
}
-
-
+int DummyPhysicsEnvironment::GetDebugMode() const
+{
+ return 0;
+}
void DummyPhysicsEnvironment::SetGravity(float x,float y,float z)
{
diff --git a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
index a645af1e471..cfc8841cac2 100644
--- a/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
+++ b/source/gameengine/Physics/Dummy/DummyPhysicsEnvironment.h
@@ -56,6 +56,8 @@ public:
virtual void SetFixedTimeStep(bool useFixedTimeStep,float fixedTimeStep);
virtual float GetFixedTimeStep();
+ virtual int GetDebugMode() const;
+
virtual void SetGravity(float x,float y,float z);
virtual void GetGravity(class MT_Vector3& grav);
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h
index 2ffb115e3b2..f9975484fa7 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsController.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h
@@ -82,7 +82,7 @@ class PHY_IPhysicsController : public PHY_IController
virtual void SetMass(MT_Scalar newmass)=0;
// physics methods
- virtual void ApplyImpulse(const MT_Point3& attach, const MT_Vector3& impulse)=0;
+ virtual void ApplyImpulse(const MT_Point3& attach, const MT_Vector3& impulse,bool local)=0;
virtual void ApplyTorque(const MT_Vector3& torque,bool local)=0;
virtual void ApplyForce(const MT_Vector3& force,bool local)=0;
virtual void SetAngularVelocity(const MT_Vector3& ang_vel,bool local)=0;
diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
index 81a45f93993..dd762b02b4e 100644
--- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
+++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h
@@ -126,6 +126,8 @@ class PHY_IPhysicsEnvironment
//returns 0.f if no fixed timestep is used
virtual float GetFixedTimeStep()=0;
+ ///getDebugMode return the actual debug visualization state
+ virtual int GetDebugMode()const=0;
///setDebugMode is used to support several ways of debug lines, contact point visualization
virtual void SetDebugMode(int debugMode) {}
///setNumIterations set the number of iterations for iterative solvers
diff --git a/source/gameengine/Rasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/CMakeLists.txt
index e254bf9b1c5..5bc3f22e327 100644
--- a/source/gameengine/Rasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/CMakeLists.txt
@@ -32,6 +32,7 @@ set(INC
../../blender/blenlib
../../blender/blenkernel
../../../intern/container
+ ../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/string
)
@@ -81,6 +82,6 @@ set(SRC
RAS_OpenGLFilters/RAS_Sobel2DFilter.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
blender_add_lib(ge_rasterizer "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
index abbe65738d4..908c5979249 100644
--- a/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_2DFilterManager.cpp
@@ -43,7 +43,7 @@
#include "RAS_2DFilterManager.h"
#include <iostream>
-#include "GL/glew.h"
+#include "glew-mx.h"
#include <stdio.h>
diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.cpp b/source/gameengine/Rasterizer/RAS_BucketManager.cpp
index eaa9b3df494..f90b5959f76 100644
--- a/source/gameengine/Rasterizer/RAS_BucketManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_BucketManager.cpp
@@ -228,28 +228,24 @@ void RAS_BucketManager::Renderbuckets(const MT_Transform& cameratrans, RAS_IRast
RenderSolidBuckets(cameratrans, rasty);
RenderAlphaBuckets(cameratrans, rasty);
- /* All meshes should be up to date now */
- /* Don't do this while processing buckets because some meshes are split between buckets */
- BucketList::iterator bit;
- list<RAS_MeshSlot>::iterator mit;
- for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
- /* This (and the similar lines of code for the alpha buckets) is kind of a hacky fix for #34382. If we're
- * drawing shadows and the material doesn't cast shadows, then the mesh is still modified, so we don't want to
- * set MeshModified to false yet. This will happen correctly in the main render pass.
- */
- if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && !(*bit)->GetPolyMaterial()->CastsShadows())
- continue;
-
- for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
- mit->m_mesh->SetMeshModified(false);
+ /* If we're drawing shadows and bucket wasn't rendered (outside of the lamp frustum or doesn't cast shadows)
+ * then the mesh is still modified, so we don't want to set MeshModified to false yet (it will mess up
+ * updating display lists). Just leave this step for the main render pass.
+ */
+ if (rasty->GetDrawingMode() != RAS_IRasterizer::KX_SHADOW) {
+ /* All meshes should be up to date now */
+ /* Don't do this while processing buckets because some meshes are split between buckets */
+ BucketList::iterator bit;
+ list<RAS_MeshSlot>::iterator mit;
+ for (bit = m_SolidBuckets.begin(); bit != m_SolidBuckets.end(); ++bit) {
+ for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
+ mit->m_mesh->SetMeshModified(false);
+ }
}
- }
- for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
- if (rasty->GetDrawingMode() == RAS_IRasterizer::KX_SHADOW && !(*bit)->GetPolyMaterial()->CastsShadows())
- continue;
-
- for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
- mit->m_mesh->SetMeshModified(false);
+ for (bit = m_AlphaBuckets.begin(); bit != m_AlphaBuckets.end(); ++bit) {
+ for (mit = (*bit)->msBegin(); mit != (*bit)->msEnd(); ++mit) {
+ mit->m_mesh->SetMeshModified(false);
+ }
}
}
diff --git a/source/gameengine/Rasterizer/RAS_BucketManager.h b/source/gameengine/Rasterizer/RAS_BucketManager.h
index f8c6375d474..5ed212ebee0 100644
--- a/source/gameengine/Rasterizer/RAS_BucketManager.h
+++ b/source/gameengine/Rasterizer/RAS_BucketManager.h
@@ -39,7 +39,9 @@
class RAS_BucketManager
{
+public:
typedef std::vector<class RAS_MaterialBucket*> BucketList;
+private:
BucketList m_SolidBuckets;
BucketList m_AlphaBuckets;
diff --git a/source/gameengine/Rasterizer/RAS_ICanvas.h b/source/gameengine/Rasterizer/RAS_ICanvas.h
index 9e8a6e8ccf6..d90cbea286e 100644
--- a/source/gameengine/Rasterizer/RAS_ICanvas.h
+++ b/source/gameengine/Rasterizer/RAS_ICanvas.h
@@ -113,8 +113,9 @@ public:
)=0;
virtual
- int
+ bool
GetSwapInterval(
+ int& intervalOut
)=0;
virtual
diff --git a/source/gameengine/Rasterizer/RAS_ILightObject.h b/source/gameengine/Rasterizer/RAS_ILightObject.h
index 28c5d9aedd7..f087f3bbb70 100644
--- a/source/gameengine/Rasterizer/RAS_ILightObject.h
+++ b/source/gameengine/Rasterizer/RAS_ILightObject.h
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file RAS_LightObject.h
+/** \file RAS_ILightObject.h
* \ingroup bgerast
*/
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
index f0410ba891d..888a7114f50 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/CMakeLists.txt
@@ -39,6 +39,7 @@ set(INC
../../../blender/gpu
../../../blender/makesdna
../../../../intern/container
+ ../../../../intern/glew-mx
../../../../intern/string
)
@@ -66,6 +67,6 @@ set(SRC
RAS_StorageVBO.h
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
blender_add_lib(ge_oglrasterizer "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp
index 32cc4ba9fea..bc22d68e218 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_GLExtensionManager.cpp
@@ -32,7 +32,7 @@
#include <iostream>
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "RAS_GLExtensionManager.h"
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
index e1dbd6f0a7f..b3da5e1f812 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_ListRasterizer.cpp
@@ -30,7 +30,7 @@
#include <windows.h>
#endif // WIN32
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "RAS_MaterialBucket.h"
#include "RAS_TexVert.h"
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
index 91ad2838ccd..4ac1c9c4ebb 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLLight.cpp
@@ -25,7 +25,10 @@
* ***** END GPL LICENSE BLOCK *****
*/
-#include "GL/glew.h"
+#include "glew-mx.h"
+
+#include <stdio.h>
+
#include "RAS_OpenGLLight.h"
#include "RAS_OpenGLRasterizer.h"
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
index 0960fdaab4f..415ea87fb1b 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp
@@ -35,7 +35,7 @@
#include "RAS_OpenGLRasterizer.h"
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "RAS_ICanvas.h"
#include "RAS_Rect.h"
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
index b138f84ea97..e0613350b77 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageIM.cpp
@@ -29,7 +29,7 @@
#include "RAS_MaterialBucket.h"
#include "RAS_IPolygonMaterial.h"
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
#include "GPU_material.h"
@@ -247,7 +247,7 @@ void RAS_StorageIM::IndexPrimitivesInternal(RAS_MeshSlot& ms, bool multi)
//ms.m_pDerivedMesh->drawMappedFacesTex(ms.m_pDerivedMesh, CheckTexfaceDM, mcol);
current_blmat_nr = current_polymat->GetMaterialIndex();
current_image = current_polymat->GetBlenderImage();
- ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL);
+ ms.m_pDerivedMesh->drawFacesTex(ms.m_pDerivedMesh, CheckTexDM, NULL, NULL, DM_DRAW_USE_ACTIVE_UV);
}
return;
}
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
index 006c07b0491..c2980a6c15f 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.cpp
@@ -27,7 +27,7 @@
#include "RAS_StorageVA.h"
-#include "GL/glew.h"
+#include "glew-mx.h"
RAS_StorageVA::RAS_StorageVA(int *texco_num, RAS_IRasterizer::TexCoGen *texco, int *attrib_num, RAS_IRasterizer::TexCoGen *attrib, int *attrib_layer) :
m_drawingmode(RAS_IRasterizer::KX_TEXTURED),
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
index 6aa90fbd6ef..58f3d4c05da 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.cpp
@@ -28,7 +28,7 @@
#include "RAS_StorageVBO.h"
#include "RAS_MeshObject.h"
-#include "GL/glew.h"
+#include "glew-mx.h"
VBO::VBO(RAS_DisplayArray *data, unsigned int indices)
{
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
index 2fe0c32f399..f156722247c 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h
@@ -29,7 +29,7 @@
#define __KX_VERTEXBUFFEROBJECTSTORAGE
#include <map>
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "RAS_IStorage.h"
#include "RAS_IRasterizer.h"
diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
index 0a7417656c6..93905f733dc 100644
--- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
+++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/SConscript
@@ -3,14 +3,15 @@ Import ('env')
sources = env.Glob('*.cpp')
-defs = [ 'GLEW_STATIC' ]
+defs = env['BF_GL_DEFINITIONS']
incs = [
'.',
'#intern/container',
'#intern/guardedalloc',
'#intern/string',
- '#extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#intern/moto/include',
'#source/blender/blenkernel',
'#source/blender/blenfont',
diff --git a/source/gameengine/Rasterizer/SConscript b/source/gameengine/Rasterizer/SConscript
index 5c68ce63a3b..c0d725ad957 100644
--- a/source/gameengine/Rasterizer/SConscript
+++ b/source/gameengine/Rasterizer/SConscript
@@ -36,15 +36,17 @@ incs = [
'#intern/moto/include',
'#intern/container',
'#source/gameengine/BlenderRoutines',
- '#extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#source/gameengine/Expressions',
'#source/gameengine/SceneGraph',
'#source/blender/blenlib',
'#source/blender/blenkernel',
+ '#source/blender/gpu',
'#source/blender/makesdna',
]
-defs = ['GLEW_STATIC']
+defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_PYTHON']:
incs.extend(Split(env['BF_PYTHON_INC']))
diff --git a/source/gameengine/VideoTexture/CMakeLists.txt b/source/gameengine/VideoTexture/CMakeLists.txt
index 3ca3917cf6d..4be9a9abe5c 100644
--- a/source/gameengine/VideoTexture/CMakeLists.txt
+++ b/source/gameengine/VideoTexture/CMakeLists.txt
@@ -42,6 +42,7 @@ set(INC
../../blender/python/generic
../../../intern/container
../../../intern/ffmpeg
+ ../../../intern/glew-mx
../../../intern/guardedalloc
../../../intern/string
)
@@ -51,7 +52,7 @@ set(INC_SYS
${GLEW_INCLUDE_PATH}
)
-add_definitions(-DGLEW_STATIC)
+add_definitions(${GL_DEFINITIONS})
set(SRC
Exception.cpp
diff --git a/source/gameengine/VideoTexture/Exception.h b/source/gameengine/VideoTexture/Exception.h
index 4410ec1aa8b..c3c27abe019 100644
--- a/source/gameengine/VideoTexture/Exception.h
+++ b/source/gameengine/VideoTexture/Exception.h
@@ -24,7 +24,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file Exception.h
+/** \file gameengine/VideoTexture/Exception.h
* \ingroup bgevideotex
*/
diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp
index 4109981a98c..0d46160a11e 100644
--- a/source/gameengine/VideoTexture/ImageBase.cpp
+++ b/source/gameengine/VideoTexture/ImageBase.cpp
@@ -32,7 +32,7 @@
extern "C" {
#include "bgl.h"
}
-#include "GL/glew.h"
+#include "glew-mx.h"
#include <vector>
#include <string.h>
diff --git a/source/gameengine/VideoTexture/ImageBuff.cpp b/source/gameengine/VideoTexture/ImageBuff.cpp
index 6cc8d287e66..705d9136cbe 100644
--- a/source/gameengine/VideoTexture/ImageBuff.cpp
+++ b/source/gameengine/VideoTexture/ImageBuff.cpp
@@ -163,7 +163,7 @@ void ImageBuff::plot(unsigned char *img, short width, short height, short x, sho
// assign temporarily our buffer to the ImBuf buffer, we use the same format
tmpbuf->rect = (unsigned int*)img;
m_imbuf->rect = m_image;
- IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode);
+ IMB_rectblend(m_imbuf, m_imbuf, tmpbuf, NULL, NULL, NULL, 0, x, y, x, y, 0, 0, width, height, (IMB_BlendMode)mode, false);
// remove so that MB_freeImBuf will free our buffer
m_imbuf->rect = NULL;
tmpbuf->rect = NULL;
@@ -186,7 +186,7 @@ void ImageBuff::plot(ImageBuff *img, short x, short y, short mode)
// assign temporarily our buffer to the ImBuf buffer, we use the same format
img->m_imbuf->rect = img->m_image;
m_imbuf->rect = m_image;
- IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode);
+ IMB_rectblend(m_imbuf, m_imbuf, img->m_imbuf, NULL, NULL, NULL, 0, x, y, x, y, 0, 0, img->m_imbuf->x, img->m_imbuf->y, (IMB_BlendMode)mode, false);
// remove so that MB_freeImBuf will free our buffer
m_imbuf->rect = NULL;
img->m_imbuf->rect = NULL;
diff --git a/source/gameengine/VideoTexture/ImageRender.cpp b/source/gameengine/VideoTexture/ImageRender.cpp
index 18474932879..617e7fd1d8e 100644
--- a/source/gameengine/VideoTexture/ImageRender.cpp
+++ b/source/gameengine/VideoTexture/ImageRender.cpp
@@ -36,7 +36,7 @@
#include <math.h>
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "KX_PythonInit.h"
#include "DNA_scene_types.h"
@@ -274,6 +274,8 @@ void ImageRender::Render()
m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera);
+ m_scene->UpdateAnimations(m_engine->GetFrameTime());
+
m_scene->RenderBuckets(camtrans, m_rasterizer);
m_scene->RenderFonts();
diff --git a/source/gameengine/VideoTexture/ImageViewport.cpp b/source/gameengine/VideoTexture/ImageViewport.cpp
index 789b6006f99..421f0df814b 100644
--- a/source/gameengine/VideoTexture/ImageViewport.cpp
+++ b/source/gameengine/VideoTexture/ImageViewport.cpp
@@ -33,7 +33,7 @@
#include "PyObjectPlus.h"
#include <structmember.h>
-#include "GL/glew.h"
+#include "glew-mx.h"
#include "KX_PythonInit.h"
#include "RAS_ICanvas.h"
diff --git a/source/gameengine/VideoTexture/SConscript b/source/gameengine/VideoTexture/SConscript
index f7bf6bd93c1..b1b02db3ebc 100644
--- a/source/gameengine/VideoTexture/SConscript
+++ b/source/gameengine/VideoTexture/SConscript
@@ -37,7 +37,8 @@ incs = [
'#intern/ffmpeg',
'#intern/guardedalloc',
'#intern/string',
- '#extern/glew/include',
+ env['BF_GLEW_INC'],
+ '#/intern/glew-mx',
'#intern/moto/include',
'#source/blender/blenkernel',
'#source/blender/blenlib',
@@ -57,7 +58,8 @@ incs = [
]
incs = ' '.join(incs)
-defs = ['GLEW_STATIC']
+defs = env['BF_GL_DEFINITIONS']
+
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc','win32-mingw', 'win64-mingw'):
if env['BF_DEBUG']:
defs.append('_DEBUG')
diff --git a/source/gameengine/VideoTexture/Texture.cpp b/source/gameengine/VideoTexture/Texture.cpp
index 35a73193a24..74f36207774 100644
--- a/source/gameengine/VideoTexture/Texture.cpp
+++ b/source/gameengine/VideoTexture/Texture.cpp
@@ -54,7 +54,7 @@
#include "Exception.h"
#include <memory.h>
-#include "GL/glew.h"
+#include "glew-mx.h"
// macro for exception handling and logging
diff --git a/source/gameengine/VideoTexture/VideoFFmpeg.cpp b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
index 179f1ced03b..edf3c58bcbe 100644
--- a/source/gameengine/VideoTexture/VideoFFmpeg.cpp
+++ b/source/gameengine/VideoTexture/VideoFFmpeg.cpp
@@ -545,6 +545,7 @@ void VideoFFmpeg::openFile (char *filename)
// but it is really not desirable to seek on http file, so force streaming.
// It would be good to find this information from the context but there are no simple indication
!strncmp(filename, "http://", 7) ||
+ !strncmp(filename, "rtsp://", 7) ||
(m_formatCtx->pb && !m_formatCtx->pb->seekable)
)
{
@@ -680,6 +681,12 @@ bool VideoFFmpeg::play (void)
{
// set video position
setPositions();
+
+ if (m_isStreaming)
+ {
+ av_read_play(m_formatCtx);
+ }
+
// return success
return true;
}
@@ -696,6 +703,10 @@ bool VideoFFmpeg::pause (void)
{
if (VideoBase::pause())
{
+ if (m_isStreaming)
+ {
+ av_read_pause(m_formatCtx);
+ }
return true;
}
}
diff --git a/source/tests/CMakeLists.txt b/source/tests/CMakeLists.txt
deleted file mode 100644
index 85c68693792..00000000000
--- a/source/tests/CMakeLists.txt
+++ /dev/null
@@ -1,360 +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.
-#
-# Contributor(s): Jacques Beaurain.
-#
-# ***** END GPL LICENSE BLOCK *****
-
-# --env-system-scripts allows to run without the install target.
-
-# Use '--write-blend=/tmp/test.blend' to view output
-
-# Some tests are interesting but take too long to run
-# and don't give deterministic results
-set(USE_EXPERIMENTAL_TESTS FALSE)
-
-set(TEST_SRC_DIR ${CMAKE_SOURCE_DIR}/../lib/tests)
-set(TEST_OUT_DIR ${CMAKE_BINARY_DIR}/tests)
-
-# ugh, any better way to do this on testing only?
-execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory ${TEST_OUT_DIR})
-
-#~ if(NOT IS_DIRECTORY ${TEST_SRC_DIR})
-#~ message(FATAL_ERROR "CMake test directory not found!")
-#~ endif()
-
-# all calls to blender use this
-if(APPLE)
- if(${CMAKE_GENERATOR} MATCHES "Xcode")
- set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/Debug/blender.app/Contents/MacOS/blender)
- else()
- set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender.app/Contents/MacOS/blender)
- endif()
-else()
- set(TEST_BLENDER_EXE ${EXECUTABLE_OUTPUT_PATH}/blender)
-endif()
-
-# for testing with valgrind prefix: valgrind --track-origins=yes --error-limit=no
-set(TEST_BLENDER_EXE ${TEST_BLENDER_EXE} --background -noaudio --factory-startup --env-system-scripts ${CMAKE_SOURCE_DIR}/release/scripts)
-
-
-# ------------------------------------------------------------------------------
-# GENERAL PYTHON CORRECTNESS TESTS
-add_test(script_load_keymap ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_keymap_completeness.py
-)
-
-add_test(script_load_addons ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_load_addons.py
-)
-
-add_test(script_load_modules ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_load_py_modules.py
-)
-
-# test running operators doesn't segfault under various conditions
-if(USE_EXPERIMENTAL_TESTS)
- add_test(script_run_operators ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_run_operators.py
- )
-endif()
-
-# test running mathutils testing script
-add_test(script_pyapi_mathutils ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_pyapi_mathutils.py
-)
-
-# ------------------------------------------------------------------------------
-# MODELING TESTS
-add_test(bevel ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/modeling/bevel_regression.blend
- --python-text run_tests
-)
-
-# ------------------------------------------------------------------------------
-# IO TESTS
-
-# OBJ Import tests
-add_test(import_obj_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/cube.obj'\)
- --md5=39cce4bacac2d1b18fc470380279bc15 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_obj_cube.blend
-)
-
-add_test(import_obj_nurbs_cyclic ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/nurbs_cyclic.obj'\)
- --md5=ad3c307e5883224a0492378cd32691ab --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_obj_nurbs_cyclic.blend
-)
-
-add_test(import_obj_makehuman ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.obj\(filepath='${TEST_SRC_DIR}/io_tests/obj/makehuman.obj'\)
- --md5=c9f78b185e58358daa4ecaecfa75464e --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_obj_makehuman.blend
-)
-
-# OBJ Export tests
-add_test(export_obj_cube ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_cube.obj',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_obj_cube.obj
- --md5_source=${TEST_OUT_DIR}/export_obj_cube.mtl
- --md5=70bdc394c2726203ad26c085176e3484 --md5_method=FILE
-)
-
-add_test(export_obj_nurbs ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_nurbs.obj',use_selection=False,use_nurbs=True\)
- --md5_source=${TEST_OUT_DIR}/export_obj_nurbs.obj
- --md5_source=${TEST_OUT_DIR}/export_obj_nurbs.mtl
- --md5=a733ae4fa4a591ea9b0912da3af042de --md5_method=FILE
-)
-
-add_test(export_obj_all_objects ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.obj\(filepath='${TEST_OUT_DIR}/export_obj_all_objects.obj',use_selection=False,use_nurbs=True\)
- --md5_source=${TEST_OUT_DIR}/export_obj_all_objects.obj
- --md5_source=${TEST_OUT_DIR}/export_obj_all_objects.mtl
- --md5=04b3ed97cede07a19548fc518ce9f8ca --md5_method=FILE
-)
-
-
-
-# PLY Import tests
-add_test(import_ply_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/cube_ascii.ply'\)
- --md5=527134343c27fc0ea73115b85fbfd3ac --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_ply_cube.blend
-)
-
-add_test(import_ply_bunny ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/bunny2.ply'\)
- --md5=6ea5b8533400a17accf928b8fd024eaa --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_ply_bunny.blend
-)
-
-add_test(import_ply_small_holes ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.ply\(filepath='${TEST_SRC_DIR}/io_tests/ply/many_small_holes.ply'\)
- --md5=c3093e26ecae5b6d59fbbcf2a0d0b39f --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_ply_small_holes.blend
-)
-
-# PLY Export
-add_test(export_ply_cube_all_data ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/cube_all_data.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_mesh.ply\(filepath='${TEST_OUT_DIR}/export_ply_cube_all_data.ply'\)
- --md5_source=${TEST_OUT_DIR}/export_ply_cube_all_data.ply
- --md5=6adc3748ceae8298496f99d0e7e76c15 --md5_method=FILE
-)
-
-add_test(export_ply_suzanne_all_data ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/suzanne_all_data.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_mesh.ply\(filepath='${TEST_OUT_DIR}/export_ply_suzanne_all_data.ply'\)
- --md5_source=${TEST_OUT_DIR}/export_ply_suzanne_all_data.ply
- --md5=68ba23f02efd6511bfd093f45f703221 --md5_method=FILE
-)
-
-add_test(export_ply_vertices ${TEST_BLENDER_EXE} # lame, add a better one
- ${TEST_SRC_DIR}/io_tests/blend_geometry/vertices.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_mesh.ply\(filepath='${TEST_OUT_DIR}/export_ply_vertices.ply'\)
- --md5_source=${TEST_OUT_DIR}/export_ply_vertices.ply
- --md5=37faba0aa2014451b27f951afa92f870 --md5_method=FILE
-)
-
-
-# STL Import tests
-add_test(import_stl_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/cube.stl'\)
- --md5=8ceb5bb7e1cb5f4342fa1669988c66b4 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_stl_cube.blend
-)
-
-add_test(import_stl_conrod ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/conrod.stl'\)
- --md5=690a4b8eb9002dcd8631c5a575ea7348 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_stl_conrod.blend
-)
-
-add_test(import_stl_knot_max_simplified ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_mesh.stl\(filepath='${TEST_SRC_DIR}/io_tests/stl/knot_max_simplified.stl'\)
- --md5=baf82803f45a84ec4ddbad9cef57dd3e --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_stl_knot_max_simplified.blend
-)
-
-# STL Export
-add_test(export_stl_cube_all_data ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/cube_all_data.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_mesh.stl\(filepath='${TEST_OUT_DIR}/export_stl_cube_all_data.stl'\)
- --md5_source=${TEST_OUT_DIR}/export_stl_cube_all_data.stl
- --md5=64cb97c0cabb015e1c3f76369835075a --md5_method=FILE
-)
-
-add_test(export_stl_suzanne_all_data ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/suzanne_all_data.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_mesh.stl\(filepath='${TEST_OUT_DIR}/export_stl_suzanne_all_data.stl'\)
- --md5_source=${TEST_OUT_DIR}/export_stl_suzanne_all_data.stl
- --md5=e9b23c97c139ad64961c635105bb9192 --md5_method=FILE
-)
-
-add_test(export_stl_vertices ${TEST_BLENDER_EXE} # lame, add a better one
- ${TEST_SRC_DIR}/io_tests/blend_geometry/vertices.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_mesh.stl\(filepath='${TEST_OUT_DIR}/export_stl_vertices.stl'\)
- --md5_source=${TEST_OUT_DIR}/export_stl_vertices.stl
- --md5=3fd3c877e573beeebc782532cc005820 --md5_method=FILE
-)
-
-
-# X3D Import
-add_test(import_x3d_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/color_cube.x3d'\)
- --md5=3fae9be004199c145941cd3f9f80ad7b --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_x3d_cube.blend
-)
-
-add_test(import_x3d_teapot ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/teapot.x3d'\)
- --md5=8ee196c71947dce4199d55698501691e --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_x3d_teapot.blend
-)
-
-add_test(import_x3d_suzanne_material ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.x3d\(filepath='${TEST_SRC_DIR}/io_tests/x3d/suzanne_material.x3d'\)
- --md5=3edea1353257d8b5a5f071942f417be6 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_x3d_suzanne_material.blend
-)
-
-# X3D Export
-add_test(export_x3d_cube ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_cube.x3d',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_x3d_cube.x3d
- --md5=05312d278fe41da33560fdfb9bdb268f --md5_method=FILE
-)
-
-add_test(export_x3d_nurbs ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_nurbs.x3d',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_x3d_nurbs.x3d
- --md5=4286d4a2aa507ef78b22ddcbdcc88481 --md5_method=FILE
-)
-
-add_test(export_x3d_all_objects ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.x3d\(filepath='${TEST_OUT_DIR}/export_x3d_all_objects.x3d',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_x3d_all_objects.x3d
- --md5=f5f9fa4c5619a0eeab66685aafd2f7f0 --md5_method=FILE
-)
-
-
-
-# 3DS Import
-add_test(import_3ds_cube ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/cube.3ds'\)
- --md5=cb5a45c35a343c3f5beca2a918472951 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_3ds_cube.blend
-)
-
-add_test(import_3ds_hierarchy_lara ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/hierarchy_lara.3ds'\)
- --md5=766c873d9fdb5f190e43796cfbae63b6 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_3ds_hierarchy_lara.blend
-)
-
-add_test(import_3ds_hierarchy_greek_trireme ${TEST_BLENDER_EXE}
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.import_scene.autodesk_3ds\(filepath='${TEST_SRC_DIR}/io_tests/3ds/hierarchy_greek_trireme.3ds'\)
- --md5=b62ee30101e8999cb91ef4f8a8760056 --md5_method=SCENE
- --write-blend=${TEST_OUT_DIR}/import_3ds_hierarchy_greek_trireme.blend
-)
-
-# 3DS Export
-add_test(export_3ds_cube ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_cube.3ds',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_3ds_cube.3ds
- --md5=a31f5071b6c6dc7445b9099cdc7f63b3 --md5_method=FILE
-)
-
-add_test(export_3ds_nurbs ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_nurbs.3ds',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_3ds_nurbs.3ds
- --md5=5bdd21be3c80d814fbc83cb25edb08c2 --md5_method=FILE
-)
-
-add_test(export_3ds_all_objects ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.autodesk_3ds\(filepath='${TEST_OUT_DIR}/export_3ds_all_objects.3ds',use_selection=False\)
- --md5_source=${TEST_OUT_DIR}/export_3ds_all_objects.3ds
- --md5=68447761ab0ca38e1e22e7c177ed48a8 --md5_method=FILE
-)
-
-
-
-# FBX Export
-# 'use_metadata=False' for reliable md5's
-add_test(export_fbx_cube ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/all_quads.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_cube.fbx',use_selection=False,use_metadata=False\)
- --md5_source=${TEST_OUT_DIR}/export_fbx_cube.fbx
- --md5=59a35577462f95f9a0b4e6035226ce9b --md5_method=FILE
-)
-
-add_test(export_fbx_nurbs ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_geometry/nurbs.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_nurbs.fbx',use_selection=False,use_metadata=False\)
- --md5_source=${TEST_OUT_DIR}/export_fbx_nurbs.fbx
- --md5=d31875f18f613fa0c3b16e978f87f6f8 --md5_method=FILE
-)
-
-add_test(export_fbx_all_objects ${TEST_BLENDER_EXE}
- ${TEST_SRC_DIR}/io_tests/blend_scene/all_objects.blend
- --python ${CMAKE_CURRENT_LIST_DIR}/bl_test.py --
- --run={'FINISHED'}&bpy.ops.export_scene.fbx\(filepath='${TEST_OUT_DIR}/export_fbx_all_objects.fbx',use_selection=False,use_metadata=False\)
- --md5_source=${TEST_OUT_DIR}/export_fbx_all_objects.fbx
- --md5=b35eb2a9d0e73762ecae2278c25a38ac --md5_method=FILE
-)
diff --git a/source/tests/batch_import.py b/source/tests/batch_import.py
deleted file mode 100644
index a2c5fb59055..00000000000
--- a/source/tests/batch_import.py
+++ /dev/null
@@ -1,201 +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 #####
-
-# <pep8 compliant>
-
-"""
-Example Usage:
-
-./blender.bin --background --python source/tests/batch_import.py -- \
- --operator="bpy.ops.import_scene.obj" \
- --path="/fe/obj" \
- --match="*.obj" \
- --start=0 --end=10 \
- --save_path=/tmp/test
-
-./blender.bin --background --python source/tests/batch_import.py -- \
- --operator="bpy.ops.import_scene.autodesk_3ds" \
- --path="/fe/" \
- --match="*.3ds" \
- --start=0 --end=1000 \
- --save_path=/tmp/test
-
-./blender.bin --background --addons io_curve_svg --python source/tests/batch_import.py -- \
- --operator="bpy.ops.import_curve.svg" \
- --path="/usr/" \
- --match="*.svg" \
- --start=0 --end=1000 \
- --save_path=/tmp/test
-
-"""
-
-import os
-import sys
-
-
-def clear_scene():
- import bpy
- unique_obs = set()
- for scene in bpy.data.scenes:
- for obj in scene.objects[:]:
- scene.objects.unlink(obj)
- unique_obs.add(obj)
-
- # remove obdata, for now only worry about the startup scene
- for bpy_data_iter in (bpy.data.objects, bpy.data.meshes, bpy.data.lamps, bpy.data.cameras):
- for id_data in bpy_data_iter:
- bpy_data_iter.remove(id_data)
-
-
-def batch_import(operator="",
- path="",
- save_path="",
- match="",
- start=0,
- end=sys.maxsize,
- ):
- import addon_utils
- _reset_all = addon_utils.reset_all # XXX, hack
-
- import fnmatch
-
- path = os.path.normpath(path)
- path = os.path.abspath(path)
-
- match_upper = match.upper()
- pattern_match = lambda a: fnmatch.fnmatchcase(a.upper(), match_upper)
-
- def file_generator(path):
- for dirpath, dirnames, filenames in os.walk(path):
-
- # skip '.svn'
- if dirpath.startswith("."):
- continue
-
- for filename in filenames:
- if pattern_match(filename):
- yield os.path.join(dirpath, filename)
-
- print("Collecting %r files in %s" % (match, path), end="")
-
- files = list(file_generator(path))
- files_len = len(files)
- end = min(end, len(files))
- print(" found %d" % files_len, end="")
-
- files.sort()
- files = files[start:end]
- if len(files) != files_len:
- print(" using a subset in (%d, %d), total %d" % (start, end, len(files)), end="")
-
- import bpy
- op = eval(operator)
-
- tot_done = 0
- tot_fail = 0
-
- for i, f in enumerate(files):
- print(" %s(filepath=%r) # %d of %d" % (operator, f, i + start, len(files)))
-
- # hack so loading the new file doesn't undo our loaded addons
- addon_utils.reset_all = lambda: None # XXX, hack
-
- bpy.ops.wm.read_factory_settings()
-
- addon_utils.reset_all = _reset_all # XXX, hack
- clear_scene()
-
- result = op(filepath=f)
-
- if 'FINISHED' in result:
- tot_done += 1
- else:
- tot_fail += 1
-
- if save_path:
- fout = os.path.join(save_path, os.path.relpath(f, path))
- fout_blend = os.path.splitext(fout)[0] + ".blend"
-
- print("\tSaving: %r" % fout_blend)
-
- fout_dir = os.path.dirname(fout_blend)
- os.makedirs(fout_dir, exist_ok=True)
-
- bpy.ops.wm.save_as_mainfile(filepath=fout_blend)
-
- print("finished, done:%d, fail:%d" % (tot_done, tot_fail))
-
-
-def main():
- import optparse
-
- # get the args passed to blender after "--", all of which are ignored by blender specifically
- # so python may receive its own arguments
- argv = sys.argv
-
- if "--" not in argv:
- argv = [] # as if no args are passed
- else:
- argv = argv[argv.index("--") + 1:] # get all args after "--"
-
- # When --help or no args are given, print this help
- usage_text = "Run blender in background mode with this script:"
- usage_text += " blender --background --python " + __file__ + " -- [options]"
-
- parser = optparse.OptionParser(usage=usage_text)
-
- # Example background utility, add some text and renders or saves it (with options)
- # Possible types are: string, int, long, choice, float and complex.
- parser.add_option("-o", "--operator", dest="operator", help="This text will be used to render an image", type="string")
- parser.add_option("-p", "--path", dest="path", help="Path to use for searching for files", type='string')
- parser.add_option("-m", "--match", dest="match", help="Wildcard to match filename", type="string")
- parser.add_option("-s", "--save_path", dest="save_path", help="Save the input file to a blend file in a new location", metavar='string')
- parser.add_option("-S", "--start", dest="start", help="From collected files, start with this index", metavar='int')
- parser.add_option("-E", "--end", dest="end", help="From collected files, end with this index", metavar='int')
-
- options, args = parser.parse_args(argv) # In this example we wont use the args
-
- if not argv:
- parser.print_help()
- return
-
- if not options.operator:
- print("Error: --operator=\"some string\" argument not given, aborting.")
- parser.print_help()
- return
-
- if options.start is None:
- options.start = 0
-
- if options.end is None:
- options.end = sys.maxsize
-
- # Run the example function
- batch_import(operator=options.operator,
- path=options.path,
- save_path=options.save_path,
- match=options.match,
- start=int(options.start),
- end=int(options.end),
- )
-
- print("batch job finished, exiting")
-
-
-if __name__ == "__main__":
- main()
diff --git a/source/tests/bl_keymap_completeness.py b/source/tests/bl_keymap_completeness.py
deleted file mode 100644
index 00322907f69..00000000000
--- a/source/tests/bl_keymap_completeness.py
+++ /dev/null
@@ -1,84 +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 #####
-
-# <pep8 compliant>
-
-# simple script to test 'keyconfig_utils' contains correct values.
-
-
-from bpy_extras import keyconfig_utils
-
-
-def check_maps():
- maps = {}
-
- def fill_maps(ls):
- for km_name, km_space_type, km_region_type, km_sub in ls:
- maps[km_name] = (km_space_type, km_region_type)
- fill_maps(km_sub)
-
- fill_maps(keyconfig_utils.KM_HIERARCHY)
-
- import bpy
- keyconf = bpy.context.window_manager.keyconfigs.active
- maps_bl = set(keyconf.keymaps.keys())
- maps_py = set(maps.keys())
-
- err = False
- # Check keyconfig contains only maps that exist in blender
- test = maps_py - maps_bl
- if test:
- print("Keymaps that are in 'keyconfig_utils' but not blender")
- for km_id in sorted(test):
- print("\t%s" % km_id)
- err = True
-
- test = maps_bl - maps_py
- if test:
- print("Keymaps that are in blender but not in 'keyconfig_utils'")
- for km_id in sorted(test):
- km = keyconf.keymaps[km_id]
- print(" ('%s', '%s', '%s', [])," % (km_id, km.space_type, km.region_type))
- err = True
-
- # Check space/region's are OK
- print("Comparing keymap space/region types...")
- for km_id, km in keyconf.keymaps.items():
- km_py = maps.get(km_id)
- if km_py is not None:
- km_space_type, km_region_type = km_py
- if km_space_type != km.space_type or km_region_type != km.region_type:
- print(" Error:")
- print(" expected -- ('%s', '%s', '%s', [])," % (km_id, km.space_type, km.region_type))
- print(" got -- ('%s', '%s', '%s', [])," % (km_id, km_space_type, km_region_type))
- print("done!")
-
- return err
-
-
-def main():
- err = check_maps()
-
- import bpy
- if err and bpy.app.background:
- # alert CTest we failed
- import sys
- sys.exit(1)
-
-if __name__ == "__main__":
- main()
diff --git a/source/tests/bl_load_addons.py b/source/tests/bl_load_addons.py
deleted file mode 100644
index f04ae64ee73..00000000000
--- a/source/tests/bl_load_addons.py
+++ /dev/null
@@ -1,111 +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 #####
-
-# <pep8 compliant>
-
-# simple script to enable all addons, and disable
-
-import bpy
-import addon_utils
-
-import sys
-import imp
-
-
-def disable_addons():
- # first disable all
- addons = bpy.context.user_preferences.addons
- for mod_name in list(addons.keys()):
- addon_utils.disable(mod_name)
- assert(bool(addons) is False)
-
-
-def test_load_addons():
- modules = addon_utils.modules({})
- modules.sort(key=lambda mod: mod.__name__)
-
- disable_addons()
-
- addons = bpy.context.user_preferences.addons
-
- addons_fail = []
-
- for mod in modules:
- mod_name = mod.__name__
- print("\tenabling:", mod_name)
- addon_utils.enable(mod_name)
- if mod_name not in addons:
- addons_fail.append(mod_name)
-
- if addons_fail:
- print("addons failed to load (%d):" % len(addons_fail))
- for mod_name in addons_fail:
- print(" %s" % mod_name)
- else:
- print("addons all loaded without errors!")
- print("")
-
-
-def reload_addons(do_reload=True, do_reverse=True):
- modules = addon_utils.modules({})
- modules.sort(key=lambda mod: mod.__name__)
- addons = bpy.context.user_preferences.addons
-
- disable_addons()
-
- # Run twice each time.
- for i in (0, 1):
- for mod in modules:
- mod_name = mod.__name__
- print("\tenabling:", mod_name)
- addon_utils.enable(mod_name)
- assert(mod_name in addons)
-
- for mod in addon_utils.modules({}):
- mod_name = mod.__name__
- print("\tdisabling:", mod_name)
- addon_utils.disable(mod_name)
- assert(not (mod_name in addons))
-
- # now test reloading
- if do_reload:
- imp.reload(sys.modules[mod_name])
-
- if do_reverse:
- # in case order matters when it shouldn't
- modules.reverse()
-
-
-def main():
- # first load addons, print a list of all addons that fail
- test_load_addons()
-
- reload_addons(do_reload=False, do_reverse=False)
- reload_addons(do_reload=False, do_reverse=True)
- reload_addons(do_reload=True, do_reverse=True)
-
-
-if __name__ == "__main__":
-
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
diff --git a/source/tests/bl_load_py_modules.py b/source/tests/bl_load_py_modules.py
deleted file mode 100644
index 9677397e01d..00000000000
--- a/source/tests/bl_load_py_modules.py
+++ /dev/null
@@ -1,167 +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 #####
-
-# <pep8 compliant>
-
-# simple script to enable all addons, and disable
-
-import bpy
-import addon_utils
-
-import sys
-import os
-
-BLACKLIST = {
- "bl_i18n_utils",
- "cycles",
- "io_export_dxf", # TODO, check on why this fails
- }
-
-
-def source_list(path, filename_check=None):
- from os.path import join
- for dirpath, dirnames, filenames in os.walk(path):
- # skip '.svn'
- if dirpath.startswith("."):
- continue
-
- for filename in filenames:
- filepath = join(dirpath, filename)
- if filename_check is None or filename_check(filepath):
- yield filepath
-
-
-def load_addons():
- modules = addon_utils.modules({})
- modules.sort(key=lambda mod: mod.__name__)
- addons = bpy.context.user_preferences.addons
-
- # first disable all
- for mod_name in list(addons.keys()):
- addon_utils.disable(mod_name)
-
- assert(bool(addons) is False)
-
- for mod in modules:
- mod_name = mod.__name__
- addon_utils.enable(mod_name)
- assert(mod_name in addons)
-
-
-def load_modules():
- modules = []
- module_paths = []
-
- # paths blender stores scripts in.
- paths = bpy.utils.script_paths()
-
- print("Paths:")
- for script_path in paths:
- print("\t'%s'" % script_path)
-
- #
- # find all sys.path we added
- for script_path in paths:
- for mod_dir in sys.path:
- if mod_dir.startswith(script_path):
- if mod_dir not in module_paths:
- if os.path.exists(mod_dir):
- module_paths.append(mod_dir)
-
- #
- # collect modules from our paths.
- module_names = {}
- for mod_dir in module_paths:
- # print("mod_dir", mod_dir)
- for mod, mod_full in bpy.path.module_names(mod_dir):
- if mod in BLACKLIST:
- continue
- if mod in module_names:
- mod_dir_prev, mod_full_prev = module_names[mod]
- raise Exception("Module found twice %r.\n (%r -> %r, %r -> %r)" %
- (mod, mod_dir, mod_full, mod_dir_prev, mod_full_prev))
-
- modules.append(__import__(mod))
-
- module_names[mod] = mod_dir, mod_full
- del module_names
-
- #
- # now submodules
- for m in modules:
- filepath = m.__file__
- if os.path.basename(filepath).startswith("__init__."):
- mod_dir = os.path.dirname(filepath)
- for submod, submod_full in bpy.path.module_names(mod_dir):
- # fromlist is ignored, ugh.
- mod_name_full = m.__name__ + "." + submod
- __import__(mod_name_full)
- mod_imp = sys.modules[mod_name_full]
-
- # check we load what we ask for.
- assert(os.path.samefile(mod_imp.__file__, submod_full))
-
- modules.append(mod_imp)
-
- #
- # check which filepaths we didn't load
- source_files = []
- for mod_dir in module_paths:
- source_files.extend(source_list(mod_dir, filename_check=lambda f: f.endswith(".py")))
-
- source_files = list(set(source_files))
- source_files.sort()
-
- #
- # remove loaded files
- loaded_files = list({m.__file__ for m in modules})
- loaded_files.sort()
-
- for f in loaded_files:
- source_files.remove(f)
-
- #
- # test we tested all files except for presets and templates
- ignore_paths = [
- os.sep + "presets" + os.sep,
- os.sep + "templates" + os.sep,
- ] + [(os.sep + f + os.sep) for f in BLACKLIST]
-
- for f in source_files:
- ok = False
- for ignore in ignore_paths:
- if ignore in f:
- ok = True
- if not ok:
- raise Exception("Source file %r not loaded in test" % f)
-
- print("loaded %d modules" % len(loaded_files))
-
-
-def main():
- load_addons()
- load_modules()
-
-if __name__ == "__main__":
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
diff --git a/source/tests/bl_mesh_modifiers.py b/source/tests/bl_mesh_modifiers.py
deleted file mode 100644
index 2f342f2c65e..00000000000
--- a/source/tests/bl_mesh_modifiers.py
+++ /dev/null
@@ -1,866 +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 #####
-
-# <pep8 compliant>
-
-# Currently this script only generates images from different modifier
-# combinations and does not validate they work correctly,
-# this is because we don't get 1:1 match with bmesh.
-#
-# Later, we may have a way to check the results are valid.
-
-
-# ./blender.bin --factory-startup --python source/tests/bl_mesh_modifiers.py
-#
-
-import math
-
-USE_QUICK_RENDER = False
-IS_BMESH = hasattr(__import__("bpy").types, "LoopColors")
-
-# -----------------------------------------------------------------------------
-# utility functions
-
-
-def render_gl(context, filepath, shade):
-
- def ctx_viewport_shade(context, shade):
- for area in context.window.screen.areas:
- if area.type == 'VIEW_3D':
- space = area.spaces.active
- # rv3d = space.region_3d
- space.viewport_shade = shade
-
- import bpy
- scene = context.scene
- render = scene.render
- render.filepath = filepath
- render.image_settings.file_format = 'PNG'
- render.image_settings.color_mode = 'RGB'
- render.use_file_extension = True
- render.use_antialiasing = False
-
- # render size
- render.resolution_percentage = 100
- render.resolution_x = 512
- render.resolution_y = 512
-
- ctx_viewport_shade(context, shade)
-
- #~ # stop to inspect!
- #~ if filepath == "test_cube_shell_solidify_subsurf_wp_wire":
- #~ assert(0)
- #~ else:
- #~ return
-
- bpy.ops.render.opengl(write_still=True,
- view_context=True)
-
-
-def render_gl_all_modes(context, obj, filepath=""):
-
- assert(obj is not None)
- assert(filepath != "")
-
- scene = context.scene
-
- # avoid drawing outline/center dot
- bpy.ops.object.select_all(action='DESELECT')
- scene.objects.active = None
-
- # editmode
- scene.tool_settings.mesh_select_mode = False, True, False
-
- # render
- render_gl(context, filepath + "_ob_solid", shade='SOLID')
-
- if USE_QUICK_RENDER:
- return
-
- render_gl(context, filepath + "_ob_wire", shade='WIREFRAME')
- render_gl(context, filepath + "_ob_textured", shade='TEXTURED')
-
- # -------------------------------------------------------------------------
- # not just draw modes, but object modes!
- scene.objects.active = obj
-
- bpy.ops.object.mode_set(mode='EDIT', toggle=False)
- bpy.ops.mesh.select_all(action='DESELECT')
- render_gl(context, filepath + "_edit_wire", shade='WIREFRAME')
- render_gl(context, filepath + "_edit_solid", shade='SOLID')
- render_gl(context, filepath + "_edit_textured", shade='TEXTURED')
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
-
- bpy.ops.object.mode_set(mode='WEIGHT_PAINT', toggle=False)
-
- render_gl(context, filepath + "_wp_wire", shade='WIREFRAME')
-
- assert(1)
-
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
-
- scene.objects.active = None
-
-
-def ctx_clear_scene(): # copied from batch_import.py
- import bpy
- unique_obs = set()
- for scene in bpy.data.scenes:
- for obj in scene.objects[:]:
- scene.objects.unlink(obj)
- unique_obs.add(obj)
-
- # remove obdata, for now only worry about the startup scene
- for bpy_data_iter in (bpy.data.objects,
- bpy.data.meshes,
- bpy.data.lamps,
- bpy.data.cameras,
- ):
-
- for id_data in bpy_data_iter:
- bpy_data_iter.remove(id_data)
-
-
-def ctx_viewport_camera(context):
- # because gl render without view_context has no shading option.
- for area in context.window.screen.areas:
- if area.type == 'VIEW_3D':
- space = area.spaces.active
- space.region_3d.view_perspective = 'CAMERA'
-
-
-def ctx_camera_setup(context,
- location=(0.0, 0.0, 0.0),
- lookat=(0.0, 0.0, 0.0),
- # most likely the following vars can be left as defaults
- up=(0.0, 0.0, 1.0),
- lookat_axis='-Z',
- up_axis='Y',
- ):
-
- camera = bpy.data.cameras.new(whoami())
- obj = bpy.data.objects.new(whoami(), camera)
-
- scene = context.scene
- scene.objects.link(obj)
- scene.camera = obj
-
- from mathutils import Vector, Matrix
-
- # setup transform
- view_vec = Vector(lookat) - Vector(location)
- rot_mat = view_vec.to_track_quat(lookat_axis, up_axis).to_matrix().to_4x4()
- tra_mat = Matrix.Translation(location)
-
- obj.matrix_world = tra_mat * rot_mat
-
- ctx_viewport_camera(context)
-
- return obj
-
-
-# -----------------------------------------------------------------------------
-# inspect functions
-
-import inspect
-
-
-# functions
-
-def whoami():
- return inspect.stack()[1][3]
-
-
-def whosdaddy():
- return inspect.stack()[2][3]
-
-
-# -----------------------------------------------------------------------------
-# models (defaults)
-
-def defaults_object(obj):
- obj.show_wire = True
-
- if obj.type == 'MESH':
- mesh = obj.data
- mesh.show_all_edges = True
-
- mesh.show_normal_vertex = True
-
- # lame!
- if IS_BMESH:
- for poly in mesh.polygons:
- poly.use_smooth = True
- else:
- for face in mesh.faces:
- face.use_smooth = True
-
-
-def defaults_modifier(mod):
- mod.show_in_editmode = True
- mod.show_on_cage = True
-
-
-# -----------------------------------------------------------------------------
-# models (utils)
-
-
-if IS_BMESH:
- def mesh_bmesh_poly_elems(poly, elems):
- vert_start = poly.loop_start
- vert_total = poly.loop_total
- return elems[vert_start:vert_start + vert_total]
-
- def mesh_bmesh_poly_vertices(poly):
- return [loop.vertex_index
- for loop in mesh_bmesh_poly_elems(poly, poly.id_data.loops)]
-
-
-def mesh_bounds(mesh):
- xmin = ymin = zmin = +100000000.0
- xmax = ymax = zmax = -100000000.0
-
- for v in mesh.vertices:
- x, y, z = v.co
- xmax = max(x, xmax)
- ymax = max(y, ymax)
- zmax = max(z, zmax)
-
- xmin = min(x, xmin)
- ymin = min(y, ymin)
- zmin = min(z, zmin)
-
- return (xmin, ymin, zmin), (xmax, ymax, zmax)
-
-
-def mesh_uv_add(obj):
-
- uvs = ((0.0, 0.0),
- (0.0, 1.0),
- (1.0, 1.0),
- (1.0, 0.0))
-
- uv_lay = obj.data.uv_textures.new()
-
- if IS_BMESH:
- # XXX, odd that we need to do this. until UV's and texface
- # are separated we will need to keep it
- uv_loops = obj.data.uv_layers[-1]
- uv_list = uv_loops.data[:]
- for poly in obj.data.polygons:
- poly_uvs = mesh_bmesh_poly_elems(poly, uv_list)
- for i, c in enumerate(poly_uvs):
- c.uv = uvs[i % 4]
- else:
- for uv in uv_lay.data:
- uv.uv1 = uvs[0]
- uv.uv2 = uvs[1]
- uv.uv3 = uvs[2]
- uv.uv4 = uvs[3]
-
- return uv_lay
-
-
-def mesh_vcol_add(obj, mode=0):
-
- colors = ((0.0, 0.0, 0.0), # black
- (1.0, 0.0, 0.0), # red
- (0.0, 1.0, 0.0), # green
- (0.0, 0.0, 1.0), # blue
- (1.0, 1.0, 0.0), # yellow
- (0.0, 1.0, 1.0), # cyan
- (1.0, 0.0, 1.0), # magenta
- (1.0, 1.0, 1.0), # white
- )
-
- def colors_get(i):
- return colors[i % len(colors)]
-
- vcol_lay = obj.data.vertex_colors.new()
-
- mesh = obj.data
-
- if IS_BMESH:
- col_list = vcol_lay.data[:]
- for poly in mesh.polygons:
- face_verts = mesh_bmesh_poly_vertices(poly)
- poly_cols = mesh_bmesh_poly_elems(poly, col_list)
- for i, c in enumerate(poly_cols):
- c.color = colors_get(face_verts[i])
- else:
- for i, col in enumerate(vcol_lay.data):
- face_verts = mesh.faces[i].vertices
- col.color1 = colors_get(face_verts[0])
- col.color2 = colors_get(face_verts[1])
- col.color3 = colors_get(face_verts[2])
- if len(face_verts) == 4:
- col.color4 = colors_get(face_verts[3])
-
- return vcol_lay
-
-
-def mesh_vgroup_add(obj, name="Group", axis=0, invert=False, mode=0):
- mesh = obj.data
- vgroup = obj.vertex_groups.new(name=name)
- vgroup.add(list(range(len(mesh.vertices))), 1.0, 'REPLACE')
- group_index = len(obj.vertex_groups) - 1
-
- min_bb, max_bb = mesh_bounds(mesh)
-
- range_axis = max_bb[axis] - min_bb[axis]
-
- # gradient
- for v in mesh.vertices:
- for vg in v.groups:
- if vg.group == group_index:
- f = (v.co[axis] - min_bb[axis]) / range_axis
- vg.weight = 1.0 - f if invert else f
-
- return vgroup
-
-
-def mesh_shape_add(obj, mode=0):
- pass
-
-
-def mesh_armature_add(obj, mode=0):
- pass
-
-
-# -----------------------------------------------------------------------------
-# modifiers
-
-def modifier_subsurf_add(scene, obj, levels=2):
- mod = obj.modifiers.new(name=whoami(), type='SUBSURF')
- defaults_modifier(mod)
-
- mod.levels = levels
- mod.render_levels = levels
- return mod
-
-
-def modifier_armature_add(scene, obj):
- mod = obj.modifiers.new(name=whoami(), type='ARMATURE')
- defaults_modifier(mod)
-
- arm_data = bpy.data.armatures.new(whoami())
- obj_arm = bpy.data.objects.new(whoami(), arm_data)
-
- scene.objects.link(obj_arm)
-
- obj_arm.select = True
- scene.objects.active = obj_arm
-
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
- bpy.ops.object.mode_set(mode='EDIT', toggle=False)
-
- # XXX, annoying, remove bone.
- while arm_data.edit_bones:
- obj_arm.edit_bones.remove(arm_data.edit_bones[-1])
-
- bone_a = arm_data.edit_bones.new("Bone.A")
- bone_b = arm_data.edit_bones.new("Bone.B")
- bone_b.parent = bone_a
-
- bone_a.head = -1, 0, 0
- bone_a.tail = 0, 0, 0
- bone_b.head = 0, 0, 0
- bone_b.tail = 1, 0, 0
-
- # Get armature animation data
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
-
- # 45d armature
- obj_arm.pose.bones["Bone.B"].rotation_quaternion = 1, -0.5, 0, 0
-
- # set back to the original
- scene.objects.active = obj
-
- # display options
- obj_arm.show_x_ray = True
- arm_data.draw_type = 'STICK'
-
- # apply to modifier
- mod.object = obj_arm
-
- mesh_vgroup_add(obj, name="Bone.A", axis=0, invert=True)
- mesh_vgroup_add(obj, name="Bone.B", axis=0, invert=False)
-
- return mod
-
-
-def modifier_mirror_add(scene, obj):
- mod = obj.modifiers.new(name=whoami(), type='MIRROR')
- defaults_modifier(mod)
-
- return mod
-
-
-def modifier_solidify_add(scene, obj, thickness=0.25):
- mod = obj.modifiers.new(name=whoami(), type='SOLIDIFY')
- defaults_modifier(mod)
-
- mod.thickness = thickness
-
- return mod
-
-
-def modifier_hook_add(scene, obj, use_vgroup=True):
- scene.objects.active = obj
-
- # no nice way to add hooks from py api yet
- # assume object mode, hook first face!
- mesh = obj.data
-
- if use_vgroup:
- for v in mesh.vertices:
- v.select = True
- else:
- for v in mesh.vertices:
- v.select = False
-
- if IS_BMESH:
- face_verts = mesh_bmesh_poly_vertices(mesh.polygons[0])
- else:
- face_verts = mesh.faces[0].vertices[:]
-
- for i in mesh.faces[0].vertices:
- mesh.vertices[i].select = True
-
- bpy.ops.object.mode_set(mode='EDIT', toggle=False)
- bpy.ops.object.hook_add_newob()
- bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
-
- # mod = obj.modifiers.new(name=whoami(), type='HOOK')
- mod = obj.modifiers[-1]
- defaults_modifier(mod)
-
- obj_hook = mod.object
- obj_hook.rotation_euler = 0, math.radians(45), 0
- obj_hook.show_x_ray = True
-
- if use_vgroup:
- mod.vertex_group = obj.vertex_groups[0].name
-
- return mod
-
-
-def modifier_decimate_add(scene, obj):
- mod = obj.modifiers.new(name=whoami(), type='DECIMATE')
- defaults_modifier(mod)
-
- mod.ratio = 1 / 3
-
- return mod
-
-
-def modifier_build_add(scene, obj):
- mod = obj.modifiers.new(name=whoami(), type='BUILD')
- defaults_modifier(mod)
-
- # ensure we display some faces
- if IS_BMESH:
- totface = len(obj.data.polygons)
- else:
- totface = len(obj.data.faces)
-
- mod.frame_start = totface // 2
- mod.frame_duration = totface
-
- return mod
-
-
-def modifier_mask_add(scene, obj):
- mod = obj.modifiers.new(name=whoami(), type='MASK')
- defaults_modifier(mod)
-
- mod.vertex_group = obj.vertex_groups[0].name
-
- return mod
-
-
-# -----------------------------------------------------------------------------
-# models
-
-# useful since its solid boxy shape but simple enough to debug errors
-cube_like_vertices = (
- (1, 1, -1),
- (1, -1, -1),
- (-1, -1, -1),
- (-1, 1, -1),
- (1, 1, 1),
- (1, -1, 1),
- (-1, -1, 1),
- (-1, 1, 1),
- (0, -1, -1),
- (1, 0, -1),
- (0, 1, -1),
- (-1, 0, -1),
- (1, 0, 1),
- (0, -1, 1),
- (-1, 0, 1),
- (0, 1, 1),
- (1, -1, 0),
- (1, 1, 0),
- (-1, -1, 0),
- (-1, 1, 0),
- (0, 0, -1),
- (0, 0, 1),
- (1, 0, 0),
- (0, -1, 0),
- (-1, 0, 0),
- (2, 0, 0),
- (2, 0, -1),
- (2, 1, 0),
- (2, 1, -1),
- (0, 1, 2),
- (0, 0, 2),
- (-1, 0, 2),
- (-1, 1, 2),
- (-1, 0, 3),
- (-1, 1, 3),
- (0, 1, 3),
- (0, 0, 3),
- )
-
-
-cube_like_faces = (
- (0, 9, 20, 10),
- (0, 10, 17),
- (0, 17, 27, 28),
- (1, 16, 23, 8),
- (2, 18, 24, 11),
- (3, 19, 10),
- (4, 15, 21, 12),
- (4, 17, 15),
- (7, 14, 31, 32),
- (7, 15, 19),
- (8, 23, 18, 2),
- (9, 0, 28, 26),
- (9, 1, 8, 20),
- (9, 22, 16, 1),
- (10, 20, 11, 3),
- (11, 24, 19, 3),
- (12, 21, 13, 5),
- (13, 6, 18),
- (14, 21, 30, 31),
- (15, 7, 32, 29),
- (15, 17, 10, 19),
- (16, 5, 13, 23),
- (17, 4, 12, 22),
- (17, 22, 25, 27),
- (18, 6, 14, 24),
- (20, 8, 2, 11),
- (21, 14, 6, 13),
- (21, 15, 29, 30),
- (22, 9, 26, 25),
- (22, 12, 5, 16),
- (23, 13, 18),
- (24, 14, 7, 19),
- (28, 27, 25, 26),
- (29, 32, 34, 35),
- (30, 29, 35, 36),
- (31, 30, 36, 33),
- (32, 31, 33, 34),
- (35, 34, 33, 36),
- )
-
-
-# useful since its a shell for solidify and it can be mirrored
-cube_shell_vertices = (
- (0, 0, 1),
- (0, 1, 1),
- (-1, 1, 1),
- (-1, 0, 1),
- (0, 0, 0),
- (0, 1, 0),
- (-1, 1, 0),
- (-1, 0, 0),
- (-1, -1, 0),
- (0, -1, 0),
- (0, 0, -1),
- (0, 1, -1),
- )
-
-
-cube_shell_face = (
- (0, 1, 2, 3),
- (0, 3, 8, 9),
- (1, 5, 6, 2),
- (2, 6, 7, 3),
- (3, 7, 8),
- (4, 7, 10),
- (6, 5, 11),
- (7, 4, 9, 8),
- (10, 7, 6, 11),
- )
-
-
-def make_cube(scene):
- bpy.ops.mesh.primitive_cube_add(view_align=False,
- enter_editmode=False,
- location=(0, 0, 0),
- rotation=(0, 0, 0),
- )
-
- obj = scene.objects.active
-
- defaults_object(obj)
- return obj
-
-
-def make_cube_extra(scene):
- obj = make_cube(scene)
-
- # extra data layers
- mesh_uv_add(obj)
- mesh_vcol_add(obj)
- mesh_vgroup_add(obj)
-
- return obj
-
-
-def make_cube_like(scene):
- mesh = bpy.data.meshes.new(whoami())
-
- mesh.from_pydata(cube_like_vertices, (), cube_like_faces)
- mesh.update() # add edges
- obj = bpy.data.objects.new(whoami(), mesh)
- scene.objects.link(obj)
-
- defaults_object(obj)
- return obj
-
-
-def make_cube_like_extra(scene):
- obj = make_cube_like(scene)
-
- # extra data layers
- mesh_uv_add(obj)
- mesh_vcol_add(obj)
- mesh_vgroup_add(obj)
-
- return obj
-
-
-def make_cube_shell(scene):
- mesh = bpy.data.meshes.new(whoami())
-
- mesh.from_pydata(cube_shell_vertices, (), cube_shell_face)
- mesh.update() # add edges
- obj = bpy.data.objects.new(whoami(), mesh)
- scene.objects.link(obj)
-
- defaults_object(obj)
- return obj
-
-
-def make_cube_shell_extra(scene):
- obj = make_cube_shell(scene)
-
- # extra data layers
- mesh_uv_add(obj)
- mesh_vcol_add(obj)
- mesh_vgroup_add(obj)
-
- return obj
-
-
-def make_monkey(scene):
- bpy.ops.mesh.primitive_monkey_add(view_align=False,
- enter_editmode=False,
- location=(0, 0, 0),
- rotation=(0, 0, 0),
- )
- obj = scene.objects.active
-
- defaults_object(obj)
- return obj
-
-
-def make_monkey_extra(scene):
- obj = make_monkey(scene)
-
- # extra data layers
- mesh_uv_add(obj)
- mesh_vcol_add(obj)
- mesh_vgroup_add(obj)
-
- return obj
-
-
-# -----------------------------------------------------------------------------
-# tests (utils)
-
-global_tests = []
-
-global_tests.append(("none",
- (),
- ))
-
-# single
-global_tests.append(("subsurf_single",
- ((modifier_subsurf_add, dict(levels=2)), ),
- ))
-
-
-global_tests.append(("armature_single",
- ((modifier_armature_add, dict()), ),
- ))
-
-
-global_tests.append(("mirror_single",
- ((modifier_mirror_add, dict()), ),
- ))
-
-global_tests.append(("hook_single",
- ((modifier_hook_add, dict()), ),
- ))
-
-global_tests.append(("decimate_single",
- ((modifier_decimate_add, dict()), ),
- ))
-
-global_tests.append(("build_single",
- ((modifier_build_add, dict()), ),
- ))
-
-global_tests.append(("mask_single",
- ((modifier_mask_add, dict()), ),
- ))
-
-
-# combinations
-global_tests.append(("mirror_subsurf",
- ((modifier_mirror_add, dict()),
- (modifier_subsurf_add, dict(levels=2))),
- ))
-
-global_tests.append(("solidify_subsurf",
- ((modifier_solidify_add, dict()),
- (modifier_subsurf_add, dict(levels=2))),
- ))
-
-
-def apply_test(test, scene, obj,
- render_func=None,
- render_args=None,
- render_kwargs=None,
- ):
-
- test_name, test_funcs = test
-
- for cb, kwargs in test_funcs:
- cb(scene, obj, **kwargs)
-
- render_kwargs_copy = render_kwargs.copy()
-
- # add test name in filepath
- render_kwargs_copy["filepath"] += "_%s" % test_name
-
- render_func(*render_args, **render_kwargs_copy)
-
-
-# -----------------------------------------------------------------------------
-# tests themselves!
-# having the 'test_' prefix automatically means these functions are called
-# for testing
-
-
-def test_cube(context, test):
- scene = context.scene
- obj = make_cube_extra(scene)
- ctx_camera_setup(context, location=(3, 3, 3))
-
- apply_test(test, scene, obj,
- render_func=render_gl_all_modes,
- render_args=(context, obj),
- render_kwargs=dict(filepath=whoami()))
-
-
-def test_cube_like(context, test):
- scene = context.scene
- obj = make_cube_like_extra(scene)
- ctx_camera_setup(context, location=(5, 5, 5))
-
- apply_test(test, scene, obj,
- render_func=render_gl_all_modes,
- render_args=(context, obj),
- render_kwargs=dict(filepath=whoami()))
-
-
-def test_cube_shell(context, test):
- scene = context.scene
- obj = make_cube_shell_extra(scene)
- ctx_camera_setup(context, location=(4, 4, 4))
-
- apply_test(test, scene, obj,
- render_func=render_gl_all_modes,
- render_args=(context, obj),
- render_kwargs=dict(filepath=whoami()))
-
-
-# -----------------------------------------------------------------------------
-# call all tests
-
-def main():
- print("Calling main!")
- #render_gl(bpy.context, "/testme")
- #ctx_clear_scene()
-
- context = bpy.context
-
- ctx_clear_scene()
-
- # run all tests
- for key, val in sorted(globals().items()):
- if key.startswith("test_") and hasattr(val, "__call__"):
- print("calling:", key)
- for t in global_tests:
- val(context, test=t)
- ctx_clear_scene()
-
-
-# -----------------------------------------------------------------------------
-# annoying workaround for theme initialization
-
-if __name__ == "__main__":
- import bpy
- from bpy.app.handlers import persistent
-
- @persistent
- def load_handler(dummy):
- print("Load Handler:", bpy.data.filepath)
- if load_handler.first is False:
- bpy.app.handlers.scene_update_post.remove(load_handler)
- try:
- main()
- import sys
- sys.exit(0)
- except:
- import traceback
- traceback.print_exc()
-
- import sys
- # sys.exit(1) # comment to debug
-
- else:
- load_handler.first = False
-
- load_handler.first = True
- bpy.app.handlers.scene_update_post.append(load_handler)
diff --git a/source/tests/bl_mesh_validate.py b/source/tests/bl_mesh_validate.py
deleted file mode 100644
index ac5be7d08d7..00000000000
--- a/source/tests/bl_mesh_validate.py
+++ /dev/null
@@ -1,161 +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 #####
-
-# <pep8 compliant>
-
-# Simple script to check mash validate code.
-# XXX Should be extended with many more "wrong cases"!
-
-import bpy
-
-import sys
-import random
-
-
-MESHES = {
- "test1": (
- (
- ( # Verts
- (-1.0, -1.0, 0.0),
- (-1.0, 0.0, 0.0),
- (-1.0, 1.0, 0.0),
- (0.0, -1.0, 0.0),
- (0.0, 0.0, 0.0),
- (0.0, 1.0, 0.0),
- (1.0, -1.0, 0.0),
- (1.0, 0.0, 0.0),
- (1.5, 0.5, 0.0),
- (1.0, 1.0, 0.0),
- ),
- ( # Edges
- ),
- ( # Loops
- 0, 1, 4, 3,
- 3, 4, 6,
- 1, 2, 5, 4,
- 3, 4, 6,
- 4, 7, 6,
- 4, 5, 9, 4, 8, 7,
- ),
- ( # Polygons
- (0, 4),
- (4, 3),
- (7, 4),
- (11, 3),
- (14, 3),
- (16, 6),
- ),
- ),
- ),
-}
-
-
-BUILTINS = (
- "primitive_plane_add",
- "primitive_cube_add",
- "primitive_circle_add",
- "primitive_uv_sphere_add",
- "primitive_ico_sphere_add",
- "primitive_cylinder_add",
- "primitive_cone_add",
- "primitive_grid_add",
- "primitive_monkey_add",
- "primitive_torus_add",
- )
-BUILTINS_NBR = 4
-BUILTINS_NBRCHANGES = 5
-
-
-def test_meshes():
- for m in MESHES["test1"]:
- bpy.ops.object.add(type="MESH")
- data = bpy.context.active_object.data
-
- # Vertices.
- data.vertices.add(len(m[0]))
- for idx, v in enumerate(m[0]):
- data.vertices[idx].co = v
- # Edges.
- data.edges.add(len(m[1]))
- for idx, e in enumerate(m[1]):
- data.edges[idx].vertices = e
- # Loops.
- data.loops.add(len(m[2]))
- for idx, v in enumerate(m[2]):
- data.loops[idx].vertex_index = v
- # Polygons.
- data.polygons.add(len(m[3]))
- for idx, l in enumerate(m[3]):
- data.polygons[idx].loop_start = l[0]
- data.polygons[idx].loop_total = l[1]
-
- while data.validate(verbose=True):
- pass
-
-
-def test_builtins():
- for x, func in enumerate(BUILTINS):
- for y in range(BUILTINS_NBR):
- getattr(bpy.ops.mesh, func)(location=(x * 2.5, y * 2.5, 0))
- data = bpy.context.active_object.data
- try:
- for n in range(BUILTINS_NBRCHANGES):
- rnd = random.randint(1, 3)
- if rnd == 1:
- # Make fun with some edge.
- e = random.randrange(0, len(data.edges))
- data.edges[e].vertices[random.randint(0, 1)] = \
- random.randrange(0, len(data.vertices) * 2)
- elif rnd == 2:
- # Make fun with some loop.
- l = random.randrange(0, len(data.loops))
- if random.randint(0, 1):
- data.loops[l].vertex_index = \
- random.randrange(0, len(data.vertices) * 2)
- else:
- data.loops[l].edge_index = \
- random.randrange(0, len(data.edges) * 2)
- elif rnd == 3:
- # Make fun with some polygons.
- p = random.randrange(0, len(data.polygons))
- if random.randint(0, 1):
- data.polygons[p].loop_start = \
- random.randrange(0, len(data.loops))
- else:
- data.polygons[p].loop_total = \
- random.randrange(0, 10)
- except:
- pass
-
- while data.validate(verbose=True):
- pass
-
-
-def main():
- test_builtins()
- test_meshes()
-
-
-if __name__ == "__main__":
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
diff --git a/source/tests/bl_pyapi_mathutils.py b/source/tests/bl_pyapi_mathutils.py
deleted file mode 100644
index c31244462cd..00000000000
--- a/source/tests/bl_pyapi_mathutils.py
+++ /dev/null
@@ -1,307 +0,0 @@
-# ./blender.bin --background -noaudio --python source/tests/bl_pyapi_mathutils.py
-import unittest
-from test import support
-from mathutils import Matrix, Vector
-from mathutils import kdtree
-import math
-
-# keep globals immutable
-vector_data = (
- (1.0, 0.0, 0.0),
- (0.0, 1.0, 0.0),
- (0.0, 0.0, 1.0),
-
- (1.0, 1.0, 1.0),
-
- (0.33783, 0.715698, -0.611206),
- (-0.944031, -0.326599, -0.045624),
- (-0.101074, -0.416443, -0.903503),
- (0.799286, 0.49411, -0.341949),
- (-0.854645, 0.518036, 0.033936),
- (0.42514, -0.437866, -0.792114),
- (-0.358948, 0.597046, 0.717377),
- (-0.985413,0.144714, 0.089294),
- )
-
-# get data at different scales
-vector_data = sum(
- (tuple(tuple(a * scale for a in v) for v in vector_data)
- for scale in (s * sign for s in (0.0001, 0.1, 1.0, 10.0, 1000.0, 100000.0)
- for sign in (1.0, -1.0))), ()) + ((0.0, 0.0, 0.0),)
-
-
-class MatrixTesting(unittest.TestCase):
- def test_matrix_column_access(self):
- #mat =
- #[ 1 2 3 4 ]
- #[ 1 2 3 4 ]
- #[ 1 2 3 4 ]
- mat = Matrix(((1, 11, 111),
- (2, 22, 222),
- (3, 33, 333),
- (4, 44, 444)))
-
- self.assertEqual(mat[0], Vector((1, 11, 111)))
- self.assertEqual(mat[1], Vector((2, 22, 222)))
- self.assertEqual(mat[2], Vector((3, 33, 333)))
- self.assertEqual(mat[3], Vector((4, 44, 444)))
-
- def test_item_access(self):
- args = ((1, 4, 0, -1),
- (2, -1, 2, -2),
- (0, 3, 8, 3),
- (-2, 9, 1, 0))
-
- mat = Matrix(args)
-
- for row in range(4):
- for col in range(4):
- self.assertEqual(mat[row][col], args[row][col])
-
- self.assertEqual(mat[0][2], 0)
- self.assertEqual(mat[3][1], 9)
- self.assertEqual(mat[2][3], 3)
- self.assertEqual(mat[0][0], 1)
- self.assertEqual(mat[3][3], 0)
-
- def test_item_assignment(self):
- mat = Matrix() - Matrix()
- indices = (0, 0), (1, 3), (2, 0), (3, 2), (3, 1)
- checked_indices = []
- for row, col in indices:
- mat[row][col] = 1
-
- for row in range(4):
- for col in range(4):
- if mat[row][col]:
- checked_indices.append((row, col))
-
- for item in checked_indices:
- self.assertIn(item, indices)
-
- def test_matrix_to_3x3(self):
- #mat =
- #[ 1 2 3 4 ]
- #[ 2 4 6 8 ]
- #[ 3 6 9 12 ]
- #[ 4 8 12 16 ]
- mat = Matrix(tuple((i, 2 * i, 3 * i, 4 * i) for i in range(1, 5)))
- mat_correct = Matrix(((1, 2, 3), (2, 4, 6), (3, 6, 9)))
- self.assertEqual(mat.to_3x3(), mat_correct)
-
- def test_matrix_to_translation(self):
- mat = Matrix()
- mat[0][3] = 1
- mat[1][3] = 2
- mat[2][3] = 3
- self.assertEqual(mat.to_translation(), Vector((1, 2, 3)))
-
- def test_matrix_translation(self):
- mat = Matrix()
- mat.translation = Vector((1, 2, 3))
- self.assertEqual(mat[0][3], 1)
- self.assertEqual(mat[1][3], 2)
- self.assertEqual(mat[2][3], 3)
-
- def test_non_square_mult(self):
- mat1 = Matrix(((1, 2, 3),
- (4, 5, 6)))
- mat2 = Matrix(((1, 2),
- (3, 4),
- (5, 6)))
-
- prod_mat1 = Matrix(((22, 28),
- (49, 64)))
- prod_mat2 = Matrix(((9, 12, 15),
- (19, 26, 33),
- (29, 40, 51)))
-
- self.assertEqual(mat1 * mat2, prod_mat1)
- self.assertEqual(mat2 * mat1, prod_mat2)
-
- def test_mat4x4_vec3D_mult(self):
- mat = Matrix(((1, 0, 2, 0),
- (0, 6, 0, 0),
- (0, 0, 1, 1),
- (0, 0, 0, 1)))
-
- vec = Vector((1, 2, 3))
-
- prod_mat_vec = Vector((7, 12, 4))
- prod_vec_mat = Vector((1, 12, 5))
-
- self.assertEqual(mat * vec, prod_mat_vec)
- self.assertEqual(vec * mat, prod_vec_mat)
-
- def test_mat_vec_mult(self):
- mat1 = Matrix()
-
- vec = Vector((1, 2))
-
- self.assertRaises(ValueError, mat1.__mul__, vec)
- self.assertRaises(ValueError, vec.__mul__, mat1)
-
- mat2 = Matrix(((1, 2),
- (-2, 3)))
-
- prod = Vector((5, 4))
-
- self.assertEqual(mat2 * vec, prod)
-
- def test_matrix_inverse(self):
- mat = Matrix(((1, 4, 0, -1),
- (2, -1, 2, -2),
- (0, 3, 8, 3),
- (-2, 9, 1, 0)))
-
- inv_mat = (1 / 285) * Matrix(((195, -57, 27, -102),
- (50, -19, 4, 6),
- (-60, 57, 18, 27),
- (110, -133, 43, -78)))
-
- self.assertEqual(mat.inverted(), inv_mat)
-
- def test_matrix_mult(self):
- mat = Matrix(((1, 4, 0, -1),
- (2, -1, 2, -2),
- (0, 3, 8, 3),
- (-2, 9, 1, 0)))
-
- prod_mat = Matrix(((11, -9, 7, -9),
- (4, -3, 12, 6),
- (0, 48, 73, 18),
- (16, -14, 26, -13)))
-
- self.assertEqual(mat * mat, prod_mat)
-
-
-class VectorTesting(unittest.TestCase):
-
- def test_orthogonal(self):
-
- angle_90d = math.pi / 2.0
- for v in vector_data:
- v = Vector(v)
- if v.length_squared != 0.0:
- self.assertAlmostEqual(v.angle(v.orthogonal()), angle_90d)
-
-
-class KDTreeTesting(unittest.TestCase):
-
- @staticmethod
- def kdtree_create_grid_3d(tot):
- k = kdtree.KDTree(tot * tot * tot)
- index = 0
- mul = 1.0 / (tot - 1)
- for x in range(tot):
- for y in range(tot):
- for z in range(tot):
- k.insert((x * mul, y * mul, z * mul), index)
- index += 1
- k.balance()
- return k
-
- def test_kdtree_single(self):
- co = (0,) * 3
- index = 2
-
- k = kdtree.KDTree(1)
- k.insert(co, index)
- k.balance()
-
- co_found, index_found, dist_found = k.find(co)
-
- self.assertEqual(tuple(co_found), co)
- self.assertEqual(index_found, index)
- self.assertEqual(dist_found, 0.0)
-
- def test_kdtree_empty(self):
- co = (0,) * 3
-
- k = kdtree.KDTree(0)
- k.balance()
-
- co_found, index_found, dist_found = k.find(co)
-
- self.assertIsNone(co_found)
- self.assertIsNone(index_found)
- self.assertIsNone(dist_found)
-
- def test_kdtree_line(self):
- tot = 10
-
- k = kdtree.KDTree(tot)
-
- for i in range(tot):
- k.insert((i,) * 3, i)
-
- k.balance()
-
- co_found, index_found, dist_found = k.find((-1,) * 3)
- self.assertEqual(tuple(co_found), (0,) * 3)
-
- co_found, index_found, dist_found = k.find((tot,) * 3)
- self.assertEqual(tuple(co_found), (tot - 1,) * 3)
-
- def test_kdtree_grid(self):
- size = 10
- k = self.kdtree_create_grid_3d(size)
-
- # find_range
- ret = k.find_range((0.5,) * 3, 2.0)
- self.assertEqual(len(ret), size * size * size)
-
- ret = k.find_range((1.0,) * 3, 1.0 / size)
- self.assertEqual(len(ret), 1)
-
- ret = k.find_range((1.0,) * 3, 2.0 / size)
- self.assertEqual(len(ret), 8)
-
- ret = k.find_range((10,) * 3, 0.5)
- self.assertEqual(len(ret), 0)
-
- # find_n
- tot = 0
- ret = k.find_n((1.0,) * 3, tot)
- self.assertEqual(len(ret), tot)
-
- tot = 10
- ret = k.find_n((1.0,) * 3, tot)
- self.assertEqual(len(ret), tot)
- self.assertEqual(ret[0][2], 0.0)
-
- tot = size * size * size
- ret = k.find_n((1.0,) * 3, tot)
- self.assertEqual(len(ret), tot)
-
- def test_kdtree_invalid_size(self):
- with self.assertRaises(ValueError):
- kdtree.KDTree(-1)
-
- def test_kdtree_invalid_balance(self):
- co = (0,) * 3
- index = 2
-
- k = kdtree.KDTree(2)
- k.insert(co, index)
- k.balance()
- k.insert(co, index)
- with self.assertRaises(RuntimeError):
- k.find(co)
-
-
-def test_main():
- try:
- support.run_unittest(MatrixTesting)
- support.run_unittest(VectorTesting)
- support.run_unittest(KDTreeTesting)
- except:
- import traceback
- traceback.print_exc()
-
- # alert CTest we failed
- import sys
- sys.exit(1)
-
-if __name__ == '__main__':
- test_main()
diff --git a/source/tests/bl_rna_wiki_reference.py b/source/tests/bl_rna_wiki_reference.py
deleted file mode 100644
index 8cb20aaf7f6..00000000000
--- a/source/tests/bl_rna_wiki_reference.py
+++ /dev/null
@@ -1,144 +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 #####
-
-# <pep8 compliant>
-
-# Use for validating our wiki interlinking.
-# ./blender.bin --background -noaudio --python source/tests/bl_rna_wiki_reference.py
-#
-# 1) test_data() -- ensure the data we have is correct format
-# 2) test_lookup_coverage() -- ensure that we have lookups for _every_ RNA path
-# 3) test_urls() -- ensure all the URL's are correct
-# 4) test_language_coverage() -- ensure language lookup table is complete
-#
-
-import bpy
-
-
-def test_data():
- import rna_wiki_reference
-
- assert(isinstance(rna_wiki_reference.url_manual_mapping, tuple))
- for i, value in enumerate(rna_wiki_reference.url_manual_mapping):
- try:
- assert(len(value) == 2)
- assert(isinstance(value[0], str))
- assert(isinstance(value[1], str))
- except:
- print("Expected a tuple of 2 strings, instead item %d is a %s: %r" % (i, type(value), value))
- import traceback
- traceback.print_exc()
- raise
-
-
-# a stripped down version of api_dump() in rna_info_dump.py
-def test_lookup_coverage():
-
- def rna_ids():
- import rna_info
- struct = rna_info.BuildRNAInfo()[0]
- for struct_id, v in sorted(struct.items()):
- props = [(prop.identifier, prop) for prop in v.properties]
- struct_path = "bpy.types.%s" % struct_id[1]
- for prop_id, prop in props:
- yield (struct_path, "%s.%s" % (struct_path, prop_id))
-
- for submod_id in dir(bpy.ops):
- op_path = "bpy.ops.%s" % submod_id
- for op_id in dir(getattr(bpy.ops, submod_id)):
- yield (op_path, "%s.%s" % (op_path, op_id))
-
- # check coverage
- from bl_operators import wm
-
- set_group_all = set()
- set_group_doc = set()
-
- for rna_group, rna_id in rna_ids():
- url = wm.WM_OT_doc_view_manual._lookup_rna_url(rna_id, verbose=False)
- print(rna_id, "->", url)
-
- set_group_all.add(rna_group)
- if url is not None:
- set_group_doc.add(rna_group)
-
- # finally report undocumented groups
- print("")
- print("---------------------")
- print("Undocumented Sections")
-
- for rna_group in sorted(set_group_all):
- if rna_group not in set_group_doc:
- print("%s.*" % rna_group)
-
-
-def test_language_coverage():
- pass # TODO
-
-
-def test_urls():
- import sys
- import rna_wiki_reference
-
- import urllib.error
- from urllib.request import urlopen
-
- prefix = rna_wiki_reference.url_manual_prefix
- urls = {suffix for (rna_id, suffix) in rna_wiki_reference.url_manual_mapping}
-
- urls_len = "%d" % len(urls)
- print("")
- print("-------------" + "-" * len(urls_len))
- print("Testing URLS %s" % urls_len)
- print("")
-
- color_red = '\033[0;31m'
- color_green = '\033[1;32m'
- color_normal = '\033[0m'
-
- urls_fail = []
-
- for url in sorted(urls):
- url_full = prefix + url
- print(" %s ... " % url_full, end="")
- sys.stdout.flush()
- try:
- urlopen(url_full)
- print(color_green + "OK" + color_normal)
- except urllib.error.HTTPError:
- print(color_red + "FAIL!" + color_normal)
- urls_fail.append(url)
-
- if urls_fail:
- urls_len = "%d" % len(urls_fail)
- print("")
- print("------------" + "-" * len(urls_len))
- print("Failed URLS %s" % urls_len)
- print("")
- for url in urls_fail:
- print(" %s%s%s" % (color_red, url, color_normal))
-
-
-def main():
- test_data()
- test_lookup_coverage()
- test_language_coverage()
- test_urls()
-
-if __name__ == "__main__":
- main()
diff --git a/source/tests/bl_rst_completeness.py b/source/tests/bl_rst_completeness.py
deleted file mode 100644
index 6e67f8d908d..00000000000
--- a/source/tests/bl_rst_completeness.py
+++ /dev/null
@@ -1,159 +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 #####
-
-# <pep8 compliant>
-
-# run this script in the game engine.
-# or on the command line with...
-# ./blender.bin --background -noaudio --python source/tests/bl_rst_completeness.py
-
-# Paste this into the bge and run on an always actuator.
-'''
-filepath = "/dsk/data/src/blender/blender/source/tests/bl_rst_completeness.py"
-exec(compile(open(filepath).read(), filepath, 'exec'))
-'''
-
-import os
-
-THIS_DIR = os.path.dirname(__file__)
-RST_DIR = os.path.normpath(os.path.join(THIS_DIR, "..", "..", "doc", "python_api", "rst"))
-
-import sys
-sys.path.append(THIS_DIR)
-
-import rst_to_doctree_mini
-
-try:
- import bge
-except:
- bge = None
-
-# (file, module)
-modules = (
- ("bge.constraints.rst", "bge.constraints", False),
- ("bge.events.rst", "bge.events", False),
- ("bge.logic.rst", "bge.logic", False),
- ("bge.render.rst", "bge.render", False),
- ("bge.texture.rst", "bge.texture", False),
- ("bge.types.rst", "bge.types", False),
-
- ("bgl.rst", "bgl", True),
- ("gpu.rst", "gpu", False),
-)
-
-
-def is_directive_pydata(filepath, directive):
- if directive.type in {"function", "method", "class", "attribute", "data"}:
- return True
- elif directive.type in {"module", "note", "warning", "code-block", "hlist", "seealso"}:
- return False
- elif directive.type in {"literalinclude"}: # TODO
- return False
- else:
- print(directive_to_str(filepath, directive), end=" ")
- print("unknown directive type %r" % directive.type)
- return False
-
-
-def directive_to_str(filepath, directive):
- return "%s:%d:%d:" % (filepath, directive.line + 1, directive.indent)
-
-
-def directive_members_dict(filepath, directive_members):
- return {directive.value_strip: directive for directive in directive_members
- if is_directive_pydata(filepath, directive)}
-
-
-def module_validate(filepath, mod, mod_name, doctree, partial_ok):
- # RST member missing from MODULE ???
- for directive in doctree:
- # print(directive.type)
- if is_directive_pydata(filepath, directive):
- attr = directive.value_strip
- has_attr = hasattr(mod, attr)
- ok = False
- if not has_attr:
- # so we can have glNormal docs cover glNormal3f
- if partial_ok:
- for s in dir(mod):
- if s.startswith(attr):
- ok = True
- break
-
- if not ok:
- print(directive_to_str(filepath, directive), end=" ")
- print("rst contains non existing member %r" % attr)
-
- # if its a class, scan down the class...
- # print(directive.type)
- if has_attr:
- if directive.type == "class":
- cls = getattr(mod, attr)
- # print("directive: ", directive)
- for directive_child in directive.members:
- # print("directive_child: ", directive_child)
- if is_directive_pydata(filepath, directive_child):
- attr_child = directive_child.value_strip
- if attr_child not in cls.__dict__:
- attr_id = "%s.%s" % (attr, attr_child)
- print(directive_to_str(filepath, directive_child), end=" ")
- print("rst contains non existing class member %r" % attr_id)
-
- # MODULE member missing from RST ???
- doctree_dict = directive_members_dict(filepath, doctree)
- for attr in dir(mod):
- if attr.startswith("_"):
- continue
-
- directive = doctree_dict.get(attr)
- if directive is None:
- print("module contains undocumented member %r from %r" % ("%s.%s" % (mod_name, attr), filepath))
- else:
- if directive.type == "class":
- directive_dict = directive_members_dict(filepath, directive.members)
- cls = getattr(mod, attr)
- for attr_child in cls.__dict__.keys():
- if attr_child.startswith("_"):
- continue
- if attr_child not in directive_dict:
- attr_id = "%s.%s.%s" % (mod_name, attr, attr_child), filepath
- print("module contains undocumented member %r from %r" % attr_id)
-
-
-def main():
-
- if bge is None:
- print("Skipping BGE modules!")
-
- for filename, modname, partial_ok in modules:
- if bge is None and modname.startswith("bge"):
- continue
-
- filepath = os.path.join(RST_DIR, filename)
- if not os.path.exists(filepath):
- raise Exception("%r not found" % filepath)
-
- doctree = rst_to_doctree_mini.parse_rst_py(filepath)
- __import__(modname)
- mod = sys.modules[modname]
-
- module_validate(filepath, mod, modname, doctree, partial_ok)
-
-
-if __name__ == "__main__":
- main()
diff --git a/source/tests/bl_run_operators.py b/source/tests/bl_run_operators.py
deleted file mode 100644
index e14b0ce6d32..00000000000
--- a/source/tests/bl_run_operators.py
+++ /dev/null
@@ -1,490 +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 #####
-
-# <pep8 compliant>
-
-# semi-useful script, runs all operators in a number of different
-# contexts, cheap way to find misc small bugs but is in no way a complete test.
-#
-# only error checked for here is a segfault.
-
-import bpy
-import sys
-
-USE_ATTRSET = False
-USE_FILES = "" # "/mango/"
-USE_RANDOM = False
-USE_RANDOM_SCREEN = False
-RANDOM_SEED = [1] # so we can redo crashes
-RANDOM_RESET = 0.1 # 10% chance of resetting on each new operator
-RANDOM_MULTIPLY = 10
-
-
-op_blacklist = (
- "script.reload",
- "export*.*",
- "import*.*",
- "*.save_*",
- "*.read_*",
- "*.open_*",
- "*.link_append",
- "render.render",
- "render.play_rendered_anim",
- "sound.bake_animation", # OK but slow
- "sound.mixdown", # OK but slow
- "object.bake_image", # OK but slow
- "object.paths_calculate", # OK but slow
- "object.paths_update", # OK but slow
- "ptcache.bake_all", # OK but slow
- "nla.bake", # OK but slow
- "*.*_export",
- "*.*_import",
- "ed.undo",
- "ed.undo_push",
- "script.autoexec_warn_clear",
- "screen.delete", # already used for random screens
- "wm.blenderplayer_start",
- "wm.recover_auto_save",
- "wm.quit_blender",
- "wm.url_open",
- "wm.doc_view",
- "wm.doc_edit",
- "wm.doc_view_manual",
- "wm.path_open",
- "wm.theme_install",
- "wm.context_*",
- "wm.properties_add",
- "wm.properties_remove",
- "wm.properties_edit",
- "wm.properties_context_change",
- "wm.operator_cheat_sheet",
- "wm.interface_theme_*",
- "wm.appconfig_*", # just annoying - but harmless
- "wm.keyitem_add", # just annoying - but harmless
- "wm.keyconfig_activate", # just annoying - but harmless
- "wm.keyconfig_preset_add", # just annoying - but harmless
- "wm.keyconfig_test", # just annoying - but harmless
- "wm.memory_statistics", # another annoying one
- "wm.dependency_relations", # another annoying one
- "wm.keymap_restore", # another annoying one
- "wm.addon_*", # harmless, but dont change state
- "console.*", # just annoying - but harmless
- )
-
-
-def blend_list(mainpath):
- import os
- from os.path import join, splitext
-
- def file_list(path, filename_check=None):
- for dirpath, dirnames, filenames in os.walk(path):
-
- # skip '.svn'
- if dirpath.startswith("."):
- continue
-
- for filename in filenames:
- filepath = join(dirpath, filename)
- if filename_check is None or filename_check(filepath):
- yield filepath
-
- def is_blend(filename):
- ext = splitext(filename)[1]
- return (ext in {".blend", })
-
- return list(sorted(file_list(mainpath, is_blend)))
-
-if USE_FILES:
- USE_FILES_LS = blend_list(USE_FILES)
- # print(USE_FILES_LS)
-
-
-def filter_op_list(operators):
- from fnmatch import fnmatchcase
-
- def is_op_ok(op):
- for op_match in op_blacklist:
- if fnmatchcase(op, op_match):
- print(" skipping: %s (%s)" % (op, op_match))
- return False
- return True
-
- operators[:] = [op for op in operators if is_op_ok(op[0])]
-
-
-def reset_blend():
- bpy.ops.wm.read_factory_settings()
- for scene in bpy.data.scenes:
- # reduce range so any bake action doesnt take too long
- scene.frame_start = 1
- scene.frame_end = 5
-
- if USE_RANDOM_SCREEN:
- import random
- for i in range(random.randint(0, len(bpy.data.screens))):
- bpy.ops.screen.delete()
- print("Scree IS", bpy.context.screen)
-
-
-def reset_file():
- import random
- f = USE_FILES_LS[random.randint(0, len(USE_FILES_LS) - 1)]
- bpy.ops.wm.open_mainfile(filepath=f)
-
-
-if USE_ATTRSET:
- def build_property_typemap(skip_classes):
-
- property_typemap = {}
-
- for attr in dir(bpy.types):
- cls = getattr(bpy.types, attr)
- if issubclass(cls, skip_classes):
- continue
-
- ## to support skip-save we cant get all props
- # properties = cls.bl_rna.properties.keys()
- properties = []
- for prop_id, prop in cls.bl_rna.properties.items():
- if not prop.is_skip_save:
- properties.append(prop_id)
-
- properties.remove("rna_type")
- property_typemap[attr] = properties
-
- return property_typemap
- CLS_BLACKLIST = (
- bpy.types.BrushTextureSlot,
- bpy.types.Brush,
- )
- property_typemap = build_property_typemap(CLS_BLACKLIST)
- bpy_struct_type = bpy.types.Struct.__base__
-
- def id_walk(value, parent):
- value_type = type(value)
- value_type_name = value_type.__name__
-
- value_id = getattr(value, "id_data", Ellipsis)
- value_props = property_typemap.get(value_type_name, ())
-
- for prop in value_props:
- subvalue = getattr(value, prop)
-
- if subvalue == parent:
- continue
- # grr, recursive!
- if prop == "point_caches":
- continue
- subvalue_type = type(subvalue)
- yield value, prop, subvalue_type
- subvalue_id = getattr(subvalue, "id_data", Ellipsis)
-
- if value_id == subvalue_id:
- if subvalue_type == float:
- pass
- elif subvalue_type == int:
- pass
- elif subvalue_type == bool:
- pass
- elif subvalue_type == str:
- pass
- elif hasattr(subvalue, "__len__"):
- for sub_item in subvalue[:]:
- if isinstance(sub_item, bpy_struct_type):
- subitem_id = getattr(sub_item, "id_data", Ellipsis)
- if subitem_id == subvalue_id:
- yield from id_walk(sub_item, value)
-
- if subvalue_type.__name__ in property_typemap:
- yield from id_walk(subvalue, value)
-
- # main function
- _random_values = (
- None, object, type,
- 1, 0.1, -1, # float("nan"),
- "", "test", b"", b"test",
- (), [], {},
- (10,), (10, 20), (0, 0, 0),
- {0: "", 1: "hello", 2: "test"}, {"": 0, "hello": 1, "test": 2},
- set(), {"", "test", "."}, {None, ..., type},
- range(10), (" " * i for i in range(10)),
- )
-
- def attrset_data():
- for attr in dir(bpy.data):
- if attr == "window_managers":
- continue
- seq = getattr(bpy.data, attr)
- if seq.__class__.__name__ == 'bpy_prop_collection':
- for id_data in seq:
- for val, prop, tp in id_walk(id_data, bpy.data):
- # print(id_data)
- for val_rnd in _random_values:
- try:
- setattr(val, prop, val_rnd)
- except:
- pass
-
-
-def run_ops(operators, setup_func=None, reset=True):
- print("\ncontext:", setup_func.__name__)
-
- # first invoke
- for op_id, op in operators:
- if op.poll():
- print(" operator:", op_id)
- sys.stdout.flush() # in case of crash
-
- # disable will get blender in a bad state and crash easy!
- if reset:
- reset_test = True
- if USE_RANDOM:
- import random
- if random.random() < (1.0 - RANDOM_RESET):
- reset_test = False
-
- if reset_test:
- if USE_FILES:
- reset_file()
- else:
- reset_blend()
- del reset_test
-
- if USE_RANDOM:
- # we can't be sure it will work
- try:
- setup_func()
- except:
- pass
- else:
- setup_func()
-
- for mode in {'EXEC_DEFAULT', 'INVOKE_DEFAULT'}:
- try:
- op(mode)
- except:
- #import traceback
- #traceback.print_exc()
- pass
-
- if USE_ATTRSET:
- attrset_data()
-
- if not operators:
- # run test
- if reset:
- reset_blend()
- if USE_RANDOM:
- # we can't be sure it will work
- try:
- setup_func()
- except:
- pass
- else:
- setup_func()
-
-
-# contexts
-def ctx_clear_scene(): # copied from batch_import.py
- unique_obs = set()
- for scene in bpy.data.scenes:
- for obj in scene.objects[:]:
- scene.objects.unlink(obj)
- unique_obs.add(obj)
-
- # remove obdata, for now only worry about the startup scene
- for bpy_data_iter in (bpy.data.objects, bpy.data.meshes, bpy.data.lamps, bpy.data.cameras):
- for id_data in bpy_data_iter:
- bpy_data_iter.remove(id_data)
-
-
-def ctx_editmode_mesh():
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_mesh_extra():
- bpy.ops.object.vertex_group_add()
- bpy.ops.object.shape_key_add(from_mix=False)
- bpy.ops.object.shape_key_add(from_mix=True)
- bpy.ops.mesh.uv_texture_add()
- bpy.ops.mesh.vertex_color_add()
- bpy.ops.object.material_slot_add()
- # editmode last!
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_mesh_empty():
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.mesh.select_all(action='SELECT')
- bpy.ops.mesh.delete()
-
-
-def ctx_editmode_curves():
- bpy.ops.curve.primitive_nurbs_circle_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_curves_empty():
- bpy.ops.curve.primitive_nurbs_circle_add()
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.curve.select_all(action='SELECT')
- bpy.ops.curve.delete(type='VERT')
-
-
-def ctx_editmode_surface():
- bpy.ops.surface.primitive_nurbs_surface_torus_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_mball():
- bpy.ops.object.metaball_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_text():
- bpy.ops.object.text_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_armature():
- bpy.ops.object.armature_add()
- bpy.ops.object.mode_set(mode='EDIT')
-
-
-def ctx_editmode_armature_empty():
- bpy.ops.object.armature_add()
- bpy.ops.object.mode_set(mode='EDIT')
- bpy.ops.armature.select_all(action='SELECT')
- bpy.ops.armature.delete()
-
-
-def ctx_editmode_lattice():
- bpy.ops.object.add(type='LATTICE')
- bpy.ops.object.mode_set(mode='EDIT')
- # bpy.ops.object.vertex_group_add()
-
-
-def ctx_object_empty():
- bpy.ops.object.add(type='EMPTY')
-
-
-def ctx_object_pose():
- bpy.ops.object.armature_add()
- bpy.ops.object.mode_set(mode='POSE')
- bpy.ops.pose.select_all(action='SELECT')
-
-
-def ctx_object_paint_weight():
- bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
-
-
-def ctx_object_paint_vertex():
- bpy.ops.object.mode_set(mode='VERTEX_PAINT')
-
-
-def ctx_object_paint_sculpt():
- bpy.ops.object.mode_set(mode='SCULPT')
-
-
-def ctx_object_paint_texture():
- bpy.ops.object.mode_set(mode='TEXTURE_PAINT')
-
-
-def bpy_check_type_duplicates():
- # non essential sanity check
- bl_types = dir(bpy.types)
- bl_types_unique = set(bl_types)
-
- if len(bl_types) != len(bl_types_unique):
- print("Error, found duplicates in 'bpy.types'")
- for t in sorted(bl_types_unique):
- tot = bl_types.count(t)
- if tot > 1:
- print(" '%s', %d" % (t, tot))
- import sys
- sys.exit(1)
-
-
-def main():
-
- bpy_check_type_duplicates()
-
- # reset_blend()
- import bpy
- operators = []
- for mod_name in dir(bpy.ops):
- mod = getattr(bpy.ops, mod_name)
- for submod_name in dir(mod):
- op = getattr(mod, submod_name)
- operators.append(("%s.%s" % (mod_name, submod_name), op))
-
- operators.sort(key=lambda op: op[0])
-
- filter_op_list(operators)
-
- # for testing, mix the list up.
- #operators.reverse()
-
- if USE_RANDOM:
- import random
- random.seed(RANDOM_SEED[0])
- operators = operators * RANDOM_MULTIPLY
- random.shuffle(operators)
-
- # 2 passes, first just run setup_func to make sure they are ok
- for operators_test in ((), operators):
- # Run the operator tests in different contexts
- run_ops(operators_test, setup_func=lambda: None)
-
- if USE_FILES:
- continue
-
- run_ops(operators_test, setup_func=ctx_clear_scene)
- # object modes
- run_ops(operators_test, setup_func=ctx_object_empty)
- run_ops(operators_test, setup_func=ctx_object_pose)
- run_ops(operators_test, setup_func=ctx_object_paint_weight)
- run_ops(operators_test, setup_func=ctx_object_paint_vertex)
- run_ops(operators_test, setup_func=ctx_object_paint_sculpt)
- run_ops(operators_test, setup_func=ctx_object_paint_texture)
- # mesh
- run_ops(operators_test, setup_func=ctx_editmode_mesh)
- run_ops(operators_test, setup_func=ctx_editmode_mesh_extra)
- run_ops(operators_test, setup_func=ctx_editmode_mesh_empty)
- # armature
- run_ops(operators_test, setup_func=ctx_editmode_armature)
- run_ops(operators_test, setup_func=ctx_editmode_armature_empty)
- # curves
- run_ops(operators_test, setup_func=ctx_editmode_curves)
- run_ops(operators_test, setup_func=ctx_editmode_curves_empty)
- run_ops(operators_test, setup_func=ctx_editmode_surface)
- # other
- run_ops(operators_test, setup_func=ctx_editmode_mball)
- run_ops(operators_test, setup_func=ctx_editmode_text)
- run_ops(operators_test, setup_func=ctx_editmode_lattice)
-
- if not operators_test:
- print("All setup functions run fine!")
-
- print("Finished %r" % __file__)
-
-if __name__ == "__main__":
- #~ for i in range(200):
- #~ RANDOM_SEED[0] += 1
- #~ main()
- main()
diff --git a/source/tests/bl_test.py b/source/tests/bl_test.py
deleted file mode 100644
index 0cb322a21b1..00000000000
--- a/source/tests/bl_test.py
+++ /dev/null
@@ -1,197 +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 #####
-
-# <pep8 compliant>
-
-import sys
-import os
-
-
-# may split this out into a new file
-def replace_bpy_app_version():
- """ So MD5's are predictable from output which uses blenders versions.
- """
-
- import bpy
-
- app = bpy.app
- app_fake = type(bpy)("bpy.app")
-
- for attr in dir(app):
- if not attr.startswith("_"):
- setattr(app_fake, attr, getattr(app, attr))
-
- app_fake.version = 0, 0, 0
- app_fake.version_string = "0.00 (sub 0)"
- bpy.app = app_fake
-
-
-def clear_startup_blend():
- import bpy
-
- for scene in bpy.data.scenes:
- for obj in scene.objects:
- scene.objects.unlink(obj)
-
-
-def blend_to_md5():
- import bpy
- scene = bpy.context.scene
- ROUND = 4
-
- def matrix2str(matrix):
- return "".join([str(round(axis, ROUND)) for vector in matrix for axis in vector]).encode('ASCII')
-
- def coords2str(seq, attr):
- return "".join([str(round(axis, ROUND)) for vertex in seq for axis in getattr(vertex, attr)]).encode('ASCII')
-
- import hashlib
-
- md5 = hashlib.new("md5")
- md5_update = md5.update
-
- for obj in scene.objects:
- md5_update(matrix2str(obj.matrix_world))
- data = obj.data
-
- if type(data) == bpy.types.Mesh:
- md5_update(coords2str(data.vertices, "co"))
- elif type(data) == bpy.types.Curve:
- for spline in data.splines:
- md5_update(coords2str(spline.bezier_points, "co"))
- md5_update(coords2str(spline.points, "co"))
-
- return md5.hexdigest()
-
-
-def main():
- argv = sys.argv
- print(" args:", " ".join(argv))
- argv = argv[argv.index("--") + 1:]
-
- def arg_extract(arg, optional=True, array=False):
- arg += "="
- if array:
- value = []
- else:
- value = None
-
- i = 0
- while i < len(argv):
- if argv[i].startswith(arg):
- item = argv[i][len(arg):]
- del argv[i]
- i -= 1
-
- if array:
- value.append(item)
- else:
- value = item
- break
-
- i += 1
-
- if (not value) and (not optional):
- print(" '%s' not set" % arg)
- sys.exit(1)
-
- return value
-
- run = arg_extract("--run", optional=False)
- md5 = arg_extract("--md5", optional=False)
- md5_method = arg_extract("--md5_method", optional=False) # 'SCENE' / 'FILE'
-
- # only when md5_method is 'FILE'
- md5_source = arg_extract("--md5_source", optional=True, array=True)
-
- # save blend file, for testing
- write_blend = arg_extract("--write-blend", optional=True)
-
- # ensure files are written anew
- for f in md5_source:
- if os.path.exists(f):
- os.remove(f)
-
- import bpy
-
- replace_bpy_app_version()
- if not bpy.data.filepath:
- clear_startup_blend()
-
- print(" Running: '%s'" % run)
- print(" MD5: '%s'!" % md5)
-
- try:
- result = eval(run)
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
-
- if write_blend is not None:
- print(" Writing Blend: %s" % write_blend)
- bpy.ops.wm.save_mainfile('EXEC_DEFAULT', filepath=write_blend)
-
- print(" Result: '%s'" % str(result))
- if not result:
- print(" Running: %s -> False" % run)
- sys.exit(1)
-
- if md5_method == 'SCENE':
- md5_new = blend_to_md5()
- elif md5_method == 'FILE':
- if not md5_source:
- print(" Missing --md5_source argument")
- sys.exit(1)
-
- for f in md5_source:
- if not os.path.exists(f):
- print(" Missing --md5_source=%r argument does not point to a file")
- sys.exit(1)
-
- import hashlib
-
- md5_instance = hashlib.new("md5")
- md5_update = md5_instance.update
-
- for f in md5_source:
- filehandle = open(f, "rb")
- md5_update(filehandle.read())
- filehandle.close()
-
- md5_new = md5_instance.hexdigest()
-
- else:
- print(" Invalid --md5_method=%s argument is not a valid source")
- sys.exit(1)
-
- if md5 != md5_new:
- print(" Running: %s\n MD5 Recieved: %s\n MD5 Expected: %s" % (run, md5_new, md5))
- sys.exit(1)
-
- print(" Success: %s" % run)
-
-
-if __name__ == "__main__":
- # So a python error exits(1)
- try:
- main()
- except:
- import traceback
- traceback.print_exc()
- sys.exit(1)
diff --git a/source/tests/check_deprecated.py b/source/tests/check_deprecated.py
deleted file mode 100644
index bb9fcd818d2..00000000000
--- a/source/tests/check_deprecated.py
+++ /dev/null
@@ -1,149 +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 #####
-
-# <pep8 compliant>
-
-import os
-from os.path import splitext
-
-DEPRECATE_DAYS = 120
-
-SKIP_DIRS = ("extern",
- "scons",
- os.path.join("source", "tests"), # not this dir
- )
-
-
-def is_c_header(filename):
- ext = splitext(filename)[1]
- return (ext in {".h", ".hpp", ".hxx", ".hh"})
-
-
-def is_c(filename):
- ext = splitext(filename)[1]
- return (ext in {".c", ".cpp", ".cxx", ".m", ".mm", ".rc", ".cc", ".inl"})
-
-
-def is_c_any(filename):
- return is_c(filename) or is_c_header(filename)
-
-
-def is_py(filename):
- ext = splitext(filename)[1]
- return (ext == ".py")
-
-
-def is_source_any(filename):
- return is_c_any(filename) or is_py(filename)
-
-
-def source_list(path, filename_check=None):
- for dirpath, dirnames, filenames in os.walk(path):
-
- # skip '.svn'
- if dirpath.startswith("."):
- continue
-
- for filename in filenames:
- if filename_check is None or filename_check(filename):
- yield os.path.join(dirpath, filename)
-
-
-def deprecations():
- """
- Searches out source code for lines like
-
- /* *DEPRECATED* 2011/7/17 bgl.Buffer.list info text */
-
- Or...
-
- # *DEPRECATED* 2010/12/22 some.py.func more info */
-
- """
- import datetime
- SOURCE_DIR = os.path.normpath(os.path.abspath(os.path.normpath(os.path.join(os.path.dirname(__file__), "..", ".."))))
-
- SKIP_DIRS_ABS = [os.path.join(SOURCE_DIR, p) for p in SKIP_DIRS]
-
- deprecations_ls = []
-
- scan_tot = 0
-
- print("scanning in %r for '*DEPRECATED* YYYY/MM/DD info'" % SOURCE_DIR)
-
- for fn in source_list(SOURCE_DIR, is_source_any):
- # print(fn)
- skip = False
- for p in SKIP_DIRS_ABS:
- if fn.startswith(p):
- skip = True
- break
- if skip:
- continue
-
- file = open(fn, 'r', encoding="utf8")
- for i, l in enumerate(file):
- # logic for deprecation warnings
- if '*DEPRECATED*' in l:
- try:
- l = l.strip()
- data = l.split('*DEPRECATED*', 1)[-1].strip().strip()
- data = [w.strip() for w in data.split('/', 2)]
- data[-1], info = data[-1].split(' ', 1)
- info = info.split("*/", 1)[0]
- if len(data) != 3:
- print(" poorly formatting line:\n"
- " %r:%d\n"
- " %s" %
- (fn, i + 1, l)
- )
- else:
- data = datetime.datetime(*tuple([int(w) for w in data]))
-
- deprecations_ls.append((data, (fn, i + 1), info))
- except:
- print("Error file - %r:%d" % (fn, i + 1))
- import traceback
- traceback.print_exc()
-
- scan_tot += 1
-
- print(" scanned %d files" % scan_tot)
-
- return deprecations_ls
-
-
-def main():
- import datetime
- now = datetime.datetime.now()
-
- deps = deprecations()
-
- print("\nAll deprecations...")
- for data, fileinfo, info in deps:
- days_old = (now - data).days
- if days_old > DEPRECATE_DAYS:
- info = "*** REMOVE! *** " + info
- print(" %r, days-old(%.2d), %s:%d - %s" % (data, days_old, fileinfo[0], fileinfo[1], info))
- if deps:
- print("\ndone!")
- else:
- print("\nnone found!")
-
-if __name__ == '__main__':
- main()
diff --git a/source/tests/pep8.py b/source/tests/pep8.py
deleted file mode 100644
index cca49d54ac0..00000000000
--- a/source/tests/pep8.py
+++ /dev/null
@@ -1,154 +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 #####
-
-# <pep8-80 compliant>
-
-import os
-
-# depends on pep8, frosted, pylint
-# for Ubuntu
-#
-# sudo apt-get install pylint
-#
-# sudo apt-get install python-setuptools python-pip
-# sudo pip install pep8
-# sudo pip install frosted
-#
-# in Debian install pylint pep8 with apt-get/aptitude/etc
-#
-# on *nix run
-# python source/tests/pep8.py > test_pep8.log 2>&1
-
-# how many lines to read into the file, pep8 comment
-# should be directly after the license header, ~20 in most cases
-PEP8_SEEK_COMMENT = 40
-SKIP_PREFIX = "./tools", "./config", "./scons", "./extern"
-SKIP_ADDONS = True
-FORCE_PEP8_ALL = False
-
-
-def file_list_py(path):
- for dirpath, dirnames, filenames in os.walk(path):
- for filename in filenames:
- if filename.endswith((".py", ".cfg")):
- yield os.path.join(dirpath, filename)
-
-
-def is_pep8(path):
- print(path)
- if open(path, 'rb').read(3) == b'\xef\xbb\xbf':
- print("\nfile contains BOM, remove first 3 bytes: %r\n" % path)
-
- # templates don't have a header but should be pep8
- for d in ("presets", "templates_py", "examples"):
- if ("%s%s%s" % (os.sep, d, os.sep)) in path:
- return 1
-
- f = open(path, 'r', encoding="utf8")
- for i in range(PEP8_SEEK_COMMENT):
- line = f.readline()
- if line.startswith("# <pep8"):
- if line.startswith("# <pep8 compliant>"):
- return 1
- elif line.startswith("# <pep8-80 compliant>"):
- return 2
- f.close()
- return 0
-
-
-def main():
- files = []
- files_skip = []
- for f in file_list_py("."):
- if [None for prefix in SKIP_PREFIX if f.startswith(prefix)]:
- continue
-
- if SKIP_ADDONS:
- if (os.sep + "addons") in f:
- continue
-
- pep8_type = FORCE_PEP8_ALL or is_pep8(f)
-
- if pep8_type:
- # so we can batch them for each tool.
- files.append((os.path.abspath(f), pep8_type))
- else:
- files_skip.append(f)
-
- print("\nSkipping...")
- for f in files_skip:
- print(" %s" % f)
-
- # strict imports
- print("\n\n\n# running pep8...")
- import re
- import_check = re.compile(r"\s*from\s+[A-z\.]+\s+import \*\s*")
- for f, pep8_type in files:
- for i, l in enumerate(open(f, 'r', encoding='utf8')):
- if import_check.match(l):
- print("%s:%d:0: global import bad practice" % (f, i + 1))
-
- print("\n\n\n# running pep8...")
-
- # these are very picky and often hard to follow
- # while keeping common script formatting.
- ignore = "E122", "E123", "E124", "E125", "E126", "E127", "E128"
-
- for f, pep8_type in files:
-
- if pep8_type == 1:
- # E501:80 line length
- ignore_tmp = ignore + ("E501", )
- else:
- ignore_tmp = ignore
-
- os.system("pep8 --repeat --ignore=%s '%s'" % (",".join(ignore_tmp), f))
-
- # frosted
- print("\n\n\n# running frosted...")
- for f, pep8_type in files:
- os.system("frosted '%s'" % f)
-
- print("\n\n\n# running pylint...")
- for f, pep8_type in files:
- # let pep8 complain about line length
- os.system("pylint "
- "--disable="
- "C0111," # missing doc string
- "C0103," # invalid name
- "W0613," # unused argument, may add this back
- # but happens a lot for 'context' for eg.
- "W0232," # class has no __init__, Operator/Panel/Menu etc
- "W0142," # Used * or ** magic
- # even needed in some cases
- "R0902," # Too many instance attributes
- "R0903," # Too many statements
- "R0911," # Too many return statements
- "R0912," # Too many branches
- "R0913," # Too many arguments
- "R0914," # Too many local variables
- "R0915," # Too many statements
- " "
- "--include-ids=y "
- "--output-format=parseable "
- "--reports=n "
- "--max-line-length=1000"
- " '%s'" % f)
-
-if __name__ == "__main__":
- main()
diff --git a/source/tests/rna_array.py b/source/tests/rna_array.py
deleted file mode 100644
index a2241dff108..00000000000
--- a/source/tests/rna_array.py
+++ /dev/null
@@ -1,297 +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 #####
-
-import unittest
-import random
-
-test= bpy.data.test
-
-# farr - 1-dimensional array of float
-# fdarr - dynamic 1-dimensional array of float
-# fmarr - 3-dimensional ([3][4][5]) array of float
-# fdmarr - dynamic 3-dimensional (ditto size) array of float
-
-# same as above for other types except that the first letter is "i" for int and "b" for bool
-
-class TestArray(unittest.TestCase):
- # test that assignment works by: assign -> test value
- # - rvalue = list of float
- # - rvalue = list of numbers
- # test.object
- # bpy.data.test.farr[3], iarr[3], barr[...], fmarr, imarr, bmarr
-
- def setUp(self):
- test.farr= (1.0, 2.0, 3.0)
- test.iarr= (7, 8, 9)
- test.barr= (False, True, False)
-
- # test access
- # test slice access, negative indices
- def test_access(self):
- rvals= ([1.0, 2.0, 3.0], [7, 8, 9], [False, True, False])
- for arr, rval in zip((test.farr, test.iarr, test.barr), rvals):
- self.assertEqual(prop_to_list(arr), rval)
- self.assertEqual(arr[0:3], rval)
- self.assertEqual(arr[1:2], rval[1:2])
- self.assertEqual(arr[-1], arr[2])
- self.assertEqual(arr[-2], arr[1])
- self.assertEqual(arr[-3], arr[0])
-
- # fail when index out of bounds
- def test_access_fail(self):
- for arr in (test.farr, test.iarr, test.barr):
- self.assertRaises(IndexError, lambda : arr[4])
-
- # test assignment of a whole array
- def test_assign_array(self):
- # should accept int as float
- test.farr= (1, 2, 3)
-
- # fail when: unexpected no. of items, invalid item type
- def test_assign_array_fail(self):
- def assign_empty_list(arr):
- setattr(test, arr, ())
-
- for arr in ("farr", "iarr", "barr"):
- self.assertRaises(ValueError, assign_empty_list, arr)
-
- def assign_invalid_float():
- test.farr= (1.0, 2.0, "3.0")
-
- def assign_invalid_int():
- test.iarr= ("1", 2, 3)
-
- def assign_invalid_bool():
- test.barr= (True, 0.123, False)
-
- for func in [assign_invalid_float, assign_invalid_int, assign_invalid_bool]:
- self.assertRaises(TypeError, func)
-
- # shouldn't accept float as int
- def assign_float_as_int():
- test.iarr= (1, 2, 3.0)
- self.assertRaises(TypeError, assign_float_as_int)
-
- # non-dynamic arrays cannot change size
- def assign_different_size(arr, val):
- setattr(test, arr, val)
- for arr, val in zip(("iarr", "farr", "barr"), ((1, 2), (1.0, 2.0), (True, False))):
- self.assertRaises(ValueError, assign_different_size, arr, val)
-
- # test assignment of specific items
- def test_assign_item(self):
- for arr, rand_func in zip((test.farr, test.iarr, test.barr), (rand_float, rand_int, rand_bool)):
- for i in range(len(arr)):
- val= rand_func()
- arr[i] = val
-
- self.assertEqual(arr[i], val)
-
- # float prop should accept also int
- for i in range(len(test.farr)):
- val= rand_int()
- test.farr[i] = val
- self.assertEqual(test.farr[i], float(val))
-
- #
-
- def test_assign_item_fail(self):
- def assign_bad_index(arr):
- arr[4] = 1.0
-
- def assign_bad_type(arr):
- arr[1] = "123"
-
- for arr in [test.farr, test.iarr, test.barr]:
- self.assertRaises(IndexError, assign_bad_index, arr)
-
- # not testing bool because bool allows not only (True|False)
- for arr in [test.farr, test.iarr]:
- self.assertRaises(TypeError, assign_bad_type, arr)
-
- def test_dynamic_assign_array(self):
- # test various lengths here
- for arr, rand_func in zip(("fdarr", "idarr", "bdarr"), (rand_float, rand_int, rand_bool)):
- for length in range(1, 64):
- rval= make_random_array(length, rand_func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- def test_dynamic_assign_array_fail(self):
- # could also test too big length here
-
- def assign_empty_list(arr):
- setattr(test, arr, ())
-
- for arr in ("fdarr", "idarr", "bdarr"):
- self.assertRaises(ValueError, assign_empty_list, arr)
-
-
-class TestMArray(unittest.TestCase):
- def setUp(self):
- # reset dynamic array sizes
- for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
- setattr(test, arr, make_random_3d_array((3, 4, 5), func))
-
- # test assignment
- def test_assign_array(self):
- for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
- # assignment of [3][4][5]
- rval= make_random_3d_array((3, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- # test assignment of [2][4][5], [1][4][5] should work on dynamic arrays
-
- def test_assign_array_fail(self):
- def assign_empty_array():
- test.fmarr= ()
- self.assertRaises(ValueError, assign_empty_array)
-
- def assign_invalid_size(arr, rval):
- setattr(test, arr, rval)
-
- # assignment of 3,4,4 or 3,3,5 should raise ex
- for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
- rval= make_random_3d_array((3, 4, 4), func)
- self.assertRaises(ValueError, assign_invalid_size, arr, rval)
-
- rval= make_random_3d_array((3, 3, 5), func)
- self.assertRaises(ValueError, assign_invalid_size, arr, rval)
-
- rval= make_random_3d_array((3, 3, 3), func)
- self.assertRaises(ValueError, assign_invalid_size, arr, rval)
-
- def test_assign_item(self):
- # arr[i] = x
- for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
- rval= make_random_2d_array((4, 5), func)
-
- for i in range(3):
- getattr(test, arr)[i] = rval
- self.assertEqual(prop_to_list(getattr(test, arr)[i]), rval)
-
- # arr[i][j] = x
- for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
-
- arr= getattr(test, arr)
- rval= make_random_array(5, func)
-
- for i in range(3):
- for j in range(4):
- arr[i][j] = rval
- self.assertEqual(prop_to_list(arr[i][j]), rval)
-
-
- def test_assign_item_fail(self):
- def assign_wrong_size(arr, i, rval):
- getattr(test, arr)[i] = rval
-
- # assign wrong size at level 2
- for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
- rval1= make_random_2d_array((3, 5), func)
- rval2= make_random_2d_array((4, 3), func)
-
- for i in range(3):
- self.assertRaises(ValueError, assign_wrong_size, arr, i, rval1)
- self.assertRaises(ValueError, assign_wrong_size, arr, i, rval2)
-
- def test_dynamic_assign_array(self):
- for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
- # assignment of [3][4][5]
- rval= make_random_3d_array((3, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- # [2][4][5]
- rval= make_random_3d_array((2, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
- # [1][4][5]
- rval= make_random_3d_array((1, 4, 5), func)
- setattr(test, arr, rval)
- self.assertEqual(prop_to_list(getattr(test, arr)), rval)
-
-
- # test access
- def test_access(self):
- pass
-
- # test slice access, negative indices
- def test_access_fail(self):
- pass
-
-random.seed()
-
-def rand_int():
- return random.randint(-1000, 1000)
-
-def rand_float():
- return float(rand_int())
-
-def rand_bool():
- return bool(random.randint(0, 1))
-
-def make_random_array(len, rand_func):
- arr= []
- for i in range(len):
- arr.append(rand_func())
-
- return arr
-
-def make_random_2d_array(dimsize, rand_func):
- marr= []
- for i in range(dimsize[0]):
- marr.append([])
-
- for j in range(dimsize[1]):
- marr[-1].append(rand_func())
-
- return marr
-
-def make_random_3d_array(dimsize, rand_func):
- marr= []
- for i in range(dimsize[0]):
- marr.append([])
-
- for j in range(dimsize[1]):
- marr[-1].append([])
-
- for k in range(dimsize[2]):
- marr[-1][-1].append(rand_func())
-
- return marr
-
-def prop_to_list(prop):
- ret= []
-
- for x in prop:
- if type(x) not in (bool, int, float):
- ret.append(prop_to_list(x))
- else:
- ret.append(x)
-
- return ret
-
-def suite():
- return unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(TestArray), unittest.TestLoader().loadTestsFromTestCase(TestMArray)])
-
-if __name__ == "__main__":
- unittest.TextTestRunner(verbosity=2).run(suite())
-
diff --git a/source/tests/rna_info_dump.py b/source/tests/rna_info_dump.py
deleted file mode 100644
index 40d7b7c38a6..00000000000
--- a/source/tests/rna_info_dump.py
+++ /dev/null
@@ -1,131 +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 #####
-
-# <pep8 compliant>
-
-# Used for generating API diffs between releases
-# ./blender.bin --background -noaudio --python source/tests/rna_info_dump.py
-
-import bpy
-
-
-def api_dump(use_properties=True, use_functions=True):
-
- def prop_type(prop):
- if prop.type == "pointer":
- return prop.fixed_type.identifier
- else:
- return prop.type
-
- def func_to_str(struct_id_str, func_id, func):
-
- args = []
- for prop in func.args:
- data_str = "%s %s" % (prop_type(prop), prop.identifier)
- if prop.array_length:
- data_str += "[%d]" % prop.array_length
- if not prop.is_required:
- data_str += "=%s" % prop.default_str
- args.append(data_str)
-
- data_str = "%s.%s(%s)" % (struct_id_str, func_id, ", ".join(args))
- if func.return_values:
- return_args = ", ".join(prop_type(arg) for arg in func.return_values)
- if len(func.return_values) > 1:
- data_str += " --> (%s)" % return_args
- else:
- data_str += " --> %s" % return_args
- return data_str
-
- def prop_to_str(struct_id_str, prop_id, prop):
-
- prop_str = " <-- %s" % prop_type(prop)
- if prop.array_length:
- prop_str += "[%d]" % prop.array_length
-
- data_str = "%s.%s %s" % (struct_id_str, prop_id, prop_str)
- return data_str
-
- def struct_full_id(v):
- struct_id_str = v.identifier # "".join(sid for sid in struct_id if struct_id)
-
- for base in v.get_bases():
- struct_id_str = base.identifier + "|" + struct_id_str
-
- return struct_id_str
-
- def dump_funcs():
- data = []
- for struct_id, v in sorted(struct.items()):
- struct_id_str = struct_full_id(v)
-
- funcs = [(func.identifier, func) for func in v.functions]
-
- for func_id, func in funcs:
- data.append(func_to_str(struct_id_str, func_id, func))
-
- for prop in v.properties:
- if prop.collection_type:
- funcs = [(prop.identifier + "." + func.identifier, func) for func in prop.collection_type.functions]
- for func_id, func in funcs:
- data.append(func_to_str(struct_id_str, func_id, func))
- data.sort()
- data.append("# * functions *")
- return data
-
- def dump_props():
- data = []
- for struct_id, v in sorted(struct.items()):
- struct_id_str = struct_full_id(v)
-
- props = [(prop.identifier, prop) for prop in v.properties]
-
- for prop_id, prop in props:
- data.append(prop_to_str(struct_id_str, prop_id, prop))
-
- for prop in v.properties:
- if prop.collection_type:
- props = [(prop.identifier + "." + prop_sub.identifier, prop_sub) for prop_sub in prop.collection_type.properties]
- for prop_sub_id, prop_sub in props:
- data.append(prop_to_str(struct_id_str, prop_sub_id, prop_sub))
- data.sort()
- data.insert(0, "# * properties *")
- return data
-
- import rna_info
- struct = rna_info.BuildRNAInfo()[0]
- data = []
-
- if use_functions:
- data.extend(dump_funcs())
-
- if use_properties:
- data.extend(dump_props())
-
- if bpy.app.background:
- import sys
- sys.stderr.write("\n".join(data))
- sys.stderr.write("\n\nEOF\n")
- else:
- text = bpy.data.texts.new(name="api.py")
- text.from_string(data)
-
- print("END")
-
-if __name__ == "__main__":
- api_dump()
diff --git a/source/tests/rst_to_doctree_mini.py b/source/tests/rst_to_doctree_mini.py
deleted file mode 100644
index 6a885a108f8..00000000000
--- a/source/tests/rst_to_doctree_mini.py
+++ /dev/null
@@ -1,90 +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 #####
-
-# <pep8 compliant>
-
-# Module with function to extract a doctree from an reStructuredText file.
-# Named 'Mini' because we only parse the minimum data needed to check
-# Python classes, methods and attributes match up to those in existing modules.
-# (To test for documentation completeness)
-
-# note: literalinclude's are not followed.
-# could be nice to add but not really needed either right now.
-
-import collections
-
-Directive = collections.namedtuple('Directive',
- ("type",
- "value",
- "value_strip",
- "line",
- "indent",
- "members"))
-
-
-def parse_rst_py(filepath):
- import re
-
- # Get the prefix assuming the line is lstrip()'d
- # ..foo:: bar
- # -->
- # ("foo", "bar")
- re_prefix = re.compile(r"^\.\.\s([a-zA-Z09\-]+)::\s*(.*)\s*$")
-
- tree = collections.defaultdict(list)
- indent_map = {}
- indent_prev = 0
- f = open(filepath, encoding="utf-8")
- for i, line in enumerate(f):
- line_strip = line.lstrip()
- # ^\.\.\s[a-zA-Z09\-]+::.*$
- #if line.startswith(".. "):
- march = re_prefix.match(line_strip)
-
- if march:
- directive, value = march.group(1, 2)
- indent = len(line) - len(line_strip)
- value_strip = value.replace("(", " ").split()
- value_strip = value_strip[0] if value_strip else ""
-
- item = Directive(type=directive,
- value=value,
- value_strip=value_strip,
- line=i,
- indent=indent,
- members=[])
-
- tree[indent].append(item)
- if indent_prev < indent:
- indent_map[indent] = indent_prev
- if indent > 0:
- tree[indent_map[indent]][-1].members.append(item)
- indent_prev = indent
- f.close()
-
- return tree[0]
-
-
-if __name__ == "__main__":
- # not intended use, but may as well print rst files passed as a test.
- import sys
- for arg in sys.argv:
- if arg.lower().endswith((".txt", ".rst")):
- items = parse_rst_py(arg)
- for i in items:
- print(i)