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:
authorLukas Tönne <lukas.toenne@gmail.com>2015-02-10 19:09:00 +0300
committerLukas Tönne <lukas.toenne@gmail.com>2015-02-10 19:09:00 +0300
commite89fd502d7b1ee5a4c17286a78ae0116f03510b7 (patch)
tree5c68b5cb560b3cc5ba62046167d364b2183abb11 /source
parent6cd3ebfc9fa4838a74192f2e5cc82b5d5d2e6fe7 (diff)
parent227a94077f508a47fe7595b9091ab86aecde4ad5 (diff)
Merge branch 'master' into alembic_pointcache
Conflicts: CMakeLists.txt build_files/build_environment/install_deps.sh source/blender/blenkernel/CMakeLists.txt source/blender/blenkernel/SConscript source/blender/blenkernel/intern/particle.c source/blender/blenkernel/intern/pointcache.c source/blender/editors/physics/particle_edit.c source/blender/editors/space_outliner/outliner_draw.c source/blender/makesdna/DNA_modifier_types.h source/blender/makesrna/SConscript source/blender/makesrna/intern/CMakeLists.txt source/blender/makesrna/intern/SConscript source/blender/makesrna/intern/rna_modifier.c source/blender/makesrna/intern/rna_object_force.c source/blender/modifiers/MOD_modifiertypes.h source/blender/modifiers/intern/MOD_util.c source/blender/render/intern/source/voxeldata.c
Diffstat (limited to 'source')
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/SConscript1
-rw-r--r--source/blender/blenfont/intern/blf.c39
-rw-r--r--source/blender/blenfont/intern/blf_lang.c33
-rw-r--r--source/blender/blenfont/intern/blf_translation.c2
-rw-r--r--source/blender/blenkernel/BKE_DerivedMesh.h9
-rw-r--r--source/blender/blenkernel/BKE_animsys.h18
-rw-r--r--source/blender/blenkernel/BKE_blender.h4
-rw-r--r--source/blender/blenkernel/BKE_cdderivedmesh.h5
-rw-r--r--source/blender/blenkernel/BKE_cloth.h81
-rw-r--r--source/blender/blenkernel/BKE_collision.h4
-rw-r--r--source/blender/blenkernel/BKE_curve.h1
-rw-r--r--source/blender/blenkernel/BKE_customdata.h2
-rw-r--r--source/blender/blenkernel/BKE_customdata_file.h12
-rw-r--r--source/blender/blenkernel/BKE_data_transfer.h5
-rw-r--r--source/blender/blenkernel/BKE_effect.h85
-rw-r--r--source/blender/blenkernel/BKE_global.h5
-rw-r--r--source/blender/blenkernel/BKE_group.h1
-rw-r--r--source/blender/blenkernel/BKE_image.h29
-rw-r--r--source/blender/blenkernel/BKE_library.h4
-rw-r--r--source/blender/blenkernel/BKE_mesh.h59
-rw-r--r--source/blender/blenkernel/BKE_mesh_remap.h4
-rw-r--r--source/blender/blenkernel/BKE_object.h1
-rw-r--r--source/blender/blenkernel/BKE_particle.h64
-rw-r--r--source/blender/blenkernel/BKE_pointcache.h1
-rw-r--r--source/blender/blenkernel/BKE_scene.h1
-rw-r--r--source/blender/blenkernel/BKE_screen.h3
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h4
-rw-r--r--source/blender/blenkernel/CMakeLists.txt6
-rw-r--r--source/blender/blenkernel/SConscript1
-rw-r--r--source/blender/blenkernel/intern/DerivedMesh.c79
-rw-r--r--source/blender/blenkernel/intern/action.c6
-rw-r--r--source/blender/blenkernel/intern/anim_sys.c132
-rw-r--r--source/blender/blenkernel/intern/appdir.c4
-rw-r--r--source/blender/blenkernel/intern/armature.c10
-rw-r--r--source/blender/blenkernel/intern/blender.c68
-rw-r--r--source/blender/blenkernel/intern/boids.c2
-rw-r--r--source/blender/blenkernel/intern/bpath.c6
-rw-r--r--source/blender/blenkernel/intern/brush.c15
-rw-r--r--source/blender/blenkernel/intern/cdderivedmesh.c97
-rw-r--r--source/blender/blenkernel/intern/cloth.c308
-rw-r--r--source/blender/blenkernel/intern/collision.c560
-rw-r--r--source/blender/blenkernel/intern/constraint.c4
-rw-r--r--source/blender/blenkernel/intern/context.c4
-rw-r--r--source/blender/blenkernel/intern/curve.c43
-rw-r--r--source/blender/blenkernel/intern/customdata.c72
-rw-r--r--source/blender/blenkernel/intern/customdata_file.c14
-rw-r--r--source/blender/blenkernel/intern/data_transfer.c144
-rw-r--r--source/blender/blenkernel/intern/deform.c2
-rw-r--r--source/blender/blenkernel/intern/dynamicpaint.c8
-rw-r--r--source/blender/blenkernel/intern/editderivedmesh.c48
-rw-r--r--source/blender/blenkernel/intern/effect.c168
-rw-r--r--source/blender/blenkernel/intern/fcurve.c8
-rw-r--r--source/blender/blenkernel/intern/font.c2
-rw-r--r--source/blender/blenkernel/intern/group.c37
-rw-r--r--source/blender/blenkernel/intern/idprop.c2
-rw-r--r--source/blender/blenkernel/intern/image.c106
-rw-r--r--source/blender/blenkernel/intern/implicit.c1770
-rw-r--r--source/blender/blenkernel/intern/ipo.c23
-rw-r--r--source/blender/blenkernel/intern/library.c11
-rw-r--r--source/blender/blenkernel/intern/material.c44
-rw-r--r--source/blender/blenkernel/intern/mball.c16
-rw-r--r--source/blender/blenkernel/intern/mesh.c12
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c1205
-rw-r--r--source/blender/blenkernel/intern/mesh_remap.c50
-rw-r--r--source/blender/blenkernel/intern/mesh_validate.c4
-rw-r--r--source/blender/blenkernel/intern/movieclip.c2
-rw-r--r--source/blender/blenkernel/intern/multires.c3
-rw-r--r--source/blender/blenkernel/intern/node.c2
-rw-r--r--source/blender/blenkernel/intern/object.c5
-rw-r--r--source/blender/blenkernel/intern/object_dupli.c6
-rw-r--r--source/blender/blenkernel/intern/ocean.c2
-rw-r--r--source/blender/blenkernel/intern/particle.c1219
-rw-r--r--source/blender/blenkernel/intern/particle_child.c726
-rw-r--r--source/blender/blenkernel/intern/particle_distribute.c1419
-rw-r--r--source/blender/blenkernel/intern/particle_system.c1370
-rw-r--r--source/blender/blenkernel/intern/pbvh.c13
-rw-r--r--source/blender/blenkernel/intern/pointcache.c18
-rw-r--r--source/blender/blenkernel/intern/property.c54
-rw-r--r--source/blender/blenkernel/intern/rigidbody.c9
-rw-r--r--source/blender/blenkernel/intern/scene.c12
-rw-r--r--source/blender/blenkernel/intern/screen.c26
-rw-r--r--source/blender/blenkernel/intern/sequencer.c68
-rw-r--r--source/blender/blenkernel/intern/shrinkwrap.c4
-rw-r--r--source/blender/blenkernel/intern/smoke.c3
-rw-r--r--source/blender/blenkernel/intern/sound.c18
-rw-r--r--source/blender/blenkernel/intern/subsurf_ccg.c63
-rw-r--r--source/blender/blenkernel/intern/text.c104
-rw-r--r--source/blender/blenkernel/intern/texture.c11
-rw-r--r--source/blender/blenkernel/intern/tracking.c6
-rw-r--r--source/blender/blenkernel/intern/tracking_auto.c2
-rw-r--r--source/blender/blenkernel/intern/writeavi.c2
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c10
-rw-r--r--source/blender/blenkernel/intern/writeframeserver.c6
-rw-r--r--source/blender/blenlib/BLI_kdopbvh.h4
-rw-r--r--source/blender/blenlib/BLI_math_base.h19
-rw-r--r--source/blender/blenlib/BLI_math_color.h4
-rw-r--r--source/blender/blenlib/BLI_math_rotation.h5
-rw-r--r--source/blender/blenlib/BLI_math_vector.h2
-rw-r--r--source/blender/blenlib/BLI_path_util.h11
-rw-r--r--source/blender/blenlib/PIL_time.h8
-rw-r--r--source/blender/blenlib/intern/BLI_args.c2
-rw-r--r--source/blender/blenlib/intern/BLI_ghash.c2
-rw-r--r--source/blender/blenlib/intern/BLI_kdopbvh.c78
-rw-r--r--source/blender/blenlib/intern/boxpack2d.c45
-rw-r--r--source/blender/blenlib/intern/dynlib.c2
-rw-r--r--source/blender/blenlib/intern/fileops.c4
-rw-r--r--source/blender/blenlib/intern/listbase.c10
-rw-r--r--source/blender/blenlib/intern/math_color_inline.c20
-rw-r--r--source/blender/blenlib/intern/math_rotation.c34
-rw-r--r--source/blender/blenlib/intern/math_vector.c7
-rw-r--r--source/blender/blenlib/intern/path_util.c27
-rw-r--r--source/blender/blenlib/intern/polyfill2d_beautify.c5
-rw-r--r--source/blender/blenlib/intern/rand.c1
-rw-r--r--source/blender/blenlib/intern/storage.c8
-rw-r--r--source/blender/blenlib/intern/system.c2
-rw-r--r--source/blender/blenlib/intern/time.c18
-rw-r--r--source/blender/blenloader/BLO_readfile.h2
-rw-r--r--source/blender/blenloader/intern/readfile.c44
-rw-r--r--source/blender/blenloader/intern/versioning_250.c6
-rw-r--r--source/blender/blenloader/intern/versioning_260.c2
-rw-r--r--source/blender/blenloader/intern/versioning_270.c107
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c12
-rw-r--r--source/blender/blenloader/intern/writefile.c49
-rw-r--r--source/blender/bmesh/CMakeLists.txt1
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.c188
-rw-r--r--source/blender/bmesh/intern/bmesh_marking.h4
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c300
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h7
-rw-r--r--source/blender/bmesh/intern/bmesh_opdefines.c23
-rw-r--r--source/blender/bmesh/intern/bmesh_operators_private.h1
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.c22
-rw-r--r--source/blender/bmesh/intern/bmesh_polygon.h2
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.c8
-rw-r--r--source/blender/bmesh/intern/bmesh_queries.h6
-rw-r--r--source/blender/bmesh/operators/bmo_connect_concave.c219
-rw-r--r--source/blender/bmesh/operators/bmo_connect_nonplanar.c21
-rw-r--r--source/blender/bmesh/operators/bmo_dissolve.c2
-rw-r--r--source/blender/bmesh/operators/bmo_extrude.c6
-rw-r--r--source/blender/bmesh/operators/bmo_removedoubles.c2
-rw-r--r--source/blender/bmesh/operators/bmo_similar.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_intersect.c4
-rw-r--r--source/blender/bmesh/tools/bmesh_triangulate.c8
-rw-r--r--source/blender/collada/AnimationExporter.cpp88
-rw-r--r--source/blender/collada/AnimationImporter.cpp2
-rw-r--r--source/blender/collada/ArmatureExporter.cpp2
-rw-r--r--source/blender/collada/ArmatureImporter.cpp2
-rw-r--r--source/blender/collada/ControllerExporter.cpp2
-rw-r--r--source/blender/collada/EffectExporter.cpp16
-rw-r--r--source/blender/collada/ErrorHandler.cpp8
-rw-r--r--source/blender/collada/ImageExporter.cpp2
-rw-r--r--source/blender/collada/ImportSettings.cpp2
-rw-r--r--source/blender/collada/ImportSettings.h2
-rw-r--r--source/blender/collada/MeshImporter.cpp10
-rw-r--r--source/blender/compositor/CMakeLists.txt2
-rw-r--r--source/blender/compositor/COM_defines.h4
-rw-r--r--source/blender/compositor/intern/COM_ChannelInfo.h121
-rw-r--r--source/blender/compositor/intern/COM_ExecutionSystem.cpp16
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.cpp92
-rw-r--r--source/blender/compositor/intern/COM_MemoryBuffer.h139
-rw-r--r--source/blender/compositor/intern/COM_MemoryProxy.cpp3
-rw-r--r--source/blender/compositor/intern/COM_MemoryProxy.h9
-rw-r--r--source/blender/compositor/intern/COM_NodeOperationBuilder.cpp8
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.cpp36
-rw-r--r--source/blender/compositor/intern/COM_OpenCLDevice.h6
-rw-r--r--source/blender/compositor/intern/COM_WorkScheduler.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp8
-rw-r--r--source/blender/compositor/nodes/COM_SocketProxyNode.cpp5
-rw-r--r--source/blender/compositor/nodes/COM_TextureNode.cpp2
-rw-r--r--source/blender/compositor/nodes/COM_TranslateNode.cpp4
-rw-r--r--source/blender/compositor/operations/COM_AntiAliasOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_BokehBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_CompositorOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ConvertOperation.cpp20
-rw-r--r--source/blender/compositor/operations/COM_DilateErodeOperation.cpp23
-rw-r--r--source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp25
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp7
-rw-r--r--source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_GlareBaseOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp18
-rw-r--r--source/blender/compositor/operations/COM_GlareGhostOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_GlareStreaksOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_ImageOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_InpaintOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_KeyingBlurOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_KeyingClipOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MapUVOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_MovieClipOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_MultilayerImageOperation.cpp4
-rw-r--r--source/blender/compositor/operations/COM_NormalizeOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_OutputFileOperation.cpp10
-rw-r--r--source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp5
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp152
-rw-r--r--source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h49
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.cpp60
-rw-r--r--source/blender/compositor/operations/COM_PlaneTrackOperation.h9
-rw-r--r--source/blender/compositor/operations/COM_QualityStepHelper.cpp6
-rw-r--r--source/blender/compositor/operations/COM_ReadBufferOperation.cpp20
-rw-r--r--source/blender/compositor/operations/COM_ReadBufferOperation.h3
-rw-r--r--source/blender/compositor/operations/COM_RenderLayersProg.cpp54
-rw-r--r--source/blender/compositor/operations/COM_SetVectorOperation.cpp1
-rw-r--r--source/blender/compositor/operations/COM_SunBeamsOperation.cpp8
-rw-r--r--source/blender/compositor/operations/COM_TextureOperation.cpp20
-rw-r--r--source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp29
-rw-r--r--source/blender/compositor/operations/COM_VectorBlurOperation.cpp6
-rw-r--r--source/blender/compositor/operations/COM_VectorCurveOperation.cpp1
-rw-r--r--source/blender/compositor/operations/COM_WrapOperation.cpp2
-rw-r--r--source/blender/compositor/operations/COM_WrapOperation.h2
-rw-r--r--source/blender/compositor/operations/COM_WriteBufferOperation.cpp22
-rw-r--r--source/blender/compositor/operations/COM_WriteBufferOperation.h2
-rwxr-xr-xsource/blender/datatoc/datatoc_icon_split.py2
-rw-r--r--source/blender/editors/animation/anim_channels_defines.c15
-rw-r--r--source/blender/editors/animation/anim_draw.c6
-rw-r--r--source/blender/editors/animation/anim_markers.c9
-rw-r--r--source/blender/editors/animation/fmodifier_ui.c6
-rw-r--r--source/blender/editors/animation/keyframes_edit.c8
-rw-r--r--source/blender/editors/animation/keyframes_general.c8
-rw-r--r--source/blender/editors/animation/keyingsets.c49
-rw-r--r--source/blender/editors/armature/armature_add.c2
-rw-r--r--source/blender/editors/armature/armature_edit.c74
-rw-r--r--source/blender/editors/armature/armature_naming.c7
-rw-r--r--source/blender/editors/armature/armature_relations.c158
-rw-r--r--source/blender/editors/armature/armature_select.c2
-rw-r--r--source/blender/editors/armature/editarmature_retarget.c6
-rw-r--r--source/blender/editors/armature/editarmature_sketch.c4
-rw-r--r--source/blender/editors/armature/pose_lib.c2
-rw-r--r--source/blender/editors/armature/pose_utils.c2
-rw-r--r--source/blender/editors/curve/editcurve.c611
-rw-r--r--source/blender/editors/curve/editcurve_add.c6
-rw-r--r--source/blender/editors/gpencil/editaction_gpencil.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c51
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c23
-rw-r--r--source/blender/editors/gpencil/gpencil_select.c11
-rw-r--r--source/blender/editors/gpencil/gpencil_undo.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c53
-rw-r--r--source/blender/editors/include/BIF_gl.h10
-rw-r--r--source/blender/editors/include/ED_gpencil.h6
-rw-r--r--source/blender/editors/include/ED_image.h3
-rw-r--r--source/blender/editors/include/ED_object.h6
-rw-r--r--source/blender/editors/include/ED_screen.h2
-rw-r--r--source/blender/editors/include/ED_view3d.h1
-rw-r--r--source/blender/editors/include/UI_icons.h12
-rw-r--r--source/blender/editors/include/UI_interface.h25
-rw-r--r--source/blender/editors/include/UI_resources.h2
-rw-r--r--source/blender/editors/interface/interface.c2
-rw-r--r--source/blender/editors/interface/interface_draw.c55
-rw-r--r--source/blender/editors/interface/interface_eyedropper.c240
-rw-r--r--source/blender/editors/interface/interface_handlers.c156
-rw-r--r--source/blender/editors/interface/interface_intern.h1
-rw-r--r--source/blender/editors/interface/interface_layout.c19
-rw-r--r--source/blender/editors/interface/interface_ops.c4
-rw-r--r--source/blender/editors/interface/interface_panel.c4
-rw-r--r--source/blender/editors/interface/interface_regions.c5
-rw-r--r--source/blender/editors/interface/interface_style.c119
-rw-r--r--source/blender/editors/interface/interface_templates.c5
-rw-r--r--source/blender/editors/interface/interface_widgets.c63
-rw-r--r--source/blender/editors/interface/resources.c59
-rw-r--r--source/blender/editors/interface/view2d.c6
-rw-r--r--source/blender/editors/interface/view2d_ops.c53
-rw-r--r--source/blender/editors/mesh/editmesh_add.c11
-rw-r--r--source/blender/editors/mesh/editmesh_knife.c4
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c36
-rw-r--r--source/blender/editors/mesh/mesh_data.c66
-rw-r--r--source/blender/editors/mesh/mesh_intern.h3
-rw-r--r--source/blender/editors/mesh/mesh_ops.c3
-rw-r--r--source/blender/editors/mesh/meshtools.c2
-rw-r--r--source/blender/editors/object/object_add.c22
-rw-r--r--source/blender/editors/object/object_bake_api.c2
-rw-r--r--source/blender/editors/object/object_constraint.c2
-rw-r--r--source/blender/editors/object/object_data_transfer.c12
-rw-r--r--source/blender/editors/object/object_edit.c6
-rw-r--r--source/blender/editors/object/object_group.c53
-rw-r--r--source/blender/editors/object/object_hook.c14
-rw-r--r--source/blender/editors/object/object_modifier.c16
-rw-r--r--source/blender/editors/object/object_relations.c12
-rw-r--r--source/blender/editors/object/object_vgroup.c2
-rw-r--r--source/blender/editors/physics/particle_edit.c212
-rw-r--r--source/blender/editors/physics/particle_object.c495
-rw-r--r--source/blender/editors/physics/physics_intern.h3
-rw-r--r--source/blender/editors/physics/physics_ops.c3
-rw-r--r--source/blender/editors/render/render_opengl.c15
-rw-r--r--source/blender/editors/render/render_preview.c4
-rw-r--r--source/blender/editors/render/render_shading.c2
-rw-r--r--source/blender/editors/render/render_view.c23
-rw-r--r--source/blender/editors/screen/area.c3
-rw-r--r--source/blender/editors/screen/glutil.c6
-rw-r--r--source/blender/editors/screen/screen_context.c4
-rw-r--r--source/blender/editors/screen/screen_edit.c37
-rw-r--r--source/blender/editors/screen/screen_ops.c61
-rw-r--r--source/blender/editors/screen/screendump.c5
-rw-r--r--source/blender/editors/sculpt_paint/paint_cursor.c16
-rw-r--r--source/blender/editors/sculpt_paint/paint_curve.c2
-rw-r--r--source/blender/editors/sculpt_paint/paint_image.c11
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_proj.c1039
-rw-r--r--source/blender/editors/sculpt_paint/paint_ops.c9
-rw-r--r--source/blender/editors/sculpt_paint/paint_stroke.c86
-rw-r--r--source/blender/editors/sculpt_paint/paint_undo.c6
-rw-r--r--source/blender/editors/sculpt_paint/paint_utils.c14
-rw-r--r--source/blender/editors/sculpt_paint/sculpt.c12
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c8
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_uv.c16
-rw-r--r--source/blender/editors/sound/sound_ops.c8
-rw-r--r--source/blender/editors/space_buttons/buttons_texture.c2
-rw-r--r--source/blender/editors/space_clip/clip_buttons.c2
-rw-r--r--source/blender/editors/space_clip/clip_ops.c3
-rw-r--r--source/blender/editors/space_console/console_ops.c6
-rw-r--r--source/blender/editors/space_file/file_draw.c15
-rw-r--r--source/blender/editors/space_file/file_ops.c10
-rw-r--r--source/blender/editors/space_file/filelist.c45
-rw-r--r--source/blender/editors/space_file/filesel.c2
-rw-r--r--source/blender/editors/space_file/fsmenu.c8
-rw-r--r--source/blender/editors/space_graph/graph_draw.c4
-rw-r--r--source/blender/editors/space_graph/graph_edit.c2
-rw-r--r--source/blender/editors/space_graph/graph_select.c66
-rw-r--r--source/blender/editors/space_image/image_buttons.c45
-rw-r--r--source/blender/editors/space_image/image_edit.c15
-rw-r--r--source/blender/editors/space_image/space_image.c4
-rw-r--r--source/blender/editors/space_logic/logic_ops.c9
-rw-r--r--source/blender/editors/space_logic/logic_window.c88
-rw-r--r--source/blender/editors/space_nla/nla_channels.c2
-rw-r--r--source/blender/editors/space_node/drawnode.c98
-rw-r--r--source/blender/editors/space_node/node_draw.c5
-rw-r--r--source/blender/editors/space_node/node_edit.c2
-rw-r--r--source/blender/editors/space_node/space_node.c8
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c101
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c173
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h5
-rw-r--r--source/blender/editors/space_outliner/outliner_ops.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c7
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c108
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c42
-rw-r--r--source/blender/editors/space_outliner/space_outliner.c56
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c49
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c242
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c1
-rw-r--r--source/blender/editors/space_sequencer/sequencer_preview.c6
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c2
-rw-r--r--source/blender/editors/space_sequencer/space_sequencer.c17
-rw-r--r--source/blender/editors/space_text/text_autocomplete.c10
-rw-r--r--source/blender/editors/space_text/text_draw.c3
-rw-r--r--source/blender/editors/space_text/text_ops.c10
-rw-r--r--source/blender/editors/space_time/space_time.c16
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/drawarmature.c2
-rw-r--r--source/blender/editors/space_view3d/drawobject.c158
-rw-r--r--source/blender/editors/space_view3d/drawsimdebug.c173
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c40
-rw-r--r--source/blender/editors/space_view3d/view3d_draw.c122
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c10
-rw-r--r--source/blender/editors/space_view3d/view3d_intern.h5
-rw-r--r--source/blender/editors/space_view3d/view3d_ops.c4
-rw-r--r--source/blender/editors/space_view3d/view3d_toolbar.c2
-rw-r--r--source/blender/editors/transform/transform.c233
-rw-r--r--source/blender/editors/transform/transform.h19
-rw-r--r--source/blender/editors/transform/transform_constraints.c2
-rw-r--r--source/blender/editors/transform/transform_conversions.c18
-rw-r--r--source/blender/editors/transform/transform_generics.c31
-rw-r--r--source/blender/editors/transform/transform_manipulator.c2
-rw-r--r--source/blender/editors/transform/transform_ops.c2
-rw-r--r--source/blender/editors/util/ed_util.c2
-rw-r--r--source/blender/editors/util/editmode_undo.c6
-rw-r--r--source/blender/editors/util/undo.c2
-rw-r--r--source/blender/editors/uvedit/uvedit_parametrizer.c6
-rw-r--r--source/blender/editors/uvedit/uvedit_smart_stitch.c11
-rw-r--r--source/blender/editors/uvedit/uvedit_unwrap_ops.c2
-rw-r--r--source/blender/freestyle/intern/application/Controller.cpp4
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp11
-rw-r--r--source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h2
-rw-r--r--source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp2
-rw-r--r--source/blender/freestyle/intern/python/BPy_Freestyle.cpp36
-rw-r--r--source/blender/freestyle/intern/python/BPy_ViewShape.cpp14
-rw-r--r--source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp2
-rw-r--r--source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h16
-rw-r--r--source/blender/freestyle/intern/scene_graph/SceneHash.cpp17
-rw-r--r--source/blender/freestyle/intern/stroke/Canvas.h6
-rw-r--r--source/blender/freestyle/intern/stroke/StrokeRep.cpp2
-rw-r--r--source/blender/gpu/GPU_material.h86
-rw-r--r--source/blender/gpu/intern/gpu_buffers.c6
-rw-r--r--source/blender/gpu/intern/gpu_codegen.c231
-rw-r--r--source/blender/gpu/intern/gpu_codegen.h72
-rw-r--r--source/blender/gpu/intern/gpu_draw.c6
-rw-r--r--source/blender/gpu/intern/gpu_material.c56
-rw-r--r--source/blender/gpu/intern/gpu_select.c12
-rw-r--r--source/blender/gpu/shaders/gpu_shader_material.glsl19
-rw-r--r--source/blender/imbuf/IMB_imbuf.h6
-rw-r--r--source/blender/imbuf/IMB_imbuf_types.h4
-rw-r--r--source/blender/imbuf/intern/IMB_metadata.h7
-rw-r--r--source/blender/imbuf/intern/anim_movie.c24
-rw-r--r--source/blender/imbuf/intern/bmp.c90
-rw-r--r--source/blender/imbuf/intern/cineon/dpxlib.c6
-rw-r--r--source/blender/imbuf/intern/colormanagement.c18
-rw-r--r--source/blender/imbuf/intern/divers.c10
-rw-r--r--source/blender/imbuf/intern/indexer.c69
-rw-r--r--source/blender/imbuf/intern/jpeg.c46
-rw-r--r--source/blender/imbuf/intern/metadata.c105
-rw-r--r--source/blender/imbuf/intern/moviecache.c45
-rw-r--r--source/blender/imbuf/intern/openexr/openexr_api.cpp17
-rw-r--r--source/blender/imbuf/intern/png.c30
-rw-r--r--source/blender/imbuf/intern/thumbs_blend.c2
-rw-r--r--source/blender/imbuf/intern/tiff.c6
-rw-r--r--source/blender/makesdna/DNA_ID.h2
-rw-r--r--source/blender/makesdna/DNA_action_types.h2
-rw-r--r--source/blender/makesdna/DNA_anim_types.h14
-rw-r--r--source/blender/makesdna/DNA_camera_types.h5
-rw-r--r--source/blender/makesdna/DNA_cloth_types.h15
-rw-r--r--source/blender/makesdna/DNA_customdata_types.h11
-rw-r--r--source/blender/makesdna/DNA_fileglobal_types.h4
-rw-r--r--source/blender/makesdna/DNA_image_types.h1
-rw-r--r--source/blender/makesdna/DNA_material_types.h1
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h68
-rw-r--r--source/blender/makesdna/DNA_node_types.h13
-rw-r--r--source/blender/makesdna/DNA_particle_types.h117
-rw-r--r--source/blender/makesdna/DNA_scene_types.h22
-rw-r--r--source/blender/makesdna/DNA_screen_types.h16
-rw-r--r--source/blender/makesdna/DNA_sequence_types.h7
-rw-r--r--source/blender/makesdna/DNA_sound_types.h4
-rw-r--r--source/blender/makesdna/DNA_space_types.h13
-rw-r--r--source/blender/makesdna/DNA_texture_types.h11
-rw-r--r--source/blender/makesdna/DNA_userdef_types.h5
-rw-r--r--source/blender/makesdna/DNA_view3d_types.h13
-rw-r--r--source/blender/makesrna/RNA_access.h2
-rw-r--r--source/blender/makesrna/SConscript1
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt23
-rw-r--r--source/blender/makesrna/intern/SConscript1
-rw-r--r--source/blender/makesrna/intern/makesrna.c68
-rw-r--r--source/blender/makesrna/intern/rna_access.c22
-rw-r--r--source/blender/makesrna/intern/rna_action.c2
-rw-r--r--source/blender/makesrna/intern/rna_actuator.c14
-rw-r--r--source/blender/makesrna/intern/rna_animation.c65
-rw-r--r--source/blender/makesrna/intern/rna_camera.c23
-rw-r--r--source/blender/makesrna/intern/rna_cloth.c96
-rw-r--r--source/blender/makesrna/intern/rna_color.c9
-rw-r--r--source/blender/makesrna/intern/rna_controller.c11
-rw-r--r--source/blender/makesrna/intern/rna_define.c42
-rw-r--r--source/blender/makesrna/intern/rna_fcurve.c4
-rw-r--r--source/blender/makesrna/intern/rna_fcurve_api.c108
-rw-r--r--source/blender/makesrna/intern/rna_image.c9
-rw-r--r--source/blender/makesrna/intern/rna_image_api.c29
-rw-r--r--source/blender/makesrna/intern/rna_internal.h3
-rw-r--r--source/blender/makesrna/intern/rna_material.c2
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c35
-rw-r--r--source/blender/makesrna/intern/rna_mesh_api.c127
-rw-r--r--source/blender/makesrna/intern/rna_mesh_utils.h2
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c169
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c59
-rw-r--r--source/blender/makesrna/intern/rna_object.c4
-rw-r--r--source/blender/makesrna/intern/rna_particle.c136
-rw-r--r--source/blender/makesrna/intern/rna_property.c11
-rw-r--r--source/blender/makesrna/intern/rna_render.c2
-rw-r--r--source/blender/makesrna/intern/rna_rna.c8
-rw-r--r--source/blender/makesrna/intern/rna_scene.c79
-rw-r--r--source/blender/makesrna/intern/rna_scene_api.c11
-rw-r--r--source/blender/makesrna/intern/rna_screen.c5
-rw-r--r--source/blender/makesrna/intern/rna_sculpt_paint.c9
-rw-r--r--source/blender/makesrna/intern/rna_sensor.c14
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c17
-rw-r--r--source/blender/makesrna/intern/rna_sound.c2
-rw-r--r--source/blender/makesrna/intern/rna_sound_api.c73
-rw-r--r--source/blender/makesrna/intern/rna_space.c53
-rw-r--r--source/blender/makesrna/intern/rna_texture.c23
-rw-r--r--source/blender/makesrna/intern/rna_texture_api.c2
-rw-r--r--source/blender/makesrna/intern/rna_ui.c4
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c12
-rw-r--r--source/blender/makesrna/intern/rna_vfont.c2
-rw-r--r--source/blender/makesrna/intern/rna_vfont_api.c73
-rw-r--r--source/blender/makesrna/intern/rna_wm.c2
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h1
-rw-r--r--source/blender/modifiers/intern/MOD_array.c2
-rw-r--r--source/blender/modifiers/intern/MOD_build.c13
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c9
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c222
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c6
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c33
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache_pc2.c2
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c501
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c49
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c32
-rw-r--r--source/blender/modifiers/intern/MOD_util.c3
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c55
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_image.c2
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c3
-rw-r--r--source/blender/nodes/intern/node_socket.c2
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_gamma.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geom.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_geometry.c1
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_lamp.c6
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c4
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_tex_coord.c6
-rw-r--r--source/blender/nodes/texture/nodes/node_texture_math.c4
-rw-r--r--source/blender/physics/BPH_mass_spring.h62
-rw-r--r--source/blender/physics/CMakeLists.txt53
-rw-r--r--source/blender/physics/SConscript44
-rw-r--r--source/blender/physics/intern/BPH_mass_spring.cpp1017
-rw-r--r--source/blender/physics/intern/ConstrainedConjugateGradient.h294
-rw-r--r--source/blender/physics/intern/eigen_utils.h230
-rw-r--r--source/blender/physics/intern/hair_volume.cpp1154
-rw-r--r--source/blender/physics/intern/implicit.h184
-rw-r--r--source/blender/physics/intern/implicit_blender.c2031
-rw-r--r--source/blender/physics/intern/implicit_eigen.cpp1369
-rw-r--r--source/blender/python/generic/bpy_internal_import.c4
-rw-r--r--source/blender/python/intern/bpy_app.c1
-rw-r--r--source/blender/python/intern/bpy_app_translations.c2
-rw-r--r--source/blender/python/mathutils/CMakeLists.txt2
-rw-r--r--source/blender/python/mathutils/mathutils.c21
-rw-r--r--source/blender/python/mathutils/mathutils_Color.c7
-rw-r--r--source/blender/python/mathutils/mathutils_Euler.c9
-rw-r--r--source/blender/python/mathutils/mathutils_Matrix.c9
-rw-r--r--source/blender/python/mathutils/mathutils_Quaternion.c69
-rw-r--r--source/blender/python/mathutils/mathutils_Vector.c7
-rw-r--r--source/blender/python/mathutils/mathutils_geometry.c28
-rw-r--r--source/blender/python/mathutils/mathutils_interpolate.c137
-rw-r--r--source/blender/python/mathutils/mathutils_interpolate.h (renamed from source/blender/compositor/intern/COM_ChannelInfo.cpp)27
-rw-r--r--source/blender/render/CMakeLists.txt1
-rw-r--r--source/blender/render/SConscript1
-rw-r--r--source/blender/render/extern/include/RE_render_ext.h2
-rw-r--r--source/blender/render/extern/include/RE_shader_ext.h4
-rw-r--r--source/blender/render/intern/include/envmap.h2
-rw-r--r--source/blender/render/intern/include/render_types.h1
-rw-r--r--source/blender/render/intern/include/texture.h4
-rw-r--r--source/blender/render/intern/source/bake_api.c2
-rw-r--r--source/blender/render/intern/source/convertblender.c16
-rw-r--r--source/blender/render/intern/source/envmap.c10
-rw-r--r--source/blender/render/intern/source/imagetexture.c14
-rw-r--r--source/blender/render/intern/source/initrender.c2
-rw-r--r--source/blender/render/intern/source/pipeline.c23
-rw-r--r--source/blender/render/intern/source/pixelshading.c6
-rw-r--r--source/blender/render/intern/source/pointdensity.c2
-rw-r--r--source/blender/render/intern/source/rayshade.c2
-rw-r--r--source/blender/render/intern/source/render_result.c69
-rw-r--r--source/blender/render/intern/source/render_texture.c102
-rw-r--r--source/blender/render/intern/source/renderdatabase.c8
-rw-r--r--source/blender/render/intern/source/shadeoutput.c2
-rw-r--r--source/blender/render/intern/source/sss.c8
-rw-r--r--source/blender/render/intern/source/sunsky.c8
-rw-r--r--source/blender/render/intern/source/voxeldata.c27
-rw-r--r--source/blender/windowmanager/WM_types.h2
-rw-r--r--source/blender/windowmanager/intern/wm.c14
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c41
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c21
-rw-r--r--source/blender/windowmanager/intern/wm_files.c22
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c152
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c36
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c2
-rw-r--r--source/blender/windowmanager/wm_event_system.h3
-rw-r--r--source/blender/windowmanager/wm_event_types.h21
-rw-r--r--source/blenderplayer/CMakeLists.txt1
-rw-r--r--source/blenderplayer/bad_level_call_stubs/stubs.c7
-rw-r--r--source/creator/CMakeLists.txt5
-rw-r--r--source/creator/creator.c9
-rw-r--r--source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp2
-rw-r--r--source/gameengine/GameLogic/SCA_IInputDevice.h2
-rw-r--r--source/gameengine/GameLogic/SCA_IObject.h2
-rw-r--r--source/gameengine/GameLogic/SCA_IScene.cpp2
-rw-r--r--source/gameengine/GameLogic/SCA_ISensor.h2
-rw-r--r--source/gameengine/GameLogic/SCA_JoystickSensor.cpp12
-rw-r--r--source/gameengine/GameLogic/SCA_LogicManager.h2
-rw-r--r--source/gameengine/GamePlayer/common/GPC_Canvas.cpp2
-rw-r--r--source/gameengine/Ketsji/BL_ActionManager.h2
-rw-r--r--source/gameengine/Ketsji/BL_BlenderShader.cpp2
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.cpp46
-rw-r--r--source/gameengine/Ketsji/KX_GameObject.h2
-rw-r--r--source/gameengine/Ketsji/KX_PyConstraintBinding.cpp140
-rw-r--r--source/gameengine/Ketsji/KX_PyConstraintBinding.h3
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.cpp380
-rw-r--r--source/gameengine/Ketsji/KX_PythonInit.h23
-rw-r--r--source/gameengine/Ketsji/KX_PythonInitTypes.cpp39
-rw-r--r--source/gameengine/Ketsji/KX_PythonInitTypes.h3
-rw-r--r--source/gameengine/Ketsji/KX_TouchEventManager.cpp24
-rw-r--r--source/gameengine/Ketsji/KX_TouchEventManager.h24
-rw-r--r--source/gameengine/Ketsji/KX_VehicleWrapper.cpp76
-rw-r--r--source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp155
-rw-r--r--source/gameengine/VideoTexture/ImageBase.cpp30
-rw-r--r--source/gameengine/VideoTexture/blendVideoTex.cpp27
579 files changed, 23152 insertions, 8969 deletions
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index e2bf5930275..52273ce3047 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -103,6 +103,7 @@ add_subdirectory(render)
add_subdirectory(blenfont)
add_subdirectory(blenloader)
add_subdirectory(ikplugin)
+add_subdirectory(physics)
add_subdirectory(gpu)
add_subdirectory(imbuf)
add_subdirectory(nodes)
diff --git a/source/blender/SConscript b/source/blender/SConscript
index 34de8a16cf1..a0ad4576e57 100644
--- a/source/blender/SConscript
+++ b/source/blender/SConscript
@@ -41,6 +41,7 @@ SConscript(['avi/SConscript',
'nodes/SConscript',
'modifiers/SConscript',
'ikplugin/SConscript',
+ 'physics/SConscript',
'windowmanager/SConscript',
'blenfont/SConscript',
'pointcache/SConscript'])
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index cdccbe044bb..127826f98c8 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -63,6 +63,9 @@
*/
#define BLF_MAX_FONT 16
+/* call BLF_default_set first! */
+#define ASSERT_DEFAULT_SET BLI_assert(global_font_default != -1)
+
/* Font array. */
static FontBLF *global_font[BLF_MAX_FONT] = {NULL};
@@ -134,7 +137,7 @@ static int blf_search(const char *name)
for (i = 0; i < BLF_MAX_FONT; i++) {
font = global_font[i];
- if (font && (!strcmp(font->name, name)))
+ if (font && (STREQ(font->name, name)))
return i;
}
@@ -160,21 +163,6 @@ void BLF_default_set(int fontid)
}
}
-static int blf_global_font_init(void)
-{
- if (global_font_default == -1) {
- global_font_default = blf_search("default");
- }
-
- if (global_font_default == -1) {
- printf("Warning: Can't find default font!\n");
- return 0;
- }
- else {
- return 1;
- }
-}
-
int BLF_load(const char *name)
{
FontBLF *font;
@@ -336,7 +324,7 @@ void BLF_unload(const char *name)
for (i = 0; i < BLF_MAX_FONT; i++) {
font = global_font[i];
- if (font && (!strcmp(font->name, name))) {
+ if (font && (STREQ(font->name, name))) {
blf_font_free(font);
global_font[i] = NULL;
}
@@ -477,8 +465,7 @@ void BLF_blur(int fontid, int size)
void BLF_draw_default(float x, float y, float z, const char *str, size_t len)
{
- if (!blf_global_font_init())
- return;
+ ASSERT_DEFAULT_SET;
BLF_size(global_font_default, global_font_points, global_font_dpi);
BLF_position(global_font_default, x, y, z);
@@ -488,8 +475,7 @@ 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 (!blf_global_font_init())
- return;
+ ASSERT_DEFAULT_SET;
BLF_size(global_font_default, global_font_points, global_font_dpi);
BLF_position(global_font_default, x, y, z);
@@ -670,10 +656,7 @@ void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_widt
void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height)
{
- if (!blf_global_font_init()) {
- *r_width = *r_height = 0.0f;
- return;
- }
+ ASSERT_DEFAULT_SET;
BLF_size(global_font_default, global_font_points, global_font_dpi);
BLF_width_and_height(global_font_default, str, len, r_width, r_height);
@@ -703,8 +686,7 @@ float BLF_fixed_width(int fontid)
float BLF_width_default(const char *str, size_t len)
{
- if (!blf_global_font_init())
- return 0.0f;
+ ASSERT_DEFAULT_SET;
BLF_size(global_font_default, global_font_points, global_font_dpi);
return BLF_width(global_font_default, str, len);
@@ -767,8 +749,7 @@ float BLF_ascender(int fontid)
float BLF_height_default(const char *str, size_t len)
{
- if (!blf_global_font_init())
- return 0.0f;
+ ASSERT_DEFAULT_SET;
BLF_size(global_font_default, global_font_points, global_font_dpi);
diff --git a/source/blender/blenfont/intern/blf_lang.c b/source/blender/blenfont/intern/blf_lang.c
index 10614e8ca59..99e1aa5d3e3 100644
--- a/source/blender/blenfont/intern/blf_lang.c
+++ b/source/blender/blenfont/intern/blf_lang.c
@@ -33,6 +33,10 @@
#include <stdlib.h>
#include <string.h>
+#ifndef _WIN32
+# include <locale.h>
+#endif
+
#include "RNA_types.h"
#include "BLF_translation.h" /* own include */
@@ -189,7 +193,36 @@ void BLF_lang_init(void)
{
#ifdef WITH_INTERNATIONAL
const char * const messagepath = BKE_appdir_folder_id(BLENDER_DATAFILES, "locale");
+#endif
+
+ /* Make sure LANG is correct and wouldn't cause std::rumtime_error. */
+#ifndef _WIN32
+ /* TODO(sergey): This code only ensures LANG is set properly, so later when
+ * Cycles will try to use file system API from boost there'll be no runtime
+ * exception generated by std::locale() which _requires_ having proper LANG
+ * set in the environment.
+ *
+ * Ideally we also need to ensure LC_ALL, LC_MESSAGES and others are also
+ * set to a proper value, but currently it's not a huge deal and doesn't
+ * cause any headache.
+ *
+ * Would also be good to find nicer way to check if LANG is correct.
+ */
+ const char *lang = getenv("LANG");
+ if (lang != NULL) {
+ char *old_locale = setlocale(LC_ALL, NULL);
+ /* Make a copy so subsequenct setlocale() doesn't interfere. */
+ old_locale = BLI_strdup(old_locale);
+ if (setlocale(LC_ALL, lang) == NULL) {
+ setenv("LANG", "C", 1);
+ printf("Warning: Falling back to the standard locale (\"C\")\n");
+ }
+ setlocale(LC_ALL, old_locale);
+ MEM_freeN(old_locale);
+ }
+#endif
+#ifdef WITH_INTERNATIONAL
if (messagepath) {
bl_locale_init(messagepath, TEXT_DOMAIN_NAME);
fill_locales();
diff --git a/source/blender/blenfont/intern/blf_translation.c b/source/blender/blenfont/intern/blf_translation.c
index e7d2c14b16f..2a4a152f0eb 100644
--- a/source/blender/blenfont/intern/blf_translation.c
+++ b/source/blender/blenfont/intern/blf_translation.c
@@ -133,7 +133,7 @@ void BLF_free_unifont_mono(void)
bool BLF_is_default_context(const char *msgctxt)
{
/* We use the "short" test, a more complete one could be:
- * return (!msgctxt || !msgctxt[0] || !strcmp(msgctxt == BLF_I18NCONTEXT_DEFAULT_BPYRNA))
+ * return (!msgctxt || !msgctxt[0] || STREQ(msgctxt, BLF_I18NCONTEXT_DEFAULT_BPYRNA))
*/
/* Note: trying without the void string check for now, it *should* not be necessary... */
return (!msgctxt || msgctxt[0] == BLF_I18NCONTEXT_DEFAULT_BPYRNA[0]);
diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h
index da4fcb4eca4..04251641d9b 100644
--- a/source/blender/blenkernel/BKE_DerivedMesh.h
+++ b/source/blender/blenkernel/BKE_DerivedMesh.h
@@ -88,6 +88,7 @@ struct MTFace;
struct Object;
struct Scene;
struct Mesh;
+struct MLoopNorSpaceArray;
struct BMEditMesh;
struct KeyBlock;
struct ModifierData;
@@ -197,7 +198,11 @@ struct DerivedMesh {
void (*calcNormals)(DerivedMesh *dm);
/** Calculate loop (split) normals */
- void (*calcLoopNormals)(DerivedMesh *dm, const float split_angle);
+ void (*calcLoopNormals)(DerivedMesh *dm, const bool use_split_normals, const float split_angle);
+
+ /** Calculate loop (split) normals, and returns split loop normal spacearr. */
+ void (*calcLoopNormalsSpaceArray)(DerivedMesh *dm, const bool use_split_normals, const float split_angle,
+ struct MLoopNorSpaceArray *r_lnors_spacearr);
/** Recalculates mesh tessellation */
void (*recalcTessellation)(DerivedMesh *dm);
@@ -746,6 +751,8 @@ typedef struct DMVertexAttribs {
void DM_vertex_attributes_from_gpu(DerivedMesh *dm,
struct GPUVertexAttribs *gattribs, DMVertexAttribs *attribs);
+void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert);
+
void DM_add_tangent_layer(DerivedMesh *dm);
void DM_calc_auto_bump_scale(DerivedMesh *dm);
diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h
index a5109acfa56..0acfd40a110 100644
--- a/source/blender/blenkernel/BKE_animsys.h
+++ b/source/blender/blenkernel/BKE_animsys.h
@@ -73,6 +73,20 @@ bool BKE_copy_animdata_id(struct ID *id_to, struct ID *id_from, const bool do_ac
/* Copy AnimData Actions */
void BKE_copy_animdata_id_action(struct ID *id);
+/* Merge copies of data from source AnimData block */
+typedef enum eAnimData_MergeCopy_Modes {
+ /* Keep destination action */
+ ADT_MERGECOPY_KEEP_DST = 0,
+
+ /* Use src action (make a new copy) */
+ ADT_MERGECOPY_SRC_COPY = 1,
+
+ /* Use src action (but just reference the existing version) */
+ ADT_MERGECOPY_SRC_REF = 2
+} eAnimData_MergeCopy_Modes;
+
+void BKE_animdata_merge_copy(struct ID *dst_id, struct ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers);
+
/* Make Local */
void BKE_animdata_make_local(struct AnimData *adt);
@@ -106,6 +120,10 @@ void BKE_keyingsets_free(struct ListBase *list);
/* ************************************* */
/* Path Fixing API */
+/* Get a "fixed" version of the given path (oldPath) */
+char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *prefix, const char *oldName,
+ const char *newName, int oldSubscript, int newSubscript, bool verify_paths);
+
/* Fix all the paths for the given ID + Action */
void BKE_action_fix_paths_rename(struct ID *owner_id, struct bAction *act, const char *prefix, const char *oldName,
const char *newName, int oldSubscript, int newSubscript, bool verify_paths);
diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h
index 0215becd2a0..2c53a247f6d 100644
--- a/source/blender/blenkernel/BKE_blender.h
+++ b/source/blender/blenkernel/BKE_blender.h
@@ -42,7 +42,7 @@ extern "C" {
* and keep comment above the defines.
* Use STRINGIFY() rather than defining with quotes */
#define BLENDER_VERSION 273
-#define BLENDER_SUBVERSION 2
+#define BLENDER_SUBVERSION 6
/* 262 was the last editmesh release but it has compatibility code for bmesh data */
#define BLENDER_MINVERSION 270
#define BLENDER_MINSUBVERSION 5
@@ -88,7 +88,7 @@ void BKE_userdef_free(void);
void BKE_userdef_state(void);
/* set this callback when a UI is running */
-void set_blender_test_break_cb(void (*func)(void) );
+void set_blender_test_break_cb(void (*func)(void));
int blender_test_break(void);
#define BKE_UNDO_STR_MAX 64
diff --git a/source/blender/blenkernel/BKE_cdderivedmesh.h b/source/blender/blenkernel/BKE_cdderivedmesh.h
index b0ade7bacdf..59ec316a403 100644
--- a/source/blender/blenkernel/BKE_cdderivedmesh.h
+++ b/source/blender/blenkernel/BKE_cdderivedmesh.h
@@ -40,6 +40,7 @@
struct DerivedMesh;
struct BMEditMesh;
struct Mesh;
+struct MLoopNorSpaceArray;
struct Object;
/* creates a new CDDerivedMesh */
@@ -106,7 +107,9 @@ void CDDM_calc_normals_mapping(struct DerivedMesh *dm);
void CDDM_calc_normals(struct DerivedMesh *dm);
void CDDM_calc_normals_tessface(struct DerivedMesh *dm);
-void CDDM_calc_loop_normals(struct DerivedMesh *dm, const float split_angle);
+void CDDM_calc_loop_normals(struct DerivedMesh *dm, const bool use_split_normals, const float split_angle);
+void CDDM_calc_loop_normals_spacearr(struct DerivedMesh *dm, const bool use_split_normals, const float split_angle,
+ struct MLoopNorSpaceArray *r_lnors_spacearr);
/* calculates edges for a CDDerivedMesh (from face data)
* this completely replaces the current edge data in the DerivedMesh
diff --git a/source/blender/blenkernel/BKE_cloth.h b/source/blender/blenkernel/BKE_cloth.h
index 757d63e6ec1..beb4f226aea 100644
--- a/source/blender/blenkernel/BKE_cloth.h
+++ b/source/blender/blenkernel/BKE_cloth.h
@@ -41,7 +41,10 @@ struct Scene;
struct MFace;
struct DerivedMesh;
struct ClothModifierData;
+struct CollisionModifierData;
struct CollisionTree;
+struct VoxelData;
+struct PartDeflect;
#define DO_INLINE MALWAYS_INLINE
@@ -53,8 +56,26 @@ struct CollisionTree;
#define ALMOST_ZERO FLT_EPSILON
/* Bits to or into the ClothVertex.flags. */
-#define CLOTH_VERT_FLAG_PINNED 1
-#define CLOTH_VERT_FLAG_NOSELFCOLL 2 /* vertex NOT used for self collisions */
+typedef enum eClothVertexFlag {
+ CLOTH_VERT_FLAG_PINNED = 1,
+ CLOTH_VERT_FLAG_NOSELFCOLL = 2, /* vertex NOT used for self collisions */
+} eClothVertexFlag;
+
+typedef struct ClothHairData {
+ float loc[3];
+ float rot[3][3];
+ float rest_target[3]; /* rest target direction for each segment */
+ float radius;
+ float bending_stiffness;
+} ClothHairData;
+
+typedef struct ClothSolverResult {
+ int status;
+
+ int max_iterations, min_iterations;
+ float avg_iterations;
+ float max_error, min_error, avg_error;
+} ClothSolverResult;
/**
* This structure describes a cloth object against which the
@@ -79,7 +100,6 @@ typedef struct Cloth {
struct BVHTree *bvhselftree; /* collision tree for this cloth object */
struct MFace *mfaces;
struct Implicit_Data *implicit; /* our implicit solver connects to this pointer */
- struct Implicit_Data *implicitEM; /* our implicit solver connects to this pointer */
struct EdgeSet *edgeset; /* used for selfcollisions */
int last_frame, pad4;
} Cloth;
@@ -116,8 +136,8 @@ ClothVertex;
typedef struct ClothSpring {
int ij; /* Pij from the paper, one end of the spring. */
int kl; /* Pkl from the paper, one end of the spring. */
+ int mn;
float restlen; /* The original length of the spring. */
- int matrix_index; /* needed for implicit solver (fast lookup) */
int type; /* types defined in BKE_cloth.h ("springType") */
int flags; /* defined in BKE_cloth.h, e.g. deactivated due to tearing */
float dfdx[3][3];
@@ -125,6 +145,9 @@ typedef struct ClothSpring {
float f[3];
float stiffness; /* stiffness factor from the vertex groups */
float editrestlen;
+
+ /* angular bending spring target and derivatives */
+ float target[3];
}
ClothSpring;
@@ -158,6 +181,7 @@ typedef enum {
typedef enum {
CLOTH_COLLSETTINGS_FLAG_ENABLED = ( 1 << 1 ), /* enables cloth - object collisions */
CLOTH_COLLSETTINGS_FLAG_SELF = ( 1 << 2 ), /* enables selfcollisions */
+ CLOTH_COLLSETTINGS_FLAG_POINTS = ( 1 << 3 ), /* enables point collisions (hair) */
} CLOTH_COLLISIONSETTINGS_FLAGS;
/* Spring types as defined in the paper.*/
@@ -166,7 +190,8 @@ typedef enum {
CLOTH_SPRING_TYPE_SHEAR = (1 << 2),
CLOTH_SPRING_TYPE_BENDING = (1 << 3),
CLOTH_SPRING_TYPE_GOAL = (1 << 4),
- CLOTH_SPRING_TYPE_SEWING = (1 << 5)
+ CLOTH_SPRING_TYPE_SEWING = (1 << 5),
+ CLOTH_SPRING_TYPE_BENDING_ANG = (1 << 6),
} CLOTH_SPRING_TYPES;
/* SPRING FLAGS */
@@ -180,21 +205,25 @@ typedef enum {
// collision.c
////////////////////////////////////////////////
+struct CollPair;
+
+typedef struct ColliderContacts {
+ struct Object *ob;
+ struct CollisionModifierData *collmd;
+
+ struct CollPair *collisions;
+ int totcollisions;
+} ColliderContacts;
+
// needed for implicit.c
int cloth_bvh_objcollision (struct Object *ob, struct ClothModifierData *clmd, float step, float dt );
+int cloth_points_objcollision(struct Object *ob, struct ClothModifierData *clmd, float step, float dt);
-////////////////////////////////////////////////
-
+void cloth_find_point_contacts(struct Object *ob, struct ClothModifierData *clmd, float step, float dt,
+ ColliderContacts **r_collider_contacts, int *r_totcolliders);
+void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders);
////////////////////////////////////////////////
-// implicit.c
-////////////////////////////////////////////////
-
-// needed for cloth.c
-int implicit_init (struct Object *ob, struct ClothModifierData *clmd );
-int implicit_free (struct ClothModifierData *clmd );
-int implicit_solver (struct Object *ob, float frame, struct ClothModifierData *clmd, struct ListBase *effectors );
-void implicit_set_positions (struct ClothModifierData *clmd );
/////////////////////////////////////////////////
// cloth.c
@@ -218,27 +247,9 @@ void cloth_clear_cache (struct Object *ob, struct ClothModifierData *clmd, float
// needed for cloth.c
int cloth_add_spring (struct ClothModifierData *clmd, unsigned int indexA, unsigned int indexB, float restlength, int spring_type);
-////////////////////////////////////////////////
-
-
-/* This enum provides the IDs for our solvers. */
-// only one available in the moment
-typedef enum {
- CM_IMPLICIT = 0,
-} CM_SOLVER_ID;
-
-
-/* This structure defines how to call the solver.
- */
-typedef struct {
- const char *name;
- CM_SOLVER_ID id;
- int ( *init ) (struct Object *ob, struct ClothModifierData *clmd );
- int ( *solver ) (struct Object *ob, float framenr, struct ClothModifierData *clmd, struct ListBase *effectors );
- int ( *free ) (struct ClothModifierData *clmd );
-}
-CM_SOLVER_DEF;
+void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3]);
+////////////////////////////////////////////////
#endif
diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h
index ec257a2f394..b81b8f04817 100644
--- a/source/blender/blenkernel/BKE_collision.h
+++ b/source/blender/blenkernel/BKE_collision.h
@@ -81,6 +81,8 @@ typedef struct CollPair {
float pa[3], pb[3]; // collision point p1 on face1, p2 on face2
int flag;
float time; // collision time, from 0 up to 1
+
+ /* mesh-mesh collision */
#ifdef WITH_ELTOPO /*either ap* or bp* can be set, but not both*/
float bary[3];
int ap1, ap2, ap3, collp, bp1, bp2, bp3;
@@ -135,6 +137,8 @@ void bvhtree_update_from_mvert(BVHTree *bvhtree, struct MFace *faces, int numfac
// defined in collisions.c
void collision_move_object(struct CollisionModifierData *collmd, float step, float prevstep);
+void collision_get_collider_velocity(float vel_old[3], float vel_new[3], struct CollisionModifierData *collmd, struct CollPair *collpair);
+
/////////////////////////////////////////////////
// used in effect.c
/////////////////////////////////////////////////
diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h
index 13a1468aee8..60cbf8b302e 100644
--- a/source/blender/blenkernel/BKE_curve.h
+++ b/source/blender/blenkernel/BKE_curve.h
@@ -176,6 +176,7 @@ void BKE_nurb_bezt_calc_plane(struct Nurb *nu, struct BezTriple *bezt, float r_p
void BKE_nurb_handle_calc(struct BezTriple *bezt, struct BezTriple *prev, struct BezTriple *next,
const bool is_fcurve);
void BKE_nurb_handle_calc_simple(struct Nurb *nu, struct BezTriple *bezt);
+void BKE_nurb_handle_calc_simple_auto(struct Nurb *nu, struct BezTriple *bezt);
void BKE_nurb_handles_calc(struct Nurb *nu);
void BKE_nurb_handles_autocalc(struct Nurb *nu, int flag);
diff --git a/source/blender/blenkernel/BKE_customdata.h b/source/blender/blenkernel/BKE_customdata.h
index f11aad27e4b..f3f1e0a407e 100644
--- a/source/blender/blenkernel/BKE_customdata.h
+++ b/source/blender/blenkernel/BKE_customdata.h
@@ -397,6 +397,8 @@ enum {
CD_FAKE_BWEIGHT = CD_FAKE | CD_BWEIGHT, /* *sigh*. */
CD_FAKE_UV = CD_FAKE | CD_MLOOPUV, /* UV flag, because we handle both loop's UVs and poly's textures. */
+ CD_FAKE_LNOR = CD_FAKE | CD_CUSTOMLOOPNORMAL, /* Because we play with clnor and temp lnor layers here. */
+
CD_FAKE_SHARP = CD_FAKE | 200, /* Sharp flag for edges, smooth flag for faces. */
};
diff --git a/source/blender/blenkernel/BKE_customdata_file.h b/source/blender/blenkernel/BKE_customdata_file.h
index 978db8a6c1a..242897f968f 100644
--- a/source/blender/blenkernel/BKE_customdata_file.h
+++ b/source/blender/blenkernel/BKE_customdata_file.h
@@ -40,14 +40,14 @@ void cdf_free(CDataFile *cdf);
/* File read/write/remove */
-int cdf_read_open(CDataFile *cdf, const char *filename);
-int cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay);
-int cdf_read_data(CDataFile *cdf, unsigned int size, void *data);
+bool cdf_read_open(CDataFile *cdf, const char *filename);
+bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay);
+bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data);
void cdf_read_close(CDataFile *cdf);
-int cdf_write_open(CDataFile *cdf, const char *filename);
-int cdf_write_layer(CDataFile *cdf, CDataFileLayer *blay);
-int cdf_write_data(CDataFile *cdf, unsigned int size, void *data);
+bool cdf_write_open(CDataFile *cdf, const char *filename);
+bool cdf_write_layer(CDataFile *cdf, CDataFileLayer *blay);
+bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data);
void cdf_write_close(CDataFile *cdf);
void cdf_remove(const char *filename);
diff --git a/source/blender/blenkernel/BKE_data_transfer.h b/source/blender/blenkernel/BKE_data_transfer.h
index d31804b3cae..cea093adca4 100644
--- a/source/blender/blenkernel/BKE_data_transfer.h
+++ b/source/blender/blenkernel/BKE_data_transfer.h
@@ -57,6 +57,7 @@ enum {
DT_TYPE_FREESTYLE_EDGE = 1 << 12,
DT_TYPE_VCOL = 1 << 16,
+ DT_TYPE_LNOR = 1 << 17,
DT_TYPE_UV = 1 << 24,
DT_TYPE_SHARP_FACE = 1 << 25,
@@ -67,7 +68,7 @@ enum {
DT_TYPE_VERT_ALL = DT_TYPE_MDEFORMVERT | DT_TYPE_SHAPEKEY | DT_TYPE_SKIN | DT_TYPE_BWEIGHT_VERT,
DT_TYPE_EDGE_ALL = DT_TYPE_SHARP_EDGE | DT_TYPE_SEAM | DT_TYPE_CREASE | DT_TYPE_BWEIGHT_EDGE |
DT_TYPE_FREESTYLE_EDGE,
- DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_UV,
+ DT_TYPE_LOOP_ALL = DT_TYPE_VCOL | DT_TYPE_LNOR | DT_TYPE_UV,
DT_TYPE_POLY_ALL = DT_TYPE_UV | DT_TYPE_SHARP_FACE | DT_TYPE_FREESTYLE_FACE,
};
@@ -85,7 +86,7 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type);
#define DT_DATATYPE_IS_EDGE(_dt) \
ELEM(_dt, DT_TYPE_CREASE, DT_TYPE_SHARP_EDGE, DT_TYPE_SEAM, DT_TYPE_BWEIGHT_EDGE, DT_TYPE_FREESTYLE_EDGE)
#define DT_DATATYPE_IS_LOOP(_dt) \
- ELEM(_dt, DT_TYPE_UV, DT_TYPE_VCOL)
+ ELEM(_dt, DT_TYPE_UV, DT_TYPE_VCOL, DT_TYPE_LNOR)
#define DT_DATATYPE_IS_POLY(_dt) \
ELEM(_dt, DT_TYPE_UV, DT_TYPE_SHARP_FACE, DT_TYPE_FREESTYLE_FACE)
diff --git a/source/blender/blenkernel/BKE_effect.h b/source/blender/blenkernel/BKE_effect.h
index d5e54d849cd..c4c27e1060d 100644
--- a/source/blender/blenkernel/BKE_effect.h
+++ b/source/blender/blenkernel/BKE_effect.h
@@ -32,8 +32,11 @@
* \since March 2001
* \author nzc
*/
+
#include "DNA_modifier_types.h"
+#include "BLI_utildefines.h"
+
struct Object;
struct Scene;
struct Effect;
@@ -136,6 +139,88 @@ int get_effector_data(struct EffectorCache *eff, struct EffectorData *efd, struc
/* EffectorData->flag */
#define PE_VELOCITY_TO_IMPULSE 1
+/* ======== Simulation Debugging ======== */
+
+#define SIM_DEBUG_HASH_BASE 5381
+
+unsigned int BKE_sim_debug_data_hash(int i);
+unsigned int BKE_sim_debug_data_hash_combine(unsigned int kx, unsigned int ky);
+
+/* _VA_SIM_DEBUG_HASH#(i, ...): combined hash value of multiple integers */
+/* internal helpers*/
+#define _VA_SIM_DEBUG_HASH1(a) \
+ (BKE_sim_debug_data_hash(a))
+#define _VA_SIM_DEBUG_HASH2(a, b) \
+ (BKE_sim_debug_data_hash_combine(BKE_sim_debug_data_hash(a), _VA_SIM_DEBUG_HASH1(b)))
+#define _VA_SIM_DEBUG_HASH3(a, b, c) \
+ (BKE_sim_debug_data_hash_combine(BKE_sim_debug_data_hash(a), _VA_SIM_DEBUG_HASH2(b, c)))
+#define _VA_SIM_DEBUG_HASH4(a, b, c, d) \
+ (BKE_sim_debug_data_hash_combine(BKE_sim_debug_data_hash(a), _VA_SIM_DEBUG_HASH3(b, c, d)))
+#define _VA_SIM_DEBUG_HASH5(a, b, c, d, e) \
+ (BKE_sim_debug_data_hash_combine(BKE_sim_debug_data_hash(a), _VA_SIM_DEBUG_HASH4(b, c, d, e)))
+#define _VA_SIM_DEBUG_HASH6(a, b, c, d, e, f) \
+ (BKE_sim_debug_data_hash_combine(BKE_sim_debug_data_hash(a), _VA_SIM_DEBUG_HASH5(b, c, d, e, f)))
+#define _VA_SIM_DEBUG_HASH7(a, b, c, d, e, f, g) \
+ (BKE_sim_debug_data_hash_combine(BKE_sim_debug_data_hash(a), _VA_SIM_DEBUG_HASH6(b, c, d, e, f, g)))
+#define _VA_SIM_DEBUG_HASH8(a, b, c, d, e, f, g, h) \
+ (BKE_sim_debug_data_hash_combine(BKE_sim_debug_data_hash(a), _VA_SIM_DEBUG_HASH7(b, c, d, e, f, g, h)))
+
+#define SIM_DEBUG_HASH(...) VA_NARGS_CALL_OVERLOAD(_VA_SIM_DEBUG_HASH, __VA_ARGS__)
+
+typedef struct SimDebugElement {
+ unsigned int category_hash;
+ unsigned int hash;
+
+ int type;
+ float color[3];
+
+ float v1[3], v2[3];
+} SimDebugElement;
+
+typedef enum eSimDebugElement_Type {
+ SIM_DEBUG_ELEM_DOT,
+ SIM_DEBUG_ELEM_CIRCLE,
+ SIM_DEBUG_ELEM_LINE,
+ SIM_DEBUG_ELEM_VECTOR,
+} eSimDebugElement_Type;
+
+typedef struct SimDebugData {
+ struct GHash *gh;
+} SimDebugData;
+
+extern SimDebugData *_sim_debug_data;
+
+void BKE_sim_debug_data_set_enabled(bool enable);
+bool BKE_sim_debug_data_get_enabled(void);
+void BKE_sim_debug_data_free(void);
+
+void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3],
+ float r, float g, float b, const char *category, unsigned int hash);
+void BKE_sim_debug_data_remove_element(unsigned int hash);
+
+#define BKE_sim_debug_data_add_dot(p, r, g, b, category, ...) { \
+ const float v2[3] = { 0.0f, 0.0f, 0.0f }; \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_DOT, p, v2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+}
+
+#define BKE_sim_debug_data_add_circle(p, radius, r, g, b, category, ...) { \
+ const float v2[3] = { radius, 0.0f, 0.0f }; \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_CIRCLE, p, v2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+}
+
+#define BKE_sim_debug_data_add_line(p1, p2, r, g, b, category, ...) { \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_LINE, p1, p2, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+}
+
+#define BKE_sim_debug_data_add_vector(p, d, r, g, b, category, ...) { \
+ BKE_sim_debug_data_add_element(SIM_DEBUG_ELEM_VECTOR, p, d, r, g, b, category, SIM_DEBUG_HASH(__VA_ARGS__)); \
+}
+
+#define BKE_sim_debug_data_remove(...) \
+ BKE_sim_debug_data_remove_element(SIM_DEBUG_HASH(__VA_ARGS__))
+
+void BKE_sim_debug_data_clear(void);
+void BKE_sim_debug_data_clear_category(const char *category);
#endif
diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h
index a7aa4c6969a..57003ffc3aa 100644
--- a/source/blender/blenkernel/BKE_global.h
+++ b/source/blender/blenkernel/BKE_global.h
@@ -70,7 +70,6 @@ typedef struct Global {
bool factory_startup;
short moving;
- short winpos, displaymode; /* used to be in Render */
/* to indicate render is busy, prevent renderwindow events etc */
bool is_rendering;
@@ -90,9 +89,6 @@ typedef struct Global {
/* this variable is written to / read from FileGlobal->fileflags */
int fileflags;
- /* save the allowed windowstate of blender when using -W or -w (GHOST_TWindowState) */
- int windowstate;
-
/* message to use when autoexec fails */
char autoexec_fail[200];
} Global;
@@ -130,6 +126,7 @@ enum {
G_DEBUG_JOBS = (1 << 6), /* jobs time profiling */
G_DEBUG_FREESTYLE = (1 << 7), /* freestyle messages */
G_DEBUG_DEPSGRAPH = (1 << 8), /* depsgraph messages */
+ G_DEBUG_SIMDATA = (1 << 9), /* sim debug data display */
};
#define G_DEBUG_ALL (G_DEBUG | G_DEBUG_FFMPEG | G_DEBUG_PYTHON | G_DEBUG_EVENTS | G_DEBUG_WM | G_DEBUG_JOBS | \
diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h
index f528fe8c7f9..820e1ea1494 100644
--- a/source/blender/blenkernel/BKE_group.h
+++ b/source/blender/blenkernel/BKE_group.h
@@ -50,6 +50,7 @@ bool BKE_group_object_add(struct Group *group, struct Object *ob, struc
bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base);
struct Group *BKE_group_object_find(struct Group *group, struct Object *ob);
bool BKE_group_object_exists(struct Group *group, struct Object *ob);
+bool BKE_group_object_cyclic_check(struct Main *bmain, struct Object *object, struct Group *group);
bool BKE_group_is_animated(struct Group *group, struct Object *parent);
void BKE_group_tag_recalc(struct Group *group);
diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h
index a225a27a00b..2c9ecef4c2d 100644
--- a/source/blender/blenkernel/BKE_image.h
+++ b/source/blender/blenkernel/BKE_image.h
@@ -57,19 +57,25 @@ void BKE_image_free_buffers(struct Image *image);
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);
+void BKE_image_stamp_buf(
+ struct Scene *scene, struct Object *camera,
+ unsigned char *rect, float *rectf, int width, int height, int channels);
bool BKE_imbuf_alpha_test(struct ImBuf *ibuf);
int BKE_imbuf_write_stamp(struct Scene *scene, struct Object *camera, struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
int BKE_imbuf_write(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf);
int BKE_imbuf_write_as(struct ImBuf *ibuf, const char *name, struct ImageFormatData *imf, const bool is_copy);
-void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame,
- const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames);
-void BKE_makepicstring_from_type(char *string, const char *base, const char *relbase, int frame,
- const char imtype, const bool use_ext, const bool use_frames);
-int BKE_add_image_extension(char *string, const struct ImageFormatData *im_format);
-int BKE_add_image_extension_from_type(char *string, const char imtype);
-char BKE_ftype_to_imtype(const int ftype);
-int BKE_imtype_to_ftype(const char imtype);
+
+void BKE_image_path_from_imformat(
+ char *string, const char *base, const char *relbase, int frame,
+ const struct ImageFormatData *im_format, const bool use_ext, const bool use_frames);
+void BKE_image_path_from_imtype(
+ char *string, const char *base, const char *relbase, int frame,
+ const char imtype, const bool use_ext, const bool use_frames);
+
+bool BKE_image_path_ensure_ext_from_imformat(char *string, const struct ImageFormatData *im_format);
+bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype);
+char BKE_image_ftype_to_imtype(const int ftype);
+int BKE_image_imtype_to_ftype(const char imtype);
bool BKE_imtype_is_movie(const char imtype);
int BKE_imtype_supports_zbuf(const char imtype);
@@ -85,13 +91,13 @@ void BKE_imformat_defaults(struct ImageFormatData *im_format);
void BKE_imbuf_to_image_format(struct ImageFormatData *im_format, const struct ImBuf *imbuf);
struct anim *openanim(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE]);
+struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE]);
void BKE_image_de_interlace(struct Image *ima, int odd);
void BKE_image_make_local(struct Image *ima);
void BKE_image_tag_time(struct Image *ima);
-void free_old_images(void);
/* ********************************** NEW IMAGE API *********************** */
@@ -180,9 +186,6 @@ void BKE_image_walk_all_users(const struct Main *mainp, void *customdata,
/* ensures an Image exists for viewing nodes or render */
struct Image *BKE_image_verify_viewer(int type, const char *name);
-/* force an ImBuf to become part of Image */
-void BKE_image_assign_ibuf(struct Image *ima, struct ImBuf *ibuf);
-
/* called on frame change or before render */
void BKE_image_user_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
void BKE_image_user_check_frame_calc(struct ImageUser *iuser, int cfra, int fieldnr);
diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h
index 500c2813a75..e88a4e88209 100644
--- a/source/blender/blenkernel/BKE_library.h
+++ b/source/blender/blenkernel/BKE_library.h
@@ -107,8 +107,8 @@ void BKE_library_make_local(struct Main *bmain, struct Library *lib, bool untagg
struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowManager *) );
-void set_free_notifier_reference_cb(void (*func)(const void *) );
+void set_free_windowmanager_cb(void (*func)(struct bContext *, struct wmWindowManager *));
+void set_free_notifier_reference_cb(void (*func)(const void *));
/* use when "" is given to new_id() */
#define ID_FALLBACK_NAME N_("Untitled")
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index b2b9e37f500..224be0f3685 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -36,6 +36,9 @@ struct BoundBox;
struct DispList;
struct EdgeHash;
struct ListBase;
+struct LinkNode;
+struct BLI_Stack;
+struct MemArena;
struct BMEditMesh;
struct BMesh;
struct Main;
@@ -174,10 +177,6 @@ void BKE_mesh_calc_normals_tessface(
struct MVert *mverts, int numVerts,
struct MFace *mfaces, int numFaces,
float (*r_faceNors)[3]);
-void BKE_mesh_normals_loop_split(
- struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
- struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
- struct MPoly *mpolys, float (*polynors)[3], const int numPolys, float split_angle);
void BKE_mesh_loop_tangents_ex(
struct MVert *mverts, const int numVerts, struct MLoop *mloops, float (*r_looptangent)[4], float (*loopnors)[3],
struct MLoopUV *loopuv, const int numLoops, struct MPoly *mpolys, const int numPolys,
@@ -185,6 +184,56 @@ void BKE_mesh_loop_tangents_ex(
void BKE_mesh_loop_tangents(
struct Mesh *mesh, const char *uvmap, float (*r_looptangents)[4], struct ReportList *reports);
+/**
+ * References a contiguous loop-fan with normal offset vars.
+ */
+typedef struct MLoopNorSpace {
+ float vec_lnor[3]; /* Automatically computed loop normal. */
+ float vec_ref[3]; /* Reference vector, orthogonal to vec_lnor. */
+ float vec_ortho[3]; /* Third vector, orthogonal to vec_lnor and vec_ref. */
+ float ref_alpha; /* Reference angle, around vec_ortho, in ]0, pi] range (0.0 marks that space as invalid). */
+ float ref_beta; /* Reference angle, around vec_lnor, in ]0, 2pi] range (0.0 marks that space as invalid). */
+ struct LinkNode *loops; /* All indices (uint_in_ptr) of loops using this lnor space (i.e. smooth fan of loops). */
+} MLoopNorSpace;
+/**
+ * Collection of #MLoopNorSpace basic storage & pre-allocation.
+ */
+typedef struct MLoopNorSpaceArray {
+ MLoopNorSpace **lspacearr; /* MLoop aligned array */
+ struct LinkNode *loops_pool; /* Allocated once, avoids to call BLI_linklist_prepend_arena() for each loop! */
+ struct MemArena *mem;
+} MLoopNorSpaceArray;
+void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops);
+void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr);
+void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr);
+MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr);
+void BKE_lnor_space_define(
+ MLoopNorSpace *lnor_space, const float lnor[3], float vec_ref[3], float vec_other[3],
+ struct BLI_Stack *edge_vectors);
+void BKE_lnor_space_add_loop(
+ MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, const int ml_index, const bool add_to_list);
+void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3]);
+void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2]);
+
+bool BKE_mesh_has_custom_loop_normals(struct Mesh *me);
+
+void BKE_mesh_normals_loop_split(struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
+ struct MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
+ struct MPoly *mpolys, const float (*polynors)[3], const int numPolys,
+ const bool use_split_normals, float split_angle,
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly);
+
+void BKE_mesh_normals_loop_custom_set(
+ struct MVert *mverts, const int numVerts, struct MEdge *medges, const int numEdges,
+ struct MLoop *mloops, float (*custom_loopnors)[3], const int numLoops,
+ struct MPoly *mpolys, const float (*polynors)[3], const int numPolys,
+ short (*r_clnors_data)[2]);
+void BKE_mesh_normals_loop_custom_from_vertices_set(
+ struct MVert *mverts, float (*custom_vertnors)[3], const int numVerts,
+ struct MEdge *medges, const int numEdges, struct MLoop *mloops, const int numLoops,
+ struct MPoly *mpolys, const float (*polynors)[3], const int numPolys,
+ short (*r_clnors_data)[2]);
+
void BKE_mesh_calc_poly_normal(
struct MPoly *mpoly, struct MLoop *loopstart,
struct MVert *mvarray, float no[3]);
@@ -286,7 +335,7 @@ void BKE_mesh_calc_relative_deform(
/* *** mesh_validate.c *** */
-int BKE_mesh_validate(struct Mesh *me, const int do_verbose);
+int BKE_mesh_validate(struct Mesh *me, const int do_verbose, const int cddata_check_mask);
void BKE_mesh_cd_validate(struct Mesh *me);
int BKE_mesh_validate_material_indices(struct Mesh *me);
diff --git a/source/blender/blenkernel/BKE_mesh_remap.h b/source/blender/blenkernel/BKE_mesh_remap.h
index e1f37a63ff0..752270a8120 100644
--- a/source/blender/blenkernel/BKE_mesh_remap.h
+++ b/source/blender/blenkernel/BKE_mesh_remap.h
@@ -158,8 +158,8 @@ void BKE_mesh_remap_calc_loops_from_dm(
struct MVert *verts_dst, const int numverts_dst, struct MEdge *edges_dst, const int numedges_dst,
struct MLoop *loops_dst, const int numloops_dst, struct MPoly *polys_dst, const int numpolys_dst,
struct CustomData *ldata_dst, struct CustomData *pdata_dst,
- const float split_angle_dst, const bool dirty_nors_dst,
- struct DerivedMesh *dm_src,
+ const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
+ struct DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src,
MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, struct MeshPairRemap *r_map);
void BKE_mesh_remap_calc_polys_from_dm(
diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h
index 1bdbc339f21..0ea460d1a60 100644
--- a/source/blender/blenkernel/BKE_object.h
+++ b/source/blender/blenkernel/BKE_object.h
@@ -57,6 +57,7 @@ void BKE_object_workob_calc_parent(struct Scene *scene, struct Object *ob, struc
void BKE_object_transform_copy(struct Object *ob_tar, const struct Object *ob_src);
struct SoftBody *copy_softbody(struct SoftBody *sb, bool copy_caches);
struct BulletSoftBody *copy_bulletsoftbody(struct BulletSoftBody *sb);
+struct ParticleSystem *BKE_object_copy_particlesystem(struct ParticleSystem *psys);
void BKE_object_copy_particlesystems(struct Object *obn, struct Object *ob);
void BKE_object_copy_softbody(struct Object *obn, struct Object *ob);
void BKE_object_free_particlesystems(struct Object *ob);
diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h
index e56add721eb..a769ce94c90 100644
--- a/source/blender/blenkernel/BKE_particle.h
+++ b/source/blender/blenkernel/BKE_particle.h
@@ -39,6 +39,8 @@
#include "DNA_particle_types.h"
#include "DNA_object_types.h"
+#include "BKE_customdata.h"
+
struct ParticleSystemModifierData;
struct ParticleSystem;
struct ParticleKey;
@@ -110,7 +112,7 @@ typedef struct ParticleTexture {
float ivel; /* used in reset */
float time, life, exist, size; /* used in init */
float damp, gravity, field; /* used in physics */
- float length, clump, kink, effector; /* used in path caching */
+ float length, clump, kink_freq, kink_amp, effector; /* used in path caching */
float rough1, rough2, roughe; /* used in path caching */
} ParticleTexture;
@@ -126,7 +128,7 @@ typedef struct ParticleCacheKey {
float rot[4];
float col[3];
float time;
- int steps;
+ int segments;
} ParticleCacheKey;
typedef struct ParticleThreadContext {
@@ -145,12 +147,12 @@ typedef struct ParticleThreadContext {
float maxweight;
int *index, *skip, jitlevel;
- int from, cfrom, distr;
+ int cfrom, distr;
struct ParticleData *tpars;
/* path caching */
- int editupdate, between, steps;
+ int editupdate, between, segments, extra_segments;
int totchild, totparent, parent_pass;
float cfra;
@@ -160,11 +162,11 @@ typedef struct ParticleThreadContext {
float *vg_effector;
} ParticleThreadContext;
-typedef struct ParticleThread {
+typedef struct ParticleTask {
ParticleThreadContext *ctx;
struct RNG *rng, *rng_path;
- int num, tot;
-} ParticleThread;
+ int begin, end;
+} ParticleTask;
typedef struct ParticleBillboardData {
struct Object *ob;
@@ -279,6 +281,9 @@ BLI_INLINE void psys_frand_vec(ParticleSystem *psys, unsigned int seed, float ve
int count_particles(struct ParticleSystem *psys);
int count_particles_mod(struct ParticleSystem *psys, int totgr, int cur);
+int psys_get_child_number(struct Scene *scene, struct ParticleSystem *psys);
+int psys_get_tot_child(struct Scene *scene, struct ParticleSystem *psys);
+
struct ParticleSystem *psys_get_current(struct Object *ob);
/* for rna */
short psys_get_current_num(struct Object *ob);
@@ -302,7 +307,6 @@ void psys_free(struct Object *ob, struct ParticleSystem *psys);
void psys_render_set(struct Object *ob, struct ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset);
void psys_render_restore(struct Object *ob, struct ParticleSystem *psys);
-int psys_render_simplify_distribution(struct ParticleThreadContext *ctx, int tot);
bool psys_render_simplify_params(struct ParticleSystem *psys, struct ChildParticle *cpa, float *params);
void psys_interpolate_uvs(const struct MTFace *tface, int quad, const float w[4], float uvco[2]);
@@ -310,6 +314,7 @@ void psys_interpolate_mcol(const struct MCol *mcol, int quad, const float w[4],
void copy_particle_key(struct ParticleKey *to, struct ParticleKey *from, int time);
+CustomDataMask psys_emitter_customdata_mask(struct ParticleSystem *psys);
void psys_particle_on_emitter(struct ParticleSystemModifierData *psmd, int distr, int index, int index_dmcache,
float fuv[4], float foffset, float vec[3], float nor[3],
float utan[3], float vtan[3], float orco[3], float ornor[3]);
@@ -328,7 +333,7 @@ void psys_find_parents(struct ParticleSimulationData *sim);
void psys_cache_paths(struct ParticleSimulationData *sim, float cfra);
void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra);
void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, int editupdate);
-int do_guides(struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
+int do_guides(struct ParticleSettings *part, struct ListBase *effectors, ParticleKey *state, int pa_num, float time);
void precalc_guides(struct ParticleSimulationData *sim, struct ListBase *effectors);
float psys_get_timestep(struct ParticleSimulationData *sim);
float psys_get_child_time(struct ParticleSystem *psys, struct ChildParticle *cpa, float cfra, float *birthtime, float *dietime);
@@ -336,6 +341,13 @@ float psys_get_child_size(struct ParticleSystem *psys, struct ChildParticle *cpa
void psys_get_particle_on_path(struct ParticleSimulationData *sim, int pa_num, struct ParticleKey *state, const bool vel);
int psys_get_particle_state(struct ParticleSimulationData *sim, int p, struct ParticleKey *state, int always);
+/* child paths */
+void BKE_particlesettings_clump_curve_init(struct ParticleSettings *part);
+void BKE_particlesettings_rough_curve_init(struct ParticleSettings *part);
+void psys_apply_child_modifiers(struct ParticleThreadContext *ctx, struct ListBase *modifiers,
+ struct ChildParticle *cpa, struct ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
+ struct ParticleCacheKey *keys, struct ParticleCacheKey *parent_keys, const float parent_orco[3]);
+
void psys_sph_init(struct ParticleSimulationData *sim, struct SPHData *sphdata);
void psys_sph_finalise(struct SPHData *sphdata);
void psys_sph_density(struct BVHTree *tree, struct SPHData *data, float co[3], float vars[2]);
@@ -347,8 +359,10 @@ void psys_get_dupli_texture(struct ParticleSystem *psys, struct ParticleSettings
void psys_get_dupli_path_transform(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ChildParticle *cpa,
struct ParticleCacheKey *cache, float mat[4][4], float *scale);
-ParticleThread *psys_threads_create(struct ParticleSimulationData *sim);
-void psys_threads_free(ParticleThread *threads);
+void psys_thread_context_init(struct ParticleThreadContext *ctx, struct ParticleSimulationData *sim);
+void psys_thread_context_free(struct ParticleThreadContext *ctx);
+void psys_tasks_create(struct ParticleThreadContext *ctx, int totpart, struct ParticleTask **r_tasks, int *r_numtasks);
+void psys_tasks_free(struct ParticleTask *tasks, int numtasks);
void psys_make_billboard(ParticleBillboardData *bb, float xvec[3], float yvec[3], float zvec[3], float center[3]);
void psys_apply_hair_lattice(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys);
@@ -403,6 +417,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 distribute_particles(struct ParticleSimulationData *sim, int from);
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);
@@ -411,6 +426,33 @@ void reset_particle(struct ParticleSimulationData *sim, struct ParticleData *pa,
float psys_get_current_display_percentage(struct ParticleSystem *psys);
+typedef struct ParticleRenderElem {
+ int curchild, totchild, reduce;
+ float lambda, t, scalemin, scalemax;
+} ParticleRenderElem;
+
+typedef struct ParticleRenderData {
+ ChildParticle *child;
+ ParticleCacheKey **pathcache;
+ ParticleCacheKey **childcache;
+ ListBase pathcachebufs, childcachebufs;
+ int totchild, totcached, totchildcache;
+ struct DerivedMesh *dm;
+ int totdmvert, totdmedge, totdmface;
+
+ float mat[4][4];
+ float viewmat[4][4], winmat[4][4];
+ int winx, winy;
+
+ int do_simplify;
+ int timeoffset;
+ ParticleRenderElem *elems;
+
+ /* ORIGINDEX */
+ const int *index_mf_to_mpoly;
+ const int *index_mp_to_orig;
+} ParticleRenderData;
+
/* psys_reset */
#define PSYS_RESET_ALL 1
#define PSYS_RESET_DEPSGRAPH 2
diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h
index 280d85c0882..05cc068848d 100644
--- a/source/blender/blenkernel/BKE_pointcache.h
+++ b/source/blender/blenkernel/BKE_pointcache.h
@@ -224,7 +224,6 @@ typedef struct PTCacheEdit {
/* particles stuff */
struct ParticleSystem *psys;
- struct ParticleData *particles;
struct KDTree *emitter_field;
float *emitter_cosnos; /* localspace face centers and normals (average of its verts), from the derived mesh */
int *mirror_cache;
diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h
index eac4f6a56a5..149472db8fa 100644
--- a/source/blender/blenkernel/BKE_scene.h
+++ b/source/blender/blenkernel/BKE_scene.h
@@ -39,6 +39,7 @@ extern "C" {
struct AviCodecData;
struct Base;
+struct DisplaySafeAreas;
struct EvaluationContext;
struct bglMats;
struct Main;
diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h
index 4c11ec9923d..3eb6ba7b6fa 100644
--- a/source/blender/blenkernel/BKE_screen.h
+++ b/source/blender/blenkernel/BKE_screen.h
@@ -265,7 +265,7 @@ struct SpaceType *BKE_spacetype_from_id(int spaceid);
struct ARegionType *BKE_regiontype_from_id(struct SpaceType *st, int regionid);
const struct ListBase *BKE_spacetypes_list(void);
void BKE_spacetype_register(struct SpaceType *st);
-int BKE_spacetype_exists(int spaceid);
+bool BKE_spacetype_exists(int spaceid);
void BKE_spacetypes_free(void); /* only for quitting blender */
/* spacedata */
@@ -282,6 +282,7 @@ 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_area_from_space(struct bScreen *sc, struct SpaceLink *sl) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
struct ScrArea *BKE_screen_find_big_area(struct bScreen *sc, const int spacetype, const short min);
+struct ScrArea *BKE_screen_find_area_xy(struct bScreen *sc, const int spacetype, int x, int y);
unsigned int BKE_screen_view3d_layer_active_ex(
const struct View3D *v3d, const struct Scene *scene, bool use_localvd) ATTR_NONNULL(2);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index 24e8d6362c1..6b9c4faa3d2 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -34,6 +34,7 @@ struct bContext;
struct EvaluationContext;
struct StripColorBalance;
struct Editing;
+struct GSet;
struct ImBuf;
struct Main;
struct Mask;
@@ -236,10 +237,11 @@ struct StripElem *BKE_sequencer_give_stripelem(struct Sequence *seq, int cfra);
void BKE_sequencer_update_changed_seq_and_deps(struct Scene *scene, struct Sequence *changed_seq, int len_change, int ibuf_change);
bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context, struct Sequence *seq, float cfra);
-struct SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq);
+struct SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(struct Main *bmain, struct Scene *scene, struct Sequence *seq, struct GSet *file_list);
void BKE_sequencer_proxy_rebuild(struct SeqIndexBuildContext *context, short *stop, short *do_update, float *progress);
void BKE_sequencer_proxy_rebuild_finish(struct SeqIndexBuildContext *context, bool stop);
+void BKE_sequencer_proxy_set(struct Sequence *seq, bool value);
/* **********************************************************************
* seqcache.c
*
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 328c465f07b..ef35cea9f39 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -36,6 +36,7 @@ set(INC
../bmesh
../modifiers
../nodes
+ ../physics
../pointcache
../render/extern/include
../../../intern/ghost
@@ -46,8 +47,8 @@ set(INC
../../../intern/mikktspace
../../../intern/raskter
../../../intern/smoke/extern
- ../../../extern/libmv
../../../intern/atomic
+ ../../../extern/libmv
# XXX - BAD LEVEL CALL WM_api.h
../windowmanager
@@ -107,7 +108,6 @@ set(SRC
intern/idprop.c
intern/image.c
intern/image_gen.c
- intern/implicit.c
intern/ipo.c
intern/key.c
intern/lamp.c
@@ -138,6 +138,8 @@ set(SRC
intern/packedFile.c
intern/paint.c
intern/particle.c
+ intern/particle_child.c
+ intern/particle_distribute.c
intern/particle_system.c
intern/pbvh.c
intern/pbvh_bmesh.c
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index 6de55e276a1..8c5d245b69c 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -65,6 +65,7 @@ incs = [
'../makesrna',
'../modifiers',
'../nodes',
+ '../physics',
'../pointcache',
'../render/extern/include',
'../windowmanager',
diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c
index 9cc99a07353..72326d39c70 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.c
+++ b/source/blender/blenkernel/intern/DerivedMesh.c
@@ -394,9 +394,9 @@ void DM_ensure_normals(DerivedMesh *dm)
BLI_assert((dm->dirty & DM_DIRTY_NORMALS) == 0);
}
-static void DM_calc_loop_normals(DerivedMesh *dm, float split_angle)
+static void DM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, float split_angle)
{
- dm->calcLoopNormals(dm, split_angle);
+ dm->calcLoopNormals(dm, use_split_normals, split_angle);
dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
}
@@ -1553,7 +1553,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
/* XXX Same as above... For now, only weights preview in WPaint mode. */
const bool do_mod_wmcol = do_init_wmcol;
- const bool do_loop_normals = (me->flag & ME_AUTOSMOOTH);
+ const bool do_loop_normals = (me->flag & ME_AUTOSMOOTH) != 0;
const float loop_normals_split_angle = me->smoothresh;
VirtualModifierData virtualModifierData;
@@ -1950,7 +1950,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
if (do_loop_normals) {
/* Compute loop normals (note: will compute poly and vert normals as well, if needed!) */
- DM_calc_loop_normals(finaldm, loop_normals_split_angle);
+ DM_calc_loop_normals(finaldm, do_loop_normals, loop_normals_split_angle);
}
{
@@ -2050,7 +2050,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
const bool do_mod_wmcol = do_init_wmcol;
VirtualModifierData virtualModifierData;
- const bool do_loop_normals = (((Mesh *)(ob->data))->flag & ME_AUTOSMOOTH);
+ const bool do_loop_normals = (((Mesh *)(ob->data))->flag & ME_AUTOSMOOTH) != 0;
const float loop_normals_split_angle = ((Mesh *)(ob->data))->smoothresh;
modifiers_clearErrors(ob);
@@ -2266,9 +2266,9 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
if (do_loop_normals) {
/* Compute loop normals */
- DM_calc_loop_normals(*final_r, loop_normals_split_angle);
+ DM_calc_loop_normals(*final_r, do_loop_normals, loop_normals_split_angle);
if (cage_r && *cage_r && (*cage_r != *final_r)) {
- DM_calc_loop_normals(*cage_r, loop_normals_split_angle);
+ DM_calc_loop_normals(*cage_r, do_loop_normals, loop_normals_split_angle);
}
}
@@ -3124,6 +3124,69 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
}
}
+/* Set vertex shader attribute inputs for a particular tessface vert
+ *
+ * a: tessface index
+ * index: vertex index
+ * vert: corner index (0, 1, 2, 3)
+ */
+void DM_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert)
+{
+ const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
+ int b;
+
+ /* orco texture coordinates */
+ if (attribs->totorco) {
+ /*const*/ float (*array)[3] = attribs->orco.array;
+ const float *orco = (array) ? array[index] : zero;
+
+ if (attribs->orco.gl_texco)
+ glTexCoord3fv(orco);
+ else
+ glVertexAttrib3fvARB(attribs->orco.gl_index, orco);
+ }
+
+ /* uv texture coordinates */
+ for (b = 0; b < attribs->tottface; b++) {
+ const float *uv;
+
+ if (attribs->tface[b].array) {
+ MTFace *tf = &attribs->tface[b].array[a];
+ uv = tf->uv[vert];
+ }
+ else {
+ uv = zero;
+ }
+
+ if (attribs->tface[b].gl_texco)
+ glTexCoord2fv(uv);
+ else
+ glVertexAttrib2fvARB(attribs->tface[b].gl_index, uv);
+ }
+
+ /* vertex colors */
+ for (b = 0; b < attribs->totmcol; b++) {
+ GLubyte col[4];
+
+ if (attribs->mcol[b].array) {
+ MCol *cp = &attribs->mcol[b].array[a * 4 + vert];
+ col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a;
+ }
+ else {
+ col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
+ }
+
+ glVertexAttrib4ubvARB(attribs->mcol[b].gl_index, col);
+ }
+
+ /* tangent for normal mapping */
+ if (attribs->tottang) {
+ /*const*/ float (*array)[4] = attribs->tang.array;
+ const float *tang = (array) ? array[a * 4 + vert] : zero;
+ glVertexAttrib4fvARB(attribs->tang.gl_index, tang);
+ }
+}
+
/* Set object's bounding box based on DerivedMesh min/max data */
void DM_set_object_boundbox(Object *ob, DerivedMesh *dm)
{
@@ -3466,7 +3529,7 @@ bool DM_is_valid(DerivedMesh *dm)
dm->getEdgeDataLayout(dm),
dm->getLoopDataLayout(dm),
dm->getPolyDataLayout(dm),
- 0, /* setting mask here isn't useful, gives false positives */
+ false, /* setting mask here isn't useful, gives false positives */
do_verbose, do_fixes, &changed);
is_valid &= BKE_mesh_validate_arrays(
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index f94f1e72638..1bae65a7fb4 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -1002,8 +1002,12 @@ void BKE_pose_remove_group(bPose *pose, bActionGroup *grp, const int index)
/* now, remove it from the pose */
BLI_freelinkN(&pose->agroups, grp);
if (pose->active_group >= idx) {
+ const bool has_groups = !BLI_listbase_is_empty(&pose->agroups);
pose->active_group--;
- if (pose->active_group < 0 || BLI_listbase_is_empty(&pose->agroups)) {
+ if (pose->active_group == 0 && has_groups) {
+ pose->active_group = 1;
+ }
+ else if (pose->active_group < 0 || !has_groups) {
pose->active_group = 0;
}
}
diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c
index 8e36449f214..8e2b3de9586 100644
--- a/source/blender/blenkernel/intern/anim_sys.c
+++ b/source/blender/blenkernel/intern/anim_sys.c
@@ -318,6 +318,77 @@ void BKE_copy_animdata_id_action(ID *id)
}
}
+/* Merge copies of the data from the src AnimData into the destination AnimData */
+void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes action_mode, bool fix_drivers)
+{
+ AnimData *src = BKE_animdata_from_id(src_id);
+ AnimData *dst = BKE_animdata_from_id(dst_id);
+
+ /* sanity checks */
+ if (ELEM(NULL, dst, src))
+ return;
+
+ // TODO: we must unset all "tweakmode" flags
+ if ((src->flag & ADT_NLA_EDIT_ON) || (dst->flag & ADT_NLA_EDIT_ON)) {
+ printf("ERROR: Merging AnimData blocks while editing NLA is dangerous as it may cause data corruption\n");
+ return;
+ }
+
+ /* handle actions... */
+ if (action_mode == ADT_MERGECOPY_SRC_COPY) {
+ /* make a copy of the actions */
+ dst->action = BKE_action_copy(src->action);
+ dst->tmpact = BKE_action_copy(src->tmpact);
+ }
+ else if (action_mode == ADT_MERGECOPY_SRC_REF) {
+ /* make a reference to it */
+ dst->action = src->action;
+ id_us_plus((ID *)dst->action);
+
+ dst->tmpact = src->tmpact;
+ id_us_plus((ID *)dst->tmpact);
+ }
+
+ /* duplicate NLA data */
+ if (src->nla_tracks.first) {
+ ListBase tracks = {NULL, NULL};
+
+ copy_nladata(&tracks, &src->nla_tracks);
+ BLI_movelisttolist(&dst->nla_tracks, &tracks);
+ }
+
+ /* duplicate drivers (F-Curves) */
+ if (src->drivers.first) {
+ ListBase drivers = {NULL, NULL};
+
+ copy_fcurves(&drivers, &src->drivers);
+
+ /* Fix up all driver targets using the old target id
+ * - This assumes that the src ID is being merged into the dst ID
+ */
+ if (fix_drivers) {
+ FCurve *fcu;
+
+ for (fcu = drivers.first; fcu; fcu = fcu->next) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+ }
+ }
+
+ BLI_movelisttolist(&dst->drivers, &drivers);
+ }
+}
+
/* Make Local -------------------------------------------- */
static void make_local_strips(ListBase *strips)
@@ -720,7 +791,7 @@ static void fcurves_path_rename_fix(ID *owner_id, const char *prefix, const char
if (fcu->rna_path != old_path) {
bActionGroup *agrp = fcu->grp;
- if ((agrp) && strcmp(oldName, agrp->name) == 0) {
+ if ((agrp) && STREQ(oldName, agrp->name)) {
BLI_strncpy(agrp->name, newName, sizeof(agrp->name));
}
}
@@ -757,7 +828,7 @@ static void drivers_path_rename_fix(ID *owner_id, ID *ref_id, const char *prefix
/* also fix the bone-name (if applicable) */
if (strstr(prefix, "bones")) {
if ( ((dtar->id) && (GS(dtar->id->name) == ID_OB) && (!ref_id || ((Object *)(dtar->id))->data == ref_id)) &&
- (dtar->pchan_name[0]) && (strcmp(oldName, dtar->pchan_name) == 0) )
+ (dtar->pchan_name[0]) && STREQ(oldName, dtar->pchan_name) )
{
BLI_strncpy(dtar->pchan_name, newName, sizeof(dtar->pchan_name));
}
@@ -787,6 +858,60 @@ static void nlastrips_path_rename_fix(ID *owner_id, const char *prefix, const ch
}
}
+/* ----------------------- */
+
+
+/* Fix up the given RNA-Path
+ *
+ * This is just an external wrapper for the RNA-Path fixing function,
+ * with input validity checks on top of the basic method.
+ *
+ * NOTE: it is assumed that the structure we're replacing is <prefix><["><name><"]>
+ * i.e. pose.bones["Bone"]
+ */
+char *BKE_animsys_fix_rna_path_rename(ID *owner_id, char *old_path, const char *prefix, const char *oldName,
+ const char *newName, int oldSubscript, int newSubscript, bool verify_paths)
+{
+ char *oldN, *newN;
+ char *result;
+
+ /* if no action, no need to proceed */
+ if (ELEM(NULL, owner_id, old_path)) {
+ printf("early abort\n");
+ return old_path;
+ }
+
+ /* Name sanitation logic - copied from BKE_animdata_fix_paths_rename() */
+ if ((oldName != NULL) && (newName != NULL)) {
+ /* pad the names with [" "] so that only exact matches are made */
+ const size_t name_old_len = strlen(oldName);
+ const size_t name_new_len = strlen(newName);
+ char *name_old_esc = BLI_array_alloca(name_old_esc, (name_old_len * 2) + 1);
+ char *name_new_esc = BLI_array_alloca(name_new_esc, (name_new_len * 2) + 1);
+
+ BLI_strescape(name_old_esc, oldName, (name_old_len * 2) + 1);
+ BLI_strescape(name_new_esc, newName, (name_new_len * 2) + 1);
+ oldN = BLI_sprintfN("[\"%s\"]", name_old_esc);
+ newN = BLI_sprintfN("[\"%s\"]", name_new_esc);
+ }
+ else {
+ oldN = BLI_sprintfN("[%d]", oldSubscript);
+ newN = BLI_sprintfN("[%d]", newSubscript);
+ }
+
+ /* fix given path */
+ printf("%s | %s | oldpath = %p ", oldN, newN, old_path);
+ result = rna_path_rename_fix(owner_id, prefix, oldN, newN, old_path, verify_paths);
+ printf("result = %p\n", result);
+
+ /* free the temp names */
+ MEM_freeN(oldN);
+ MEM_freeN(newN);
+
+ /* return the resulting path - may be the same path again if nothing changed */
+ return result;
+}
+
/* Fix all RNA_Paths in the given Action, relative to the given ID block
*
* This is just an external wrapper for the F-Curve fixing function,
@@ -1156,7 +1281,7 @@ KS_Path *BKE_keyingset_find_path(KeyingSet *ks, ID *id, const char group_name[],
eq_id = 0;
/* path */
- if ((ksp->rna_path == NULL) || strcmp(rna_path, ksp->rna_path))
+ if ((ksp->rna_path == NULL) || !STREQ(rna_path, ksp->rna_path))
eq_path = 0;
/* index - need to compare whole-array setting too... */
@@ -1192,6 +1317,7 @@ KeyingSet *BKE_keyingset_add(ListBase *list, const char idname[], const char nam
ks->flag = flag;
ks->keyingflag = keyingflag;
+ ks->keyingoverride = keyingflag; /* NOTE: assume that if one is set one way, the other should be too, so that it'll work */
/* add KeyingSet to list */
BLI_addtail(list, ks);
diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c
index 50f9a9be05d..60e81003c40 100644
--- a/source/blender/blenkernel/intern/appdir.c
+++ b/source/blender/blenkernel/intern/appdir.c
@@ -17,7 +17,7 @@
*
*/
-/** \file blender/blenlib/intern/appdir.c
+/** \file blender/blenkernel/intern/appdir.c
* \ingroup bke
*
* Access to application level directories.
@@ -641,7 +641,7 @@ static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name
}
}
#if defined(DEBUG)
- if (strcmp(name, fullname)) {
+ if (!STREQ(name, fullname)) {
printf("guessing '%s' == '%s'\n", name, fullname);
}
#endif
diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c
index 431c24d3ed0..31695b05352 100644
--- a/source/blender/blenkernel/intern/armature.c
+++ b/source/blender/blenkernel/intern/armature.c
@@ -233,7 +233,7 @@ static Bone *get_named_bone_bonechildren(Bone *bone, const char *name)
{
Bone *curBone, *rbone;
- if (!strcmp(bone->name, name))
+ if (STREQ(bone->name, name))
return bone;
for (curBone = bone->childbase.first; curBone; curBone = curBone->next) {
@@ -2206,7 +2206,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
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);
+ float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
bulge = interpf(soft, hard, ikData->bulge_smooth);
}
@@ -2218,7 +2218,7 @@ static void splineik_evaluate_bone(tSplineIK_Tree *tree, Scene *scene, Object *o
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);
+ float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
bulge = interpf(soft, hard, ikData->bulge_smooth);
}
@@ -2417,7 +2417,7 @@ static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseCha
/* validate first */
if (amod->ob && amod->ob->type == OB_CURVE && amod->channel[0]) {
- if (strcmp(pchan->name, amod->channel) == 0) {
+ if (STREQ(pchan->name, amod->channel)) {
float mat4[4][4], mat3[3][3];
curve_deform_vector(scene, amod->ob, armob, bone->arm_mat[3], pchan->pose_mat[3], mat3, amod->no_rot_axis);
@@ -2430,7 +2430,7 @@ static void do_strip_modifiers(Scene *scene, Object *armob, Bone *bone, bPoseCha
break;
case ACTSTRIP_MOD_NOISE:
{
- if (strcmp(pchan->name, amod->channel) == 0) {
+ if (STREQ(pchan->name, amod->channel)) {
float nor[3], loc[3], ofs;
float eul[3], size[3], eulo[3], sizeo[3];
diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c
index 96f769587d9..dda790ea700 100644
--- a/source/blender/blenkernel/intern/blender.c
+++ b/source/blender/blenkernel/intern/blender.c
@@ -146,10 +146,6 @@ void initglobals(void)
else
BLI_snprintf(versionstr, sizeof(versionstr), "v%d.%02d", BLENDER_VERSION / 100, BLENDER_VERSION % 100);
-#ifdef _WIN32
- G.windowstate = 0;
-#endif
-
#ifndef WITH_PYTHON_SECURITY /* default */
G.f |= G_SCRIPT_AUTOEXEC;
#else
@@ -189,6 +185,17 @@ static void clean_paths(Main *main)
}
}
+static bool wm_scene_is_visible(wmWindowManager *wm, Scene *scene)
+{
+ wmWindow *win;
+ for (win = wm->windows.first; win; win = win->next) {
+ if (win->screen->scene == scene) {
+ return true;
+ }
+ }
+ return false;
+}
+
/* context matching */
/* handle no-ui case */
@@ -232,24 +239,54 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
/* no load screens? */
if (mode != LOAD_UI) {
+ /* Logic for 'track_undo_scene' is to keep using the scene which the active screen has,
+ * as long as the scene associated with the undo operation is visible in one of the open windows.
+ *
+ * - 'curscreen->scene' - scene the user is currently looking at.
+ * - 'bfd->curscene' - scene undo-step was created in.
+ *
+ * This means users can have 2+ windows open and undo in both without screens switching.
+ * But if they close one of the screens,
+ * undo will ensure that the scene being operated on will be activated
+ * (otherwise we'd be undoing on an off-screen scene which isn't acceptable).
+ * see: T43424
+ */
+ bool track_undo_scene;
+
/* comes from readfile.c */
SWAP(ListBase, G.main->wm, bfd->main->wm);
SWAP(ListBase, G.main->screen, bfd->main->screen);
SWAP(ListBase, G.main->script, bfd->main->script);
- /* we re-use current screen */
curscreen = CTX_wm_screen(C);
- /* but use new Scene pointer */
- curscene = bfd->curscene;
+
+ track_undo_scene = (mode == LOAD_UNDO && curscreen && bfd->main->wm.first);
+ if (track_undo_scene) {
+ curscene = curscreen->scene;
+ }
+ else {
+ /* but use new Scene pointer */
+ curscene = bfd->curscene;
+ }
+
if (curscene == NULL) curscene = bfd->main->scene.first;
/* empty file, we add a scene to make Blender work */
if (curscene == NULL) curscene = BKE_scene_add(bfd->main, "Empty");
-
+
/* and we enforce curscene to be in current screen */
if (curscreen) curscreen->scene = curscene; /* can run in bgmode */
/* clear_global will free G.main, here we can still restore pointers */
blo_lib_link_screen_restore(bfd->main, curscreen, curscene);
+ curscene = curscreen->scene;
+
+ if (track_undo_scene) {
+ wmWindowManager *wm = bfd->main->wm.first;
+ if (wm_scene_is_visible(wm, bfd->curscene) == false) {
+ curscene = bfd->curscene;
+ curscreen->scene = curscene;
+ }
+ }
}
/* free G.main Main database */
@@ -271,6 +308,17 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
BKE_userdef_free();
U = *bfd->user;
+
+ /* Security issue: any blend file could include a USER block.
+ *
+ * Currently we load prefs from BLENDER_STARTUP_FILE and later on load BLENDER_USERPREF_FILE,
+ * to load the preferences defined in the users home dir.
+ *
+ * This means we will never accidentally (or maliciously)
+ * enable scripts auto-execution by loading a '.blend' file.
+ */
+ U.flag |= USER_SCRIPT_AUTOEXEC_DISABLE;
+
MEM_freeN(bfd->user);
}
@@ -280,8 +328,6 @@ static void setup_app_data(bContext *C, BlendFileData *bfd, const char *filepath
CTX_data_scene_set(C, curscene);
}
else {
- G.winpos = bfd->winpos;
- G.displaymode = bfd->displaymode;
G.fileflags = bfd->fileflags;
CTX_wm_manager_set(C, G.main->wm.first);
CTX_wm_screen_set(C, bfd->curscreen);
@@ -568,7 +614,7 @@ int BKE_write_file_userdef(const char *filepath, ReportList *reports)
static void (*blender_test_break_cb)(void) = NULL;
-void set_blender_test_break_cb(void (*func)(void) )
+void set_blender_test_break_cb(void (*func)(void))
{
blender_test_break_cb = func;
}
diff --git a/source/blender/blenkernel/intern/boids.c b/source/blender/blenkernel/intern/boids.c
index 4a564614ff3..11879c7973c 100644
--- a/source/blender/blenkernel/intern/boids.c
+++ b/source/blender/blenkernel/intern/boids.c
@@ -994,7 +994,7 @@ void boid_brain(BoidBrainData *bbd, int p, ParticleData *pa)
}
case eBoidRulesetType_Random:
{
- /* use random rule for each particle (allways same for same particle though) */
+ /* use random rule for each particle (always same for same particle though) */
rule = BLI_findlink(&state->rules, rand % BLI_listbase_count(&state->rules));
apply_boid_rule(bbd, rule, &val, pa, -1.0);
diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c
index 964d876a9a0..aa92b67c737 100644
--- a/source/blender/blenkernel/intern/bpath.c
+++ b/source/blender/blenkernel/intern/bpath.c
@@ -229,7 +229,7 @@ static int findFileRecursive(char *filename_new,
while ((de = readdir(dir)) != NULL) {
- if (STREQ(".", de->d_name) || STREQ("..", de->d_name))
+ if (FILENAME_IS_CURRPAR(de->d_name))
continue;
BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
@@ -285,7 +285,7 @@ static bool findMissingFiles_visit_cb(void *userdata, char *path_dst, const char
filename_new[0] = '\0';
found = findFileRecursive(filename_new,
- data->searchdir, BLI_path_basename((char *)path_src),
+ data->searchdir, BLI_path_basename(path_src),
&filesize, &recur_depth);
if (filesize == -1) { /* could not open dir */
@@ -297,7 +297,7 @@ static bool findMissingFiles_visit_cb(void *userdata, char *path_dst, const char
else if (found == false) {
BKE_reportf(data->reports, RPT_WARNING,
"Could not find '%s' in '%s'",
- BLI_path_basename((char *)path_src), data->searchdir);
+ BLI_path_basename(path_src), data->searchdir);
return false;
}
else {
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index 55d347a4fb2..10d77921515 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -542,7 +542,7 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
/* Get strength by feeding the vertex
* location directly into a texture */
hasrgb = externtex(mtex, point, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
}
else if (mtex->brush_map_mode == MTEX_MAP_MODE_STENCIL) {
float rotation = -mtex->rot;
@@ -573,7 +573,7 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
co[2] = 0.0f;
hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
}
else {
float rotation = -mtex->rot;
@@ -630,7 +630,7 @@ float BKE_brush_sample_tex_3D(const Scene *scene, Brush *br,
co[2] = 0.0f;
hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
}
intensity += br->texture_sample_bias;
@@ -690,7 +690,7 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
co[2] = 0.0f;
externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
}
else {
float rotation = -mtex->rot;
@@ -747,7 +747,7 @@ float BKE_brush_sample_masktex(const Scene *scene, Brush *br,
co[2] = 0.0f;
externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
}
CLAMP(intensity, 0.0f, 1.0f);
@@ -810,6 +810,9 @@ void BKE_brush_size_set(Scene *scene, Brush *brush, int size)
size = (int)((float)size / U.pixelsize);
+ /* make sure range is sane */
+ CLAMP(size, 1, MAX_BRUSH_PIXEL_RADIUS);
+
if (ups->flag & UNIFIED_PAINT_SIZE)
ups->size = size;
else
@@ -1007,7 +1010,7 @@ unsigned int *BKE_brush_gen_texture_cache(Brush *br, int half_side, bool use_sec
/* This is copied from displace modifier code */
/* TODO(sergey): brush are always cacheing with CM enabled for now. */
externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL);
+ rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false);
((char *)texcache)[(iy * side + ix) * 4] =
((char *)texcache)[(iy * side + ix) * 4 + 1] =
diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c
index a1bf255c239..2554151c99d 100644
--- a/source/blender/blenkernel/intern/cdderivedmesh.c
+++ b/source/blender/blenkernel/intern/cdderivedmesh.c
@@ -869,59 +869,7 @@ static void cdDM_drawMappedFacesTex(DerivedMesh *dm,
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;
-
- /* orco texture coordinates */
- if (attribs->totorco) {
- /*const*/ float (*array)[3] = attribs->orco.array;
- const float *orco = (array) ? array[index] : zero;
-
- if (attribs->orco.gl_texco)
- glTexCoord3fv(orco);
- else
- glVertexAttrib3fvARB(attribs->orco.gl_index, orco);
- }
-
- /* uv texture coordinates */
- for (b = 0; b < attribs->tottface; b++) {
- const float *uv;
-
- if (attribs->tface[b].array) {
- MTFace *tf = &attribs->tface[b].array[a];
- uv = tf->uv[vert];
- }
- else {
- uv = zero;
- }
-
- if (attribs->tface[b].gl_texco)
- glTexCoord2fv(uv);
- else
- glVertexAttrib2fvARB(attribs->tface[b].gl_index, uv);
- }
-
- /* vertex colors */
- for (b = 0; b < attribs->totmcol; b++) {
- GLubyte col[4];
-
- if (attribs->mcol[b].array) {
- MCol *cp = &attribs->mcol[b].array[a * 4 + vert];
- col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a;
- }
- else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
- }
-
- glVertexAttrib4ubvARB(attribs->mcol[b].gl_index, col);
- }
-
- /* tangent for normal mapping */
- if (attribs->tottang) {
- /*const*/ float (*array)[4] = attribs->tang.array;
- const float *tang = (array) ? array[a * 4 + vert] : zero;
- glVertexAttrib4fvARB(attribs->tang.gl_index, tang);
- }
+ DM_draw_attrib_vertex(attribs, a, index, vert);
/* vertex normal */
if (lnor) {
@@ -1592,6 +1540,7 @@ static CDDerivedMesh *cdDM_create(const char *desc)
dm->calcNormals = CDDM_calc_normals;
dm->calcLoopNormals = CDDM_calc_loop_normals;
+ dm->calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr;
dm->recalcTessellation = CDDM_recalc_tessellation;
dm->getVertCos = cdDM_getVertCos;
@@ -2208,7 +2157,15 @@ void CDDM_calc_normals(DerivedMesh *dm)
#endif
-void CDDM_calc_loop_normals(DerivedMesh *dm, const float split_angle)
+void CDDM_calc_loop_normals(DerivedMesh *dm, const bool use_split_normals, const float split_angle)
+{
+ CDDM_calc_loop_normals_spacearr(dm, use_split_normals, split_angle, NULL);
+}
+
+/* #define DEBUG_CLNORS */
+
+void CDDM_calc_loop_normals_spacearr(
+ DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr)
{
MVert *mverts = dm->getVertArray(dm);
MEdge *medges = dm->getEdgeArray(dm);
@@ -2218,6 +2175,7 @@ void CDDM_calc_loop_normals(DerivedMesh *dm, const float split_angle)
CustomData *ldata, *pdata;
float (*lnors)[3];
+ short (*clnor_data)[2];
float (*pnors)[3];
const int numVerts = dm->getNumVerts(dm);
@@ -2245,8 +2203,37 @@ void CDDM_calc_loop_normals(DerivedMesh *dm, const float split_angle)
dm->dirty &= ~DM_DIRTY_NORMALS;
+ clnor_data = CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL);
+
BKE_mesh_normals_loop_split(mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
- mpolys, pnors, numPolys, split_angle);
+ mpolys, (const float (*)[3])pnors, numPolys,
+ use_split_normals, split_angle,
+ r_lnors_spacearr, clnor_data, NULL);
+#ifdef DEBUG_CLNORS
+ if (r_lnors_spacearr) {
+ int i;
+ for (i = 0; i < numLoops; i++) {
+ if (r_lnors_spacearr->lspacearr[i]->ref_alpha != 0.0f) {
+ LinkNode *loops = r_lnors_spacearr->lspacearr[i]->loops;
+ printf("Loop %d uses lnor space %p:\n", i, r_lnors_spacearr->lspacearr[i]);
+ print_v3("\tfinal lnor", lnors[i]);
+ print_v3("\tauto lnor", r_lnors_spacearr->lspacearr[i]->vec_lnor);
+ print_v3("\tref_vec", r_lnors_spacearr->lspacearr[i]->vec_ref);
+ printf("\talpha: %f\n\tbeta: %f\n\tloops: %p\n", r_lnors_spacearr->lspacearr[i]->ref_alpha,
+ r_lnors_spacearr->lspacearr[i]->ref_beta, r_lnors_spacearr->lspacearr[i]->loops);
+ printf("\t\t(shared with loops");
+ while (loops) {
+ printf(" %d", GET_INT_FROM_POINTER(loops->link));
+ loops = loops->next;
+ }
+ printf(")\n");
+ }
+ else {
+ printf("Loop %d has no lnor space\n", i);
+ }
+ }
+ }
+#endif
}
diff --git a/source/blender/blenkernel/intern/cloth.c b/source/blender/blenkernel/intern/cloth.c
index e1b5dd6d39d..765986cc82b 100644
--- a/source/blender/blenkernel/intern/cloth.c
+++ b/source/blender/blenkernel/intern/cloth.c
@@ -47,16 +47,9 @@
#include "BKE_modifier.h"
#include "BKE_pointcache.h"
-// #include "PIL_time.h" /* timing for debug prints */
+#include "BPH_mass_spring.h"
-/* Our available solvers. */
-// 255 is the magic reserved number, so NEVER try to put 255 solvers in here!
-// 254 = MAX!
-static CM_SOLVER_DEF solvers [] =
-{
- { "Implicit", CM_IMPLICIT, implicit_init, implicit_solver, implicit_free },
- // { "Implicit C++", CM_IMPLICITCPP, implicitcpp_init, implicitcpp_solver, implicitcpp_free },
-};
+// #include "PIL_time.h" /* timing for debug prints */
/* ********** cloth engine ******* */
/* Prototypes for internal functions.
@@ -68,7 +61,6 @@ static void cloth_update_springs( ClothModifierData *clmd );
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm );
static void cloth_apply_vgroup ( ClothModifierData *clmd, DerivedMesh *dm );
-
/******************************************************************************
*
* External interface called by modifier.c clothModifier functions.
@@ -89,6 +81,7 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->structural = 15.0;
clmd->sim_parms->shear = 15.0;
clmd->sim_parms->bending = 0.5;
+ clmd->sim_parms->bending_damping = 0.5;
clmd->sim_parms->Cdis = 5.0;
clmd->sim_parms->Cvi = 1.0;
clmd->sim_parms->mass = 0.3f;
@@ -130,6 +123,8 @@ void cloth_init(ClothModifierData *clmd )
clmd->sim_parms->goalfrict = 0.0f;
clmd->sim_parms->velocity_smooth = 0.0f;
+ clmd->sim_parms->voxel_cell_size = 0.1f;
+
if (!clmd->sim_parms->effector_weights)
clmd->sim_parms->effector_weights = BKE_add_effector_weights(NULL);
@@ -343,7 +338,7 @@ static int do_init_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
return 0;
}
- implicit_set_positions(clmd);
+ BKE_cloth_solver_set_positions(clmd);
clmd->clothObject->last_frame= MINFRAME-1;
}
@@ -385,8 +380,7 @@ static int do_step_cloth(Object *ob, ClothModifierData *clmd, DerivedMesh *resul
// TIMEIT_START(cloth_step)
/* call the solver. */
- if (solvers [clmd->sim_parms->solver_type].solver)
- ret = solvers[clmd->sim_parms->solver_type].solver(ob, framenr, clmd, effectors);
+ ret = BPH_cloth_solve(ob, framenr, clmd, effectors);
// TIMEIT_END(cloth_step)
@@ -531,7 +525,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
cache_result = BKE_ptcache_read(&pid, (float)framenr+scene->r.subframe);
if (cache_result == PTCACHE_READ_EXACT || cache_result == PTCACHE_READ_INTERPOLATED) {
- implicit_set_positions(clmd);
+ BKE_cloth_solver_set_positions(clmd);
cloth_to_object (ob, clmd, vertexCos);
BKE_ptcache_validate(cache, framenr);
@@ -544,7 +538,7 @@ void clothModifier_do(ClothModifierData *clmd, Scene *scene, Object *ob, Derived
return;
}
else if (cache_result==PTCACHE_READ_OLD) {
- implicit_set_positions(clmd);
+ BKE_cloth_solver_set_positions(clmd);
}
if (framenr!=clmd->clothObject->last_frame+1)
@@ -581,10 +575,7 @@ void cloth_free_modifier(ClothModifierData *clmd )
if ( cloth ) {
- // If our solver provides a free function, call it
- if ( solvers [clmd->sim_parms->solver_type].free ) {
- solvers [clmd->sim_parms->solver_type].free ( clmd );
- }
+ BPH_cloth_solver_free(clmd);
// Free the verts.
if ( cloth->verts != NULL )
@@ -650,10 +641,7 @@ void cloth_free_modifier_extern(ClothModifierData *clmd )
if (G.debug_value > 0)
printf("cloth_free_modifier_extern in\n");
- // If our solver provides a free function, call it
- if ( solvers [clmd->sim_parms->solver_type].free ) {
- solvers [clmd->sim_parms->solver_type].free ( clmd );
- }
+ BPH_cloth_solver_free(clmd);
// Free the verts.
if ( cloth->verts != NULL )
@@ -931,12 +919,10 @@ static int cloth_from_object(Object *ob, ClothModifierData *clmd, DerivedMesh *d
}
// init our solver
- if ( solvers [clmd->sim_parms->solver_type].init ) {
- solvers [clmd->sim_parms->solver_type].init ( ob, clmd );
- }
+ BPH_cloth_solver_init(ob, clmd);
if (!first)
- implicit_set_positions(clmd);
+ BKE_cloth_solver_set_positions(clmd);
clmd->clothObject->bvhtree = bvhtree_build_from_cloth ( clmd, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel) );
@@ -1068,6 +1054,135 @@ static void cloth_free_errorsprings(Cloth *cloth, LinkNode **edgelist)
}
}
+static void cloth_hair_update_bending_targets(ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = NULL;
+ float hair_frame[3][3], dir_old[3], dir_new[3];
+ int prev_mn; /* to find hair chains */
+
+ if (!clmd->hairdata)
+ return;
+
+ /* XXX Note: we need to propagate frames from the root up,
+ * but structural hair springs are stored in reverse order.
+ * The bending springs however are then inserted in the same
+ * order as vertices again ...
+ * This messy situation can be resolved when solver data is
+ * generated directly from a dedicated hair system.
+ */
+
+ prev_mn = -1;
+ for (search = cloth->springs; search; search = search->next) {
+ ClothSpring *spring = search->link;
+ ClothHairData *hair_ij, *hair_kl;
+ bool is_root = spring->kl != prev_mn;
+
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) {
+ continue;
+ }
+
+ hair_ij = &clmd->hairdata[spring->ij];
+ hair_kl = &clmd->hairdata[spring->kl];
+ if (is_root) {
+ /* initial hair frame from root orientation */
+ copy_m3_m3(hair_frame, hair_ij->rot);
+ /* surface normal is the initial direction,
+ * parallel transport then keeps it aligned to the hair direction
+ */
+ copy_v3_v3(dir_new, hair_frame[2]);
+ }
+
+ copy_v3_v3(dir_old, dir_new);
+ sub_v3_v3v3(dir_new, cloth->verts[spring->mn].x, cloth->verts[spring->kl].x);
+ normalize_v3(dir_new);
+
+#if 0
+ if (clmd->debug_data && (spring->ij == 0 || spring->ij == 1)) {
+ float a[3], b[3];
+
+ copy_v3_v3(a, cloth->verts[spring->kl].x);
+// BKE_sim_debug_data_add_dot(clmd->debug_data, cloth_vert ? cloth_vert->x : key->co, 1, 1, 0, "frames", 8246, p, k);
+
+ mul_v3_v3fl(b, hair_frame[0], clmd->sim_parms->avg_spring_len);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 1, 0, 0, "frames", 8247, spring->kl, spring->mn);
+
+ mul_v3_v3fl(b, hair_frame[1], clmd->sim_parms->avg_spring_len);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 1, 0, "frames", 8248, spring->kl, spring->mn);
+
+ mul_v3_v3fl(b, hair_frame[2], clmd->sim_parms->avg_spring_len);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, a, b, 0, 0, 1, "frames", 8249, spring->kl, spring->mn);
+ }
+#endif
+
+ /* get local targets for kl/mn vertices by putting rest targets into the current frame,
+ * then multiply with the rest length to get the actual goals
+ */
+
+ mul_v3_m3v3(spring->target, hair_frame, hair_kl->rest_target);
+ mul_v3_fl(spring->target, spring->restlen);
+
+ /* move frame to next hair segment */
+ cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new);
+
+ prev_mn = spring->mn;
+ }
+}
+
+static void cloth_hair_update_bending_rest_targets(ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+ LinkNode *search = NULL;
+ float hair_frame[3][3], dir_old[3], dir_new[3];
+ int prev_mn; /* to find hair roots */
+
+ if (!clmd->hairdata)
+ return;
+
+ /* XXX Note: we need to propagate frames from the root up,
+ * but structural hair springs are stored in reverse order.
+ * The bending springs however are then inserted in the same
+ * order as vertices again ...
+ * This messy situation can be resolved when solver data is
+ * generated directly from a dedicated hair system.
+ */
+
+ prev_mn = -1;
+ for (search = cloth->springs; search; search = search->next) {
+ ClothSpring *spring = search->link;
+ ClothHairData *hair_ij, *hair_kl;
+ bool is_root = spring->kl != prev_mn;
+
+ if (spring->type != CLOTH_SPRING_TYPE_BENDING_ANG) {
+ continue;
+ }
+
+ hair_ij = &clmd->hairdata[spring->ij];
+ hair_kl = &clmd->hairdata[spring->kl];
+ if (is_root) {
+ /* initial hair frame from root orientation */
+ copy_m3_m3(hair_frame, hair_ij->rot);
+ /* surface normal is the initial direction,
+ * parallel transport then keeps it aligned to the hair direction
+ */
+ copy_v3_v3(dir_new, hair_frame[2]);
+ }
+
+ copy_v3_v3(dir_old, dir_new);
+ sub_v3_v3v3(dir_new, cloth->verts[spring->mn].xrest, cloth->verts[spring->kl].xrest);
+ normalize_v3(dir_new);
+
+ /* dir expressed in the hair frame defines the rest target direction */
+ copy_v3_v3(hair_kl->rest_target, dir_new);
+ mul_transposed_m3_v3(hair_frame, hair_kl->rest_target);
+
+ /* move frame to next hair segment */
+ cloth_parallel_transport_hair_frame(hair_frame, dir_old, dir_new);
+
+ prev_mn = spring->mn;
+ }
+}
+
/* update stiffness if vertex group values are changing from frame to frame */
static void cloth_update_springs( ClothModifierData *clmd )
{
@@ -1089,6 +1204,16 @@ static void cloth_update_springs( ClothModifierData *clmd )
else if (spring->type == CLOTH_SPRING_TYPE_BENDING) {
spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
}
+ else if (spring->type == CLOTH_SPRING_TYPE_BENDING_ANG) {
+ ClothVertex *v1 = &cloth->verts[spring->ij];
+ ClothVertex *v2 = &cloth->verts[spring->kl];
+ if (clmd->hairdata) {
+ /* copy extra hair data to generic cloth vertices */
+ v1->bend_stiff = clmd->hairdata[spring->ij].bending_stiffness;
+ v2->bend_stiff = clmd->hairdata[spring->kl].bending_stiffness;
+ }
+ spring->stiffness = (v1->bend_stiff + v2->bend_stiff) / 2.0f;
+ }
else if (spring->type == CLOTH_SPRING_TYPE_GOAL) {
/* Warning: Appending NEW goal springs does not work because implicit solver would need reset! */
@@ -1105,8 +1230,43 @@ static void cloth_update_springs( ClothModifierData *clmd )
search = search->next;
}
+
+ cloth_hair_update_bending_targets(clmd);
+}
+BLI_INLINE void cross_identity_v3(float r[3][3], const float v[3])
+{
+ zero_m3(r);
+ r[0][1] = v[2];
+ r[0][2] = -v[1];
+ r[1][0] = -v[2];
+ r[1][2] = v[0];
+ r[2][0] = v[1];
+ r[2][1] = -v[0];
+}
+BLI_INLINE void madd_m3_m3fl(float r[3][3], float m[3][3], float f)
+{
+ r[0][0] += m[0][0] * f;
+ r[0][1] += m[0][1] * f;
+ r[0][2] += m[0][2] * f;
+ r[1][0] += m[1][0] * f;
+ r[1][1] += m[1][1] * f;
+ r[1][2] += m[1][2] * f;
+ r[2][0] += m[2][0] * f;
+ r[2][1] += m[2][1] * f;
+ r[2][2] += m[2][2] * f;
+}
+
+void cloth_parallel_transport_hair_frame(float mat[3][3], const float dir_old[3], const float dir_new[3])
+{
+ float rot[3][3];
+
+ /* rotation between segments */
+ rotation_between_vecs_to_mat3(rot, dir_old, dir_new);
+
+ /* rotate the frame */
+ mul_m3_m3m3(mat, rot, mat);
}
static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
@@ -1283,40 +1443,74 @@ static int cloth_build_springs ( ClothModifierData *clmd, DerivedMesh *dm )
}
}
else if (struct_springs > 2) {
- /* bending springs for hair strands */
- /* The current algorightm only goes through the edges in order of the mesh edges list */
- /* and makes springs between the outer vert of edges sharing a vertice. This works just */
- /* fine for hair, but not for user generated string meshes. This could/should be later */
- /* extended to work with non-ordered edges so that it can be used for general "rope */
- /* dynamics" without the need for the vertices or edges to be ordered through the length*/
- /* of the strands. -jahka */
- search = cloth->springs;
- search2 = search->next;
- while (search && search2) {
- tspring = search->link;
- tspring2 = search2->link;
-
- if (tspring->ij == tspring2->kl) {
- spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+ if (G.debug_value != 1112) {
+ search = cloth->springs;
+ search2 = search->next;
+ while (search && search2) {
+ tspring = search->link;
+ tspring2 = search2->link;
- if (!spring) {
- cloth_free_errorsprings(cloth, edgelist);
- return 0;
+ if (tspring->ij == tspring2->kl) {
+ spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+
+ if (!spring) {
+ cloth_free_errorsprings(cloth, edgelist);
+ return 0;
+ }
+
+ spring->ij = tspring2->ij;
+ spring->kl = tspring->ij;
+ spring->mn = tspring->kl;
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
+ spring->type = CLOTH_SPRING_TYPE_BENDING_ANG;
+ spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ bend_springs++;
+
+ BLI_linklist_prepend ( &cloth->springs, spring );
}
-
- spring->ij = tspring2->ij;
- spring->kl = tspring->kl;
- spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
- spring->type = CLOTH_SPRING_TYPE_BENDING;
- spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
- bend_springs++;
-
- BLI_linklist_prepend ( &cloth->springs, spring );
+
+ search = search->next;
+ search2 = search2->next;
+ }
+ }
+ else {
+ /* bending springs for hair strands */
+ /* The current algorightm only goes through the edges in order of the mesh edges list */
+ /* and makes springs between the outer vert of edges sharing a vertice. This works just */
+ /* fine for hair, but not for user generated string meshes. This could/should be later */
+ /* extended to work with non-ordered edges so that it can be used for general "rope */
+ /* dynamics" without the need for the vertices or edges to be ordered through the length*/
+ /* of the strands. -jahka */
+ search = cloth->springs;
+ search2 = search->next;
+ while (search && search2) {
+ tspring = search->link;
+ tspring2 = search2->link;
+
+ if (tspring->ij == tspring2->kl) {
+ spring = (ClothSpring *)MEM_callocN ( sizeof ( ClothSpring ), "cloth spring" );
+
+ if (!spring) {
+ cloth_free_errorsprings(cloth, edgelist);
+ return 0;
+ }
+
+ spring->ij = tspring2->ij;
+ spring->kl = tspring->kl;
+ spring->restlen = len_v3v3(cloth->verts[spring->kl].xrest, cloth->verts[spring->ij].xrest);
+ spring->type = CLOTH_SPRING_TYPE_BENDING;
+ spring->stiffness = (cloth->verts[spring->kl].bend_stiff + cloth->verts[spring->ij].bend_stiff) / 2.0f;
+ bend_springs++;
+
+ BLI_linklist_prepend ( &cloth->springs, spring );
+ }
+
+ search = search->next;
+ search2 = search2->next;
}
-
- search = search->next;
- search2 = search2->next;
}
+
+ cloth_hair_update_bending_rest_targets(clmd);
}
/* note: the edges may already exist so run reinsert */
diff --git a/source/blender/blenkernel/intern/collision.c b/source/blender/blenkernel/intern/collision.c
index 3030ee4b4a4..5266c5b323d 100644
--- a/source/blender/blenkernel/intern/collision.c
+++ b/source/blender/blenkernel/intern/collision.c
@@ -33,6 +33,7 @@
#include "MEM_guardedalloc.h"
#include "DNA_cloth_types.h"
+#include "DNA_effect_types.h"
#include "DNA_group_types.h"
#include "DNA_object_types.h"
#include "DNA_object_force.h"
@@ -45,6 +46,7 @@
#include "BLI_edgehash.h"
#include "BKE_cloth.h"
+#include "BKE_effect.h"
#include "BKE_modifier.h"
#include "BKE_scene.h"
@@ -652,8 +654,8 @@ static void cloth_bvh_objcollisions_nearcheck ( ClothModifierData * clmd, Collis
*collisions_index = *collisions;
for ( i = 0; i < numresult; i++ ) {
- *collisions_index = cloth_collision ( (ModifierData *)clmd, (ModifierData *)collmd,
- overlap+i, *collisions_index, dt );
+ *collisions_index = cloth_collision((ModifierData *)clmd, (ModifierData *)collmd,
+ overlap+i, *collisions_index, dt);
}
}
@@ -913,3 +915,557 @@ int cloth_bvh_objcollision(Object *ob, ClothModifierData *clmd, float step, floa
return 1|MIN2 ( ret, 1 );
}
+
+BLI_INLINE void max_v3_v3v3(float r[3], const float a[3], const float b[3])
+{
+ r[0] = max_ff(a[0], b[0]);
+ r[1] = max_ff(a[1], b[1]);
+ r[2] = max_ff(a[2], b[2]);
+}
+
+void collision_get_collider_velocity(float vel_old[3], float vel_new[3], CollisionModifierData *collmd, CollPair *collpair)
+{
+ float u1, u2, u3;
+
+ /* compute barycentric coordinates */
+ collision_compute_barycentric(collpair->pb,
+ collmd->current_x[collpair->bp1].co,
+ collmd->current_x[collpair->bp2].co,
+ collmd->current_x[collpair->bp3].co,
+ &u1, &u2, &u3);
+
+ collision_interpolateOnTriangle(vel_new, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3);
+ /* XXX assume constant velocity of the collider for now */
+ copy_v3_v3(vel_old, vel_new);
+}
+
+static bool cloth_points_collision_response_static(ClothModifierData *clmd, CollisionModifierData *collmd, PartDeflect *pd,
+ CollPair *collpair, CollPair *collision_end, float dt)
+{
+ bool result = false;
+ float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - pd->pdef_sbdamp);
+ float inv_dt = 1.0f / dt;
+ Cloth *cloth1 = clmd->clothObject;
+
+ float w1, w2, u1, u2, u3;
+ float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
+ float epsilon2 = BLI_bvhtree_getepsilon ( collmd->bvhtree );
+
+ for ( ; collpair != collision_end; collpair++ ) {
+ float margin_distance = collpair->distance - epsilon2;
+ float impulse[3];
+ float mag_v_rel;
+
+ if (margin_distance > 0.0f)
+ continue;
+
+ zero_v3(impulse);
+
+ /* only handle static collisions here */
+ if ( collpair->flag & COLLISION_IN_FUTURE )
+ continue;
+
+ /* compute barycentric coordinates for both collision points */
+ w1 = 1.0f - collpair->time;
+ w2 = collpair->time;
+
+ /* was: txold */
+ collision_compute_barycentric ( collpair->pb,
+ collmd->current_x[collpair->bp1].co,
+ collmd->current_x[collpair->bp2].co,
+ collmd->current_x[collpair->bp3].co,
+ &u1, &u2, &u3 );
+
+ /* Calculate relative velocity */
+ copy_v3_v3(v1, cloth1->verts[collpair->ap1].tv);
+
+ collision_interpolateOnTriangle ( v2_new, collmd->current_v[collpair->bp1].co, collmd->current_v[collpair->bp2].co, collmd->current_v[collpair->bp3].co, u1, u2, u3 );
+ /* XXX assume constant velocity of the collider for now */
+ copy_v3_v3(v2_old, v2_new);
+
+ sub_v3_v3v3(v_rel_old, v1, v2_old);
+ sub_v3_v3v3(v_rel_new, v1, v2_new);
+
+ /* normal component of the relative velocity */
+ mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
+
+ /**** DEBUG ****/
+ BKE_sim_debug_data_add_dot(collpair->pa, 0.9, 0.2, 0.2, "collision", 833, collpair->face1, collpair->face2);
+ BKE_sim_debug_data_add_dot(collpair->pb, 0.2, 0.9, 0.2, "collision", 834, collpair->face1, collpair->face2);
+ BKE_sim_debug_data_add_line(collpair->pa, collpair->pb, 0.8, 0.8, 0.8, "collision", 835, collpair->face1, collpair->face2);
+ /********/
+
+ if (mag_v_rel < -ALMOST_ZERO) {
+ float v_nor_old, v_nor_new;
+ float v_tan_old[3], v_tan_new[3];
+ float bounce, repulse;
+
+ /* Collision response based on
+ * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
+ * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
+ */
+
+ v_nor_old = mag_v_rel;
+ v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
+
+ madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
+ madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
+
+ repulse = -margin_distance * inv_dt + dot_v3v3(v1, collpair->normal);
+
+ if (margin_distance < -epsilon2) {
+ bounce = -v_nor_new + v_nor_old * restitution;
+ mul_v3_v3fl(impulse, collpair->normal, max_ff(repulse, bounce));
+ }
+ else {
+ bounce = 0.0f;
+ mul_v3_v3fl(impulse, collpair->normal, repulse);
+ }
+ cloth1->verts[collpair->ap1].impulse_count++;
+
+ result = true;
+ }
+
+ if (result) {
+ int i = 0;
+
+ for (i = 0; i < 3; i++) {
+ if (cloth1->verts[collpair->ap1].impulse_count > 0 && fabsf(cloth1->verts[collpair->ap1].impulse[i]) < fabsf(impulse[i]))
+ cloth1->verts[collpair->ap1].impulse[i] = impulse[i];
+ }
+ }
+ }
+ return result;
+}
+
+BLI_INLINE bool cloth_point_face_collision_params(const float p1[3], const float p2[3], const float v0[3], const float v1[3], const float v2[3],
+ float r_nor[3], float *r_lambda, float r_w[4])
+{
+ float edge1[3], edge2[3], p2face[3], p1p2[3], v0p2[3];
+ float nor_v0p2, nor_p1p2;
+
+ sub_v3_v3v3(edge1, v1, v0);
+ sub_v3_v3v3(edge2, v2, v0);
+ cross_v3_v3v3(r_nor, edge1, edge2);
+ normalize_v3(r_nor);
+
+ nor_v0p2 = dot_v3v3(v0p2, r_nor);
+ madd_v3_v3v3fl(p2face, p2, r_nor, -nor_v0p2);
+ interp_weights_face_v3(r_w, v0, v1, v2, NULL, p2face);
+
+ sub_v3_v3v3(p1p2, p2, p1);
+ sub_v3_v3v3(v0p2, p2, v0);
+ nor_p1p2 = dot_v3v3(p1p2, r_nor);
+ *r_lambda = (nor_p1p2 != 0.0f ? nor_v0p2 / nor_p1p2 : 0.0f);
+
+ return r_w[1] >= 0.0f && r_w[2] >= 0.0f && r_w[1] + r_w[2] <= 1.0f;
+
+#if 0 /* XXX this method uses the intersection point, but is broken and doesn't work well in general */
+ float p[3], vec1[3], line[3], edge1[3], edge2[3], q[3];
+ float a, f, u, v;
+
+ sub_v3_v3v3(edge1, v1, v0);
+ sub_v3_v3v3(edge2, v2, v0);
+ sub_v3_v3v3(line, p2, p1);
+
+ cross_v3_v3v3(p, line, edge2);
+ a = dot_v3v3(edge1, p);
+ if (a == 0.0f) return 0;
+ f = 1.0f / a;
+
+ sub_v3_v3v3(vec1, p1, v0);
+
+ u = f * dot_v3v3(vec1, p);
+ if ((u < 0.0f) || (u > 1.0f))
+ return false;
+
+ cross_v3_v3v3(q, vec1, edge1);
+
+ v = f * dot_v3v3(line, q);
+ if ((v < 0.0f) || ((u + v) > 1.0f))
+ return false;
+
+ *r_lambda = f * dot_v3v3(edge2, q);
+ /* don't care about 0..1 lambda range here */
+ /*if ((*r_lambda < 0.0f) || (*r_lambda > 1.0f))
+ * return 0;
+ */
+
+ r_w[0] = 1.0f - u - v;
+ r_w[1] = u;
+ r_w[2] = v;
+ r_w[3] = 0.0f;
+
+ cross_v3_v3v3(r_nor, edge1, edge2);
+ normalize_v3(r_nor);
+
+ return true;
+#endif
+}
+
+static CollPair *cloth_point_collpair(float p1[3], float p2[3], MVert *mverts, int bp1, int bp2, int bp3,
+ int index_cloth, int index_coll, float epsilon, CollPair *collpair)
+{
+ float *co1 = mverts[bp1].co, *co2 = mverts[bp2].co, *co3 = mverts[bp3].co;
+ float lambda, distance1, distance2;
+ float facenor[3], v1p1[3], v1p2[3];
+ float w[4];
+
+ if (!cloth_point_face_collision_params(p1, p2, co1, co2, co3, facenor, &lambda, w))
+ return collpair;
+
+ sub_v3_v3v3(v1p1, p1, co1);
+ distance1 = dot_v3v3(v1p1, facenor);
+ sub_v3_v3v3(v1p2, p2, co1);
+ distance2 = dot_v3v3(v1p2, facenor);
+// if (distance2 > epsilon || (distance1 < 0.0f && distance2 < 0.0f))
+ if (distance2 > epsilon)
+ return collpair;
+
+ collpair->face1 = index_cloth; /* XXX actually not a face, but equivalent index for point */
+ collpair->face2 = index_coll;
+ collpair->ap1 = index_cloth;
+ collpair->ap2 = collpair->ap3 = -1; /* unused */
+ collpair->bp1 = bp1;
+ collpair->bp2 = bp2;
+ collpair->bp3 = bp3;
+
+ /* note: using the second point here, which is
+ * the current updated position that needs to be corrected
+ */
+ copy_v3_v3(collpair->pa, p2);
+ collpair->distance = distance2;
+ mul_v3_v3fl(collpair->vector, facenor, -distance2);
+
+ interp_v3_v3v3v3(collpair->pb, co1, co2, co3, w);
+
+ copy_v3_v3(collpair->normal, facenor);
+ collpair->time = lambda;
+ collpair->flag = 0;
+
+ collpair++;
+ return collpair;
+}
+
+//Determines collisions on overlap, collisions are written to collpair[i] and collision+number_collision_found is returned
+static CollPair* cloth_point_collision(ModifierData *md1, ModifierData *md2,
+ BVHTreeOverlap *overlap, float epsilon, CollPair *collpair, float UNUSED(dt))
+{
+ ClothModifierData *clmd = (ClothModifierData *)md1;
+ CollisionModifierData *collmd = (CollisionModifierData *) md2;
+ /* Cloth *cloth = clmd->clothObject; */ /* UNUSED */
+ ClothVertex *vert = NULL;
+ MFace *face = NULL;
+ MVert *mverts = collmd->current_x;
+
+ vert = &clmd->clothObject->verts[overlap->indexA];
+ face = &collmd->mfaces[overlap->indexB];
+
+ collpair = cloth_point_collpair(vert->tx, vert->x, mverts, face->v1, face->v2, face->v3, overlap->indexA, overlap->indexB, epsilon, collpair);
+ if (face->v4)
+ collpair = cloth_point_collpair(vert->tx, vert->x, mverts, face->v3, face->v4, face->v1, overlap->indexA, overlap->indexB, epsilon, collpair);
+
+ return collpair;
+}
+
+static void cloth_points_objcollisions_nearcheck(ClothModifierData * clmd, CollisionModifierData *collmd,
+ CollPair **collisions, CollPair **collisions_index,
+ int numresult, BVHTreeOverlap *overlap, float epsilon, double dt)
+{
+ int i;
+
+ /* can return 2 collisions in total */
+ *collisions = (CollPair *) MEM_mallocN(sizeof(CollPair) * numresult * 2, "collision array" );
+ *collisions_index = *collisions;
+
+ for ( i = 0; i < numresult; i++ ) {
+ *collisions_index = cloth_point_collision((ModifierData *)clmd, (ModifierData *)collmd,
+ overlap+i, epsilon, *collisions_index, dt);
+ }
+}
+
+static int cloth_points_objcollisions_resolve(ClothModifierData * clmd, CollisionModifierData *collmd, PartDeflect *pd,
+ CollPair *collisions, CollPair *collisions_index, float dt)
+{
+ Cloth *cloth = clmd->clothObject;
+ int i=0, numverts = clmd->clothObject->numverts;
+ ClothVertex *verts = cloth->verts;
+ int ret = 0;
+
+ // process all collisions
+ if ( collmd->bvhtree ) {
+ bool result = cloth_points_collision_response_static(clmd, collmd, pd, collisions, collisions_index, dt);
+
+ // apply impulses in parallel
+ if (result) {
+ for (i = 0; i < numverts; i++) {
+ // calculate "velocities" (just xnew = xold + v; no dt in v)
+ if (verts[i].impulse_count) {
+ // VECADDMUL ( verts[i].tv, verts[i].impulse, 1.0f / verts[i].impulse_count );
+ VECADD ( verts[i].tv, verts[i].tv, verts[i].impulse);
+ zero_v3(verts[i].impulse);
+ verts[i].impulse_count = 0;
+
+ ret++;
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+// cloth - object collisions
+int cloth_points_objcollision(Object *ob, ClothModifierData *clmd, float step, float dt)
+{
+ Cloth *cloth= clmd->clothObject;
+ BVHTree *cloth_bvh;
+ int rounds = 0; // result counts applied collisions; ic is for debug output;
+ float round_dt = dt / (float)clmd->coll_parms->loop_count;
+ unsigned int i=0, numverts = 0;
+ ClothVertex *verts = NULL;
+ int ret = 0, ret2 = 0;
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0;
+
+ verts = cloth->verts;
+ numverts = cloth->numverts;
+
+ ////////////////////////////////////////////////////////////
+ // static collisions
+ ////////////////////////////////////////////////////////////
+
+ // create temporary cloth points bvh
+ cloth_bvh = BLI_bvhtree_new(numverts, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
+ /* fill tree */
+ for (i = 0; i < numverts; i++) {
+ float co[6];
+
+ copy_v3_v3(&co[0*3], verts[i].x);
+ copy_v3_v3(&co[1*3], verts[i].tx);
+
+ BLI_bvhtree_insert(cloth_bvh, i, co, 2);
+ }
+ /* balance tree */
+ BLI_bvhtree_balance(cloth_bvh);
+
+ collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ if (!collobjs)
+ return 0;
+
+ /* move object to position (step) in time */
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob= collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
+ if (!collmd->bvhtree)
+ continue;
+
+ /* move object to position (step) in time */
+ collision_move_object ( collmd, step + dt, step );
+ }
+
+ do {
+ CollPair **collisions, **collisions_index;
+
+ ret2 = 0;
+
+ collisions = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
+ collisions_index = MEM_callocN(sizeof(CollPair *) *numcollobj, "CollPair");
+
+ // check all collision objects
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob= collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
+ BVHTreeOverlap *overlap = NULL;
+ unsigned int result = 0;
+ float epsilon;
+
+ if (!collmd->bvhtree)
+ continue;
+
+ /* search for overlapping collision pairs */
+ overlap = BLI_bvhtree_overlap ( cloth_bvh, collmd->bvhtree, &result );
+ epsilon = BLI_bvhtree_getepsilon(collmd->bvhtree);
+
+ // go to next object if no overlap is there
+ if (result && overlap) {
+ /* check if collisions really happen (costly near check) */
+ cloth_points_objcollisions_nearcheck(clmd, collmd, &collisions[i], &collisions_index[i],
+ result, overlap, epsilon, round_dt);
+
+ // resolve nearby collisions
+ ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], round_dt);
+ ret2 += ret;
+ }
+
+ if (overlap)
+ MEM_freeN ( overlap );
+ }
+ rounds++;
+
+ for (i = 0; i < numcollobj; i++) {
+ if (collisions[i])
+ MEM_freeN(collisions[i]);
+ }
+
+ MEM_freeN(collisions);
+ MEM_freeN(collisions_index);
+
+ ////////////////////////////////////////////////////////////
+ // update positions
+ // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
+ ////////////////////////////////////////////////////////////
+
+ // verts come from clmd
+ for ( i = 0; i < numverts; i++ ) {
+ if ( clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL ) {
+ if ( verts [i].flags & CLOTH_VERT_FLAG_PINNED ) {
+ continue;
+ }
+ }
+
+ VECADD ( verts[i].tx, verts[i].txold, verts[i].tv );
+ }
+ ////////////////////////////////////////////////////////////
+ }
+ while ( ret2 && ( clmd->coll_parms->loop_count>rounds ) );
+
+ if (collobjs)
+ MEM_freeN(collobjs);
+
+ BLI_bvhtree_free(cloth_bvh);
+
+ return 1|MIN2 ( ret, 1 );
+}
+
+void cloth_find_point_contacts(Object *ob, ClothModifierData *clmd, float step, float dt,
+ ColliderContacts **r_collider_contacts, int *r_totcolliders)
+{
+ Cloth *cloth= clmd->clothObject;
+ BVHTree *cloth_bvh;
+ unsigned int i=0, numverts = 0;
+ ClothVertex *verts = NULL;
+
+ ColliderContacts *collider_contacts;
+
+ Object **collobjs = NULL;
+ unsigned int numcollobj = 0;
+
+ verts = cloth->verts;
+ numverts = cloth->numverts;
+
+ ////////////////////////////////////////////////////////////
+ // static collisions
+ ////////////////////////////////////////////////////////////
+
+ // create temporary cloth points bvh
+ cloth_bvh = BLI_bvhtree_new(numverts, MAX2(clmd->coll_parms->epsilon, clmd->coll_parms->distance_repel), 4, 6);
+ /* fill tree */
+ for (i = 0; i < numverts; i++) {
+ float co[6];
+
+ copy_v3_v3(&co[0*3], verts[i].x);
+ copy_v3_v3(&co[1*3], verts[i].tx);
+
+ BLI_bvhtree_insert(cloth_bvh, i, co, 2);
+ }
+ /* balance tree */
+ BLI_bvhtree_balance(cloth_bvh);
+
+ collobjs = get_collisionobjects(clmd->scene, ob, clmd->coll_parms->group, &numcollobj, eModifierType_Collision);
+ if (!collobjs) {
+ *r_collider_contacts = NULL;
+ *r_totcolliders = 0;
+ return;
+ }
+
+ /* move object to position (step) in time */
+ for (i = 0; i < numcollobj; i++) {
+ Object *collob= collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
+ if (!collmd->bvhtree)
+ continue;
+
+ /* move object to position (step) in time */
+ collision_move_object ( collmd, step + dt, step );
+ }
+
+ collider_contacts = MEM_callocN(sizeof(ColliderContacts) * numcollobj, "CollPair");
+
+ // check all collision objects
+ for (i = 0; i < numcollobj; i++) {
+ ColliderContacts *ct = collider_contacts + i;
+ Object *collob= collobjs[i];
+ CollisionModifierData *collmd = (CollisionModifierData *)modifiers_findByType(collob, eModifierType_Collision);
+ BVHTreeOverlap *overlap;
+ unsigned int result = 0;
+ float epsilon;
+
+ ct->ob = collob;
+ ct->collmd = collmd;
+ ct->collisions = NULL;
+ ct->totcollisions = 0;
+
+ if (!collmd->bvhtree)
+ continue;
+
+ /* search for overlapping collision pairs */
+ overlap = BLI_bvhtree_overlap(cloth_bvh, collmd->bvhtree, &result);
+ epsilon = BLI_bvhtree_getepsilon(collmd->bvhtree);
+
+ // go to next object if no overlap is there
+ if (result && overlap) {
+ CollPair *collisions_index;
+
+ /* check if collisions really happen (costly near check) */
+ cloth_points_objcollisions_nearcheck(clmd, collmd, &ct->collisions, &collisions_index,
+ result, overlap, epsilon, dt);
+ ct->totcollisions = (int)(collisions_index - ct->collisions);
+
+ // resolve nearby collisions
+// ret += cloth_points_objcollisions_resolve(clmd, collmd, collob->pd, collisions[i], collisions_index[i], dt);
+ }
+
+ if (overlap)
+ MEM_freeN(overlap);
+ }
+
+ if (collobjs)
+ MEM_freeN(collobjs);
+
+ BLI_bvhtree_free(cloth_bvh);
+
+ ////////////////////////////////////////////////////////////
+ // update positions
+ // this is needed for bvh_calc_DOP_hull_moving() [kdop.c]
+ ////////////////////////////////////////////////////////////
+
+ // verts come from clmd
+ for (i = 0; i < numverts; i++) {
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
+ if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
+ continue;
+ }
+ }
+
+ VECADD(verts[i].tx, verts[i].txold, verts[i].tv);
+ }
+ ////////////////////////////////////////////////////////////
+
+ *r_collider_contacts = collider_contacts;
+ *r_totcolliders = numcollobj;
+}
+
+void cloth_free_contacts(ColliderContacts *collider_contacts, int totcolliders)
+{
+ if (collider_contacts) {
+ int i;
+ for (i = 0; i < totcolliders; ++i) {
+ ColliderContacts *ct = collider_contacts + i;
+ if (ct->collisions) {
+ MEM_freeN(ct->collisions);
+ }
+ }
+ MEM_freeN(collider_contacts);
+ }
+}
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index f591fe857f8..668b78a08d4 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -2715,7 +2715,7 @@ static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
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);
+ float soft = 1.0f + range * atanf((bulge - 1.0f) * scale) / (float)M_PI_2;
bulge = interpf(soft, hard, data->bulge_smooth);
}
@@ -2727,7 +2727,7 @@ static void stretchto_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *t
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);
+ float soft = 1.0f - range * atanf((1.0f - bulge) * scale) / (float)M_PI_2;
bulge = interpf(soft, hard, data->bulge_smooth);
}
diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c
index 8f6c9735aaf..7142c092583 100644
--- a/source/blender/blenkernel/intern/context.c
+++ b/source/blender/blenkernel/intern/context.c
@@ -454,7 +454,7 @@ static void data_dir_add(ListBase *lb, const char *member, const bool use_all)
{
LinkData *link;
- if ((use_all == false) && strcmp(member, "scene") == 0) /* exception */
+ if ((use_all == false) && STREQ(member, "scene")) /* exception */
return;
if (BLI_findstring(lb, member, offsetof(LinkData, data)))
@@ -546,7 +546,7 @@ ListBase CTX_data_dir_get(const bContext *C)
bool CTX_data_equals(const char *member, const char *str)
{
- return (strcmp(member, str) == 0);
+ return (STREQ(member, str));
}
bool CTX_data_dir(const char *member)
diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c
index 3abe3c58562..e88a8ecde8e 100644
--- a/source/blender/blenkernel/intern/curve.c
+++ b/source/blender/blenkernel/intern/curve.c
@@ -593,6 +593,10 @@ Nurb *BKE_nurb_copy(Nurb *src, int pntsu, int pntsv)
newnu->pntsu = pntsu;
newnu->pntsv = pntsv;
+ /* caller can manually handle these arrays */
+ newnu->knotsu = NULL;
+ newnu->knotsv = NULL;
+
if (src->bezt) {
newnu->bezt = (BezTriple *)MEM_mallocN(pntsu * pntsv * sizeof(BezTriple), "copyNurb2");
}
@@ -1738,7 +1742,7 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
/* half a circle */
fp = dl->verts;
- dangle = (0.5 * M_PI / (dnr - 1));
+ dangle = ((float)M_PI_2 / (dnr - 1));
angle = -(nr - 1) * dangle;
for (a = 0; a < nr; a++) {
@@ -1797,7 +1801,7 @@ void BKE_curve_bevel_make(Scene *scene, Object *ob, ListBase *disp,
/* half a circle */
fp = dl->verts;
angle = 0.0;
- dangle = (0.5 * M_PI / (dnr - 1));
+ dangle = ((float)M_PI_2 / (dnr - 1));
for (a = 0; a < nr; a++) {
fp[0] = 0.0;
@@ -1939,7 +1943,7 @@ static void calc_bevel_sin_cos(float x1, float y1, float x2, float y2,
t02 = x1 * x2 + y1 * y2;
if (fabsf(t02) >= 1.0f)
- t02 = 0.5 * M_PI;
+ t02 = M_PI_2;
else
t02 = (saacos(t02)) / 2.0f;
@@ -2472,7 +2476,7 @@ static void make_bevel_list_2D(BevList *bl)
/* first */
bevp = bl->bevpoints;
- angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)(M_PI / 2.0f);
+ angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2;
bevp->sina = sinf(angle);
bevp->cosa = cosf(angle);
vec_to_quat(bevp->quat, bevp->dir, 5, 1);
@@ -2480,7 +2484,7 @@ static void make_bevel_list_2D(BevList *bl)
/* last */
bevp = bl->bevpoints;
bevp += (bl->nr - 1);
- angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)(M_PI / 2.0f);
+ angle = atan2f(bevp->dir[0], bevp->dir[1]) - (float)M_PI_2;
bevp->sina = sinf(angle);
bevp->cosa = cosf(angle);
vec_to_quat(bevp->quat, bevp->dir, 5, 1);
@@ -3347,6 +3351,21 @@ void BKE_nurb_handle_calc_simple(Nurb *nu, BezTriple *bezt)
}
}
+void BKE_nurb_handle_calc_simple_auto(Nurb *nu, BezTriple *bezt)
+{
+ if (nu->pntsu > 1) {
+ const char h1_back = bezt->h1, h2_back = bezt->h2;
+
+ bezt->h1 = bezt->h2 = HD_AUTO;
+
+ /* Override handle types to HD_AUTO and recalculate */
+ BKE_nurb_handle_calc_simple(nu, bezt);
+
+ bezt->h1 = h1_back;
+ bezt->h2 = h2_back;
+ }
+}
+
/**
* Use when something has changed handle positions.
*
@@ -3604,24 +3623,12 @@ void BKE_nurbList_handles_recalculate(ListBase *editnurb, const bool calc_length
if (h1_select || h2_select) {
- /* Override handle types to HD_AUTO and recalculate */
-
- char h1_back, h2_back;
float co1_back[3], co2_back[3];
- h1_back = bezt->h1;
- h2_back = bezt->h2;
-
- bezt->h1 = HD_AUTO;
- bezt->h2 = HD_AUTO;
-
copy_v3_v3(co1_back, bezt->vec[0]);
copy_v3_v3(co2_back, bezt->vec[2]);
- BKE_nurb_handle_calc_simple(nu, bezt);
-
- bezt->h1 = h1_back;
- bezt->h2 = h2_back;
+ BKE_nurb_handle_calc_simple_auto(nu, bezt);
if (h1_select) {
if (!calc_length) {
diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c
index 89ebed258a3..0436ec0ef22 100644
--- a/source/blender/blenkernel/intern/customdata.c
+++ b/source/blender/blenkernel/intern/customdata.c
@@ -300,6 +300,49 @@ static void layerInterp_mdeformvert(void **sources, const float *weights,
}
}
+static void layerInterp_normal(void **sources, const float *weights,
+ const float *UNUSED(sub_weights), int count, void *dest)
+{
+ float no[3] = {0.0f};
+
+ while (count--) {
+ madd_v3_v3fl(no, (float *)sources[count], weights[count]);
+ }
+
+ copy_v3_v3((float *)dest, no);
+}
+
+static void layerCopyValue_normal(const void *source, void *dest, const int mixmode, const float mixfactor)
+{
+ const float *no_src = source;
+ float *no_dst = dest;
+ float no_tmp[3];
+
+ if (ELEM(mixmode, CDT_MIX_NOMIX, CDT_MIX_REPLACE_ABOVE_THRESHOLD, CDT_MIX_REPLACE_BELOW_THRESHOLD)) {
+ /* Above/below threshold modes are not supported here, fallback to nomix (just in case). */
+ copy_v3_v3(no_dst, no_src);
+ }
+ else { /* Modes that support 'real' mix factor. */
+ /* Since we normalize in the end, MIX and ADD are the same op here. */
+ if (ELEM(mixmode, CDT_MIX_MIX, CDT_MIX_ADD)) {
+ add_v3_v3v3(no_tmp, no_dst, no_src);
+ normalize_v3(no_tmp);
+ }
+ else if (mixmode == CDT_MIX_SUB) {
+ sub_v3_v3v3(no_tmp, no_dst, no_src);
+ normalize_v3(no_tmp);
+ }
+ else if (mixmode == CDT_MIX_MUL) {
+ mul_v3_v3v3(no_tmp, no_dst, no_src);
+ normalize_v3(no_tmp);
+ }
+ else {
+ copy_v3_v3(no_tmp, no_src);
+ }
+ interp_v3_v3v3_slerp_safe(no_dst, no_dst, no_tmp, mixfactor);
+ }
+}
+
static void layerCopy_tface(const void *source, void *dest, int count)
{
const MTFace *source_tf = (const MTFace *)source;
@@ -1165,7 +1208,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex},
/* 8: CD_NORMAL */
/* 3 floats per normal vector */
- {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL},
+ {sizeof(float) * 3, "vec3f", 1, NULL, NULL, NULL, layerInterp_normal, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, layerCopyValue_normal},
/* 9: CD_POLYINDEX (deprecated) */
{sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 10: CD_PROP_FLT */
@@ -1255,6 +1299,8 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
{sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL},
/* 40: CD_TESSLOOPNORMAL */
{sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL},
+ /* 41: CD_CUSTOMLOOPNORMAL */
+ {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL},
};
/* note, numbers are from trunk and need updating for bmesh */
@@ -1270,7 +1316,8 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = {
/* 25-29 */ "CDMPoly", "CDMLoop", "CDShapeKeyIndex", "CDShapeKey", "CDBevelWeight",
/* 30-34 */ "CDSubSurfCrease", "CDOrigSpaceLoop", "CDPreviewLoopCol", "CDBMElemPyPtr", "CDPaintMask",
/* 35-36 */ "CDGridPaintMask", "CDMVertSkin",
- /* 37-40 */ "CDFreestyleEdge", "CDFreestyleFace", "CDMLoopTangent", "CDTessLoopNormal",
+ /* 37-38 */ "CDFreestyleEdge", "CDFreestyleFace",
+ /* 39-41 */ "CDMLoopTangent", "CDTessLoopNormal", "CDCustomLoopNormal",
};
@@ -1282,26 +1329,29 @@ const CustomDataMask CD_MASK_MESH =
CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR | CD_MASK_MDISPS |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MPOLY | CD_MASK_MLOOP |
CD_MASK_MTEXPOLY | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
+ CD_MASK_CUSTOMLOOPNORMAL;
const CustomDataMask CD_MASK_EDITMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_SHAPE_KEYINDEX |
CD_MASK_MCOL | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_PROP_STR |
CD_MASK_MDISPS | CD_MASK_SHAPEKEY | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN;
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_CUSTOMLOOPNORMAL;
const CustomDataMask CD_MASK_DERIVEDMESH =
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_MTFACE |
CD_MASK_MCOL | CD_MASK_PROP_FLT | CD_MASK_PROP_INT | CD_MASK_CLOTH_ORCO |
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY | CD_MASK_PREVIEW_MLOOPCOL |
CD_MASK_PROP_STR | CD_MASK_ORIGSPACE | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORCO | CD_MASK_TANGENT |
CD_MASK_PREVIEW_MCOL | CD_MASK_SHAPEKEY | CD_MASK_RECAST |
- CD_MASK_ORIGINDEX | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
+ CD_MASK_ORIGINDEX | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
+ CD_MASK_CUSTOMLOOPNORMAL;
const CustomDataMask CD_MASK_BMESH =
CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_MTEXPOLY |
CD_MASK_MSTICKY | CD_MASK_MDEFORMVERT | CD_MASK_PROP_FLT | CD_MASK_PROP_INT |
CD_MASK_PROP_STR | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_MDISPS |
CD_MASK_CREASE | CD_MASK_BWEIGHT | CD_MASK_RECAST | CD_MASK_PAINT_MASK |
- CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE;
+ CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
+ CD_MASK_CUSTOMLOOPNORMAL;
const CustomDataMask CD_MASK_FACECORNERS = /* XXX Not used anywhere! */
CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV |
CD_MASK_MLOOPCOL | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT;
@@ -1316,7 +1366,7 @@ const CustomDataMask CD_MASK_EVERYTHING =
/* BMESH ONLY END */
CD_MASK_PAINT_MASK | CD_MASK_GRID_PAINT_MASK | CD_MASK_MVERT_SKIN |
CD_MASK_FREESTYLE_EDGE | CD_MASK_FREESTYLE_FACE |
- CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL;
+ CD_MASK_MLOOPTANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_CUSTOMLOOPNORMAL;
static const LayerTypeInfo *layerType_getInfo(int type)
{
@@ -1553,7 +1603,7 @@ int CustomData_get_named_layer_index(const CustomData *data, int type, const cha
for (i = 0; i < data->totlayer; ++i)
if (data->layers[i].type == type)
- if (strcmp(data->layers[i].name, name) == 0)
+ if (STREQ(data->layers[i].name, name))
return i;
return -1;
@@ -2690,7 +2740,7 @@ void CustomData_bmesh_copy_data(const CustomData *source, CustomData *dest,
/* if we found a matching layer, copy the data */
if (dest->layers[dest_i].type == source->layers[src_i].type &&
- strcmp(dest->layers[dest_i].name, source->layers[src_i].name) == 0)
+ STREQ(dest->layers[dest_i].name, source->layers[src_i].name))
{
const char *src_data = (char *)src_block + source->layers[src_i].offset;
char *dest_data = (char *)*dest_block + dest->layers[dest_i].offset;
@@ -3163,12 +3213,12 @@ static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int
CustomDataLayer *layer = &data->layers[i];
if (CustomData_is_property_layer(type)) {
- if (CustomData_is_property_layer(layer->type) && strcmp(layer->name, name) == 0) {
+ if (CustomData_is_property_layer(layer->type) && STREQ(layer->name, name)) {
return true;
}
}
else {
- if (i != index && layer->type == type && strcmp(layer->name, name) == 0) {
+ if (i != index && layer->type == type && STREQ(layer->name, name)) {
return true;
}
}
diff --git a/source/blender/blenkernel/intern/customdata_file.c b/source/blender/blenkernel/intern/customdata_file.c
index c72eea50e40..41579aaa568 100644
--- a/source/blender/blenkernel/intern/customdata_file.c
+++ b/source/blender/blenkernel/intern/customdata_file.c
@@ -276,7 +276,7 @@ static int cdf_write_header(CDataFile *cdf)
return 1;
}
-int cdf_read_open(CDataFile *cdf, const char *filename)
+bool cdf_read_open(CDataFile *cdf, const char *filename)
{
FILE *f;
@@ -299,7 +299,7 @@ int cdf_read_open(CDataFile *cdf, const char *filename)
return 1;
}
-int cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
+bool cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
{
size_t offset;
int a;
@@ -316,7 +316,7 @@ int cdf_read_layer(CDataFile *cdf, CDataFileLayer *blay)
return (fseek(cdf->readf, offset, SEEK_SET) == 0);
}
-int cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
+bool cdf_read_data(CDataFile *cdf, unsigned int size, void *data)
{
/* read data */
if (!fread(data, size, 1, cdf->readf))
@@ -338,7 +338,7 @@ void cdf_read_close(CDataFile *cdf)
}
}
-int cdf_write_open(CDataFile *cdf, const char *filename)
+bool cdf_write_open(CDataFile *cdf, const char *filename)
{
CDataFileHeader *header;
CDataFileImageHeader *image;
@@ -380,12 +380,12 @@ int cdf_write_open(CDataFile *cdf, const char *filename)
return 1;
}
-int cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
+bool cdf_write_layer(CDataFile *UNUSED(cdf), CDataFileLayer *UNUSED(blay))
{
return 1;
}
-int cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
+bool cdf_write_data(CDataFile *cdf, unsigned int size, void *data)
{
/* write data */
if (!fwrite(data, size, 1, cdf->writef))
@@ -417,7 +417,7 @@ CDataFileLayer *cdf_layer_find(CDataFile *cdf, int type, const char *name)
for (a = 0; a < cdf->totlayer; a++) {
layer = &cdf->layer[a];
- if (layer->type == type && strcmp(layer->name, name) == 0)
+ if (layer->type == type && STREQ(layer->name, name))
return layer;
}
diff --git a/source/blender/blenkernel/intern/data_transfer.c b/source/blender/blenkernel/intern/data_transfer.c
index d41c74770f1..5ac7b928d96 100644
--- a/source/blender/blenkernel/intern/data_transfer.c
+++ b/source/blender/blenkernel/intern/data_transfer.c
@@ -47,6 +47,7 @@
#include "BKE_data_transfer.h"
#include "BKE_deform.h"
#include "BKE_DerivedMesh.h"
+#include "BKE_mesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
#include "BKE_object.h"
@@ -79,6 +80,9 @@ CustomDataMask BKE_object_data_transfer_dttypes_to_cdmask(const int dtdata_types
else if (cddata_type == CD_FAKE_UV) {
cddata_mask |= CD_MASK_MTEXPOLY | CD_MASK_MLOOPUV;
}
+ else if (cddata_type == CD_FAKE_LNOR) {
+ cddata_mask |= CD_MASK_NORMAL | CD_MASK_CUSTOMLOOPNORMAL;
+ }
}
return cddata_mask;
@@ -143,6 +147,10 @@ bool BKE_object_data_transfer_get_dttypes_capacity(
*r_threshold = true;
ret = true;
break;
+ case DT_TYPE_LNOR:
+ *r_advanced_mixing = true;
+ ret = true;
+ break;
case DT_TYPE_SHARP_FACE:
*r_threshold = true;
ret = true;
@@ -217,6 +225,8 @@ int BKE_object_data_transfer_dttype_to_cdtype(const int dtdata_type)
case DT_TYPE_VCOL:
return CD_MLOOPCOL;
+ case DT_TYPE_LNOR:
+ return CD_FAKE_LNOR;
default:
BLI_assert(0);
@@ -242,6 +252,105 @@ int BKE_object_data_transfer_dttype_to_srcdst_index(const int dtdata_type)
/* ********** */
+/* Generic pre/post processing, only used by custom loop normals currently. */
+
+static void data_transfer_dtdata_type_preprocess(
+ Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *dm_src, DerivedMesh *dm_dst, Mesh *me_dst,
+ const int dtdata_type, const bool dirty_nors_dst, const bool use_split_nors_src, const float split_angle_src)
+{
+ if (dtdata_type == DT_TYPE_LNOR) {
+ /* Compute custom normals into regular loop normals, which will be used for the transfer. */
+ MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
+ const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
+ MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
+ const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
+ MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
+ const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
+ MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
+ const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
+ CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
+ CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+
+ const bool use_split_nors_dst = (me_dst->flag & ME_AUTOSMOOTH) != 0;
+ const float split_angle_dst = me_dst->smoothresh;
+
+ dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
+
+ if (dm_dst) {
+ dm_dst->calcLoopNormals(dm_dst, use_split_nors_dst, split_angle_dst);
+ }
+ else {
+ float (*poly_nors_dst)[3];
+ float (*loop_nors_dst)[3];
+ short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
+
+ /* Cache poly nors into a temp CDLayer. */
+ poly_nors_dst = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ if (dirty_nors_dst || !poly_nors_dst) {
+ if (!poly_nors_dst) {
+ poly_nors_dst = CustomData_add_layer(pdata_dst, CD_NORMAL, CD_CALLOC, NULL, num_polys_dst);
+ CustomData_set_layer_flag(pdata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ BKE_mesh_calc_normals_poly(verts_dst, num_verts_dst, loops_dst, polys_dst,
+ num_loops_dst, num_polys_dst, poly_nors_dst, true);
+ }
+ /* Cache loop nors into a temp CDLayer. */
+ loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
+ if (dirty_nors_dst || loop_nors_dst) {
+ if (!loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, num_loops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+ BKE_mesh_normals_loop_split(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
+ loops_dst, loop_nors_dst, num_loops_dst,
+ polys_dst, (const float (*)[3])poly_nors_dst, num_polys_dst,
+ use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
+ }
+ }
+ }
+}
+
+static void data_transfer_dtdata_type_postprocess(
+ Object *UNUSED(ob_src), Object *UNUSED(ob_dst), DerivedMesh *UNUSED(dm_src), DerivedMesh *dm_dst, Mesh *me_dst,
+ const int dtdata_type, const bool changed)
+{
+ if (dtdata_type == DT_TYPE_LNOR) {
+ /* Bake edited destination loop normals into custom normals again. */
+ MVert *verts_dst = dm_dst ? dm_dst->getVertArray(dm_dst) : me_dst->mvert;
+ const int num_verts_dst = dm_dst ? dm_dst->getNumVerts(dm_dst) : me_dst->totvert;
+ MEdge *edges_dst = dm_dst ? dm_dst->getEdgeArray(dm_dst) : me_dst->medge;
+ const int num_edges_dst = dm_dst ? dm_dst->getNumEdges(dm_dst) : me_dst->totedge;
+ MPoly *polys_dst = dm_dst ? dm_dst->getPolyArray(dm_dst) : me_dst->mpoly;
+ const int num_polys_dst = dm_dst ? dm_dst->getNumPolys(dm_dst) : me_dst->totpoly;
+ MLoop *loops_dst = dm_dst ? dm_dst->getLoopArray(dm_dst) : me_dst->mloop;
+ const int num_loops_dst = dm_dst ? dm_dst->getNumLoops(dm_dst) : me_dst->totloop;
+ CustomData *pdata_dst = dm_dst ? dm_dst->getPolyDataLayout(dm_dst) : &me_dst->pdata;
+ CustomData *ldata_dst = dm_dst ? dm_dst->getLoopDataLayout(dm_dst) : &me_dst->ldata;
+
+ const float (*poly_nors_dst)[3] = CustomData_get_layer(pdata_dst, CD_NORMAL);
+ float (*loop_nors_dst)[3] = CustomData_get_layer(ldata_dst, CD_NORMAL);
+ short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
+
+ BLI_assert(poly_nors_dst);
+
+ if (!changed) {
+ return;
+ }
+
+ if (!custom_nors_dst) {
+ custom_nors_dst = CustomData_add_layer(ldata_dst, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL, num_loops_dst);
+ }
+
+ /* Note loop_nors_dst contains our custom normals as transferred from source... */
+ BKE_mesh_normals_loop_custom_set(verts_dst, num_verts_dst, edges_dst, num_edges_dst,
+ loops_dst, loop_nors_dst, num_loops_dst,
+ polys_dst, poly_nors_dst, num_polys_dst,
+ custom_nors_dst);
+ }
+}
+
+/* ********** */
+
static MeshRemapIslandsCalc data_transfer_get_loop_islands_generator(const int cddata_type)
{
switch (cddata_type) {
@@ -690,13 +799,19 @@ static bool data_transfer_layersmapping_generate(
return true;
}
else if (cddata_type == CD_FAKE_MDEFORMVERT) {
+ bool ret;
+
cd_src = dm_src->getVertDataLayout(dm_src);
cd_dst = dm_dst ? dm_dst->getVertDataLayout(dm_dst) : &me_dst->vdata;
- return data_transfer_layersmapping_vgroups(r_map, mix_mode, mix_factor, mix_weights,
- num_elem_dst, use_create, use_delete,
- ob_src, ob_dst, cd_src, cd_dst, dm_dst != NULL,
- fromlayers, tolayers);
+ ret = data_transfer_layersmapping_vgroups(r_map, mix_mode, mix_factor, mix_weights,
+ num_elem_dst, use_create, use_delete,
+ ob_src, ob_dst, cd_src, cd_dst, dm_dst != NULL,
+ fromlayers, tolayers);
+
+ /* Mesh stores its dvert in a specific pointer too. :( */
+ me_dst->dvert = CustomData_get_layer(&me_dst->vdata, CD_MDEFORMVERT);
+ return ret;
}
else if (cddata_type == CD_FAKE_SHAPEKEY) {
/* TODO: leaving shapekeys asside for now, quite specific case, since we can't access them from MVert :/ */
@@ -799,6 +914,10 @@ static bool data_transfer_layersmapping_generate(
if (cddata_type == CD_FAKE_UV) {
cddata_type = CD_MLOOPUV;
}
+ else if (cddata_type == CD_FAKE_LNOR) {
+ /* Preprocess should have generated it, Postprocess will convert it back to CD_CUSTOMLOOPNORMAL. */
+ cddata_type = CD_NORMAL;
+ }
if (!(cddata_type & CD_FAKE)) {
cd_src = dm_src->getLoopDataLayout(dm_src);
@@ -957,7 +1076,7 @@ bool BKE_object_data_transfer_dm(
#define DATAMAX 4
DerivedMesh *dm_src;
- Mesh *me_dst;
+ Mesh *me_dst, *me_src;
bool dirty_nors_dst = true; /* Assumed always true if not using a dm as destination. */
int i;
@@ -967,7 +1086,7 @@ bool BKE_object_data_transfer_dm(
MeshPairRemap geom_map[DATAMAX] = {{0}};
bool geom_map_init[DATAMAX] = {0};
- ListBase lay_map = {0};
+ ListBase lay_map = {NULL};
bool changed = false;
const bool use_delete = false; /* We never delete data layers from destination here. */
@@ -977,6 +1096,7 @@ bool BKE_object_data_transfer_dm(
BLI_assert((ob_src != ob_dst) && (ob_src->type == OB_MESH) && (ob_dst->type == OB_MESH));
me_dst = ob_dst->data;
+ me_src = ob_src->data;
if (dm_dst) {
dirty_nors_dst = (dm_dst->dirty & DM_DIRTY_NORMALS) != 0;
use_create = false; /* Never create needed custom layers on DM (modifier case). */
@@ -1016,6 +1136,10 @@ bool BKE_object_data_transfer_dm(
continue;
}
+ data_transfer_dtdata_type_preprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst,
+ dtdata_type, dirty_nors_dst,
+ (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh);
+
cddata_type = BKE_object_data_transfer_dttype_to_cdtype(dtdata_type);
fromto_idx = BKE_object_data_transfer_dttype_to_srcdst_index(dtdata_type);
@@ -1133,8 +1257,10 @@ bool BKE_object_data_transfer_dm(
map_loop_mode, space_transform, max_distance, ray_radius,
verts_dst, num_verts_dst, edges_dst, num_edges_dst,
loops_dst, num_loops_dst, polys_dst, num_polys_dst,
- ldata_dst, pdata_dst, me_dst->smoothresh, dirty_nors_dst,
- dm_src, island_callback, islands_handling_precision, &geom_map[LDATA]);
+ ldata_dst, pdata_dst,
+ (me_dst->flag & ME_AUTOSMOOTH) != 0, me_dst->smoothresh, dirty_nors_dst,
+ dm_src, (me_src->flag & ME_AUTOSMOOTH) != 0, me_src->smoothresh,
+ island_callback, islands_handling_precision, &geom_map[LDATA]);
geom_map_init[LDATA] = true;
}
@@ -1208,6 +1334,8 @@ bool BKE_object_data_transfer_dm(
BLI_freelistN(&lay_map);
}
}
+
+ data_transfer_dtdata_type_postprocess(ob_src, ob_dst, dm_src, dm_dst, me_dst, dtdata_type, changed);
}
for (i = 0; i < DATAMAX; i++) {
diff --git a/source/blender/blenkernel/intern/deform.c b/source/blender/blenkernel/intern/deform.c
index 80db62801d6..e2bb326b226 100644
--- a/source/blender/blenkernel/intern/deform.c
+++ b/source/blender/blenkernel/intern/deform.c
@@ -542,7 +542,7 @@ static bool defgroup_find_name_dupe(const char *name, bDeformGroup *dg, Object *
for (curdef = ob->defbase.first; curdef; curdef = curdef->next) {
if (dg != curdef) {
- if (!strcmp(curdef->name, name)) {
+ if (STREQ(curdef->name, name)) {
return true;
}
}
diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c
index 58a7702828c..e268f95b8ac 100644
--- a/source/blender/blenkernel/intern/dynamicpaint.c
+++ b/source/blender/blenkernel/intern/dynamicpaint.c
@@ -370,7 +370,7 @@ static bool surface_duplicateNameExists(void *arg, const char *name)
DynamicPaintSurface *surface = t_surface->canvas->surfaces.first;
for (; surface; surface = surface->next) {
- if (surface != t_surface && !strcmp(name, surface->name)) return true;
+ if (surface != t_surface && STREQ(name, surface->name)) return true;
}
return false;
}
@@ -1502,7 +1502,7 @@ static void dynamicPaint_setInitialColor(Scene *scene, DynamicPaintSurface *surf
uv[0] = tface[i].uv[j][0] * 2.0f - 1.0f;
uv[1] = tface[i].uv[j][1] * 2.0f - 1.0f;
- multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage);
+ multitex_ext_safe(tex, uv, &texres, pool, scene_color_manage, false);
if (texres.tin > pPoint[*vert].alpha) {
copy_v3_v3(pPoint[*vert].color, &texres.tr);
@@ -1536,7 +1536,7 @@ static void dynamicPaint_setInitialColor(Scene *scene, DynamicPaintSurface *surf
uv_final[0] = uv_final[0] * 2.0f - 1.0f;
uv_final[1] = uv_final[1] * 2.0f - 1.0f;
- multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage);
+ multitex_ext_safe(tex, uv_final, &texres, NULL, scene_color_manage, false);
/* apply color */
copy_v3_v3(pPoint[i].color, &texres.tr);
@@ -2707,7 +2707,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam
if (format == R_IMF_IMTYPE_OPENEXR) format = R_IMF_IMTYPE_PNG;
#endif
BLI_strncpy(output_file, filename, sizeof(output_file));
- BKE_add_image_extension_from_type(output_file, format);
+ BKE_image_path_ensure_ext_from_imtype(output_file, format);
/* Validate output file path */
BLI_path_abs(output_file, G.main->name);
diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c
index eb7c78c2760..082edb01efd 100644
--- a/source/blender/blenkernel/intern/editderivedmesh.c
+++ b/source/blender/blenkernel/intern/editderivedmesh.c
@@ -169,12 +169,25 @@ static void emDM_calcNormals(DerivedMesh *dm)
dm->dirty &= ~DM_DIRTY_NORMALS;
}
-static void emDM_calcLoopNormals(DerivedMesh *dm, const float split_angle)
+static void emDM_calcLoopNormalsSpaceArray(
+ DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr);
+
+static void emDM_calcLoopNormals(DerivedMesh *dm, const bool use_split_normals, const float split_angle)
+{
+ emDM_calcLoopNormalsSpaceArray(dm, use_split_normals, split_angle, NULL);
+}
+
+/* #define DEBUG_CLNORS */
+
+static void emDM_calcLoopNormalsSpaceArray(
+ DerivedMesh *dm, const bool use_split_normals, const float split_angle, MLoopNorSpaceArray *r_lnors_spacearr)
{
EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
BMesh *bm = bmdm->em->bm;
const float (*vertexCos)[3], (*vertexNos)[3], (*polyNos)[3];
float (*loopNos)[3];
+ short (*clnors_data)[2];
+ int cd_loop_clnors_offset;
/* calculate loop normals from poly and vertex normals */
emDM_ensureVertNormals(bmdm);
@@ -191,7 +204,37 @@ static void emDM_calcLoopNormals(DerivedMesh *dm, const float split_angle)
loopNos = dm->getLoopDataArray(dm, CD_NORMAL);
}
- BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, split_angle, loopNos);
+ /* We can have both, give priority to dm's data, and fallback to bm's ones. */
+ clnors_data = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL);
+ cd_loop_clnors_offset = clnors_data ? -1 : CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
+
+ BM_loops_calc_normal_vcos(bm, vertexCos, vertexNos, polyNos, use_split_normals, split_angle, loopNos,
+ r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
+#ifdef DEBUG_CLNORS
+ if (r_lnors_spacearr) {
+ int i;
+ for (i = 0; i < numLoops; i++) {
+ if (r_lnors_spacearr->lspacearr[i]->ref_alpha != 0.0f) {
+ LinkNode *loops = r_lnors_spacearr->lspacearr[i]->loops;
+ printf("Loop %d uses lnor space %p:\n", i, r_lnors_spacearr->lspacearr[i]);
+ print_v3("\tfinal lnor:", loopNos[i]);
+ print_v3("\tauto lnor:", r_lnors_spacearr->lspacearr[i]->vec_lnor);
+ print_v3("\tref_vec:", r_lnors_spacearr->lspacearr[i]->vec_ref);
+ printf("\talpha: %f\n\tbeta: %f\n\tloops: %p\n", r_lnors_spacearr->lspacearr[i]->ref_alpha,
+ r_lnors_spacearr->lspacearr[i]->ref_beta, r_lnors_spacearr->lspacearr[i]->loops);
+ printf("\t\t(shared with loops");
+ while (loops) {
+ printf(" %d", GET_INT_FROM_POINTER(loops->link));
+ loops = loops->next;
+ }
+ printf(")\n");
+ }
+ else {
+ printf("Loop %d has no lnor space\n", i);
+ }
+ }
+ }
+#endif
}
static void emDM_recalcTessellation(DerivedMesh *UNUSED(dm))
@@ -1764,6 +1807,7 @@ DerivedMesh *getEditDerivedBMesh(BMEditMesh *em,
bmdm->dm.calcNormals = emDM_calcNormals;
bmdm->dm.calcLoopNormals = emDM_calcLoopNormals;
+ bmdm->dm.calcLoopNormalsSpaceArray = emDM_calcLoopNormalsSpaceArray;
bmdm->dm.recalcTessellation = emDM_recalcTessellation;
bmdm->dm.foreachMappedVert = emDM_foreachMappedVert;
diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c
index ced9da8d0b1..76a39fed3f6 100644
--- a/source/blender/blenkernel/intern/effect.c
+++ b/source/blender/blenkernel/intern/effect.c
@@ -30,6 +30,7 @@
*/
#include <stddef.h>
+#include <stdarg.h>
#include <math.h>
#include <stdlib.h>
@@ -51,6 +52,7 @@
#include "BLI_noise.h"
#include "BLI_rand.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "PIL_time.h"
@@ -61,6 +63,7 @@
#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_effect.h"
+#include "BKE_global.h"
#include "BKE_modifier.h"
#include "BKE_object.h"
#include "BKE_particle.h"
@@ -754,7 +757,7 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
scene_color_manage = BKE_scene_check_color_management_enabled(eff->scene);
- hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result, NULL, scene_color_manage);
+ hasrgb = multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result, NULL, scene_color_manage, false);
if (hasrgb && mode==PFIELD_TEX_RGB) {
force[0] = (0.5f - result->tr) * strength;
@@ -765,15 +768,15 @@ static void do_texture_effector(EffectorCache *eff, EffectorData *efd, EffectedP
strength/=nabla;
tex_co[0] += nabla;
- multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1, NULL, scene_color_manage);
+ multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+1, NULL, scene_color_manage, false);
tex_co[0] -= nabla;
tex_co[1] += nabla;
- multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2, NULL, scene_color_manage);
+ multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+2, NULL, scene_color_manage, false);
tex_co[1] -= nabla;
tex_co[2] += nabla;
- multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3, NULL, scene_color_manage);
+ multitex_ext(eff->pd->tex, tex_co, NULL, NULL, 0, result+3, NULL, scene_color_manage, false);
if (mode == PFIELD_TEX_GRAD || !hasrgb) { /* if we don't have rgb fall back to grad */
/* generate intensity if texture only has rgb value */
@@ -1024,3 +1027,160 @@ void pdDoEffectors(ListBase *effectors, ListBase *colliders, EffectorWeights *we
}
}
}
+
+/* ======== Simulation Debugging ======== */
+
+SimDebugData *_sim_debug_data = NULL;
+
+unsigned int BKE_sim_debug_data_hash(int i)
+{
+ return BLI_ghashutil_uinthash((unsigned int)i);
+}
+
+unsigned int BKE_sim_debug_data_hash_combine(unsigned int kx, unsigned int ky)
+{
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+ unsigned int a, b, c;
+
+ a = b = c = 0xdeadbeef + (2 << 2) + 13;
+ a += kx;
+ b += ky;
+
+ c ^= b; c -= rot(b,14);
+ a ^= c; a -= rot(c,11);
+ b ^= a; b -= rot(a,25);
+ c ^= b; c -= rot(b,16);
+ a ^= c; a -= rot(c,4);
+ b ^= a; b -= rot(a,14);
+ c ^= b; c -= rot(b,24);
+
+ return c;
+
+#undef rot
+}
+
+static unsigned int debug_element_hash(const void *key)
+{
+ const SimDebugElement *elem = key;
+ return elem->hash;
+}
+
+static bool debug_element_compare(const void *a, const void *b)
+{
+ const SimDebugElement *elem1 = a;
+ const SimDebugElement *elem2 = b;
+
+ if (elem1->hash == elem2->hash) {
+ return 0;
+ }
+ return 1;
+}
+
+static void debug_element_free(void *val)
+{
+ SimDebugElement *elem = val;
+ MEM_freeN(elem);
+}
+
+void BKE_sim_debug_data_set_enabled(bool enable)
+{
+ if (enable) {
+ if (!_sim_debug_data) {
+ _sim_debug_data = MEM_callocN(sizeof(SimDebugData), "sim debug data");
+ _sim_debug_data->gh = BLI_ghash_new(debug_element_hash, debug_element_compare, "sim debug element hash");
+ }
+ }
+ else {
+ BKE_sim_debug_data_free();
+ }
+}
+
+bool BKE_sim_debug_data_get_enabled(void)
+{
+ return _sim_debug_data != NULL;
+}
+
+void BKE_sim_debug_data_free(void)
+{
+ if (_sim_debug_data) {
+ if (_sim_debug_data->gh)
+ BLI_ghash_free(_sim_debug_data->gh, NULL, debug_element_free);
+ MEM_freeN(_sim_debug_data);
+ }
+}
+
+static void debug_data_insert(SimDebugData *debug_data, SimDebugElement *elem)
+{
+ SimDebugElement *old_elem = BLI_ghash_lookup(debug_data->gh, elem);
+ if (old_elem) {
+ *old_elem = *elem;
+ MEM_freeN(elem);
+ }
+ else
+ BLI_ghash_insert(debug_data->gh, elem, elem);
+}
+
+void BKE_sim_debug_data_add_element(int type, const float v1[3], const float v2[3], float r, float g, float b, const char *category, unsigned int hash)
+{
+ unsigned int category_hash = BLI_ghashutil_strhash_p(category);
+ SimDebugElement *elem;
+
+ if (!_sim_debug_data) {
+ if (G.debug & G_DEBUG_SIMDATA)
+ BKE_sim_debug_data_set_enabled(true);
+ else
+ return;
+ }
+
+ elem = MEM_callocN(sizeof(SimDebugElement), "sim debug data element");
+ elem->type = type;
+ elem->category_hash = category_hash;
+ elem->hash = hash;
+ elem->color[0] = r;
+ elem->color[1] = g;
+ elem->color[2] = b;
+ copy_v3_v3(elem->v1, v1);
+ copy_v3_v3(elem->v2, v2);
+
+ debug_data_insert(_sim_debug_data, elem);
+}
+
+void BKE_sim_debug_data_remove_element(unsigned int hash)
+{
+ SimDebugElement dummy;
+ if (!_sim_debug_data)
+ return;
+
+ dummy.hash = hash;
+ BLI_ghash_remove(_sim_debug_data->gh, &dummy, NULL, debug_element_free);
+}
+
+void BKE_sim_debug_data_clear(void)
+{
+ if (!_sim_debug_data)
+ return;
+
+ if (_sim_debug_data->gh)
+ BLI_ghash_clear(_sim_debug_data->gh, NULL, debug_element_free);
+}
+
+void BKE_sim_debug_data_clear_category(const char *category)
+{
+ int category_hash = (int)BLI_ghashutil_strhash_p(category);
+
+ if (!_sim_debug_data)
+ return;
+
+ if (_sim_debug_data->gh) {
+ GHashIterator iter;
+ BLI_ghashIterator_init(&iter, _sim_debug_data->gh);
+ while (!BLI_ghashIterator_done(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ BLI_ghashIterator_step(&iter); /* removing invalidates the current iterator, so step before removing */
+
+ if (elem->category_hash == category_hash)
+ BLI_ghash_remove(_sim_debug_data->gh, elem, NULL, debug_element_free);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c
index b50e563775e..765917794e8 100644
--- a/source/blender/blenkernel/intern/fcurve.c
+++ b/source/blender/blenkernel/intern/fcurve.c
@@ -230,7 +230,7 @@ FCurve *list_find_fcurve(ListBase *list, const char rna_path[], const int array_
/* check paths of curves, then array indices... */
for (fcu = list->first; fcu; fcu = fcu->next) {
/* simple string-compare (this assumes that they have the same root...) */
- if (fcu->rna_path && !strcmp(fcu->rna_path, rna_path)) {
+ if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
/* now check indices */
if (fcu->array_index == array_index)
return fcu;
@@ -253,7 +253,7 @@ FCurve *iter_step_fcurve(FCurve *fcu_iter, const char rna_path[])
/* check paths of curves, then array indices... */
for (fcu = fcu_iter; fcu; fcu = fcu->next) {
/* simple string-compare (this assumes that they have the same root...) */
- if (fcu->rna_path && !strcmp(fcu->rna_path, rna_path)) {
+ if (fcu->rna_path && STREQ(fcu->rna_path, rna_path)) {
return fcu;
}
}
@@ -290,7 +290,7 @@ int list_find_data_fcurves(ListBase *dst, ListBase *src, const char *dataPrefix,
if (quotedName) {
/* check if the quoted name matches the required name */
- if (strcmp(quotedName, dataName) == 0) {
+ if (STREQ(quotedName, dataName)) {
LinkData *ld = MEM_callocN(sizeof(LinkData), __func__);
ld->data = fcu;
@@ -820,7 +820,7 @@ void fcurve_store_samples(FCurve *fcu, void *data, int start, int end, FcuSample
printf("Error: No F-Curve with F-Curve Modifiers to Bake\n");
return;
}
- if (start >= end) {
+ if (start > end) {
printf("Error: Frame range for Sampled F-Curve creation is inappropriate\n");
return;
}
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 8d4bb7ec058..2adf8ebc615 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -245,7 +245,7 @@ VFont *BKE_vfont_load(Main *bmain, const char *name)
}
/* Do not add FO_BUILTIN_NAME to temporary listbase */
- if (strcmp(filename, FO_BUILTIN_NAME)) {
+ if (!STREQ(filename, FO_BUILTIN_NAME)) {
vfont->temp_pf = temp_pf;
}
}
diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c
index 1f9cf2e11b7..ae3ab833a87 100644
--- a/source/blender/blenkernel/intern/group.c
+++ b/source/blender/blenkernel/intern/group.c
@@ -219,6 +219,43 @@ static int group_object_unlink_internal(Group *group, Object *ob)
return removed;
}
+static bool group_object_cyclic_check_internal(Object *object, Group *group)
+{
+ 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;
+ }
+ /* 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 (group_object_cyclic_check_internal(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;
+ }
+
+ return false;
+}
+
+bool BKE_group_object_cyclic_check(Main *bmain, Object *object, Group *group)
+{
+ /* first flag all groups */
+ BKE_main_id_tag_listbase(&bmain->group, true);
+
+ return group_object_cyclic_check_internal(object, group);
+}
+
bool BKE_group_object_unlink(Group *group, Object *object, Scene *scene, Base *base)
{
if (group_object_unlink_internal(group, object)) {
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 2b99b5f4620..4d83f8cf916 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -804,7 +804,7 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is
case IDP_STRING:
{
return (((prop1->len == prop2->len) &&
- strncmp(IDP_String(prop1), IDP_String(prop2), (size_t)prop1->len) == 0));
+ STREQLEN(IDP_String(prop1), IDP_String(prop2), (size_t)prop1->len)));
}
case IDP_ARRAY:
if (prop1->len == prop2->len && prop1->subtype == prop2->subtype) {
diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c
index 870c077ff78..131a19b8108 100644
--- a/source/blender/blenkernel/intern/image.c
+++ b/source/blender/blenkernel/intern/image.c
@@ -803,7 +803,9 @@ Image *BKE_image_add_generated(Main *bmain, unsigned int width, unsigned int hei
return ima;
}
-/* creates an image image owns the imbuf passed */
+/* Create an image image from ibuf. The refcount of ibuf is increased,
+ * caller should take care to drop its reference by calling
+ * IMB_freeImBuf if needed. */
Image *BKE_image_add_from_imbuf(ImBuf *ibuf)
{
/* on save, type is changed to FILE in editsima.c */
@@ -860,14 +862,14 @@ void BKE_image_memorypack(Image *ima)
void BKE_image_tag_time(Image *ima)
{
- ima->lastused = (int)PIL_check_seconds_timer();
+ ima->lastused = PIL_check_seconds_timer_i();
}
#if 0
static void tag_all_images_time()
{
Image *ima;
- int ctime = (int)PIL_check_seconds_timer();
+ int ctime = PIL_check_seconds_timer_i();
ima = G.main->image.first;
while (ima) {
@@ -1011,7 +1013,7 @@ void BKE_image_all_free_anim_ibufs(int cfra)
/* *********** READ AND WRITE ************** */
-int BKE_imtype_to_ftype(const char imtype)
+int BKE_image_imtype_to_ftype(const char imtype)
{
if (imtype == R_IMF_IMTYPE_TARGA)
return TGA;
@@ -1051,7 +1053,7 @@ int BKE_imtype_to_ftype(const char imtype)
return JPG | 90;
}
-char BKE_ftype_to_imtype(const int ftype)
+char BKE_image_ftype_to_imtype(const int ftype)
{
if (ftype == 0)
return R_IMF_IMTYPE_TARGA;
@@ -1223,42 +1225,42 @@ char BKE_imtype_valid_depths(const char imtype)
* creator.c help info */
char BKE_imtype_from_arg(const char *imtype_arg)
{
- if (!strcmp(imtype_arg, "TGA")) return R_IMF_IMTYPE_TARGA;
- else if (!strcmp(imtype_arg, "IRIS")) return R_IMF_IMTYPE_IRIS;
+ if (STREQ(imtype_arg, "TGA")) return R_IMF_IMTYPE_TARGA;
+ else if (STREQ(imtype_arg, "IRIS")) return R_IMF_IMTYPE_IRIS;
#ifdef WITH_DDS
- else if (!strcmp(imtype_arg, "DDS")) return R_IMF_IMTYPE_DDS;
+ else if (STREQ(imtype_arg, "DDS")) return R_IMF_IMTYPE_DDS;
#endif
- else if (!strcmp(imtype_arg, "JPEG")) return R_IMF_IMTYPE_JPEG90;
- else if (!strcmp(imtype_arg, "IRIZ")) return R_IMF_IMTYPE_IRIZ;
- else if (!strcmp(imtype_arg, "RAWTGA")) return R_IMF_IMTYPE_RAWTGA;
- else if (!strcmp(imtype_arg, "AVIRAW")) return R_IMF_IMTYPE_AVIRAW;
- else if (!strcmp(imtype_arg, "AVIJPEG")) return R_IMF_IMTYPE_AVIJPEG;
- else if (!strcmp(imtype_arg, "PNG")) return R_IMF_IMTYPE_PNG;
- else if (!strcmp(imtype_arg, "QUICKTIME")) return R_IMF_IMTYPE_QUICKTIME;
- else if (!strcmp(imtype_arg, "BMP")) return R_IMF_IMTYPE_BMP;
+ else if (STREQ(imtype_arg, "JPEG")) return R_IMF_IMTYPE_JPEG90;
+ else if (STREQ(imtype_arg, "IRIZ")) return R_IMF_IMTYPE_IRIZ;
+ else if (STREQ(imtype_arg, "RAWTGA")) return R_IMF_IMTYPE_RAWTGA;
+ else if (STREQ(imtype_arg, "AVIRAW")) return R_IMF_IMTYPE_AVIRAW;
+ else if (STREQ(imtype_arg, "AVIJPEG")) return R_IMF_IMTYPE_AVIJPEG;
+ else if (STREQ(imtype_arg, "PNG")) return R_IMF_IMTYPE_PNG;
+ else if (STREQ(imtype_arg, "QUICKTIME")) return R_IMF_IMTYPE_QUICKTIME;
+ else if (STREQ(imtype_arg, "BMP")) return R_IMF_IMTYPE_BMP;
#ifdef WITH_HDR
- else if (!strcmp(imtype_arg, "HDR")) return R_IMF_IMTYPE_RADHDR;
+ else if (STREQ(imtype_arg, "HDR")) return R_IMF_IMTYPE_RADHDR;
#endif
#ifdef WITH_TIFF
- else if (!strcmp(imtype_arg, "TIFF")) return R_IMF_IMTYPE_TIFF;
+ else if (STREQ(imtype_arg, "TIFF")) return R_IMF_IMTYPE_TIFF;
#endif
#ifdef WITH_OPENEXR
- else if (!strcmp(imtype_arg, "EXR")) return R_IMF_IMTYPE_OPENEXR;
- else if (!strcmp(imtype_arg, "MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER;
+ else if (STREQ(imtype_arg, "EXR")) return R_IMF_IMTYPE_OPENEXR;
+ else if (STREQ(imtype_arg, "MULTILAYER")) return R_IMF_IMTYPE_MULTILAYER;
#endif
- else if (!strcmp(imtype_arg, "MPEG")) return R_IMF_IMTYPE_FFMPEG;
- else if (!strcmp(imtype_arg, "FRAMESERVER")) return R_IMF_IMTYPE_FRAMESERVER;
+ else if (STREQ(imtype_arg, "MPEG")) return R_IMF_IMTYPE_FFMPEG;
+ else if (STREQ(imtype_arg, "FRAMESERVER")) return R_IMF_IMTYPE_FRAMESERVER;
#ifdef WITH_CINEON
- else if (!strcmp(imtype_arg, "CINEON")) return R_IMF_IMTYPE_CINEON;
- else if (!strcmp(imtype_arg, "DPX")) return R_IMF_IMTYPE_DPX;
+ else if (STREQ(imtype_arg, "CINEON")) return R_IMF_IMTYPE_CINEON;
+ else if (STREQ(imtype_arg, "DPX")) return R_IMF_IMTYPE_DPX;
#endif
#ifdef WITH_OPENJPEG
- else if (!strcmp(imtype_arg, "JP2")) return R_IMF_IMTYPE_JP2;
+ else if (STREQ(imtype_arg, "JP2")) return R_IMF_IMTYPE_JP2;
#endif
else return R_IMF_IMTYPE_INVALID;
}
-static bool do_add_image_extension(char *string, const char imtype, const ImageFormatData *im_format)
+static bool image_path_ensure_ext(char *string, const char imtype, const ImageFormatData *im_format)
{
const char *extension = NULL;
const char *extension_test;
@@ -1368,14 +1370,14 @@ static bool do_add_image_extension(char *string, const char imtype, const ImageF
}
}
-int BKE_add_image_extension(char *string, const ImageFormatData *im_format)
+bool BKE_image_path_ensure_ext_from_imformat(char *string, const ImageFormatData *im_format)
{
- return do_add_image_extension(string, im_format->imtype, im_format);
+ return image_path_ensure_ext(string, im_format->imtype, im_format);
}
-int BKE_add_image_extension_from_type(char *string, const char imtype)
+bool BKE_image_path_ensure_ext_from_imtype(char *string, const char imtype)
{
- return do_add_image_extension(string, imtype, NULL);
+ return image_path_ensure_ext(string, imtype, NULL);
}
void BKE_imformat_defaults(ImageFormatData *im_format)
@@ -1651,7 +1653,9 @@ static void stampdata(Scene *scene, Object *camera, StampData *stamp_data, int d
}
}
-void BKE_stamp_buf(Scene *scene, Object *camera, unsigned char *rect, float *rectf, int width, int height, int channels)
+void BKE_image_stamp_buf(
+ Scene *scene, Object *camera,
+ unsigned char *rect, float *rectf, int width, int height, int channels)
{
struct StampData stamp_data;
float w, h, pad;
@@ -2076,8 +2080,9 @@ int BKE_imbuf_write_stamp(Scene *scene, struct Object *camera, ImBuf *ibuf, cons
}
-static void do_makepicstring(char *string, const char *base, const char *relbase, int frame, const char imtype,
- const ImageFormatData *im_format, const short use_ext, const short use_frames)
+static void image_path_makepicstring(
+ char *string, const char *base, const char *relbase, int frame, const char imtype,
+ const ImageFormatData *im_format, const short use_ext, const short use_frames)
{
if (string == NULL) return;
BLI_strncpy(string, base, FILE_MAX - 10); /* weak assumption */
@@ -2087,19 +2092,29 @@ static void do_makepicstring(char *string, const char *base, const char *relbase
BLI_path_frame(string, frame, 4);
if (use_ext)
- do_add_image_extension(string, imtype, im_format);
+ image_path_ensure_ext(string, imtype, im_format);
}
-void BKE_makepicstring(char *string, const char *base, const char *relbase, int frame,
- const ImageFormatData *im_format, const bool use_ext, const bool use_frames)
+void BKE_image_path_from_imformat(
+ char *string, const char *base, const char *relbase, int frame,
+ const ImageFormatData *im_format, const bool use_ext, const bool use_frames)
{
- do_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames);
+ image_path_makepicstring(string, base, relbase, frame, im_format->imtype, im_format, use_ext, use_frames);
}
-void BKE_makepicstring_from_type(char *string, const char *base, const char *relbase, int frame,
- const char imtype, const bool use_ext, const bool use_frames)
+void BKE_image_path_from_imtype(
+ char *string, const char *base, const char *relbase, int frame,
+ const char imtype, const bool use_ext, const bool use_frames)
{
- do_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames);
+ image_path_makepicstring(string, base, relbase, frame, imtype, NULL, use_ext, use_frames);
+}
+
+struct anim *openanim_noload(const char *name, int flags, int streamindex, char colorspace[IMA_MAX_SPACE])
+{
+ struct anim *anim;
+
+ anim = IMB_open_anim(name, flags, streamindex, colorspace);
+ return anim;
}
/* used by sequencer too */
@@ -2167,11 +2182,6 @@ Image *BKE_image_verify_viewer(int type, const char *name)
return ima;
}
-void BKE_image_assign_ibuf(Image *ima, ImBuf *ibuf)
-{
- image_assign_ibuf(ima, ibuf, IMA_NO_INDEX, 0);
-}
-
void BKE_image_walk_all_users(const Main *mainp, void *customdata,
void callback(Image *ima, ImageUser *iuser, void *customdata))
{
@@ -2595,11 +2605,15 @@ static ImBuf *image_load_movie_file(Image *ima, ImageUser *iuser, int frame)
if (ima->anim == NULL) {
char str[FILE_MAX];
+ int flags = IB_rect;
+ if (ima->flag & IMA_DEINTERLACE) {
+ flags |= IB_animdeinterlace;
+ }
BKE_image_user_file_path(iuser, ima, str);
/* FIXME: make several stream accessible in image editor, too*/
- ima->anim = openanim(str, IB_rect, 0, ima->colorspace_settings.name);
+ ima->anim = openanim(str, flags, 0, ima->colorspace_settings.name);
/* let's initialize this user */
if (ima->anim && iuser && iuser->frames == 0)
diff --git a/source/blender/blenkernel/intern/implicit.c b/source/blender/blenkernel/intern/implicit.c
deleted file mode 100644
index fe64af184a9..00000000000
--- a/source/blender/blenkernel/intern/implicit.c
+++ /dev/null
@@ -1,1770 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) Blender Foundation
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): none yet.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-/** \file blender/blenkernel/intern/implicit.c
- * \ingroup bke
- */
-
-
-#include "MEM_guardedalloc.h"
-
-#include "DNA_scene_types.h"
-#include "DNA_object_types.h"
-#include "DNA_object_force.h"
-#include "DNA_meshdata_types.h"
-
-#include "BLI_math.h"
-#include "BLI_linklist.h"
-#include "BLI_utildefines.h"
-
-#include "BKE_cloth.h"
-#include "BKE_collision.h"
-#include "BKE_effect.h"
-#include "BKE_global.h"
-
-
-#ifdef __GNUC__
-# pragma GCC diagnostic ignored "-Wtype-limits"
-#endif
-
-#ifdef _OPENMP
-# define CLOTH_OPENMP_LIMIT 512
-#endif
-
-#if 0 /* debug timing */
-#ifdef _WIN32
-#include <windows.h>
-static LARGE_INTEGER _itstart, _itend;
-static LARGE_INTEGER ifreq;
-static void itstart(void)
-{
- static int first = 1;
- if (first) {
- QueryPerformanceFrequency(&ifreq);
- first = 0;
- }
- QueryPerformanceCounter(&_itstart);
-}
-static void itend(void)
-{
- QueryPerformanceCounter(&_itend);
-}
-double itval(void)
-{
- return ((double)_itend.QuadPart -
- (double)_itstart.QuadPart)/((double)ifreq.QuadPart);
-}
-#else
-#include <sys/time.h>
-// intrinsics need better compile flag checking
-// #include <xmmintrin.h>
-// #include <pmmintrin.h>
-// #include <pthread.h>
-
-static struct timeval _itstart, _itend;
-static struct timezone itz;
-static void itstart(void)
-{
- gettimeofday(&_itstart, &itz);
-}
-static void itend(void)
-{
- gettimeofday(&_itend, &itz);
-}
-static double itval(void)
-{
- double t1, t2;
- t1 = (double)_itstart.tv_sec + (double)_itstart.tv_usec/(1000*1000);
- t2 = (double)_itend.tv_sec + (double)_itend.tv_usec/(1000*1000);
- return t2-t1;
-}
-#endif
-#endif /* debug timing */
-
-static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
-static float ZERO[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
-
-/*
-#define C99
-#ifdef C99
-#defineDO_INLINE inline
-#else
-#defineDO_INLINE static
-#endif
-*/
-struct Cloth;
-
-//////////////////////////////////////////
-/* fast vector / matrix library, enhancements are welcome :) -dg */
-/////////////////////////////////////////
-
-/* DEFINITIONS */
-typedef float lfVector[3];
-typedef struct fmatrix3x3 {
- float m[3][3]; /* 3x3 matrix */
- unsigned int c, r; /* column and row number */
- /* int pinned; // is this vertex allowed to move? */
- float n1, n2, n3; /* three normal vectors for collision constrains */
- unsigned int vcount; /* vertex count */
- unsigned int scount; /* spring count */
-} fmatrix3x3;
-
-///////////////////////////
-// float[3] vector
-///////////////////////////
-/* simple vector code */
-/* STATUS: verified */
-DO_INLINE void mul_fvector_S(float to[3], float from[3], float scalar)
-{
- to[0] = from[0] * scalar;
- to[1] = from[1] * scalar;
- to[2] = from[2] * scalar;
-}
-/* simple v^T * v product ("outer product") */
-/* STATUS: HAS TO BE verified (*should* work) */
-DO_INLINE void mul_fvectorT_fvector(float to[3][3], float vectorA[3], float vectorB[3])
-{
- mul_fvector_S(to[0], vectorB, vectorA[0]);
- mul_fvector_S(to[1], vectorB, vectorA[1]);
- mul_fvector_S(to[2], vectorB, vectorA[2]);
-}
-/* simple v^T * v product with scalar ("outer product") */
-/* STATUS: HAS TO BE verified (*should* work) */
-DO_INLINE void mul_fvectorT_fvectorS(float to[3][3], float vectorA[3], float vectorB[3], float aS)
-{
- mul_fvectorT_fvector(to, vectorA, vectorB);
-
- mul_fvector_S(to[0], to[0], aS);
- mul_fvector_S(to[1], to[1], aS);
- mul_fvector_S(to[2], to[2], aS);
-}
-
-#if 0
-/* printf vector[3] on console: for debug output */
-static void print_fvector(float m3[3])
-{
- printf("%f\n%f\n%f\n\n", m3[0], m3[1], m3[2]);
-}
-
-///////////////////////////
-// long float vector float (*)[3]
-///////////////////////////
-/* print long vector on console: for debug output */
-DO_INLINE void print_lfvector(float (*fLongVector)[3], unsigned int verts)
-{
- unsigned int i = 0;
- for (i = 0; i < verts; i++) {
- print_fvector(fLongVector[i]);
- }
-}
-#endif
-
-/* create long vector */
-DO_INLINE lfVector *create_lfvector(unsigned int verts)
-{
- /* TODO: check if memory allocation was successful */
- return (lfVector *)MEM_callocN(verts * sizeof(lfVector), "cloth_implicit_alloc_vector");
- // return (lfVector *)cloth_aligned_malloc(&MEMORY_BASE, verts * sizeof(lfVector));
-}
-/* delete long vector */
-DO_INLINE void del_lfvector(float (*fLongVector)[3])
-{
- if (fLongVector != NULL) {
- MEM_freeN(fLongVector);
- // cloth_aligned_free(&MEMORY_BASE, fLongVector);
- }
-}
-/* copy long vector */
-DO_INLINE void cp_lfvector(float (*to)[3], float (*from)[3], unsigned int verts)
-{
- memcpy(to, from, verts * sizeof(lfVector));
-}
-/* init long vector with float[3] */
-DO_INLINE void init_lfvector(float (*fLongVector)[3], float vector[3], unsigned int verts)
-{
- unsigned int i = 0;
- for (i = 0; i < verts; i++) {
- copy_v3_v3(fLongVector[i], vector);
- }
-}
-/* zero long vector with float[3] */
-DO_INLINE void zero_lfvector(float (*to)[3], unsigned int verts)
-{
- memset(to, 0.0f, verts * sizeof(lfVector));
-}
-/* multiply long vector with scalar*/
-DO_INLINE void mul_lfvectorS(float (*to)[3], float (*fLongVector)[3], float scalar, unsigned int verts)
-{
- unsigned int i = 0;
-
- for (i = 0; i < verts; i++) {
- mul_fvector_S(to[i], fLongVector[i], scalar);
- }
-}
-/* multiply long vector with scalar*/
-/* A -= B * float */
-DO_INLINE void submul_lfvectorS(float (*to)[3], float (*fLongVector)[3], float scalar, unsigned int verts)
-{
- unsigned int i = 0;
- for (i = 0; i < verts; i++) {
- VECSUBMUL(to[i], fLongVector[i], scalar);
- }
-}
-/* dot product for big vector */
-DO_INLINE float dot_lfvector(float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts)
-{
- long i = 0;
- float temp = 0.0;
-// XXX brecht, disabled this for now (first schedule line was already disabled),
-// due to non-commutative nature of floating point ops this makes the sim give
-// different results each time you run it!
-// schedule(guided, 2)
-//#pragma omp parallel for reduction(+: temp) if (verts > CLOTH_OPENMP_LIMIT)
- for (i = 0; i < (long)verts; i++) {
- temp += dot_v3v3(fLongVectorA[i], fLongVectorB[i]);
- }
- return temp;
-}
-/* A = B + C --> for big vector */
-DO_INLINE void add_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts)
-{
- unsigned int i = 0;
-
- for (i = 0; i < verts; i++) {
- VECADD(to[i], fLongVectorA[i], fLongVectorB[i]);
- }
-
-}
-/* A = B + C * float --> for big vector */
-DO_INLINE void add_lfvector_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], float bS, unsigned int verts)
-{
- unsigned int i = 0;
-
- for (i = 0; i < verts; i++) {
- VECADDS(to[i], fLongVectorA[i], fLongVectorB[i], bS);
-
- }
-}
-/* A = B * float + C * float --> for big vector */
-DO_INLINE void add_lfvectorS_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float aS, float (*fLongVectorB)[3], float bS, unsigned int verts)
-{
- unsigned int i = 0;
-
- for (i = 0; i < verts; i++) {
- VECADDSS(to[i], fLongVectorA[i], aS, fLongVectorB[i], bS);
- }
-}
-/* A = B - C * float --> for big vector */
-DO_INLINE void sub_lfvector_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], float bS, unsigned int verts)
-{
- unsigned int i = 0;
- for (i = 0; i < verts; i++) {
- VECSUBS(to[i], fLongVectorA[i], fLongVectorB[i], bS);
- }
-
-}
-/* A = B - C --> for big vector */
-DO_INLINE void sub_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts)
-{
- unsigned int i = 0;
-
- for (i = 0; i < verts; i++) {
- sub_v3_v3v3(to[i], fLongVectorA[i], fLongVectorB[i]);
- }
-
-}
-///////////////////////////
-// 3x3 matrix
-///////////////////////////
-#if 0
-/* printf 3x3 matrix on console: for debug output */
-static void print_fmatrix(float m3[3][3])
-{
- printf("%f\t%f\t%f\n", m3[0][0], m3[0][1], m3[0][2]);
- printf("%f\t%f\t%f\n", m3[1][0], m3[1][1], m3[1][2]);
- printf("%f\t%f\t%f\n\n", m3[2][0], m3[2][1], m3[2][2]);
-}
-#endif
-
-/* copy 3x3 matrix */
-DO_INLINE void cp_fmatrix(float to[3][3], float from[3][3])
-{
- // memcpy(to, from, sizeof (float) * 9);
- copy_v3_v3(to[0], from[0]);
- copy_v3_v3(to[1], from[1]);
- copy_v3_v3(to[2], from[2]);
-}
-
-/* copy 3x3 matrix */
-DO_INLINE void initdiag_fmatrixS(float to[3][3], float aS)
-{
- cp_fmatrix(to, ZERO);
-
- to[0][0] = aS;
- to[1][1] = aS;
- to[2][2] = aS;
-}
-
-#if 0
-/* calculate determinant of 3x3 matrix */
-DO_INLINE float det_fmatrix(float m[3][3])
-{
- return m[0][0]*m[1][1]*m[2][2] + m[1][0]*m[2][1]*m[0][2] + m[0][1]*m[1][2]*m[2][0]
- -m[0][0]*m[1][2]*m[2][1] - m[0][1]*m[1][0]*m[2][2] - m[2][0]*m[1][1]*m[0][2];
-}
-
-DO_INLINE void inverse_fmatrix(float to[3][3], float from[3][3])
-{
- unsigned int i, j;
- float d;
-
- if ((d=det_fmatrix(from)) == 0) {
- printf("can't build inverse");
- exit(0);
- }
- for (i=0;i<3;i++) {
- for (j=0;j<3;j++) {
- int i1=(i+1)%3;
- int i2=(i+2)%3;
- int j1=(j+1)%3;
- int j2=(j+2)%3;
- // reverse indexs i&j to take transpose
- to[j][i] = (from[i1][j1]*from[i2][j2]-from[i1][j2]*from[i2][j1])/d;
- /*
- if (i==j)
- to[i][j] = 1.0f / from[i][j];
- else
- to[i][j] = 0;
- */
- }
- }
-
-}
-#endif
-
-/* 3x3 matrix multiplied by a scalar */
-/* STATUS: verified */
-DO_INLINE void mul_fmatrix_S(float matrix[3][3], float scalar)
-{
- mul_fvector_S(matrix[0], matrix[0], scalar);
- mul_fvector_S(matrix[1], matrix[1], scalar);
- mul_fvector_S(matrix[2], matrix[2], scalar);
-}
-
-/* a vector multiplied by a 3x3 matrix */
-/* STATUS: verified */
-DO_INLINE void mul_fvector_fmatrix(float *to, float *from, float matrix[3][3])
-{
- to[0] = matrix[0][0]*from[0] + matrix[1][0]*from[1] + matrix[2][0]*from[2];
- to[1] = matrix[0][1]*from[0] + matrix[1][1]*from[1] + matrix[2][1]*from[2];
- to[2] = matrix[0][2]*from[0] + matrix[1][2]*from[1] + matrix[2][2]*from[2];
-}
-
-/* 3x3 matrix multiplied by a vector */
-/* STATUS: verified */
-DO_INLINE void mul_fmatrix_fvector(float *to, float matrix[3][3], float from[3])
-{
- to[0] = dot_v3v3(matrix[0], from);
- to[1] = dot_v3v3(matrix[1], from);
- to[2] = dot_v3v3(matrix[2], from);
-}
-/* 3x3 matrix addition with 3x3 matrix */
-DO_INLINE void add_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
-{
- VECADD(to[0], matrixA[0], matrixB[0]);
- VECADD(to[1], matrixA[1], matrixB[1]);
- VECADD(to[2], matrixA[2], matrixB[2]);
-}
-/* A -= B*x + C*y (3x3 matrix sub-addition with 3x3 matrix) */
-DO_INLINE void subadd_fmatrixS_fmatrixS(float to[3][3], float matrixA[3][3], float aS, float matrixB[3][3], float bS)
-{
- VECSUBADDSS(to[0], matrixA[0], aS, matrixB[0], bS);
- VECSUBADDSS(to[1], matrixA[1], aS, matrixB[1], bS);
- VECSUBADDSS(to[2], matrixA[2], aS, matrixB[2], bS);
-}
-/* A = B - C (3x3 matrix subtraction with 3x3 matrix) */
-DO_INLINE void sub_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
-{
- sub_v3_v3v3(to[0], matrixA[0], matrixB[0]);
- sub_v3_v3v3(to[1], matrixA[1], matrixB[1]);
- sub_v3_v3v3(to[2], matrixA[2], matrixB[2]);
-}
-/////////////////////////////////////////////////////////////////
-// special functions
-/////////////////////////////////////////////////////////////////
-/* 3x3 matrix multiplied+added by a vector */
-/* STATUS: verified */
-DO_INLINE void muladd_fmatrix_fvector(float to[3], float matrix[3][3], float from[3])
-{
- to[0] += dot_v3v3(matrix[0], from);
- to[1] += dot_v3v3(matrix[1], from);
- to[2] += dot_v3v3(matrix[2], from);
-}
-/////////////////////////////////////////////////////////////////
-
-///////////////////////////
-// SPARSE SYMMETRIC big matrix with 3x3 matrix entries
-///////////////////////////
-/* printf a big matrix on console: for debug output */
-#if 0
-static void print_bfmatrix(fmatrix3x3 *m3)
-{
- unsigned int i = 0;
-
- for (i = 0; i < m3[0].vcount + m3[0].scount; i++)
- {
- print_fmatrix(m3[i].m);
- }
-}
-#endif
-
-/* create big matrix */
-DO_INLINE fmatrix3x3 *create_bfmatrix(unsigned int verts, unsigned int springs)
-{
- // TODO: check if memory allocation was successful */
- fmatrix3x3 *temp = (fmatrix3x3 *)MEM_callocN(sizeof(fmatrix3x3) * (verts + springs), "cloth_implicit_alloc_matrix");
- temp[0].vcount = verts;
- temp[0].scount = springs;
- return temp;
-}
-/* delete big matrix */
-DO_INLINE void del_bfmatrix(fmatrix3x3 *matrix)
-{
- if (matrix != NULL) {
- MEM_freeN(matrix);
- }
-}
-
-/* copy big matrix */
-DO_INLINE void cp_bfmatrix(fmatrix3x3 *to, fmatrix3x3 *from)
-{
- // TODO bounds checking
- memcpy(to, from, sizeof(fmatrix3x3) * (from[0].vcount+from[0].scount));
-}
-
-/* init big matrix */
-// slow in parallel
-DO_INLINE void init_bfmatrix(fmatrix3x3 *matrix, float m3[3][3])
-{
- unsigned int i;
-
- for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
- cp_fmatrix(matrix[i].m, m3);
- }
-}
-
-/* init the diagonal of big matrix */
-// slow in parallel
-DO_INLINE void initdiag_bfmatrix(fmatrix3x3 *matrix, float m3[3][3])
-{
- unsigned int i, j;
- float tmatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
-
- for (i = 0; i < matrix[0].vcount; i++) {
- cp_fmatrix(matrix[i].m, m3);
- }
- for (j = matrix[0].vcount; j < matrix[0].vcount+matrix[0].scount; j++) {
- cp_fmatrix(matrix[j].m, tmatrix);
- }
-}
-
-/* SPARSE SYMMETRIC multiply big matrix with long vector*/
-/* STATUS: verified */
-DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector *fLongVector)
-{
- unsigned int i = 0;
- unsigned int vcount = from[0].vcount;
- lfVector *temp = create_lfvector(vcount);
-
- zero_lfvector(to, vcount);
-
-#pragma omp parallel sections private(i) if (vcount > CLOTH_OPENMP_LIMIT)
- {
-#pragma omp section
- {
- for (i = from[0].vcount; i < from[0].vcount+from[0].scount; i++) {
- muladd_fmatrix_fvector(to[from[i].c], from[i].m, fLongVector[from[i].r]);
- }
- }
-#pragma omp section
- {
- for (i = 0; i < from[0].vcount+from[0].scount; i++) {
- muladd_fmatrix_fvector(temp[from[i].r], from[i].m, fLongVector[from[i].c]);
- }
- }
- }
- add_lfvector_lfvector(to, to, temp, from[0].vcount);
-
- del_lfvector(temp);
-
-
-}
-
-/* SPARSE SYMMETRIC sub big matrix with big matrix*/
-/* A -= B * float + C * float --> for big matrix */
-/* VERIFIED */
-DO_INLINE void subadd_bfmatrixS_bfmatrixS( fmatrix3x3 *to, fmatrix3x3 *from, float aS, fmatrix3x3 *matrix, float bS)
-{
- unsigned int i = 0;
-
- /* process diagonal elements */
- for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
- subadd_fmatrixS_fmatrixS(to[i].m, from[i].m, aS, matrix[i].m, bS);
- }
-
-}
-
-///////////////////////////////////////////////////////////////////
-// simulator start
-///////////////////////////////////////////////////////////////////
-typedef struct Implicit_Data {
- lfVector *X, *V, *Xnew, *Vnew, *olddV, *F, *B, *dV, *z;
- fmatrix3x3 *A, *dFdV, *dFdX, *S, *P, *Pinv, *bigI, *M;
-} Implicit_Data;
-
-/* Init constraint matrix */
-static void update_matrixS(ClothVertex *verts, int numverts, fmatrix3x3 *S)
-{
- unsigned int pinned = 0;
- int i = 0;
-
- /* Clear matrix from old vertex constraints */
- for (i = 0; i < S[0].vcount; i++)
- S[i].c = S[i].r = 0;
-
- /* Set new vertex constraints */
- for (i = 0; i < numverts; i++) {
- if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
- S[pinned].c = S[pinned].r = i;
- pinned++;
- }
- }
-
- // S is special and needs specific vcount and scount
- S[0].vcount = pinned;
- S[0].scount = 0;
-}
-
-int implicit_init(Object *UNUSED(ob), ClothModifierData *clmd)
-{
- unsigned int i = 0;
- Cloth *cloth = NULL;
- ClothVertex *verts = NULL;
- ClothSpring *spring = NULL;
- Implicit_Data *id = NULL;
- LinkNode *search = NULL;
-
- if (G.debug_value > 0)
- printf("implicit_init\n");
-
- // init memory guard
- // BLI_listbase_clear(&MEMORY_BASE);
-
- cloth = (Cloth *)clmd->clothObject;
- verts = cloth->verts;
-
- // create implicit base
- id = (Implicit_Data *)MEM_callocN(sizeof(Implicit_Data), "implicit vecmat");
- cloth->implicit = id;
-
- /* process diagonal elements */
- id->A = create_bfmatrix(cloth->numverts, cloth->numsprings);
- id->dFdV = create_bfmatrix(cloth->numverts, cloth->numsprings);
- id->dFdX = create_bfmatrix(cloth->numverts, cloth->numsprings);
- id->S = create_bfmatrix(cloth->numverts, 0);
- id->Pinv = create_bfmatrix(cloth->numverts, cloth->numsprings);
- id->P = create_bfmatrix(cloth->numverts, cloth->numsprings);
- id->bigI = create_bfmatrix(cloth->numverts, cloth->numsprings); // TODO 0 springs
- id->M = create_bfmatrix(cloth->numverts, cloth->numsprings);
- id->X = create_lfvector(cloth->numverts);
- id->Xnew = create_lfvector(cloth->numverts);
- id->V = create_lfvector(cloth->numverts);
- id->Vnew = create_lfvector(cloth->numverts);
- id->olddV = create_lfvector(cloth->numverts);
- zero_lfvector(id->olddV, cloth->numverts);
- id->F = create_lfvector(cloth->numverts);
- id->B = create_lfvector(cloth->numverts);
- id->dV = create_lfvector(cloth->numverts);
- id->z = create_lfvector(cloth->numverts);
-
- id->S[0].vcount = 0;
- update_matrixS(verts, cloth->numverts, id->S);
-
- for (i = 0; i < cloth->numverts; i++) {
- id->A[i].r = id->A[i].c = id->dFdV[i].r = id->dFdV[i].c = id->dFdX[i].r = id->dFdX[i].c = id->P[i].c = id->P[i].r = id->Pinv[i].c = id->Pinv[i].r = id->bigI[i].c = id->bigI[i].r = id->M[i].r = id->M[i].c = i;
-
- initdiag_fmatrixS(id->M[i].m, verts[i].mass);
- }
-
- // init springs
- search = cloth->springs;
- for (i = 0; i < cloth->numsprings; i++) {
- spring = search->link;
-
- // dFdV_start[i].r = big_I[i].r = big_zero[i].r =
- id->A[i+cloth->numverts].r = id->dFdV[i+cloth->numverts].r = id->dFdX[i+cloth->numverts].r =
- id->P[i+cloth->numverts].r = id->Pinv[i+cloth->numverts].r = id->bigI[i+cloth->numverts].r = id->M[i+cloth->numverts].r = spring->ij;
-
- // dFdV_start[i].c = big_I[i].c = big_zero[i].c =
- id->A[i+cloth->numverts].c = id->dFdV[i+cloth->numverts].c = id->dFdX[i+cloth->numverts].c =
- id->P[i+cloth->numverts].c = id->Pinv[i+cloth->numverts].c = id->bigI[i+cloth->numverts].c = id->M[i+cloth->numverts].c = spring->kl;
-
- spring->matrix_index = i + cloth->numverts;
-
- search = search->next;
- }
-
- initdiag_bfmatrix(id->bigI, I);
-
- for (i = 0; i < cloth->numverts; i++) {
- copy_v3_v3(id->X[i], verts[i].x);
- }
-
- return 1;
-}
-
-int implicit_free(ClothModifierData *clmd)
-{
- Implicit_Data *id;
- Cloth *cloth;
- cloth = (Cloth *)clmd->clothObject;
-
- if (cloth) {
- id = cloth->implicit;
-
- if (id) {
- del_bfmatrix(id->A);
- del_bfmatrix(id->dFdV);
- del_bfmatrix(id->dFdX);
- del_bfmatrix(id->S);
- del_bfmatrix(id->P);
- del_bfmatrix(id->Pinv);
- del_bfmatrix(id->bigI);
- del_bfmatrix(id->M);
-
- del_lfvector(id->X);
- del_lfvector(id->Xnew);
- del_lfvector(id->V);
- del_lfvector(id->Vnew);
- del_lfvector(id->olddV);
- del_lfvector(id->F);
- del_lfvector(id->B);
- del_lfvector(id->dV);
- del_lfvector(id->z);
-
- MEM_freeN(id);
- }
- }
-
- return 1;
-}
-
-DO_INLINE float fb(float length, float L)
-{
- float x = length / L;
- float xx = x * x;
- float xxx = xx * x;
- float xxxx = xxx * x;
- return (-11.541f * xxxx + 34.193f * xxx - 39.083f * xx + 23.116f * x - 9.713f);
-}
-
-DO_INLINE float fbderiv(float length, float L)
-{
- float x = length/L;
- float xx = x * x;
- float xxx = xx * x;
- return (-46.164f * xxx + 102.579f * xx - 78.166f * x + 23.116f);
-}
-
-DO_INLINE float fbstar(float length, float L, float kb, float cb)
-{
- float tempfb_fl = kb * fb(length, L);
- float fbstar_fl = cb * (length - L);
-
- if (tempfb_fl < fbstar_fl)
- return fbstar_fl;
- else
- return tempfb_fl;
-}
-
-// function to calculae bending spring force (taken from Choi & Co)
-DO_INLINE float fbstar_jacobi(float length, float L, float kb, float cb)
-{
- float tempfb_fl = kb * fb(length, L);
- float fbstar_fl = cb * (length - L);
-
- if (tempfb_fl < fbstar_fl) {
- return cb;
- }
- else {
- return kb * fbderiv(length, L);
- }
-}
-
-DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
-{
- unsigned int i=0;
-
- for (i = 0; i < S[0].vcount; i++) {
- mul_fvector_fmatrix(V[S[i].r], V[S[i].r], S[i].m);
- }
-}
-
-static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S)
-{
- // Solves for unknown X in equation AX=B
- unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100;
- float conjgrad_epsilon=0.0001f /* , conjgrad_lasterror=0 */ /* UNUSED */;
- lfVector *q, *d, *tmp, *r;
- float s, starget, a, s_prev;
- unsigned int numverts = lA[0].vcount;
- q = create_lfvector(numverts);
- d = create_lfvector(numverts);
- tmp = create_lfvector(numverts);
- r = create_lfvector(numverts);
-
- // zero_lfvector(ldV, CLOTHPARTICLES);
- filter(ldV, S);
-
- add_lfvector_lfvector(ldV, ldV, z, numverts);
-
- // r = B - Mul(tmp, A, X); // just use B if X known to be zero
- cp_lfvector(r, lB, numverts);
- mul_bfmatrix_lfvector(tmp, lA, ldV);
- sub_lfvector_lfvector(r, r, tmp, numverts);
-
- filter(r, S);
-
- cp_lfvector(d, r, numverts);
-
- s = dot_lfvector(r, r, numverts);
- starget = s * sqrtf(conjgrad_epsilon);
-
- while (s>starget && conjgrad_loopcount < conjgrad_looplimit) {
- // Mul(q, A, d); // q = A*d;
- mul_bfmatrix_lfvector(q, lA, d);
-
- filter(q, S);
-
- a = s/dot_lfvector(d, q, numverts);
-
- // X = X + d*a;
- add_lfvector_lfvectorS(ldV, ldV, d, a, numverts);
-
- // r = r - q*a;
- sub_lfvector_lfvectorS(r, r, q, a, numverts);
-
- s_prev = s;
- s = dot_lfvector(r, r, numverts);
-
- //d = r+d*(s/s_prev);
- add_lfvector_lfvectorS(d, r, d, (s/s_prev), numverts);
-
- filter(d, S);
-
- conjgrad_loopcount++;
- }
- /* conjgrad_lasterror = s; */ /* UNUSED */
-
- del_lfvector(q);
- del_lfvector(d);
- del_lfvector(tmp);
- del_lfvector(r);
- // printf("W/O conjgrad_loopcount: %d\n", conjgrad_loopcount);
-
- return conjgrad_loopcount<conjgrad_looplimit; // true means we reached desired accuracy in given time - ie stable
-}
-
-#if 0
-// block diagonalizer
-DO_INLINE void BuildPPinv(fmatrix3x3 *lA, fmatrix3x3 *P, fmatrix3x3 *Pinv)
-{
- unsigned int i = 0;
-
- // Take only the diagonal blocks of A
-// #pragma omp parallel for private(i) if (lA[0].vcount > CLOTH_OPENMP_LIMIT)
- for (i = 0; i<lA[0].vcount; i++) {
- // block diagonalizer
- cp_fmatrix(P[i].m, lA[i].m);
- inverse_fmatrix(Pinv[i].m, P[i].m);
-
- }
-}
-/*
-// version 1.3
-static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv)
-{
- unsigned int numverts = lA[0].vcount, iterations = 0, conjgrad_looplimit=100;
- float delta0 = 0, deltaNew = 0, deltaOld = 0, alpha = 0;
- float conjgrad_epsilon=0.0001; // 0.2 is dt for steps=5
- lfVector *r = create_lfvector(numverts);
- lfVector *p = create_lfvector(numverts);
- lfVector *s = create_lfvector(numverts);
- lfVector *h = create_lfvector(numverts);
-
- BuildPPinv(lA, P, Pinv);
-
- filter(dv, S);
- add_lfvector_lfvector(dv, dv, z, numverts);
-
- mul_bfmatrix_lfvector(r, lA, dv);
- sub_lfvector_lfvector(r, lB, r, numverts);
- filter(r, S);
-
- mul_prevfmatrix_lfvector(p, Pinv, r);
- filter(p, S);
-
- deltaNew = dot_lfvector(r, p, numverts);
-
- delta0 = deltaNew * sqrt(conjgrad_epsilon);
-
- // itstart();
-
- while ((deltaNew > delta0) && (iterations < conjgrad_looplimit))
- {
- iterations++;
-
- mul_bfmatrix_lfvector(s, lA, p);
- filter(s, S);
-
- alpha = deltaNew / dot_lfvector(p, s, numverts);
-
- add_lfvector_lfvectorS(dv, dv, p, alpha, numverts);
-
- add_lfvector_lfvectorS(r, r, s, -alpha, numverts);
-
- mul_prevfmatrix_lfvector(h, Pinv, r);
- filter(h, S);
-
- deltaOld = deltaNew;
-
- deltaNew = dot_lfvector(r, h, numverts);
-
- add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts);
-
- filter(p, S);
-
- }
-
- // itend();
- // printf("cg_filtered_pre time: %f\n", (float)itval());
-
- del_lfvector(h);
- del_lfvector(s);
- del_lfvector(p);
- del_lfvector(r);
-
- printf("iterations: %d\n", iterations);
-
- return iterations<conjgrad_looplimit;
-}
-*/
-// version 1.4
-static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv, fmatrix3x3 *bigI)
-{
- unsigned int numverts = lA[0].vcount, iterations = 0, conjgrad_looplimit=100;
- float delta0 = 0, deltaNew = 0, deltaOld = 0, alpha = 0, tol = 0;
- lfVector *r = create_lfvector(numverts);
- lfVector *p = create_lfvector(numverts);
- lfVector *s = create_lfvector(numverts);
- lfVector *h = create_lfvector(numverts);
- lfVector *bhat = create_lfvector(numverts);
- lfVector *btemp = create_lfvector(numverts);
-
- BuildPPinv(lA, P, Pinv);
-
- initdiag_bfmatrix(bigI, I);
- sub_bfmatrix_Smatrix(bigI, bigI, S);
-
- // x = Sx_0+(I-S)z
- filter(dv, S);
- add_lfvector_lfvector(dv, dv, z, numverts);
-
- // b_hat = S(b-A(I-S)z)
- mul_bfmatrix_lfvector(r, lA, z);
- mul_bfmatrix_lfvector(bhat, bigI, r);
- sub_lfvector_lfvector(bhat, lB, bhat, numverts);
-
- // r = S(b-Ax)
- mul_bfmatrix_lfvector(r, lA, dv);
- sub_lfvector_lfvector(r, lB, r, numverts);
- filter(r, S);
-
- // p = SP^-1r
- mul_prevfmatrix_lfvector(p, Pinv, r);
- filter(p, S);
-
- // delta0 = bhat^TP^-1bhat
- mul_prevfmatrix_lfvector(btemp, Pinv, bhat);
- delta0 = dot_lfvector(bhat, btemp, numverts);
-
- // deltaNew = r^TP
- deltaNew = dot_lfvector(r, p, numverts);
-
- /*
- filter(dv, S);
- add_lfvector_lfvector(dv, dv, z, numverts);
-
- mul_bfmatrix_lfvector(r, lA, dv);
- sub_lfvector_lfvector(r, lB, r, numverts);
- filter(r, S);
-
- mul_prevfmatrix_lfvector(p, Pinv, r);
- filter(p, S);
-
- deltaNew = dot_lfvector(r, p, numverts);
-
- delta0 = deltaNew * sqrt(conjgrad_epsilon);
- */
-
- // itstart();
-
- tol = (0.01*0.2);
-
- while ((deltaNew > delta0*tol*tol) && (iterations < conjgrad_looplimit))
- {
- iterations++;
-
- mul_bfmatrix_lfvector(s, lA, p);
- filter(s, S);
-
- alpha = deltaNew / dot_lfvector(p, s, numverts);
-
- add_lfvector_lfvectorS(dv, dv, p, alpha, numverts);
-
- add_lfvector_lfvectorS(r, r, s, -alpha, numverts);
-
- mul_prevfmatrix_lfvector(h, Pinv, r);
- filter(h, S);
-
- deltaOld = deltaNew;
-
- deltaNew = dot_lfvector(r, h, numverts);
-
- add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts);
-
- filter(p, S);
-
- }
-
- // itend();
- // printf("cg_filtered_pre time: %f\n", (float)itval());
-
- del_lfvector(btemp);
- del_lfvector(bhat);
- del_lfvector(h);
- del_lfvector(s);
- del_lfvector(p);
- del_lfvector(r);
-
- // printf("iterations: %d\n", iterations);
-
- return iterations<conjgrad_looplimit;
-}
-#endif
-
-DO_INLINE void dfdx_spring_type2(float to[3][3], float dir[3], float length, float L, float k, float cb)
-{
- // return outerprod(dir, dir)*fbstar_jacobi(length, L, k, cb);
- mul_fvectorT_fvectorS(to, dir, dir, fbstar_jacobi(length, L, k, cb));
-}
-
-DO_INLINE void dfdv_damp(float to[3][3], float dir[3], float damping)
-{
- // derivative of force wrt velocity.
- mul_fvectorT_fvectorS(to, dir, dir, damping);
-
-}
-
-DO_INLINE void dfdx_spring(float to[3][3], float dir[3], float length, float L, float k)
-{
- // dir is unit length direction, rest is spring's restlength, k is spring constant.
- //return ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k;
- mul_fvectorT_fvector(to, dir, dir);
- sub_fmatrix_fmatrix(to, I, to);
-
- mul_fmatrix_S(to, (L/length));
- sub_fmatrix_fmatrix(to, to, I);
- mul_fmatrix_S(to, -k);
-}
-
-DO_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, lfVector *UNUSED(lF), lfVector *X, lfVector *V, fmatrix3x3 *UNUSED(dFdV), fmatrix3x3 *UNUSED(dFdX), float time)
-{
- Cloth *cloth = clmd->clothObject;
- ClothVertex *verts = cloth->verts;
- float extent[3];
- float length = 0, dot = 0;
- float dir[3] = {0, 0, 0};
- float vel[3];
- float k = 0.0f;
- float L = s->restlen;
- float cb; /* = clmd->sim_parms->structural; */ /*UNUSED*/
-
- float nullf[3] = {0, 0, 0};
- float stretch_force[3] = {0, 0, 0};
- float bending_force[3] = {0, 0, 0};
- float damping_force[3] = {0, 0, 0};
- float nulldfdx[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
-
- float scaling = 0.0;
-
- int no_compress = clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
-
- copy_v3_v3(s->f, nullf);
- cp_fmatrix(s->dfdx, nulldfdx);
- cp_fmatrix(s->dfdv, nulldfdx);
-
- // calculate elonglation
- 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 = sqrtf(dot);
-
- s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
-
- if (length > ALMOST_ZERO) {
- /*
- if (length>L)
- {
- if ((clmd->sim_parms->flags & CSIMSETT_FLAG_TEARING_ENABLED) &&
- ((((length-L)*100.0f/L) > clmd->sim_parms->maxspringlen))) // cut spring!
- {
- s->flags |= CSPRING_FLAG_DEACTIVATE;
- return;
- }
- }
- */
- mul_fvector_S(dir, extent, 1.0f/length);
- }
- else {
- mul_fvector_S(dir, extent, 0.0f);
- }
-
- // calculate force of structural + shear springs
- if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) {
- if (length > L || no_compress) {
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- k = clmd->sim_parms->structural;
-
- scaling = k + s->stiffness * fabsf(clmd->sim_parms->max_struct - k);
-
- k = scaling / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
-
- // TODO: verify, half verified (couldn't see error)
- if (s->type & CLOTH_SPRING_TYPE_SEWING) {
- // sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects
- float force = k*(length-L);
- if (force > clmd->sim_parms->max_sewing) {
- force = clmd->sim_parms->max_sewing;
- }
- mul_fvector_S(stretch_force, dir, force);
- }
- else {
- mul_fvector_S(stretch_force, dir, k * (length - L));
- }
-
- VECADD(s->f, s->f, stretch_force);
-
- // Ascher & Boxman, p.21: Damping only during elonglation
- // something wrong with it...
- mul_fvector_S(damping_force, dir, clmd->sim_parms->Cdis * dot_v3v3(vel, dir));
- VECADD(s->f, s->f, damping_force);
-
- /* VERIFIED */
- dfdx_spring(s->dfdx, dir, length, L, k);
-
- /* VERIFIED */
- dfdv_damp(s->dfdv, dir, clmd->sim_parms->Cdis);
-
- }
- }
- else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
- float tvect[3];
-
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- // current_position = xold + t * (newposition - xold)
- sub_v3_v3v3(tvect, verts[s->ij].xconst, verts[s->ij].xold);
- mul_fvector_S(tvect, tvect, time);
- VECADD(tvect, tvect, verts[s->ij].xold);
-
- sub_v3_v3v3(extent, X[s->ij], tvect);
-
- // SEE MSG BELOW (these are UNUSED)
- // dot = dot_v3v3(extent, extent);
- // length = sqrt(dot);
-
- k = clmd->sim_parms->goalspring;
-
- scaling = k + s->stiffness * fabsf(clmd->sim_parms->max_struct - k);
-
- k = verts [s->ij].goal * scaling / (clmd->sim_parms->avg_spring_len + FLT_EPSILON);
-
- VECADDS(s->f, s->f, extent, -k);
-
- mul_fvector_S(damping_force, dir, clmd->sim_parms->goalfrict * 0.01f * dot_v3v3(vel, dir));
- VECADD(s->f, s->f, damping_force);
-
- // HERE IS THE PROBLEM!!!!
- // dfdx_spring(s->dfdx, dir, length, 0.0, k);
- // dfdv_damp(s->dfdv, dir, MIN2(1.0, (clmd->sim_parms->goalfrict/100.0)));
- }
- else { /* calculate force of bending springs */
- if (length < L) {
- s->flags |= CLOTH_SPRING_FLAG_NEEDED;
-
- k = clmd->sim_parms->bending;
-
- scaling = k + s->stiffness * fabsf(clmd->sim_parms->max_bend - k);
- cb = k = scaling / (20.0f * (clmd->sim_parms->avg_spring_len + FLT_EPSILON));
-
- mul_fvector_S(bending_force, dir, fbstar(length, L, k, cb));
- VECADD(s->f, s->f, bending_force);
-
- dfdx_spring_type2(s->dfdx, dir, length, L, k, cb);
- }
- }
-}
-
-DO_INLINE void cloth_apply_spring_force(ClothModifierData *UNUSED(clmd), ClothSpring *s, lfVector *lF, lfVector *UNUSED(X), lfVector *UNUSED(V), fmatrix3x3 *dFdV, fmatrix3x3 *dFdX)
-{
- if (s->flags & CLOTH_SPRING_FLAG_NEEDED) {
- if (!(s->type & CLOTH_SPRING_TYPE_BENDING)) {
- sub_fmatrix_fmatrix(dFdV[s->ij].m, dFdV[s->ij].m, s->dfdv);
- sub_fmatrix_fmatrix(dFdV[s->kl].m, dFdV[s->kl].m, s->dfdv);
- add_fmatrix_fmatrix(dFdV[s->matrix_index].m, dFdV[s->matrix_index].m, s->dfdv);
- }
-
- VECADD(lF[s->ij], lF[s->ij], s->f);
-
- if (!(s->type & CLOTH_SPRING_TYPE_GOAL))
- sub_v3_v3v3(lF[s->kl], lF[s->kl], s->f);
-
- sub_fmatrix_fmatrix(dFdX[s->kl].m, dFdX[s->kl].m, s->dfdx);
- sub_fmatrix_fmatrix(dFdX[s->ij].m, dFdX[s->ij].m, s->dfdx);
- add_fmatrix_fmatrix(dFdX[s->matrix_index].m, dFdX[s->matrix_index].m, s->dfdx);
- }
-}
-
-
-static void CalcFloat( float *v1, float *v2, float *v3, float *n)
-{
- float n1[3], n2[3];
-
- n1[0] = v1[0]-v2[0];
- n2[0] = v2[0]-v3[0];
- n1[1] = v1[1]-v2[1];
- n2[1] = v2[1]-v3[1];
- n1[2] = v1[2]-v2[2];
- n2[2] = v2[2]-v3[2];
- n[0] = n1[1]*n2[2]-n1[2]*n2[1];
- n[1] = n1[2]*n2[0]-n1[0]*n2[2];
- n[2] = n1[0]*n2[1]-n1[1]*n2[0];
-}
-
-static void CalcFloat4( float *v1, float *v2, float *v3, float *v4, float *n)
-{
- /* real cross! */
- float n1[3], n2[3];
-
- n1[0] = v1[0]-v3[0];
- n1[1] = v1[1]-v3[1];
- n1[2] = v1[2]-v3[2];
-
- n2[0] = v2[0]-v4[0];
- n2[1] = v2[1]-v4[1];
- n2[2] = v2[2]-v4[2];
-
- n[0] = n1[1]*n2[2]-n1[2]*n2[1];
- n[1] = n1[2]*n2[0]-n1[0]*n2[2];
- n[2] = n1[0]*n2[1]-n1[1]*n2[0];
-}
-
-static float calculateVertexWindForce(const float wind[3], const float vertexnormal[3])
-{
- return dot_v3v3(wind, vertexnormal);
-}
-
-typedef struct HairGridVert {
- float velocity[3];
- float density;
-} HairGridVert;
-#define HAIR_GRID_INDEX(vec, min, max, axis) (int)((vec[axis] - min[axis]) / (max[axis] - min[axis]) * 9.99f)
-/* Smoothing of hair velocities:
- * adapted from
- * Volumetric Methods for Simulation and Rendering of Hair
- * by Lena Petrovic, Mark Henne and John Anderson
- * Pixar Technical Memo #06-08, Pixar Animation Studios
- */
-static void hair_velocity_smoothing(ClothModifierData *clmd, lfVector *lF, lfVector *lX, lfVector *lV, unsigned int numverts)
-{
- /* TODO: This is an initial implementation and should be made much better in due time.
- * What should at least be implemented is a grid size parameter and a smoothing kernel
- * for bigger grids.
- */
-
- /* 10x10x10 grid gives nice initial results */
- HairGridVert grid[10][10][10];
- HairGridVert colg[10][10][10];
- ListBase *colliders = get_collider_cache(clmd->scene, NULL, NULL);
- ColliderCache *col = NULL;
- float gmin[3], gmax[3], density;
- /* 2.0f is an experimental value that seems to give good results */
- float smoothfac = 2.0f * clmd->sim_parms->velocity_smooth;
- float collfac = 2.0f * clmd->sim_parms->collider_friction;
- unsigned int v = 0;
- int i = 0;
- int j = 0;
- int k = 0;
-
- INIT_MINMAX(gmin, gmax);
-
- for (i = 0; i < numverts; i++)
- DO_MINMAX(lX[i], gmin, gmax);
-
- /* initialize grid */
- for (i = 0; i < 10; i++) {
- for (j = 0; j < 10; j++) {
- for (k = 0; k < 10; k++) {
- grid[i][j][k].velocity[0] = 0.0f;
- grid[i][j][k].velocity[1] = 0.0f;
- grid[i][j][k].velocity[2] = 0.0f;
- grid[i][j][k].density = 0.0f;
-
- colg[i][j][k].velocity[0] = 0.0f;
- colg[i][j][k].velocity[1] = 0.0f;
- colg[i][j][k].velocity[2] = 0.0f;
- colg[i][j][k].density = 0.0f;
- }
- }
- }
-
- /* gather velocities & density */
- if (smoothfac > 0.0f) for (v = 0; v < numverts; v++) {
- i = HAIR_GRID_INDEX(lX[v], gmin, gmax, 0);
- j = HAIR_GRID_INDEX(lX[v], gmin, gmax, 1);
- k = HAIR_GRID_INDEX(lX[v], gmin, gmax, 2);
- if (i < 0 || j < 0 || k < 0 || i >= 10 || j >= 10 || k >= 10)
- continue;
-
- grid[i][j][k].velocity[0] += lV[v][0];
- grid[i][j][k].velocity[1] += lV[v][1];
- grid[i][j][k].velocity[2] += lV[v][2];
- grid[i][j][k].density += 1.0f;
- }
-
- /* gather colliders */
- if (colliders && collfac > 0.0f) for (col = colliders->first; col; col = col->next) {
- MVert *loc0 = col->collmd->x;
- MVert *loc1 = col->collmd->xnew;
- float vel[3];
-
- for (v=0; v<col->collmd->numverts; v++, loc0++, loc1++) {
- i = HAIR_GRID_INDEX(loc1->co, gmin, gmax, 0);
-
- if (i>=0 && i<10) {
- j = HAIR_GRID_INDEX(loc1->co, gmin, gmax, 1);
-
- if (j>=0 && j<10) {
- k = HAIR_GRID_INDEX(loc1->co, gmin, gmax, 2);
-
- if (k>=0 && k<10) {
- sub_v3_v3v3(vel, loc1->co, loc0->co);
-
- colg[i][j][k].velocity[0] += vel[0];
- colg[i][j][k].velocity[1] += vel[1];
- colg[i][j][k].velocity[2] += vel[2];
- colg[i][j][k].density += 1.0f;
- }
- }
- }
- }
- }
-
-
- /* divide velocity with density */
- for (i = 0; i < 10; i++) {
- for (j = 0; j < 10; j++) {
- for (k = 0; k < 10; k++) {
- density = grid[i][j][k].density;
- if (density > 0.0f) {
- grid[i][j][k].velocity[0] /= density;
- grid[i][j][k].velocity[1] /= density;
- grid[i][j][k].velocity[2] /= density;
- }
-
- density = colg[i][j][k].density;
- if (density > 0.0f) {
- colg[i][j][k].velocity[0] /= density;
- colg[i][j][k].velocity[1] /= density;
- colg[i][j][k].velocity[2] /= density;
- }
- }
- }
- }
-
- /* calculate forces */
- for (v = 0; v < numverts; v++) {
- i = HAIR_GRID_INDEX(lX[v], gmin, gmax, 0);
- j = HAIR_GRID_INDEX(lX[v], gmin, gmax, 1);
- k = HAIR_GRID_INDEX(lX[v], gmin, gmax, 2);
- if (i < 0 || j < 0 || k < 0 || i >= 10 || j >= 10 || k >= 10)
- continue;
-
- lF[v][0] += smoothfac * (grid[i][j][k].velocity[0] - lV[v][0]);
- lF[v][1] += smoothfac * (grid[i][j][k].velocity[1] - lV[v][1]);
- lF[v][2] += smoothfac * (grid[i][j][k].velocity[2] - lV[v][2]);
-
- if (colg[i][j][k].density > 0.0f) {
- lF[v][0] += collfac * (colg[i][j][k].velocity[0] - lV[v][0]);
- lF[v][1] += collfac * (colg[i][j][k].velocity[1] - lV[v][1]);
- lF[v][2] += collfac * (colg[i][j][k].velocity[2] - lV[v][2]);
- }
- }
-
- free_collider_cache(&colliders);
-}
-
-static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), lfVector *lF, lfVector *lX, lfVector *lV, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, ListBase *effectors, float time, fmatrix3x3 *M)
-{
- /* Collect forces and derivatives: F, dFdX, dFdV */
- Cloth *cloth = clmd->clothObject;
- unsigned int i = 0;
- float spring_air = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
- float gravity[3] = {0.0f, 0.0f, 0.0f};
- float tm2[3][3] = {{0}};
- MFace *mfaces = cloth->mfaces;
- unsigned int numverts = cloth->numverts;
- LinkNode *search;
- lfVector *winvec;
- EffectedPoint epoint;
-
- tm2[0][0] = tm2[1][1] = tm2[2][2] = -spring_air;
-
- /* global acceleration (gravitation) */
- if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
- copy_v3_v3(gravity, clmd->scene->physics_settings.gravity);
- mul_fvector_S(gravity, gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity); /* scale gravity force */
- }
-
- /* set dFdX jacobi matrix to zero */
- init_bfmatrix(dFdX, ZERO);
- /* set dFdX jacobi matrix diagonal entries to -spring_air */
- initdiag_bfmatrix(dFdV, tm2);
-
- init_lfvector(lF, gravity, numverts);
-
- if (clmd->sim_parms->velocity_smooth > 0.0f || clmd->sim_parms->collider_friction > 0.0f)
- hair_velocity_smoothing(clmd, lF, lX, lV, numverts);
-
- /* multiply lF with mass matrix
- * force = mass * acceleration (in this case: gravity)
- */
- for (i = 0; i < numverts; i++) {
- float temp[3];
- copy_v3_v3(temp, lF[i]);
- mul_fmatrix_fvector(lF[i], M[i].m, temp);
- }
-
- submul_lfvectorS(lF, lV, spring_air, numverts);
-
- /* handle external forces like wind */
- if (effectors) {
- // 0 = force, 1 = normalized force
- winvec = create_lfvector(cloth->numverts);
-
- if (!winvec)
- printf("winvec: out of memory in implicit.c\n");
-
- // precalculate wind forces
- for (i = 0; i < cloth->numverts; i++) {
- pd_point_from_loc(clmd->scene, (float*)lX[i], (float*)lV[i], i, &epoint);
- pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
- }
-
- for (i = 0; i < cloth->numfaces; i++) {
- float trinormal[3] = {0, 0, 0}; // normalized triangle normal
- float triunnormal[3] = {0, 0, 0}; // not-normalized-triangle normal
- float tmp[3] = {0, 0, 0};
- float factor = (mfaces[i].v4) ? 0.25 : 1.0 / 3.0;
- factor *= 0.02f;
-
- // calculate face normal
- if (mfaces[i].v4)
- CalcFloat4(lX[mfaces[i].v1], lX[mfaces[i].v2], lX[mfaces[i].v3], lX[mfaces[i].v4], triunnormal);
- else
- CalcFloat(lX[mfaces[i].v1], lX[mfaces[i].v2], lX[mfaces[i].v3], triunnormal);
-
- normalize_v3_v3(trinormal, triunnormal);
-
- // add wind from v1
- copy_v3_v3(tmp, trinormal);
- mul_v3_fl(tmp, calculateVertexWindForce(winvec[mfaces[i].v1], triunnormal));
- VECADDS(lF[mfaces[i].v1], lF[mfaces[i].v1], tmp, factor);
-
- // add wind from v2
- copy_v3_v3(tmp, trinormal);
- mul_v3_fl(tmp, calculateVertexWindForce(winvec[mfaces[i].v2], triunnormal));
- VECADDS(lF[mfaces[i].v2], lF[mfaces[i].v2], tmp, factor);
-
- // add wind from v3
- copy_v3_v3(tmp, trinormal);
- mul_v3_fl(tmp, calculateVertexWindForce(winvec[mfaces[i].v3], triunnormal));
- VECADDS(lF[mfaces[i].v3], lF[mfaces[i].v3], tmp, factor);
-
- // add wind from v4
- if (mfaces[i].v4) {
- copy_v3_v3(tmp, trinormal);
- mul_v3_fl(tmp, calculateVertexWindForce(winvec[mfaces[i].v4], triunnormal));
- VECADDS(lF[mfaces[i].v4], lF[mfaces[i].v4], tmp, factor);
- }
- }
-
- /* Hair has only edges */
- if (cloth->numfaces == 0) {
- ClothSpring *spring;
- float edgevec[3] = {0, 0, 0}; //edge vector
- float edgeunnormal[3] = {0, 0, 0}; // not-normalized-edge normal
- float tmp[3] = {0, 0, 0};
- float factor = 0.01;
-
- search = cloth->springs;
- while (search) {
- spring = search->link;
-
- if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
- sub_v3_v3v3(edgevec, (float*)lX[spring->ij], (float*)lX[spring->kl]);
-
- project_v3_v3v3(tmp, winvec[spring->ij], edgevec);
- sub_v3_v3v3(edgeunnormal, winvec[spring->ij], tmp);
- /* hair doesn't stretch too much so we can use restlen pretty safely */
- VECADDS(lF[spring->ij], lF[spring->ij], edgeunnormal, spring->restlen * factor);
-
- project_v3_v3v3(tmp, winvec[spring->kl], edgevec);
- sub_v3_v3v3(edgeunnormal, winvec[spring->kl], tmp);
- VECADDS(lF[spring->kl], lF[spring->kl], edgeunnormal, spring->restlen * factor);
- }
-
- search = search->next;
- }
- }
-
- del_lfvector(winvec);
- }
-
- // calculate spring forces
- search = cloth->springs;
- while (search) {
- // only handle active springs
- ClothSpring *spring = search->link;
- if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
- cloth_calc_spring_force(clmd, search->link, lF, lX, lV, dFdV, dFdX, time);
-
- search = search->next;
- }
-
- // apply spring forces
- search = cloth->springs;
- while (search) {
- // only handle active springs
- ClothSpring *spring = search->link;
- if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
- cloth_apply_spring_force(clmd, search->link, lF, lX, lV, dFdV, dFdX);
- search = search->next;
- }
- // printf("\n");
-}
-
-static void simulate_implicit_euler(lfVector *Vnew, lfVector *UNUSED(lX), lfVector *lV, lfVector *lF, fmatrix3x3 *dFdV, fmatrix3x3 *dFdX, float dt, fmatrix3x3 *A, lfVector *B, lfVector *dV, fmatrix3x3 *S, lfVector *z, lfVector *olddV, fmatrix3x3 *UNUSED(P), fmatrix3x3 *UNUSED(Pinv), fmatrix3x3 *M, fmatrix3x3 *UNUSED(bigI))
-{
- unsigned int numverts = dFdV[0].vcount;
-
- lfVector *dFdXmV = create_lfvector(numverts);
- zero_lfvector(dV, numverts);
-
- cp_bfmatrix(A, M);
-
- subadd_bfmatrixS_bfmatrixS(A, dFdV, dt, dFdX, (dt*dt));
-
- mul_bfmatrix_lfvector(dFdXmV, dFdX, lV);
-
- add_lfvectorS_lfvectorS(B, lF, dt, dFdXmV, (dt*dt), numverts);
-
- // itstart();
-
- cg_filtered(dV, A, B, z, S); /* conjugate gradient algorithm to solve Ax=b */
- // cg_filtered_pre(dV, A, B, z, S, P, Pinv, bigI);
-
- // itend();
- // printf("cg_filtered calc time: %f\n", (float)itval());
-
- cp_lfvector(olddV, dV, numverts);
-
- // advance velocities
- add_lfvector_lfvector(Vnew, lV, dV, numverts);
-
-
- del_lfvector(dFdXmV);
-}
-
-/* computes where the cloth would be if it were subject to perfectly stiff edges
- * (edge distance constraints) in a lagrangian solver. then add forces to help
- * guide the implicit solver to that state. this function is called after
- * collisions*/
-static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothModifierData *clmd, float (*initial_cos)[3], float UNUSED(step), float dt)
-{
- Cloth *cloth= clmd->clothObject;
- float (*cos)[3] = MEM_callocN(sizeof(float)*3*cloth->numverts, "cos cloth_calc_helper_forces");
- float *masses = MEM_callocN(sizeof(float)*cloth->numverts, "cos cloth_calc_helper_forces");
- LinkNode *node;
- ClothSpring *spring;
- ClothVertex *cv;
- int i, steps;
-
- cv = cloth->verts;
- for (i=0; i<cloth->numverts; i++, cv++) {
- copy_v3_v3(cos[i], cv->tx);
-
- if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) {
- masses[i] = 1e+10;
- }
- else {
- masses[i] = cv->mass;
- }
- }
-
- steps = 55;
- for (i=0; i<steps; i++) {
- for (node=cloth->springs; node; node=node->next) {
- /* ClothVertex *cv1, *cv2; */ /* UNUSED */
- int v1, v2;
- float len, c, l, vec[3];
-
- spring = node->link;
- if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR)
- continue;
-
- v1 = spring->ij; v2 = spring->kl;
- /* cv1 = cloth->verts + v1; */ /* UNUSED */
- /* cv2 = cloth->verts + v2; */ /* UNUSED */
- len = len_v3v3(cos[v1], cos[v2]);
-
- sub_v3_v3v3(vec, cos[v1], cos[v2]);
- normalize_v3(vec);
-
- c = (len - spring->restlen);
- if (c == 0.0f)
- continue;
-
- l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2]));
-
- mul_v3_fl(vec, -(1.0f / masses[v1]) * l);
- add_v3_v3(cos[v1], vec);
-
- sub_v3_v3v3(vec, cos[v2], cos[v1]);
- normalize_v3(vec);
-
- mul_v3_fl(vec, -(1.0f / masses[v2]) * l);
- add_v3_v3(cos[v2], vec);
- }
- }
-
- cv = cloth->verts;
- for (i=0; i<cloth->numverts; i++, cv++) {
- float vec[3];
-
- /*compute forces*/
- sub_v3_v3v3(vec, cos[i], cv->tx);
- mul_v3_fl(vec, cv->mass*dt*20.0f);
- add_v3_v3(cv->tv, vec);
- //copy_v3_v3(cv->tx, cos[i]);
- }
-
- MEM_freeN(cos);
- MEM_freeN(masses);
-
- return 1;
-}
-
-int implicit_solver(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
-{
- unsigned int i=0;
- float step=0.0f, tf=clmd->sim_parms->timescale;
- Cloth *cloth = clmd->clothObject;
- ClothVertex *verts = cloth->verts, *cv;
- unsigned int numverts = cloth->numverts;
- float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
- float spf = (float)clmd->sim_parms->stepsPerFrame / clmd->sim_parms->timescale;
- float (*initial_cos)[3] = MEM_callocN(sizeof(float)*3*cloth->numverts, "initial_cos implicit.c");
- Implicit_Data *id = cloth->implicit;
- int do_extra_solve;
-
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
-
- /* Update vertex constraints for pinned vertices */
- update_matrixS(verts, cloth->numverts, id->S);
-
- for (i = 0; i < numverts; i++) {
- // update velocities with constrained velocities from pinned verts
- if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
- sub_v3_v3v3(id->V[i], verts[i].xconst, verts[i].xold);
- // mul_v3_fl(id->V[i], clmd->sim_parms->stepsPerFrame);
- }
- }
- }
-
- while (step < tf) {
- // damping velocity for artistic reasons
- mul_lfvectorS(id->V, id->V, clmd->sim_parms->vel_damping, numverts);
-
- // calculate forces
- cloth_calc_force(clmd, frame, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step, id->M);
-
- // calculate new velocity
- simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv, id->M, id->bigI);
-
- // advance positions
- add_lfvector_lfvectorS(id->Xnew, id->X, id->Vnew, dt, numverts);
-
- /* move pinned verts to correct position */
- for (i = 0; i < numverts; i++) {
- if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
- if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
- float tvect[3] = {0.0f, 0.0f, 0.0f};
- sub_v3_v3v3(tvect, verts[i].xconst, verts[i].xold);
- mul_fvector_S(tvect, tvect, step+dt);
- VECADD(tvect, tvect, verts[i].xold);
- copy_v3_v3(id->Xnew[i], tvect);
- }
- }
-
- copy_v3_v3(verts[i].txold, id->X[i]);
- }
-
- if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED && clmd->clothObject->bvhtree) {
- // collisions
- // itstart();
-
- // update verts to current positions
- for (i = 0; i < numverts; i++) {
- copy_v3_v3(verts[i].tx, id->Xnew[i]);
-
- sub_v3_v3v3(verts[i].tv, verts[i].tx, verts[i].txold);
- copy_v3_v3(verts[i].v, verts[i].tv);
- }
-
- for (i=0, cv=cloth->verts; i<cloth->numverts; i++, cv++) {
- copy_v3_v3(initial_cos[i], cv->tx);
- }
-
- // call collision function
- // TODO: check if "step" or "step+dt" is correct - dg
- do_extra_solve = cloth_bvh_objcollision(ob, clmd, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
-
- // copy corrected positions back to simulation
- for (i = 0; i < numverts; i++) {
- // correct velocity again, just to be sure we had to change it due to adaptive collisions
- sub_v3_v3v3(verts[i].tv, verts[i].tx, id->X[i]);
- }
-
- //if (do_extra_solve)
- // cloth_calc_helper_forces(ob, clmd, initial_cos, step/clmd->sim_parms->timescale, dt/clmd->sim_parms->timescale);
-
- 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;
-
- copy_v3_v3(id->Xnew[i], verts[i].tx);
- copy_v3_v3(id->Vnew[i], verts[i].tv);
- mul_v3_fl(id->Vnew[i], spf);
- }
- }
-
- // X = Xnew;
- cp_lfvector(id->X, id->Xnew, numverts);
-
- // if there were collisions, advance the velocity from v_n+1/2 to v_n+1
-
- if (do_extra_solve) {
- // V = Vnew;
- cp_lfvector(id->V, id->Vnew, numverts);
-
- // calculate
- cloth_calc_force(clmd, frame, id->F, id->X, id->V, id->dFdV, id->dFdX, effectors, step+dt, id->M);
-
- simulate_implicit_euler(id->Vnew, id->X, id->V, id->F, id->dFdV, id->dFdX, dt / 2.0f, id->A, id->B, id->dV, id->S, id->z, id->olddV, id->P, id->Pinv, id->M, id->bigI);
- }
- }
- else {
- // X = Xnew;
- cp_lfvector(id->X, id->Xnew, numverts);
- }
-
- // itend();
- // printf("collision time: %f\n", (float)itval());
-
- // V = Vnew;
- cp_lfvector(id->V, id->Vnew, numverts);
-
- step += dt;
- }
-
- for (i = 0; i < numverts; i++) {
- if ((clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) && (verts [i].flags & CLOTH_VERT_FLAG_PINNED)) {
- copy_v3_v3(verts[i].txold, verts[i].xconst); // TODO: test --> should be .x
- copy_v3_v3(verts[i].x, verts[i].xconst);
- copy_v3_v3(verts[i].v, id->V[i]);
- }
- else {
- copy_v3_v3(verts[i].txold, id->X[i]);
- copy_v3_v3(verts[i].x, id->X[i]);
- copy_v3_v3(verts[i].v, id->V[i]);
- }
- }
-
- MEM_freeN(initial_cos);
-
- return 1;
-}
-
-void implicit_set_positions(ClothModifierData *clmd)
-{
- Cloth *cloth = clmd->clothObject;
- ClothVertex *verts = cloth->verts;
- unsigned int numverts = cloth->numverts, i;
- Implicit_Data *id = cloth->implicit;
-
- for (i = 0; i < numverts; i++) {
- copy_v3_v3(id->X[i], verts[i].x);
- copy_v3_v3(id->V[i], verts[i].v);
- }
- if (G.debug_value > 0)
- printf("implicit_set_positions\n");
-}
-
diff --git a/source/blender/blenkernel/intern/ipo.c b/source/blender/blenkernel/intern/ipo.c
index 34877c7559c..c748568b4c5 100644
--- a/source/blender/blenkernel/intern/ipo.c
+++ b/source/blender/blenkernel/intern/ipo.c
@@ -161,21 +161,24 @@ static AdrBit2Path ma_mode_bits[] = {
{ \
*tot = sizeof(items) / sizeof(AdrBit2Path); \
return items; \
- }
+ } (void)0
/* This function checks if a Blocktype+Adrcode combo, returning a mapping table */
static AdrBit2Path *adrcode_bitmaps_to_paths(int blocktype, int adrcode, int *tot)
{
/* Object layers */
- if ((blocktype == ID_OB) && (adrcode == OB_LAY))
- RET_ABP(ob_layer_bits)
- else if ((blocktype == ID_MA) && (adrcode == MA_MODE))
- RET_ABP(ma_mode_bits)
+ if ((blocktype == ID_OB) && (adrcode == OB_LAY)) {
+ RET_ABP(ob_layer_bits);
+ }
+ else if ((blocktype == ID_MA) && (adrcode == MA_MODE)) {
+ RET_ABP(ma_mode_bits);
+ }
// XXX TODO: add other types...
/* Normal curve */
return NULL;
}
+#undef RET_ABP
/* *************************************************** */
/* ADRCODE to RNA-Path Conversion Code - Standard */
@@ -919,11 +922,11 @@ static char *get_rna_access(int blocktype, int adrcode, char actname[], char con
BLI_snprintf(buf, sizeof(buf), "pose.bones[\"%s\"].constraints[\"%s\"]", actname, constname);
}
else if (actname && actname[0]) {
- if ((blocktype == ID_OB) && strcmp(actname, "Object") == 0) {
+ if ((blocktype == ID_OB) && STREQ(actname, "Object")) {
/* Actionified "Object" IPO's... no extra path stuff needed */
buf[0] = '\0'; /* empty string */
}
- else if ((blocktype == ID_KE) && strcmp(actname, "Shape") == 0) {
+ else if ((blocktype == ID_KE) && STREQ(actname, "Shape")) {
/* Actionified "Shape" IPO's - these are forced onto object level via the action container there... */
strcpy(buf, "data.shape_keys");
}
@@ -1323,7 +1326,7 @@ static void icu_to_fcurves(ID *id, ListBase *groups, ListBase *list, IpoCurve *i
* - we now need as 'frames'
*/
if ( (id) && (icu->blocktype == GS(id->name)) &&
- (fcu->rna_path && strcmp(fcu->rna_path, "eval_time") == 0) )
+ (fcu->rna_path && STREQ(fcu->rna_path, "eval_time")) )
{
Curve *cu = (Curve *)id;
@@ -1400,9 +1403,9 @@ static void ipo_to_animato(ID *id, Ipo *ipo, char actname[], char constname[], S
* F-Curves for bones). This may be added later... for now let's just dump without them...
*/
if (actname) {
- if ((ipo->blocktype == ID_OB) && (strcmp(actname, "Object") == 0))
+ if ((ipo->blocktype == ID_OB) && STREQ(actname, "Object"))
actname = NULL;
- else if ((ipo->blocktype == ID_OB) && (strcmp(actname, "Shape") == 0))
+ else if ((ipo->blocktype == ID_OB) && STREQ(actname, "Shape"))
actname = NULL;
}
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index 752c2961f28..fa4f9c6ed52 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -378,7 +378,8 @@ bool id_copy(ID *id, ID **newid, bool test)
case ID_WM:
return false; /* can't be copied from here */
case ID_GD:
- return false; /* not implemented */
+ if (!test) *newid = (ID *)gpencil_data_duplicate((bGPdata *)id, false);
+ return true;
case ID_MSK:
if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id);
return true;
@@ -1202,7 +1203,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name)
/* do not test alphabetic! */
/* optimized */
if (idtest->name[2] == name[0]) {
- if (strcmp(name, idtest->name + 2) == 0) break;
+ if (STREQ(name, idtest->name + 2)) break;
}
}
}
@@ -1260,7 +1261,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name)
if ( (id != idtest) &&
(idtest->lib == NULL) &&
(*name == *(idtest->name + 2)) &&
- (strncmp(name, idtest->name + 2, left_len) == 0) &&
+ STREQLEN(name, idtest->name + 2, left_len) &&
(BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len)
)
{
@@ -1571,7 +1572,7 @@ void test_idbutton(char *name)
ID *idtest;
- lb = which_libbase(G.main, GS(name) );
+ lb = which_libbase(G.main, GS(name));
if (lb == NULL) return;
/* search for id */
@@ -1590,7 +1591,7 @@ void rename_id(ID *id, const char *name)
ListBase *lb;
BLI_strncpy(id->name + 2, name, sizeof(id->name) - 2);
- lb = which_libbase(G.main, GS(id->name) );
+ lb = which_libbase(G.main, GS(id->name));
new_id(lb, id, name);
}
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index 981064bb22a..9b682f101ad 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1027,7 +1027,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb)
Group *group;
for (group = G.main->group.first; group; group = group->id.next) {
- if (!group->id.lib && strcmp(group->id.name, ma->group->id.name) == 0) {
+ if (!group->id.lib && STREQ(group->id.name, ma->group->id.name)) {
ma->group = group;
}
}
@@ -1317,6 +1317,26 @@ static bool get_mtex_slot_valid_texpaint(struct MTex *mtex)
mtex->tex->ima);
}
+static bNode *nodetree_uv_node_recursive(bNode *node)
+{
+ bNode *inode;
+ bNodeSocket *sock;
+
+ for (sock = node->inputs.first; sock; sock = sock->next) {
+ if (sock->link) {
+ inode = sock->link->fromnode;
+ if (inode->typeinfo->nclass == NODE_CLASS_INPUT && inode->typeinfo->type == SH_NODE_UVMAP) {
+ return inode;
+ }
+ else {
+ return nodetree_uv_node_recursive(inode);
+ }
+ }
+ }
+
+ return NULL;
+}
+
void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
{
MTex **mtex;
@@ -1368,7 +1388,27 @@ void BKE_texpaint_slot_refresh_cache(Scene *scene, Material *ma)
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;
+ ma->texpaintslot[index].ima = (Image *)node->id;
+
+ /* for new renderer, we need to traverse the treeback in search of a UV node */
+ if (use_nodes) {
+ bNode *uvnode = nodetree_uv_node_recursive(node);
+
+ if (uvnode) {
+ NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
+ ma->texpaintslot[index].uvname = storage->uv_map;
+ /* set a value to index so UI knows that we have a valid pointer for the mesh */
+ ma->texpaintslot[index].index = 0;
+ }
+ else {
+ /* just invalidate the index here so UV map does not get displayed on the UI */
+ ma->texpaintslot[index].index = -1;
+ }
+ }
+ else {
+ ma->texpaintslot[index].index = -1;
+ }
+ index++;
}
}
}
diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c
index 34ab2a85593..ce20636233a 100644
--- a/source/blender/blenkernel/intern/mball.c
+++ b/source/blender/blenkernel/intern/mball.c
@@ -468,7 +468,7 @@ bool BKE_mball_is_basis_for(Object *ob1, Object *ob2)
BLI_split_name_num(basis1name, &basis1nr, ob1->id.name + 2, '.');
BLI_split_name_num(basis2name, &basis2nr, ob2->id.name + 2, '.');
- if (!strcmp(basis1name, basis2name)) {
+ if (STREQ(basis1name, basis2name)) {
return BKE_mball_is_basis(ob1);
}
else {
@@ -503,7 +503,7 @@ void BKE_mball_properties_copy(Scene *scene, Object *active_object)
/* 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 (STREQ(obname, basisname)) {
MetaBall *mb = ob->data;
/* Copy properties from selected/edited metaball */
@@ -545,7 +545,7 @@ Object *BKE_mball_basis_find(Scene *scene, Object *basis)
BLI_split_name_num(obname, &obnr, ob->id.name + 2, '.');
/* object ob has to be in same "group" ... it means, that it has to have same base of its name */
- if (strcmp(obname, basisname) == 0) {
+ if (STREQ(obname, basisname)) {
if (obnr < basisnr) {
basis = ob;
basisnr = obnr;
@@ -913,7 +913,11 @@ static void docube(PROCESS *process, CUBE *cube, MetaBall *mb)
CORNER *c1, *c2;
int i, index = 0, count, indexar[8];
- for (i = 0; i < 8; i++) if (cube->corners[i]->value > 0.0f) index += (1 << i);
+ for (i = 0; i < 8; i++) {
+ if (cube->corners[i]->value > 0.0f) {
+ index += (1 << i);
+ }
+ }
for (polys = cubetable[index]; polys; polys = polys->next) {
INTLIST *edges;
@@ -1675,7 +1679,7 @@ static float init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *sce
int nr;
BLI_split_name_num(name, &nr, bob->id.name + 2, '.');
- if (strcmp(obname, name) == 0) {
+ if (STREQ(obname, name)) {
mb = bob->data;
if (mb->editelems) ml = mb->editelems->first;
@@ -2239,7 +2243,7 @@ static void mball_count(EvaluationContext *eval_ctx, PROCESS *process, Scene *sc
/* 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 (STREQ(obname, basisname)) {
MetaBall *mb = ob->data;
/* if object is in edit mode, then dynamic list of all MetaElems
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index c47d294cfb2..7757babaca2 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -414,6 +414,16 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd)
me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
}
+bool BKE_mesh_has_custom_loop_normals(Mesh *me)
+{
+ if (me->edit_btmesh) {
+ return CustomData_has_layer(&me->edit_btmesh->bm->ldata, CD_CUSTOMLOOPNORMAL);
+ }
+ else {
+ return CustomData_has_layer(&me->ldata, CD_CUSTOMLOOPNORMAL);
+ }
+}
+
/* Note: unlinking is called when me->id.us is 0, question remains how
* much unlinking of Library data in Mesh should be done... probably
* we need a more generic method, like the expand() functions in
@@ -703,7 +713,7 @@ bool BKE_mesh_uv_cdlayer_rename_index(Mesh *me, const int poly_index, const int
}
/* Loop until we do have exactly the same name for all layers! */
- for (i = 1; (strcmp(cdlp->name, cdlu->name) != 0 || (cdlf && strcmp(cdlp->name, cdlf->name) != 0)); i++) {
+ for (i = 1; !STREQ(cdlp->name, cdlu->name) || (cdlf && !STREQ(cdlp->name, cdlf->name)); i++) {
switch (i % step) {
case 0:
BLI_strncpy(cdlp->name, cdlu->name, sizeof(cdlp->name));
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 915abdb6766..40a09eba658 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -39,6 +39,7 @@
#include "BLI_utildefines.h"
#include "BLI_memarena.h"
+#include "BLI_mempool.h"
#include "BLI_math.h"
#include "BLI_edgehash.h"
#include "BLI_bitmap.h"
@@ -46,6 +47,8 @@
#include "BLI_linklist.h"
#include "BLI_linklist_stack.h"
#include "BLI_alloca.h"
+#include "BLI_stack.h"
+#include "BLI_task.h"
#include "BKE_customdata.h"
#include "BKE_mesh.h"
@@ -58,8 +61,8 @@
// #define DEBUG_TIME
+#include "PIL_time.h"
#ifdef DEBUG_TIME
-# include "PIL_time.h"
# include "PIL_time_utildefines.h"
#endif
@@ -316,19 +319,783 @@ void BKE_mesh_calc_normals_tessface(MVert *mverts, int numVerts, MFace *mfaces,
MEM_freeN(fnors);
}
-/**
- * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
- * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
+void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops)
+{
+ if (!(lnors_spacearr->lspacearr && lnors_spacearr->loops_pool)) {
+ MemArena *mem;
+
+ if (!lnors_spacearr->mem) {
+ lnors_spacearr->mem = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
+ }
+ mem = lnors_spacearr->mem;
+ lnors_spacearr->lspacearr = BLI_memarena_calloc(mem, sizeof(MLoopNorSpace *) * (size_t)numLoops);
+ lnors_spacearr->loops_pool = BLI_memarena_alloc(mem, sizeof(LinkNode) * (size_t)numLoops);
+ }
+}
+
+void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
+{
+ BLI_memarena_clear(lnors_spacearr->mem);
+ lnors_spacearr->lspacearr = NULL;
+ lnors_spacearr->loops_pool = NULL;
+}
+
+void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
+{
+ BLI_memarena_free(lnors_spacearr->mem);
+ lnors_spacearr->lspacearr = NULL;
+ lnors_spacearr->loops_pool = NULL;
+ lnors_spacearr->mem = NULL;
+}
+
+MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
+{
+ return BLI_memarena_calloc(lnors_spacearr->mem, sizeof(MLoopNorSpace));
+}
+
+/* This threshold is a bit touchy (usual float precision issue), this value seems OK. */
+#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-6f)
+
+/* Should only be called once.
+ * Beware, this modifies ref_vec and other_vec in place!
+ * In case no valid space can be generated, ref_alpha and ref_beta are set to zero (which means 'use auto lnors').
*/
-void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdge *medges, const int numEdges,
- MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
- MPoly *mpolys, float (*polynors)[3], const int numPolys, float split_angle)
+void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3],
+ float vec_ref[3], float vec_other[3], BLI_Stack *edge_vectors)
+{
+ const float pi2 = (float)M_PI * 2.0f;
+ float tvec[3], dtp;
+ const float dtp_ref = dot_v3v3(vec_ref, lnor);
+ const float dtp_other = dot_v3v3(vec_other, lnor);
+
+ if (UNLIKELY(fabsf(dtp_ref) >= LNOR_SPACE_TRIGO_THRESHOLD || fabsf(dtp_other) >= LNOR_SPACE_TRIGO_THRESHOLD)) {
+ /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space,
+ * tag it as invalid and abort. */
+ lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f;
+ return;
+ }
+
+ copy_v3_v3(lnor_space->vec_lnor, lnor);
+
+ /* Compute ref alpha, average angle of all available edge vectors to lnor. */
+ if (edge_vectors) {
+ float alpha = 0.0f;
+ int nbr = 0;
+ while (!BLI_stack_is_empty(edge_vectors)) {
+ const float *vec = BLI_stack_peek(edge_vectors);
+ alpha += saacosf(dot_v3v3(vec, lnor));
+ BLI_stack_discard(edge_vectors);
+ nbr++;
+ }
+ BLI_assert(nbr > 2); /* This piece of code shall only be called for more than one loop... */
+ lnor_space->ref_alpha = alpha / (float)nbr;
+ }
+ else {
+ lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + saacosf(dot_v3v3(vec_other, lnor))) / 2.0f;
+ }
+
+ /* Project vec_ref on lnor's ortho plane. */
+ mul_v3_v3fl(tvec, lnor, dtp_ref);
+ sub_v3_v3(vec_ref, tvec);
+ normalize_v3_v3(lnor_space->vec_ref, vec_ref);
+
+ cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref);
+ normalize_v3_v3(lnor_space->vec_ortho, tvec);
+
+ /* Project vec_other on lnor's ortho plane. */
+ mul_v3_v3fl(tvec, lnor, dtp_other);
+ sub_v3_v3(vec_other, tvec);
+ normalize_v3(vec_other);
+
+ /* Beta is angle between ref_vec and other_vec, around lnor. */
+ dtp = dot_v3v3(lnor_space->vec_ref, vec_other);
+ if (LIKELY(dtp < LNOR_SPACE_TRIGO_THRESHOLD)) {
+ const float beta = saacos(dtp);
+ lnor_space->ref_beta = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta;
+ }
+ else {
+ lnor_space->ref_beta = pi2;
+ }
+}
+
+void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, const int ml_index,
+ const bool do_add_loop)
+{
+ lnors_spacearr->lspacearr[ml_index] = lnor_space;
+ if (do_add_loop) {
+ BLI_linklist_prepend_nlink(&lnor_space->loops, SET_INT_IN_POINTER(ml_index), &lnors_spacearr->loops_pool[ml_index]);
+ }
+}
+
+MINLINE float unit_short_to_float(const short val)
+{
+ return (float)val / (float)SHRT_MAX;
+}
+
+MINLINE short unit_float_to_short(const float val)
+{
+ /* Rounding... */
+ return (short)floorf(val * (float)SHRT_MAX + 0.5f);
+}
+
+void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3])
+{
+ /* NOP custom normal data or invalid lnor space, return. */
+ if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) {
+ copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor);
+ return;
+ }
+
+ {
+ /* TODO Check whether using sincosf() gives any noticeable benefit
+ * (could not even get it working under linux though)! */
+ const float pi2 = (float)(M_PI * 2.0);
+ const float alphafac = unit_short_to_float(clnor_data[0]);
+ const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) * alphafac;
+ const float betafac = unit_short_to_float(clnor_data[1]);
+
+ mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha));
+
+ if (betafac == 0.0f) {
+ madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha));
+ }
+ else {
+ const float sinalpha = sinf(alpha);
+ const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) * betafac;
+ madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta));
+ madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta));
+ }
+ }
+}
+
+void BKE_lnor_space_custom_normal_to_data(MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2])
{
+ /* We use null vector as NOP custom normal (can be simpler than giving autocomputed lnor...). */
+ if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) {
+ r_clnor_data[0] = r_clnor_data[1] = 0;
+ return;
+ }
+
+ {
+ const float pi2 = (float)(M_PI * 2.0);
+ const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor);
+ float vec[3], cos_beta;
+ float alpha;
+
+ alpha = saacosf(cos_alpha);
+ if (alpha > lnor_space->ref_alpha) {
+ /* Note we could stick to [0, pi] range here, but makes decoding more complex, not worth it. */
+ r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha));
+ }
+ else {
+ r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha);
+ }
+
+ /* Project custom lnor on (vec_ref, vec_ortho) plane. */
+ mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha);
+ add_v3_v3(vec, custom_lnor);
+ normalize_v3(vec);
+
+ cos_beta = dot_v3v3(lnor_space->vec_ref, vec);
+
+ if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) {
+ float beta = saacosf(cos_beta);
+ if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) {
+ beta = pi2 - beta;
+ }
+
+ if (beta > lnor_space->ref_beta) {
+ r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta));
+ }
+ else {
+ r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta);
+ }
+ }
+ else {
+ r_clnor_data[1] = 0;
+ }
+ }
+}
+
+#define LOOP_SPLIT_TASK_BLOCK_SIZE 1024
+
+typedef struct LoopSplitTaskData {
+ /* Specific to each instance (each task). */
+ MLoopNorSpace *lnor_space; /* We have to create those outside of tasks, since afaik memarena is not threadsafe. */
+ float (*lnor)[3];
+ const MLoop *ml_curr;
+ const MLoop *ml_prev;
+ int ml_curr_index;
+ int ml_prev_index;
+ const int *e2l_prev; /* Also used a flag to switch between single or fan process! */
+ int mp_index;
+
+ /* This one is special, it's owned and managed by worker tasks, avoid to have to create it for each fan! */
+ BLI_Stack *edge_vectors;
+
+ char pad_c;
+} LoopSplitTaskData;
+
+typedef struct LoopSplitTaskDataCommon {
+ /* Read/write.
+ * Note we do not need to protect it, though, since two different tasks will *always* affect different
+ * elements in the arrays. */
+ MLoopNorSpaceArray *lnors_spacearr;
+ BLI_bitmap *sharp_verts;
+ float (*loopnors)[3];
+ short (*clnors_data)[2];
+
+ /* Read-only. */
+ const MVert *mverts;
+ const MEdge *medges;
+ const MLoop *mloops;
+ const MPoly *mpolys;
+ const int (*edge_to_loops)[2];
+ const int *loop_to_poly;
+ const float (*polynors)[3];
+
+ int numPolys;
+
+ /* ***** Workers communication. ***** */
+ ThreadQueue *task_queue;
+
+} LoopSplitTaskDataCommon;
+
#define INDEX_UNSET INT_MIN
#define INDEX_INVALID -1
/* See comment about edge_to_loops below. */
#define IS_EDGE_SHARP(_e2l) (ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID))
+static void split_loop_nor_single_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
+{
+ MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
+ short (*clnors_data)[2] = common_data->clnors_data;
+
+ const MVert *mverts = common_data->mverts;
+ const MEdge *medges = common_data->medges;
+ const float (*polynors)[3] = common_data->polynors;
+
+ MLoopNorSpace *lnor_space = data->lnor_space;
+ float (*lnor)[3] = data->lnor;
+ const MLoop *ml_curr = data->ml_curr;
+ const MLoop *ml_prev = data->ml_prev;
+ const int ml_curr_index = data->ml_curr_index;
+#if 0 /* Not needed for 'single' loop. */
+ const int ml_prev_index = data->ml_prev_index;
+ const int *e2l_prev = data->e2l_prev;
+#endif
+ const int mp_index = data->mp_index;
+
+ /* Simple case (both edges around that vertex are sharp in current polygon),
+ * this loop just takes its poly normal.
+ */
+ copy_v3_v3(*lnor, polynors[mp_index]);
+
+ /* printf("BASIC: handling loop %d / edge %d / vert %d\n", ml_curr_index, ml_curr->e, ml_curr->v); */
+
+ /* If needed, generate this (simple!) lnor space. */
+ if (lnors_spacearr) {
+ float vec_curr[3], vec_prev[3];
+
+ const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const MVert *mv_pivot = &mverts[mv_pivot_index];
+ const MEdge *me_curr = &medges[ml_curr->e];
+ const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : &mverts[me_curr->v1];
+ const MEdge *me_prev = &medges[ml_prev->e];
+ const MVert *mv_3 = (me_prev->v1 == mv_pivot_index) ? &mverts[me_prev->v2] : &mverts[me_prev->v1];
+
+ sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
+ normalize_v3(vec_curr);
+ sub_v3_v3v3(vec_prev, mv_3->co, mv_pivot->co);
+ normalize_v3(vec_prev);
+
+ BKE_lnor_space_define(lnor_space, *lnor, vec_curr, vec_prev, NULL);
+ /* We know there is only one loop in this space, no need to create a linklist in this case... */
+ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, false);
+
+ if (clnors_data) {
+ BKE_lnor_space_custom_data_to_normal(lnor_space, clnors_data[ml_curr_index], *lnor);
+ }
+ }
+}
+
+static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data)
+{
+ MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
+ float (*loopnors)[3] = common_data->loopnors;
+ short (*clnors_data)[2] = common_data->clnors_data;
+
+ const MVert *mverts = common_data->mverts;
+ const MEdge *medges = common_data->medges;
+ const MLoop *mloops = common_data->mloops;
+ const MPoly *mpolys = common_data->mpolys;
+ const int (*edge_to_loops)[2] = common_data->edge_to_loops;
+ const int *loop_to_poly = common_data->loop_to_poly;
+ const float (*polynors)[3] = common_data->polynors;
+
+ MLoopNorSpace *lnor_space = data->lnor_space;
+#if 0 /* Not needed for 'fan' loops. */
+ float (*lnor)[3] = data->lnor;
+#endif
+ const MLoop *ml_curr = data->ml_curr;
+ const MLoop *ml_prev = data->ml_prev;
+ const int ml_curr_index = data->ml_curr_index;
+ const int ml_prev_index = data->ml_prev_index;
+ const int mp_index = data->mp_index;
+ const int *e2l_prev = data->e2l_prev;
+
+ BLI_Stack *edge_vectors = data->edge_vectors;
+
+ /* 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
+ * the vertex normal, but I do not see any easy way to detect that (would need to count number
+ * of sharp edges per vertex, I doubt the additional memory usage would be worth it, especially as
+ * it should not be a common case in real-life meshes anyway).
+ */
+ const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
+ const MVert *mv_pivot = &mverts[mv_pivot_index];
+ const MEdge *me_org = &medges[ml_curr->e]; /* ml_curr would be mlfan_prev if we needed that one */
+ const int *e2lfan_curr;
+ float vec_curr[3], vec_prev[3], vec_org[3];
+ const MLoop *mlfan_curr, *mlfan_next;
+ const MPoly *mpfan_next;
+ float lnor[3] = {0.0f, 0.0f, 0.0f};
+ /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
+ int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
+
+ /* We validate clnors data on the fly - cheapest way to do! */
+ int clnors_avg[2] = {0, 0};
+ short (*clnor_ref)[2] = NULL;
+ int clnors_nbr = 0;
+ bool clnors_invalid = false;
+
+ /* Temp loop normal stack. */
+ BLI_SMALLSTACK_DECLARE(normal, float *);
+ /* Temp clnors stack. */
+ BLI_SMALLSTACK_DECLARE(clnors, short *);
+
+ e2lfan_curr = e2l_prev;
+ mlfan_curr = ml_prev;
+ mlfan_curr_index = ml_prev_index;
+ 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 MVert *mv_2 = (me_org->v1 == mv_pivot_index) ? &mverts[me_org->v2] : &mverts[me_org->v1];
+
+ sub_v3_v3v3(vec_org, mv_2->co, mv_pivot->co);
+ normalize_v3(vec_org);
+ copy_v3_v3(vec_prev, vec_org);
+
+ if (lnors_spacearr) {
+ BLI_stack_push(edge_vectors, vec_org);
+ }
+ }
+
+ /* printf("FAN: vert %d, start edge %d\n", mv_pivot_index, ml_curr->e); */
+
+ while (true) {
+ const MEdge *me_curr = &medges[mlfan_curr->e];
+ /* Compute edge vectors.
+ * NOTE: We could pre-compute those into an array, in the first iteration, instead of computing them
+ * twice (or more) here. However, time gained is not worth memory and time lost,
+ * given the fact that this code should not be called that much in real-life meshes...
+ */
+ {
+ const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] : &mverts[me_curr->v1];
+
+ sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
+ normalize_v3(vec_curr);
+ }
+
+ /* printf("\thandling edge %d / loop %d\n", mlfan_curr->e, mlfan_curr_index); */
+
+ {
+ /* Code similar to accumulate_vertex_normals_poly. */
+ /* Calculate angle between the two poly edges incident on this vertex. */
+ const float fac = saacos(dot_v3v3(vec_curr, vec_prev));
+ /* Accumulate */
+ madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac);
+
+ if (clnors_data) {
+ /* Accumulate all clnors, if they are not all equal we have to fix that! */
+ short (*clnor)[2] = &clnors_data[mlfan_vert_index];
+ if (clnors_nbr) {
+ clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
+ }
+ else {
+ clnor_ref = clnor;
+ }
+ clnors_avg[0] += (*clnor)[0];
+ clnors_avg[1] += (*clnor)[1];
+ clnors_nbr++;
+ /* We store here a pointer to all custom lnors processed. */
+ BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
+ }
+ }
+
+ /* We store here a pointer to all loop-normals processed. */
+ BLI_SMALLSTACK_PUSH(normal, (float *)(loopnors[mlfan_vert_index]));
+
+ if (lnors_spacearr) {
+ /* Assign current lnor space to current 'vertex' loop. */
+ BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, true);
+ if (me_curr != me_org) {
+ /* We store here all edges-normalized vectors processed. */
+ BLI_stack_push(edge_vectors, vec_curr);
+ }
+ }
+
+ if (IS_EDGE_SHARP(e2lfan_curr) || (me_curr == me_org)) {
+ /* Current edge is sharp and we have finished with this fan of faces around this vert,
+ * or this vert is smooth, and we have completed a full turn around it.
+ */
+ /* printf("FAN: Finished!\n"); */
+ break;
+ }
+
+ copy_v3_v3(vec_prev, vec_curr);
+
+ /* Warning! This is rather complex!
+ * We have to find our next edge around the vertex (fan mode).
+ * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
+ * whether both loops using current edge are in the same direction or not, and whether
+ * mlfan_curr_index actually uses the vertex we are fanning around!
+ * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
+ * (i.e. not the future mlfan_curr)...
+ */
+ mlfan_curr_index = (e2lfan_curr[0] == mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
+ mpfan_curr_index = loop_to_poly[mlfan_curr_index];
+
+ BLI_assert(mlfan_curr_index >= 0);
+ BLI_assert(mpfan_curr_index >= 0);
+
+ mlfan_next = &mloops[mlfan_curr_index];
+ mpfan_next = &mpolys[mpfan_curr_index];
+ if ((mlfan_curr->v == mlfan_next->v && mlfan_curr->v == mv_pivot_index) ||
+ (mlfan_curr->v != mlfan_next->v && mlfan_curr->v != mv_pivot_index))
+ {
+ /* We need the previous loop, but current one is our vertex's loop. */
+ mlfan_vert_index = mlfan_curr_index;
+ if (--mlfan_curr_index < mpfan_next->loopstart) {
+ mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
+ }
+ }
+ else {
+ /* We need the next loop, which is also our vertex's loop. */
+ if (++mlfan_curr_index >= mpfan_next->loopstart + mpfan_next->totloop) {
+ mlfan_curr_index = mpfan_next->loopstart;
+ }
+ mlfan_vert_index = mlfan_curr_index;
+ }
+ mlfan_curr = &mloops[mlfan_curr_index];
+ /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
+
+ e2lfan_curr = edge_to_loops[mlfan_curr->e];
+ }
+
+ {
+ float lnor_len = normalize_v3(lnor);
+
+ /* If we are generating lnor spacearr, we can now define the one for this fan,
+ * and optionally compute final lnor from custom data too!
+ */
+ if (lnors_spacearr) {
+ if (UNLIKELY(lnor_len == 0.0f)) {
+ /* Use vertex normal as fallback! */
+ copy_v3_v3(lnor, loopnors[mlfan_vert_index]);
+ lnor_len = 1.0f;
+ }
+
+ BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, edge_vectors);
+
+ if (clnors_data) {
+ if (clnors_invalid) {
+ short *clnor;
+
+ clnors_avg[0] /= clnors_nbr;
+ clnors_avg[1] /= clnors_nbr;
+ /* Fix/update all clnors of this fan with computed average value. */
+ printf("Invalid clnors in this fan!\n");
+ while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
+ //print_v2("org clnor", clnor);
+ clnor[0] = (short)clnors_avg[0];
+ clnor[1] = (short)clnors_avg[1];
+ }
+ //print_v2("new clnors", clnors_avg);
+ }
+ /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
+
+ BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
+ }
+ }
+
+ /* In case we get a zero normal here, just use vertex normal already set! */
+ if (LIKELY(lnor_len != 0.0f)) {
+ /* Copy back the final computed normal into all related loop-normals. */
+ float *nor;
+
+ while ((nor = BLI_SMALLSTACK_POP(normal))) {
+ copy_v3_v3(nor, lnor);
+ }
+ }
+ /* Extra bonus: since smallstack is local to this func, no more need to empty it at all cost! */
+ }
+}
+
+static void loop_split_worker_do(
+ LoopSplitTaskDataCommon *common_data, LoopSplitTaskData *data, BLI_Stack *edge_vectors)
+{
+ BLI_assert(data->ml_curr);
+ if (data->e2l_prev) {
+ BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
+ data->edge_vectors = edge_vectors;
+ split_loop_nor_fan_do(common_data, data);
+ }
+ else {
+ /* No need for edge_vectors for 'single' case! */
+ split_loop_nor_single_do(common_data, data);
+ }
+}
+
+static void loop_split_worker(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ LoopSplitTaskDataCommon *common_data = taskdata;
+ LoopSplitTaskData *data_buff;
+
+ /* Temp edge vectors stack, only used when computing lnor spacearr. */
+ BLI_Stack *edge_vectors = common_data->lnors_spacearr ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(loop_split_worker);
+#endif
+
+ while ((data_buff = BLI_thread_queue_pop(common_data->task_queue))) {
+ LoopSplitTaskData *data = data_buff;
+ int i;
+
+ for (i = 0; i < LOOP_SPLIT_TASK_BLOCK_SIZE; i++, data++) {
+ /* A NULL ml_curr is used to tag ended data! */
+ if (data->ml_curr == NULL) {
+ break;
+ }
+ loop_split_worker_do(common_data, data, edge_vectors);
+ }
+
+ MEM_freeN(data_buff);
+ }
+
+ if (edge_vectors) {
+ BLI_stack_free(edge_vectors);
+ }
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(loop_split_worker);
+#endif
+}
+
+/* Note we use data_buff to detect whether we are in threaded context or not, in later case it is NULL. */
+static void loop_split_generator_do(LoopSplitTaskDataCommon *common_data, const bool threaded)
+{
+ MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr;
+ BLI_bitmap *sharp_verts = common_data->sharp_verts;
+ float (*loopnors)[3] = common_data->loopnors;
+
+ const MLoop *mloops = common_data->mloops;
+ const MPoly *mpolys = common_data->mpolys;
+ const int (*edge_to_loops)[2] = common_data->edge_to_loops;
+ const int numPolys = common_data->numPolys;
+
+ const MPoly *mp;
+ int mp_index;
+
+ LoopSplitTaskData *data, *data_buff = NULL, data_mem;
+ int data_idx = 0;
+
+ /* Temp edge vectors stack, only used when computing lnor spacearr (and we are not multi-threading). */
+ BLI_Stack *edge_vectors = (lnors_spacearr && !data_buff) ? BLI_stack_new(sizeof(float[3]), __func__) : NULL;
+
+#ifdef DEBUG_TIME
+ TIMEIT_START(loop_split_generator);
+#endif
+
+ if (!threaded) {
+ memset(&data_mem, 0, sizeof(data_mem));
+ data = &data_mem;
+ }
+
+ /* We now know edges that can be smoothed (with their vector, and their two loops), and edges that will be hard!
+ * Now, time to generate the normals.
+ */
+ for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
+ const MLoop *ml_curr, *ml_prev;
+ float (*lnors)[3];
+ const int ml_last_index = (mp->loopstart + mp->totloop) - 1;
+ int ml_curr_index = mp->loopstart;
+ int ml_prev_index = ml_last_index;
+
+ ml_curr = &mloops[ml_curr_index];
+ ml_prev = &mloops[ml_prev_index];
+ lnors = &loopnors[ml_curr_index];
+
+ for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++, lnors++) {
+ const int *e2l_curr = edge_to_loops[ml_curr->e];
+ const int *e2l_prev = edge_to_loops[ml_prev->e];
+
+ if (!IS_EDGE_SHARP(e2l_curr) && (!lnors_spacearr || BLI_BITMAP_TEST_BOOL(sharp_verts, ml_curr->v))) {
+ /* A smooth edge, and we are not generating lnor_spacearr, or the related vertex is sharp.
+ * We skip it because it is either:
+ * - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit
+ * one of its ends, i.e. one of its two sharp edges), or...
+ * - the related vertex is a "full smooth" one, in which case pre-populated normals from vertex
+ * are just fine (or it has already be handled in a previous loop in case of needed lnors spacearr)!
+ */
+ /* printf("Skipping loop %d / edge %d / vert %d(%d)\n", ml_curr_index, ml_curr->e, ml_curr->v, sharp_verts[ml_curr->v]); */
+ }
+ else {
+ if (threaded) {
+ if (data_idx == 0) {
+ data_buff = MEM_callocN(sizeof(*data_buff) * LOOP_SPLIT_TASK_BLOCK_SIZE, __func__);
+ }
+ data = &data_buff[data_idx];
+ }
+
+ if (IS_EDGE_SHARP(e2l_curr) && IS_EDGE_SHARP(e2l_prev)) {
+ data->lnor = lnors;
+ data->ml_curr = ml_curr;
+ data->ml_prev = ml_prev;
+ data->ml_curr_index = ml_curr_index;
+#if 0 /* Not needed for 'single' loop. */
+ data->ml_prev_index = ml_prev_index;
+ data->e2l_prev = NULL; /* Tag as 'single' task. */
+#endif
+ data->mp_index = mp_index;
+ if (lnors_spacearr) {
+ data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
+ }
+ }
+ /* 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 (i.e. winding).
+ */
+ else {
+#if 0 /* Not needed for 'fan' loops. */
+ data->lnor = lnors;
+#endif
+ data->ml_curr = ml_curr;
+ data->ml_prev = ml_prev;
+ data->ml_curr_index = ml_curr_index;
+ data->ml_prev_index = ml_prev_index;
+ data->e2l_prev = e2l_prev; /* Also tag as 'fan' task. */
+ data->mp_index = mp_index;
+ if (lnors_spacearr) {
+ data->lnor_space = BKE_lnor_space_create(lnors_spacearr);
+ /* Tag related vertex as sharp, to avoid fanning around it again (in case it was a smooth one).
+ * This *has* to be done outside of workers tasks! */
+ BLI_BITMAP_ENABLE(sharp_verts, ml_curr->v);
+ }
+ }
+
+ if (threaded) {
+ data_idx++;
+ if (data_idx == LOOP_SPLIT_TASK_BLOCK_SIZE) {
+ BLI_thread_queue_push(common_data->task_queue, data_buff);
+ data_idx = 0;
+ }
+ }
+ else {
+ loop_split_worker_do(common_data, data, edge_vectors);
+ memset(data, 0, sizeof(data_mem));
+ }
+ }
+
+ ml_prev = ml_curr;
+ ml_prev_index = ml_curr_index;
+ }
+ }
+
+ if (threaded) {
+ /* Last block of data... Since it is calloc'ed and we use first NULL item as stopper, everything is fine. */
+ if (LIKELY(data_idx)) {
+ BLI_thread_queue_push(common_data->task_queue, data_buff);
+ }
+
+ /* This will signal all other worker threads to wake up and finish! */
+ BLI_thread_queue_nowait(common_data->task_queue);
+ }
+
+ if (edge_vectors) {
+ BLI_stack_free(edge_vectors);
+ }
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(loop_split_generator);
+#endif
+}
+
+static void loop_split_generator(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ LoopSplitTaskDataCommon *common_data = taskdata;
+
+ loop_split_generator_do(common_data, true);
+}
+
+/**
+ * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
+ * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
+ */
+void BKE_mesh_normals_loop_split(
+ MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
+ MLoop *mloops, float (*r_loopnors)[3], const int numLoops,
+ MPoly *mpolys, const float (*polynors)[3], const int numPolys,
+ const bool use_split_normals, float split_angle,
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], int *r_loop_to_poly)
+{
+
+ /* For now this is not supported. If we do not use split normals, we do not generate anything fancy! */
+ BLI_assert(use_split_normals || !(r_lnors_spacearr));
+
+ if (!use_split_normals) {
+ /* In this case, we simply fill lnors with vnors (or fnors for flat faces), quite simple!
+ * Note this is done here to keep some logic and consistency in this quite complex code,
+ * since we may want to use lnors even when mesh's 'autosmooth' is disabled (see e.g. mesh mapping code).
+ * As usual, we could handle that on case-by-case basis, but simpler to keep it well confined here.
+ */
+ int mp_index;
+
+ for (mp_index = 0; mp_index < numPolys; mp_index++) {
+ MPoly *mp = &mpolys[mp_index];
+ int ml_index = mp->loopstart;
+ const int ml_index_end = ml_index + mp->totloop;
+ const bool is_poly_flat = ((mp->flag & ME_SMOOTH) == 0);
+
+ for (; ml_index < ml_index_end; ml_index++) {
+ if (r_loop_to_poly) {
+ r_loop_to_poly[ml_index] = mp_index;
+ }
+ if (is_poly_flat) {
+ copy_v3_v3(r_loopnors[ml_index], polynors[mp_index]);
+ }
+ else {
+ normal_short_to_float_v3(r_loopnors[ml_index], mverts[mloops[ml_index].v].no);
+ }
+ }
+ }
+ return;
+ }
+
+ {
+
/* Mapping edge -> loops.
* If that edge is used by more than two loops (polys), it is always sharp (and tagged as such, see below).
* We also use the second loop index as a kind of flag: smooth edge: > 0,
@@ -341,21 +1108,39 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
int (*edge_to_loops)[2] = MEM_callocN(sizeof(int[2]) * (size_t)numEdges, __func__);
/* Simple mapping from a loop to its polygon index. */
- int *loop_to_poly = MEM_mallocN(sizeof(int) * (size_t)numLoops, __func__);
+ int *loop_to_poly = r_loop_to_poly ? r_loop_to_poly : MEM_mallocN(sizeof(int) * (size_t)numLoops, __func__);
MPoly *mp;
- int mp_index;
- const bool check_angle = (split_angle < (float)M_PI);
+ int mp_index, me_index;
+ bool check_angle = (split_angle < (float)M_PI);
+ int i;
- /* Temp normal stack. */
- BLI_SMALLSTACK_DECLARE(normal, float *);
+ BLI_bitmap *sharp_verts = NULL;
+ MLoopNorSpaceArray _lnors_spacearr = {NULL};
+
+ LoopSplitTaskDataCommon common_data = {NULL};
#ifdef DEBUG_TIME
TIMEIT_START(BKE_mesh_normals_loop_split);
#endif
if (check_angle) {
- split_angle = cosf(split_angle);
+ /* When using custom loop normals, disable the angle feature! */
+ if (clnors_data) {
+ check_angle = false;
+ }
+ else {
+ split_angle = cosf(split_angle);
+ }
+ }
+
+ if (!r_lnors_spacearr && clnors_data) {
+ /* We need to compute lnor spacearr if some custom lnor data are given to us! */
+ r_lnors_spacearr = &_lnors_spacearr;
+ }
+ if (r_lnors_spacearr) {
+ BKE_lnor_spacearr_init(r_lnors_spacearr, numLoops);
+ sharp_verts = BLI_BITMAP_NEW((size_t)numVerts, __func__);
}
/* This first loop check which edges are actually smooth, and compute edge vectors. */
@@ -409,187 +1194,271 @@ void BKE_mesh_normals_loop_split(MVert *mverts, const int UNUSED(numVerts), MEdg
}
}
- /* We now know edges that can be smoothed (with their vector, and their two loops), and edges that will be hard!
- * Now, time to generate the normals.
- */
- for (mp = mpolys, mp_index = 0; mp_index < numPolys; mp++, mp_index++) {
- MLoop *ml_curr, *ml_prev;
- float (*lnors)[3];
- const int ml_last_index = (mp->loopstart + mp->totloop) - 1;
- int ml_curr_index = mp->loopstart;
- int ml_prev_index = ml_last_index;
+ if (r_lnors_spacearr) {
+ /* Tag vertices that have at least one sharp edge as 'sharp' (used for the lnor spacearr computation).
+ * XXX This third loop over edges is a bit disappointing, could not find any other way yet.
+ * Not really performance-critical anyway.
+ */
+ for (me_index = 0; me_index < numEdges; me_index++) {
+ const int *e2l = edge_to_loops[me_index];
+ const MEdge *me = &medges[me_index];
+ if (IS_EDGE_SHARP(e2l)) {
+ BLI_BITMAP_ENABLE(sharp_verts, me->v1);
+ BLI_BITMAP_ENABLE(sharp_verts, me->v2);
+ }
+ }
+ }
- ml_curr = &mloops[ml_curr_index];
- ml_prev = &mloops[ml_prev_index];
- lnors = &r_loopnors[ml_curr_index];
+ /* Init data common to all tasks. */
+ common_data.lnors_spacearr = r_lnors_spacearr;
+ common_data.loopnors = r_loopnors;
+ common_data.clnors_data = clnors_data;
- for (; ml_curr_index <= ml_last_index; ml_curr++, ml_curr_index++, lnors++) {
- const int *e2l_curr = edge_to_loops[ml_curr->e];
- const int *e2l_prev = edge_to_loops[ml_prev->e];
+ common_data.mverts = mverts;
+ common_data.medges = medges;
+ common_data.mloops = mloops;
+ common_data.mpolys = mpolys;
+ common_data.sharp_verts = sharp_verts;
+ common_data.edge_to_loops = (const int(*)[2])edge_to_loops;
+ common_data.loop_to_poly = loop_to_poly;
+ common_data.polynors = polynors;
+ common_data.numPolys = numPolys;
- if (!IS_EDGE_SHARP(e2l_curr)) {
- /* A smooth edge.
- * We skip it because it is either:
- * - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit
- * one of its ends, i.e. one of its two sharp edges), or...
- * - the related vertex is a "full smooth" one, in which case pre-populated normals from vertex
- * are just fine!
- */
- }
- else if (IS_EDGE_SHARP(e2l_prev)) {
- /* Simple case (both edges around that vertex are sharp in current polygon),
- * this vertex just takes its poly normal.
- */
- copy_v3_v3(*lnors, polynors[mp_index]);
- /* No need to mark loop as done here, we won't run into it again anyway! */
- }
- /* 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
- * the vertex normal, but I do not see any easy way to detect that (would need to count number
- * of sharp edges per vertex, I doubt the additional memory usage would be worth it, especially as
- * it should not be a common case in real-life meshes anyway).
- */
- const unsigned int mv_pivot_index = ml_curr->v; /* The vertex we are "fanning" around! */
- const MVert *mv_pivot = &mverts[mv_pivot_index];
- const int *e2lfan_curr;
- float vec_curr[3], vec_prev[3];
- MLoop *mlfan_curr, *mlfan_next;
- MPoly *mpfan_next;
- float lnor[3] = {0.0f, 0.0f, 0.0f};
- /* mlfan_vert_index: the loop of our current edge might not be the loop of our current vertex! */
- int mlfan_curr_index, mlfan_vert_index, mpfan_curr_index;
-
- e2lfan_curr = e2l_prev;
- mlfan_curr = ml_prev;
- mlfan_curr_index = ml_prev_index;
- 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 */
- const MVert *mv_2 = (me_prev->v1 == mv_pivot_index) ? &mverts[me_prev->v2] : &mverts[me_prev->v1];
+ if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
+ /* Not enough loops to be worth the whole threading overhead... */
+ loop_split_generator_do(&common_data, false);
+ }
+ else {
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ int nbr_workers;
- sub_v3_v3v3(vec_prev, mv_2->co, mv_pivot->co);
- normalize_v3(vec_prev);
- }
+ common_data.task_queue = BLI_thread_queue_init();
- while (true) {
- /* Compute edge vectors.
- * NOTE: We could pre-compute those into an array, in the first iteration, instead of computing them
- * twice (or more) here. However, time gained is not worth memory and time lost,
- * given the fact that this code should not be called that much in real-life meshes...
- */
- {
- const MEdge *me_curr = &medges[mlfan_curr->e];
- const MVert *mv_2 = (me_curr->v1 == mv_pivot_index) ? &mverts[me_curr->v2] :
- &mverts[me_curr->v1];
-
- sub_v3_v3v3(vec_curr, mv_2->co, mv_pivot->co);
- normalize_v3(vec_curr);
- }
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, NULL);
- {
- /* Code similar to accumulate_vertex_normals_poly. */
- /* Calculate angle between the two poly edges incident on this vertex. */
- const float fac = saacos(dot_v3v3(vec_curr, vec_prev));
- /* Accumulate */
- madd_v3_v3fl(lnor, polynors[mpfan_curr_index], fac);
- }
+ nbr_workers = max_ii(2, BLI_task_scheduler_num_threads(task_scheduler));
+ for (i = 1; i < nbr_workers; i++) {
+ BLI_task_pool_push(task_pool, loop_split_worker, &common_data, false, TASK_PRIORITY_HIGH);
+ }
+ BLI_task_pool_push(task_pool, loop_split_generator, &common_data, false, TASK_PRIORITY_HIGH);
+ BLI_task_pool_work_and_wait(task_pool);
- /* We store here a pointer to all loop-normals processed. */
- BLI_SMALLSTACK_PUSH(normal, &(r_loopnors[mlfan_vert_index][0]));
+ BLI_task_pool_free(task_pool);
- if (IS_EDGE_SHARP(e2lfan_curr)) {
- /* Current edge is sharp, we have finished with this fan of faces around this vert! */
- break;
- }
+ BLI_thread_queue_free(common_data.task_queue);
+ }
+
+ MEM_freeN(edge_to_loops);
+ if (!r_loop_to_poly) {
+ MEM_freeN(loop_to_poly);
+ }
+
+ if (r_lnors_spacearr) {
+ MEM_freeN(sharp_verts);
+ if (r_lnors_spacearr == &_lnors_spacearr) {
+ BKE_lnor_spacearr_free(r_lnors_spacearr);
+ }
+ }
+
+#ifdef DEBUG_TIME
+ TIMEIT_END(BKE_mesh_normals_loop_split);
+#endif
- copy_v3_v3(vec_prev, vec_curr);
-
- /* Warning! This is rather complex!
- * We have to find our next edge around the vertex (fan mode).
- * First we find the next loop, which is either previous or next to mlfan_curr_index, depending
- * whether both loops using current edge are in the same direction or not, and whether
- * mlfan_curr_index actually uses the vertex we are fanning around!
- * mlfan_curr_index is the index of mlfan_next here, and mlfan_next is not the real next one
- * (i.e. not the future mlfan_curr)...
- */
- mlfan_curr_index = (e2lfan_curr[0] == mlfan_curr_index) ? e2lfan_curr[1] : e2lfan_curr[0];
- mpfan_curr_index = loop_to_poly[mlfan_curr_index];
-
- BLI_assert(mlfan_curr_index >= 0);
- BLI_assert(mpfan_curr_index >= 0);
-
- mlfan_next = &mloops[mlfan_curr_index];
- mpfan_next = &mpolys[mpfan_curr_index];
- if ((mlfan_curr->v == mlfan_next->v && mlfan_curr->v == mv_pivot_index) ||
- (mlfan_curr->v != mlfan_next->v && mlfan_curr->v != mv_pivot_index))
- {
- /* We need the previous loop, but current one is our vertex's loop. */
- mlfan_vert_index = mlfan_curr_index;
- if (--mlfan_curr_index < mpfan_next->loopstart) {
- mlfan_curr_index = mpfan_next->loopstart + mpfan_next->totloop - 1;
- }
+ }
+}
+
+#undef INDEX_UNSET
+#undef INDEX_INVALID
+#undef IS_EDGE_SHARP
+
+/**
+ * Compute internal representation of given custom normals (as an array of float[2]).
+ * It also makes sure the mesh matches those custom normals, by setting sharp edges flag as needed to get a
+ * same custom lnor for all loops sharing a same smooth fan.
+ * If use_vertices if true, custom_loopnors is assumed to be per-vertex, not per-loop
+ * (this allows to set whole vert's normals at once, useful in some cases).
+ */
+static void mesh_normals_loop_custom_set(
+ MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
+ MLoop *mloops, float (*custom_loopnors)[3], const int numLoops,
+ MPoly *mpolys, const float (*polynors)[3], const int numPolys,
+ short (*r_clnors_data)[2], const bool use_vertices)
+{
+ /* We *may* make that poor BKE_mesh_normals_loop_split() even more complex by making it handling that
+ * feature too, would probably be more efficient in absolute.
+ * However, this function *is not* performance-critical, since it is mostly expected to be called
+ * by io addons when importing custom normals, and modifier (and perhaps from some editing tools later?).
+ * So better to keep some simplicity here, and just call BKE_mesh_normals_loop_split() twice!
+ */
+ MLoopNorSpaceArray lnors_spacearr = {NULL};
+ BLI_bitmap *done_loops = BLI_BITMAP_NEW((size_t)numLoops, __func__);
+ float (*lnors)[3] = MEM_callocN(sizeof(*lnors) * (size_t)numLoops, __func__);
+ int *loop_to_poly = MEM_mallocN(sizeof(int) * (size_t)numLoops, __func__);
+ /* In this case we always consider split nors as ON, and do not want to use angle to define smooth fans! */
+ const bool use_split_normals = true;
+ const float split_angle = (float)M_PI;
+ int i;
+
+ BLI_SMALLSTACK_DECLARE(clnors_data, short *);
+
+ /* Compute current lnor spacearr. */
+ BKE_mesh_normals_loop_split(mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
+ mpolys, polynors, numPolys, use_split_normals, split_angle,
+ &lnors_spacearr, NULL, loop_to_poly);
+
+ /* Now, check each current smooth fan (one lnor space per smooth fan!), and if all its matching custom lnors
+ * are not (enough) equal, add sharp edges as needed.
+ * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans matching
+ * given custom lnors.
+ * Note this code *will never* unsharp edges!
+ * And quite obviously, when we set custom normals per vertices, running this is absolutely useless.
+ */
+ if (!use_vertices) {
+ for (i = 0; i < numLoops; i++) {
+ if (!lnors_spacearr.lspacearr[i]) {
+ /* This should not happen in theory, but in some rare case (probably ugly geometry)
+ * we can get some NULL loopspacearr at this point. :/
+ * Maybe we should set those loops' edges as sharp?
+ */
+ BLI_BITMAP_ENABLE(done_loops, i);
+ printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i);
+ continue;
+ }
+
+ if (!BLI_BITMAP_TEST(done_loops, i)) {
+ /* Notes:
+ * * In case of mono-loop smooth fan, loops is NULL, so everything is fine (we have nothing to do).
+ * * Loops in this linklist are ordered (in reversed order compared to how they were discovered by
+ * BKE_mesh_normals_loop_split(), but this is not a problem). Which means if we find a
+ * mismatching clnor, we know all remaining loops will have to be in a new, different smooth fan/
+ * lnor space.
+ * * In smooth fan case, we compare each clnor against a ref one, to avoid small differences adding
+ * up into a real big one in the end!
+ */
+ LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
+ MLoop *prev_ml = NULL;
+ const float *org_nor = NULL;
+
+ while (loops) {
+ const int lidx = GET_INT_FROM_POINTER(loops->link);
+ MLoop *ml = &mloops[lidx];
+ const int nidx = lidx;
+ float *nor = custom_loopnors[nidx];
+
+ if (!org_nor) {
+ org_nor = nor;
}
- else {
- /* We need the next loop, which is also our vertex's loop. */
- if (++mlfan_curr_index >= mpfan_next->loopstart + mpfan_next->totloop) {
- mlfan_curr_index = mpfan_next->loopstart;
- }
- mlfan_vert_index = mlfan_curr_index;
+ else if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) {
+ /* Current normal differs too much from org one, we have to tag the edge between
+ * previous loop's face and current's one as sharp.
+ * We know those two loops do not point to the same edge, since we do not allow reversed winding
+ * in a same smooth fan.
+ */
+ const MPoly *mp = &mpolys[loop_to_poly[lidx]];
+ const MLoop *mlp = &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
+ medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
+
+ org_nor = nor;
}
- mlfan_curr = &mloops[mlfan_curr_index];
- /* And now we are back in sync, mlfan_curr_index is the index of mlfan_curr! Pff! */
- e2lfan_curr = edge_to_loops[mlfan_curr->e];
+ prev_ml = ml;
+ loops = loops->next;
+ BLI_BITMAP_ENABLE(done_loops, lidx);
}
+ BLI_BITMAP_ENABLE(done_loops, i); /* For single loops, where lnors_spacearr.lspacearr[i]->loops is NULL. */
+ }
+ }
- /* In case we get a zero normal here, just use vertex normal already set! */
- if (LIKELY(normalize_v3(lnor) != 0.0f)) {
- /* Copy back the final computed normal into all related loop-normals. */
- float *nor;
- while ((nor = BLI_SMALLSTACK_POP(normal))) {
- copy_v3_v3(nor, lnor);
- }
+ /* And now, recompute our new auto lnors and lnor spacearr! */
+ BKE_lnor_spacearr_clear(&lnors_spacearr);
+ BKE_mesh_normals_loop_split(mverts, numVerts, medges, numEdges, mloops, lnors, numLoops,
+ mpolys, polynors, numPolys, use_split_normals, split_angle,
+ &lnors_spacearr, NULL, loop_to_poly);
+ }
+ else {
+ BLI_BITMAP_SET_ALL(done_loops, true, (size_t)numLoops);
+ }
+
+ /* And we just have to convert plain object-space custom normals to our lnor space-encoded ones. */
+ for (i = 0; i < numLoops; i++) {
+ if (!lnors_spacearr.lspacearr[i]) {
+ BLI_BITMAP_DISABLE(done_loops, i);
+ printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i);
+ continue;
+ }
+
+ if (BLI_BITMAP_TEST_BOOL(done_loops, i)) {
+ /* Note we accumulate and average all custom normals in current smooth fan, to avoid getting different
+ * clnors data (tiny differences in plain custom normals can give rather huge differences in
+ * computed 2D factors).
+ */
+ LinkNode *loops = lnors_spacearr.lspacearr[i]->loops;
+ if (loops) {
+ int nbr_nors = 0;
+ float avg_nor[3];
+ short clnor_data_tmp[2], *clnor_data;
+
+ zero_v3(avg_nor);
+ while (loops) {
+ const int lidx = GET_INT_FROM_POINTER(loops->link);
+ const int nidx = use_vertices ? (int)mloops[lidx].v : lidx;
+ float *nor = custom_loopnors[nidx];
+
+ nbr_nors++;
+ add_v3_v3(avg_nor, nor);
+ BLI_SMALLSTACK_PUSH(clnors_data, (short *)r_clnors_data[lidx]);
+
+ loops = loops->next;
+ BLI_BITMAP_DISABLE(done_loops, lidx);
}
- else {
- /* We still have to clear the stack! */
- while (BLI_SMALLSTACK_POP(normal));
+
+ mul_v3_fl(avg_nor, 1.0f / (float)nbr_nors);
+ BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp);
+
+ while ((clnor_data = BLI_SMALLSTACK_POP(clnors_data))) {
+ clnor_data[0] = clnor_data_tmp[0];
+ clnor_data[1] = clnor_data_tmp[1];
}
}
+ else {
+ const int nidx = use_vertices ? (int)mloops[i].v : i;
+ float *nor = custom_loopnors[nidx];
- ml_prev = ml_curr;
- ml_prev_index = ml_curr_index;
+ BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]);
+ BLI_BITMAP_DISABLE(done_loops, i);
+ }
}
}
- MEM_freeN(edge_to_loops);
+ MEM_freeN(lnors);
MEM_freeN(loop_to_poly);
+ MEM_freeN(done_loops);
+ BKE_lnor_spacearr_free(&lnors_spacearr);
+}
-#ifdef DEBUG_TIME
- TIMEIT_END(BKE_mesh_normals_loop_split);
-#endif
+void BKE_mesh_normals_loop_custom_set(
+ MVert *mverts, const int numVerts, MEdge *medges, const int numEdges,
+ MLoop *mloops, float (*custom_loopnors)[3], const int numLoops,
+ MPoly *mpolys, const float (*polynors)[3], const int numPolys,
+ short (*r_clnors_data)[2])
+{
+ mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, custom_loopnors, numLoops,
+ mpolys, polynors, numPolys, r_clnors_data, false);
+}
-#undef INDEX_UNSET
-#undef INDEX_INVALID
-#undef IS_EDGE_SHARP
+void BKE_mesh_normals_loop_custom_from_vertices_set(
+ MVert *mverts, float (*custom_vertnors)[3], const int numVerts,
+ MEdge *medges, const int numEdges, MLoop *mloops, const int numLoops,
+ MPoly *mpolys, const float (*polynors)[3], const int numPolys,
+ short (*r_clnors_data)[2])
+{
+ mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, custom_vertnors, numLoops,
+ mpolys, polynors, numPolys, r_clnors_data, true);
}
+#undef LNOR_SPACE_TRIGO_THRESHOLD
/** \} */
diff --git a/source/blender/blenkernel/intern/mesh_remap.c b/source/blender/blenkernel/intern/mesh_remap.c
index 1deb7cfdd7f..aca72614094 100644
--- a/source/blender/blenkernel/intern/mesh_remap.c
+++ b/source/blender/blenkernel/intern/mesh_remap.c
@@ -933,8 +933,9 @@ void BKE_mesh_remap_calc_loops_from_dm(
const int mode, const SpaceTransform *space_transform, const float max_dist, const float ray_radius,
MVert *verts_dst, const int numverts_dst, MEdge *edges_dst, const int numedges_dst,
MLoop *loops_dst, const int numloops_dst, MPoly *polys_dst, const int numpolys_dst,
- CustomData *ldata_dst, CustomData *pdata_dst, const float split_angle_dst, const bool dirty_nors_dst,
- DerivedMesh *dm_src,
+ CustomData *ldata_dst, CustomData *pdata_dst,
+ const bool use_split_nors_dst, const float split_angle_dst, const bool dirty_nors_dst,
+ DerivedMesh *dm_src, const bool use_split_nors_src, const float split_angle_src,
MeshRemapIslandsCalc gen_islands_src, const float islands_precision_src, MeshPairRemap *r_map)
{
const float full_weight = 1.0f;
@@ -1046,21 +1047,24 @@ void BKE_mesh_remap_calc_loops_from_dm(
}
}
if (need_lnors_dst) {
+ short (*custom_nors_dst)[2] = CustomData_get_layer(ldata_dst, CD_CUSTOMLOOPNORMAL);
+
/* Cache poly nors into a temp CDLayer. */
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
- if (!loop_nors_dst) {
- loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
- CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
- }
- if (dirty_nors_dst) {
+ if (dirty_nors_dst || !loop_nors_dst) {
+ if (!loop_nors_dst) {
+ loop_nors_dst = CustomData_add_layer(ldata_dst, CD_NORMAL, CD_CALLOC, NULL, numloops_dst);
+ CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
BKE_mesh_normals_loop_split(verts_dst, numverts_dst, edges_dst, numedges_dst,
loops_dst, loop_nors_dst, numloops_dst,
- polys_dst, poly_nors_dst, numpolys_dst, split_angle_dst);
+ polys_dst, (const float (*)[3])poly_nors_dst, numpolys_dst,
+ use_split_nors_dst, split_angle_dst, NULL, custom_nors_dst, NULL);
}
}
if (need_pnors_src || need_lnors_src) {
/* Simpler for now, calcNormals never stores pnors :( */
- dm_src->calcLoopNormals(dm_src, /* TODO */ (float)M_PI);
+ dm_src->calcLoopNormals(dm_src, use_split_nors_src, split_angle_src);
if (need_pnors_src) {
poly_nors_src = dm_src->getPolyDataArray(dm_src, CD_NORMAL);
@@ -1425,7 +1429,7 @@ void BKE_mesh_remap_calc_loops_from_dm(
best_island = use_islands ? island_store.islands[best_island_index] : NULL;
as_graph = &as_graphdata[best_island_index];
poly_island_index_map = (int *)as_graph->custom_data;
- BLI_astar_solution_init(as_graph, &as_solution, false);
+ BLI_astar_solution_init(as_graph, &as_solution, NULL);
}
for (plidx_dst = 0; plidx_dst < mp_dst->totloop; plidx_dst++) {
@@ -1448,8 +1452,18 @@ void BKE_mesh_remap_calc_loops_from_dm(
pidx_src = loop_to_poly_map_src[lidx_src];
/* If prev and curr poly are the same, no need to do anything more!!! */
if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
+ int pidx_isld_src, pidx_isld_src_prev;
+ if (poly_island_index_map) {
+ pidx_isld_src = poly_island_index_map[pidx_src];
+ pidx_isld_src_prev = poly_island_index_map[pidx_src_prev];
+ }
+ else {
+ pidx_isld_src = pidx_src;
+ pidx_isld_src_prev = pidx_src_prev;
+ }
+
BLI_astar_graph_solve(
- as_graph, poly_island_index_map[pidx_src_prev], poly_island_index_map[pidx_src],
+ as_graph, pidx_isld_src_prev, pidx_isld_src,
mesh_remap_calc_loops_astar_f_cost, &as_solution, isld_steps_src);
if (GET_INT_FROM_POINTER(as_solution.custom_data) && (as_solution.steps > 0)) {
/* Find first 'cutting edge' on path, and bring back lidx_src on poly just
@@ -1459,7 +1473,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
* but this is one more level of complexity, better to first see if
* simple solution works!
*/
- int pidx_isld_src = poly_island_index_map[pidx_src];
int last_valid_pidx_isld_src = -1;
/* Note we go backward here, from dest to src poly. */
for (i = as_solution.steps - 1; i--;) {
@@ -1525,8 +1538,18 @@ void BKE_mesh_remap_calc_loops_from_dm(
/* If prev and curr poly are the same, no need to do anything more!!! */
if (!ELEM(pidx_src_prev, -1, pidx_src) && isld_steps_src) {
+ int pidx_isld_src, pidx_isld_src_prev;
+ if (poly_island_index_map) {
+ pidx_isld_src = poly_island_index_map[pidx_src];
+ pidx_isld_src_prev = poly_island_index_map[pidx_src_prev];
+ }
+ else {
+ pidx_isld_src = pidx_src;
+ pidx_isld_src_prev = pidx_src_prev;
+ }
+
BLI_astar_graph_solve(
- as_graph, poly_island_index_map[pidx_src_prev], poly_island_index_map[pidx_src],
+ as_graph, pidx_isld_src_prev, pidx_isld_src,
mesh_remap_calc_loops_astar_f_cost, &as_solution, isld_steps_src);
if (GET_INT_FROM_POINTER(as_solution.custom_data) && (as_solution.steps > 0)) {
/* Find first 'cutting edge' on path, and bring back lidx_src on poly just
@@ -1536,7 +1559,6 @@ void BKE_mesh_remap_calc_loops_from_dm(
* but this is one more level of complexity, better to first see if
* simple solution works!
*/
- int pidx_isld_src = poly_island_index_map[pidx_src];
int last_valid_pidx_isld_src = -1;
/* Note we go backward here, from dest to src poly. */
for (i = as_solution.steps - 1; i--;) {
diff --git a/source/blender/blenkernel/intern/mesh_validate.c b/source/blender/blenkernel/intern/mesh_validate.c
index 3a6c949fe9c..4b2c2aba691 100644
--- a/source/blender/blenkernel/intern/mesh_validate.c
+++ b/source/blender/blenkernel/intern/mesh_validate.c
@@ -963,7 +963,7 @@ bool BKE_mesh_validate_all_customdata(CustomData *vdata, CustomData *edata,
*
* \returns true if a change is made.
*/
-int BKE_mesh_validate(Mesh *me, const int do_verbose)
+int BKE_mesh_validate(Mesh *me, const int do_verbose, const int cddata_check_mask)
{
bool is_valid = true;
bool changed;
@@ -974,7 +974,7 @@ int BKE_mesh_validate(Mesh *me, const int do_verbose)
is_valid &= BKE_mesh_validate_all_customdata(
&me->vdata, &me->edata, &me->ldata, &me->pdata,
- true,
+ cddata_check_mask,
do_verbose, true,
&changed);
diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c
index fe38fedd7aa..491fb46bd1f 100644
--- a/source/blender/blenkernel/intern/movieclip.c
+++ b/source/blender/blenkernel/intern/movieclip.c
@@ -621,7 +621,7 @@ MovieClip *BKE_movieclip_file_add(Main *bmain, const char *name)
BLI_strncpy(strtest, clip->name, sizeof(clip->name));
BLI_path_abs(strtest, G.main->name);
- if (strcmp(strtest, str) == 0) {
+ if (STREQ(strtest, str)) {
BLI_strncpy(clip->name, name, sizeof(clip->name)); /* for stringcode */
clip->id.us++; /* officially should not, it doesn't link here! */
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c
index 0adc65bd806..220d0f7c604 100644
--- a/source/blender/blenkernel/intern/multires.c
+++ b/source/blender/blenkernel/intern/multires.c
@@ -1641,7 +1641,8 @@ void multires_free(Multires *mr)
lvl = lvl->next;
}
- MEM_freeN(mr->verts);
+ /* mr->verts may be NULL when loading old files, see direct_link_mesh() in readfile.c, and T43560. */
+ MEM_SAFE_FREE(mr->verts);
BLI_freelistN(&mr->levels);
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 039af949d81..f30e3b699dd 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -2250,7 +2250,7 @@ StructRNA *ntreeInterfaceTypeGet(bNodeTree *ntree, int create)
ntree_interface_identifier_base(ntree, base);
/* RNA identifier may have a number suffix, but should start with the idbase string */
- if (strncmp(RNA_struct_identifier(srna), base, sizeof(base)) != 0) {
+ if (!STREQLEN(RNA_struct_identifier(srna), base, sizeof(base))) {
/* generate new unique RNA identifier from the ID name */
ntree_interface_identifier(ntree, base, identifier, sizeof(identifier), name, description);
diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c
index 41f7721d59f..7e0228ac09c 100644
--- a/source/blender/blenkernel/intern/object.c
+++ b/source/blender/blenkernel/intern/object.c
@@ -684,6 +684,7 @@ void BKE_object_unlink(Object *ob)
if (sce->camera == ob) sce->camera = NULL;
if (sce->toolsettings->skgen_template == ob) sce->toolsettings->skgen_template = NULL;
if (sce->toolsettings->particle.object == ob) sce->toolsettings->particle.object = NULL;
+ if (sce->toolsettings->particle.shape_object == ob) sce->toolsettings->particle.shape_object = NULL;
#ifdef DURIAN_CAMERA_SWITCH
{
@@ -1234,7 +1235,7 @@ BulletSoftBody *copy_bulletsoftbody(BulletSoftBody *bsb)
return bsbn;
}
-static ParticleSystem *copy_particlesystem(ParticleSystem *psys)
+ParticleSystem *BKE_object_copy_particlesystem(ParticleSystem *psys)
{
ParticleSystem *psysn;
ParticleData *pa;
@@ -1314,7 +1315,7 @@ void BKE_object_copy_particlesystems(Object *obn, Object *ob)
BLI_listbase_clear(&obn->particlesystem);
for (psys = ob->particlesystem.first; psys; psys = psys->next) {
- npsys = copy_particlesystem(psys);
+ npsys = BKE_object_copy_particlesystem(psys);
BLI_addtail(&obn->particlesystem, npsys);
diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c
index 2bee6b76ad6..c77f65f69e1 100644
--- a/source/blender/blenkernel/intern/object_dupli.c
+++ b/source/blender/blenkernel/intern/object_dupli.c
@@ -969,9 +969,9 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem
}
/* some hair paths might be non-existent so they can't be used for duplication */
- if (hair &&
- ((a < totpart && psys->pathcache[a]->steps < 0) ||
- (a >= totpart && psys->childcache[a - totpart]->steps < 0)))
+ if (hair && psys->pathcache &&
+ ((a < totpart && psys->pathcache[a]->segments < 0) ||
+ (a >= totpart && psys->childcache[a - totpart]->segments < 0)))
{
continue;
}
diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c
index 373ad34e7bd..12e82d3a34f 100644
--- a/source/blender/blenkernel/intern/ocean.c
+++ b/source/blender/blenkernel/intern/ocean.c
@@ -1002,7 +1002,7 @@ static void cache_filename(char *string, const char *path, const char *relbase,
BLI_join_dirfile(cachepath, sizeof(cachepath), path, fname);
- BKE_makepicstring_from_type(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true);
+ BKE_image_path_from_imtype(string, cachepath, relbase, frame, R_IMF_IMTYPE_OPENEXR, true, true);
}
/* silly functions but useful to inline when the args do a lot of indirections */
diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c
index 78a54e5c6ac..03a25301e3c 100644
--- a/source/blender/blenkernel/intern/particle.c
+++ b/source/blender/blenkernel/intern/particle.c
@@ -55,6 +55,7 @@
#include "BLI_utildefines.h"
#include "BLI_kdtree.h"
#include "BLI_rand.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_linklist.h"
@@ -65,6 +66,7 @@
#include "BKE_boids.h"
#include "BKE_cloth.h"
+#include "BKE_colortools.h"
#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_group.h"
@@ -103,9 +105,9 @@ void psys_init_rng(void)
static void get_child_modifier_parameters(ParticleSettings *part, ParticleThreadContext *ctx,
ChildParticle *cpa, short cpa_from, int cpa_num, float *cpa_fuv, float *orco, ParticleTexture *ptex);
-static void do_child_modifiers(ParticleSimulationData *sim,
- ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa,
- float *orco, float mat[4][4], ParticleKey *state, float t);
+extern void do_child_modifiers(ParticleSimulationData *sim,
+ ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
+ ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
/* few helpers for countall etc. */
int count_particles(ParticleSystem *psys)
@@ -139,7 +141,7 @@ int count_particles_mod(ParticleSystem *psys, int totgr, int cur)
#define PATH_CACHE_BUF_SIZE 1024
-static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot, int steps)
+static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot, int totkeys)
{
LinkData *buf;
ParticleCacheKey **cache;
@@ -152,10 +154,10 @@ static ParticleCacheKey **psys_alloc_path_cache_buffers(ListBase *bufs, int tot,
while (totkey < tot) {
totbufkey = MIN2(tot - totkey, PATH_CACHE_BUF_SIZE);
buf = MEM_callocN(sizeof(LinkData), "PathCacheLinkData");
- buf->data = MEM_callocN(sizeof(ParticleCacheKey) * totbufkey * steps, "ParticleCacheKey");
+ buf->data = MEM_callocN(sizeof(ParticleCacheKey) * totbufkey * totkeys, "ParticleCacheKey");
for (i = 0; i < totbufkey; i++)
- cache[totkey + i] = ((ParticleCacheKey *)buf->data) + i * steps;
+ cache[totkey + i] = ((ParticleCacheKey *)buf->data) + i * totkeys;
totkey += totbufkey;
BLI_addtail(bufs, buf);
@@ -374,6 +376,12 @@ void BKE_particlesettings_free(ParticleSettings *part)
MTex *mtex;
int a;
BKE_free_animdata(&part->id);
+
+ if (part->clumpcurve)
+ curvemapping_free(part->clumpcurve);
+ if (part->roughcurve)
+ curvemapping_free(part->roughcurve);
+
free_partdeflect(part->pd);
free_partdeflect(part->pd2);
@@ -408,6 +416,7 @@ void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics)
if (psys->clmd) {
if (dynamics) {
BKE_ptcache_free(psys->pointcache);
+ psys->clmd->point_cache = psys->pointcache = NULL;
modifier_free((ModifierData *)psys->clmd);
@@ -591,89 +600,6 @@ void psys_free(Object *ob, ParticleSystem *psys)
* rendering, to make different render settings possible without
* removing the previous data. this should be solved properly once */
-typedef struct ParticleRenderElem {
- int curchild, totchild, reduce;
- float lambda, t, scalemin, scalemax;
-} ParticleRenderElem;
-
-typedef struct ParticleRenderData {
- ChildParticle *child;
- ParticleCacheKey **pathcache;
- ParticleCacheKey **childcache;
- ListBase pathcachebufs, childcachebufs;
- int totchild, totcached, totchildcache;
- DerivedMesh *dm;
- int totdmvert, totdmedge, totdmface;
-
- float mat[4][4];
- float viewmat[4][4], winmat[4][4];
- int winx, winy;
-
- int do_simplify;
- int timeoffset;
- ParticleRenderElem *elems;
-
- /* ORIGINDEX */
- const int *index_mf_to_mpoly;
- const int *index_mp_to_orig;
-} ParticleRenderData;
-
-static float psys_render_viewport_falloff(double rate, float dist, float width)
-{
- return pow(rate, dist / width);
-}
-
-static float psys_render_projected_area(ParticleSystem *psys, const float center[3], float area, double vprate, float *viewport)
-{
- ParticleRenderData *data = psys->renderdata;
- float co[4], view[3], ortho1[3], ortho2[3], w, dx, dy, radius;
-
- /* transform to view space */
- copy_v3_v3(co, center);
- co[3] = 1.0f;
- mul_m4_v4(data->viewmat, co);
-
- /* compute two vectors orthogonal to view vector */
- normalize_v3_v3(view, co);
- ortho_basis_v3v3_v3(ortho1, ortho2, view);
-
- /* compute on screen minification */
- w = co[2] * data->winmat[2][3] + data->winmat[3][3];
- dx = data->winx * ortho2[0] * data->winmat[0][0];
- dy = data->winy * ortho2[1] * data->winmat[1][1];
- w = sqrtf(dx * dx + dy * dy) / w;
-
- /* w squared because we are working with area */
- area = area * w * w;
-
- /* viewport of the screen test */
-
- /* project point on screen */
- mul_m4_v4(data->winmat, co);
- if (co[3] != 0.0f) {
- co[0] = 0.5f * data->winx * (1.0f + co[0] / co[3]);
- co[1] = 0.5f * data->winy * (1.0f + co[1] / co[3]);
- }
-
- /* screen space radius */
- radius = sqrtf(area / (float)M_PI);
-
- /* make smaller using fallof once over screen edge */
- *viewport = 1.0f;
-
- if (co[0] + radius < 0.0f)
- *viewport *= psys_render_viewport_falloff(vprate, -(co[0] + radius), data->winx);
- else if (co[0] - radius > data->winx)
- *viewport *= psys_render_viewport_falloff(vprate, (co[0] - radius) - data->winx, data->winx);
-
- if (co[1] + radius < 0.0f)
- *viewport *= psys_render_viewport_falloff(vprate, -(co[1] + radius), data->winy);
- else if (co[1] - radius > data->winy)
- *viewport *= psys_render_viewport_falloff(vprate, (co[1] - radius) - data->winy, data->winy);
-
- return area;
-}
-
void psys_render_set(Object *ob, ParticleSystem *psys, float viewmat[4][4], float winmat[4][4], int winx, int winy, int timeoffset)
{
ParticleRenderData *data;
@@ -788,191 +714,6 @@ void psys_render_restore(Object *ob, ParticleSystem *psys)
}
}
-/* BMESH_TODO, for orig face data, we need to use MPoly */
-
-int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
-{
- DerivedMesh *dm = ctx->dm;
- Mesh *me = (Mesh *)(ctx->sim.ob->data);
- MFace *mf, *mface;
- MVert *mvert;
- ParticleRenderData *data;
- ParticleRenderElem *elems, *elem;
- ParticleSettings *part = ctx->sim.psys->part;
- float *facearea, (*facecenter)[3], size[3], fac, powrate, scaleclamp;
- float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport;
- double vprate;
- int *facetotvert;
- int a, b, totorigface, totface, newtot, skipped;
-
- /* double lookup */
- const int *index_mf_to_mpoly;
- const int *index_mp_to_orig;
-
- if (part->ren_as != PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND))
- return tot;
- if (!ctx->sim.psys->renderdata)
- return tot;
-
- data = ctx->sim.psys->renderdata;
- if (data->timeoffset)
- return 0;
- if (!(part->simplify_flag & PART_SIMPLIFY_ENABLE))
- return tot;
-
- mvert = dm->getVertArray(dm);
- mface = dm->getTessFaceArray(dm);
- totface = dm->getNumTessFaces(dm);
- totorigface = me->totpoly;
-
- if (totface == 0 || totorigface == 0)
- return tot;
-
- index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
-
- facearea = MEM_callocN(sizeof(float) * totorigface, "SimplifyFaceArea");
- facecenter = MEM_callocN(sizeof(float[3]) * totorigface, "SimplifyFaceCenter");
- facetotvert = MEM_callocN(sizeof(int) * totorigface, "SimplifyFaceArea");
- elems = MEM_callocN(sizeof(ParticleRenderElem) * totorigface, "SimplifyFaceElem");
-
- if (data->elems)
- MEM_freeN(data->elems);
-
- data->do_simplify = true;
- data->elems = elems;
- data->index_mf_to_mpoly = index_mf_to_mpoly;
- data->index_mp_to_orig = index_mp_to_orig;
-
- /* compute number of children per original face */
- for (a = 0; a < tot; a++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
- if (b != ORIGINDEX_NONE) {
- elems[b].totchild++;
- }
- }
-
- /* compute areas and centers of original faces */
- for (mf = mface, a = 0; a < totface; a++, mf++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
-
- if (b != ORIGINDEX_NONE) {
- copy_v3_v3(co1, mvert[mf->v1].co);
- copy_v3_v3(co2, mvert[mf->v2].co);
- copy_v3_v3(co3, mvert[mf->v3].co);
-
- add_v3_v3(facecenter[b], co1);
- add_v3_v3(facecenter[b], co2);
- add_v3_v3(facecenter[b], co3);
-
- if (mf->v4) {
- copy_v3_v3(co4, mvert[mf->v4].co);
- add_v3_v3(facecenter[b], co4);
- facearea[b] += area_quad_v3(co1, co2, co3, co4);
- facetotvert[b] += 4;
- }
- else {
- facearea[b] += area_tri_v3(co1, co2, co3);
- facetotvert[b] += 3;
- }
- }
- }
-
- for (a = 0; a < totorigface; a++)
- if (facetotvert[a] > 0)
- mul_v3_fl(facecenter[a], 1.0f / facetotvert[a]);
-
- /* for conversion from BU area / pixel area to reference screen size */
- BKE_mesh_texspace_get(me, 0, 0, size);
- fac = ((size[0] + size[1] + size[2]) / 3.0f) / part->simplify_refsize;
- fac = fac * fac;
-
- powrate = log(0.5f) / log(part->simplify_rate * 0.5f);
- if (part->simplify_flag & PART_SIMPLIFY_VIEWPORT)
- vprate = pow(1.0f - part->simplify_viewport, 5.0);
- else
- vprate = 1.0;
-
- /* set simplification parameters per original face */
- for (a = 0, elem = elems; a < totorigface; a++, elem++) {
- area = psys_render_projected_area(ctx->sim.psys, facecenter[a], facearea[a], vprate, &viewport);
- arearatio = fac * area / facearea[a];
-
- if ((arearatio < 1.0f || viewport < 1.0f) && elem->totchild) {
- /* lambda is percentage of elements to keep */
- lambda = (arearatio < 1.0f) ? powf(arearatio, powrate) : 1.0f;
- lambda *= viewport;
-
- lambda = MAX2(lambda, 1.0f / elem->totchild);
-
- /* compute transition region */
- t = part->simplify_transition;
- elem->t = (lambda - t < 0.0f) ? lambda : (lambda + t > 1.0f) ? 1.0f - lambda : t;
- elem->reduce = 1;
-
- /* scale at end and beginning of the transition region */
- 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 = sqrtf(elem->scalemin);
- elem->scalemax = sqrtf(elem->scalemax);
-
- /* clamp scaling */
- scaleclamp = (float)min_ii(elem->totchild, 10);
- elem->scalemin = MIN2(scaleclamp, elem->scalemin);
- elem->scalemax = MIN2(scaleclamp, elem->scalemax);
-
- /* extend lambda to include transition */
- lambda = lambda + elem->t;
- if (lambda > 1.0f)
- lambda = 1.0f;
- }
- else {
- lambda = arearatio;
-
- elem->scalemax = 1.0f; //sqrt(lambda);
- elem->scalemin = 1.0f; //sqrt(lambda);
- elem->reduce = 0;
- }
-
- elem->lambda = lambda;
- elem->scalemin = sqrtf(elem->scalemin);
- elem->scalemax = sqrtf(elem->scalemax);
- elem->curchild = 0;
- }
-
- MEM_freeN(facearea);
- MEM_freeN(facecenter);
- MEM_freeN(facetotvert);
-
- /* move indices and set random number skipping */
- ctx->skip = MEM_callocN(sizeof(int) * tot, "SimplificationSkip");
-
- skipped = 0;
- for (a = 0, newtot = 0; a < tot; a++) {
- b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
-
- if (b != ORIGINDEX_NONE) {
- if (elems[b].curchild++ < ceil(elems[b].lambda * elems[b].totchild)) {
- ctx->index[newtot] = ctx->index[a];
- ctx->skip[newtot] = skipped;
- skipped = 0;
- newtot++;
- }
- else skipped++;
- }
- else skipped++;
- }
-
- for (a = 0, elem = elems; a < totorigface; a++, elem++)
- elem->curchild = 0;
-
- return newtot;
-}
-
bool psys_render_simplify_params(ParticleSystem *psys, ChildParticle *cpa, float *params)
{
ParticleRenderData *data;
@@ -1399,9 +1140,9 @@ static void interpolate_pathcache(ParticleCacheKey *first, float t, ParticleCach
ParticleCacheKey *cur = first;
/* scale the requested time to fit the entire path even if the path is cut early */
- t *= (first + first->steps)->time;
+ t *= (first + first->segments)->time;
- while (i < first->steps && cur->time < t)
+ while (i < first->segments && cur->time < t)
cur++;
if (cur->time == t)
@@ -1906,6 +1647,42 @@ static void psys_particle_on_shape(int UNUSED(distr), int UNUSED(index),
/************************************************/
/* Particles on emitter */
/************************************************/
+
+CustomDataMask psys_emitter_customdata_mask(ParticleSystem *psys)
+{
+ CustomDataMask dataMask = 0;
+ MTex *mtex;
+ int i;
+
+ if (!psys->part)
+ return 0;
+
+ for (i = 0; i < MAX_MTEX; i++) {
+ mtex = psys->part->mtex[i];
+ if (mtex && mtex->mapto && (mtex->texco & TEXCO_UV))
+ dataMask |= CD_MASK_MTFACE;
+ }
+
+ if (psys->part->tanfac != 0.0f)
+ dataMask |= CD_MASK_MTFACE;
+
+ /* ask for vertexgroups if we need them */
+ for (i = 0; i < PSYS_TOT_VG; i++) {
+ if (psys->vgroup[i]) {
+ dataMask |= CD_MASK_MDEFORMVERT;
+ break;
+ }
+ }
+
+ /* particles only need this if they are after a non deform modifier, and
+ * the modifier stack will only create them in that case. */
+ dataMask |= CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORIGINDEX;
+
+ dataMask |= CD_MASK_ORCO;
+
+ return dataMask;
+}
+
void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int index, int index_dmcache,
float fuv[4], float foffset, float vec[3], float nor[3], float utan[3], float vtan[3],
float orco[3], float ornor[3])
@@ -1930,202 +1707,11 @@ void psys_particle_on_emitter(ParticleSystemModifierData *psmd, int from, int in
/* Path Cache */
/************************************************/
-static void do_kink(ParticleKey *state, ParticleKey *par, float *par_rot, float time, float freq, float shape, float amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start)
-{
- float kink[3] = {1.f, 0.f, 0.f}, par_vec[3], q1[4] = {1.f, 0.f, 0.f, 0.f};
- float t, dt = 1.f, result[3];
-
- if (par == NULL || type == PART_KINK_NO)
- return;
-
- CLAMP(time, 0.f, 1.f);
-
- if (shape != 0.0f && type != PART_KINK_BRAID) {
- if (shape < 0.0f)
- time = (float)pow(time, 1.f + shape);
- else
- time = (float)pow(time, 1.f / (1.f - shape));
- }
-
- t = time * freq * (float)M_PI;
-
- if (smooth_start) {
- dt = fabsf(t);
- /* smooth the beginning of kink */
- CLAMP(dt, 0.f, (float)M_PI);
- dt = sinf(dt / 2.f);
- }
-
- if (type != PART_KINK_RADIAL) {
- float temp[3];
-
- kink[axis] = 1.f;
-
- if (obmat)
- mul_mat3_m4_v3(obmat, kink);
-
- if (par_rot)
- mul_qt_v3(par_rot, kink);
-
- /* make sure kink is normal to strand */
- project_v3_v3v3(temp, kink, par->vel);
- sub_v3_v3(kink, temp);
- normalize_v3(kink);
- }
-
- copy_v3_v3(result, state->co);
- sub_v3_v3v3(par_vec, par->co, state->co);
-
- switch (type) {
- case PART_KINK_CURL:
- {
- negate_v3(par_vec);
-
- if (flat > 0.f) {
- float proj[3];
- project_v3_v3v3(proj, par_vec, par->vel);
- madd_v3_v3fl(par_vec, proj, -flat);
-
- project_v3_v3v3(proj, par_vec, kink);
- madd_v3_v3fl(par_vec, proj, -flat);
- }
-
- axis_angle_to_quat(q1, kink, (float)M_PI / 2.f);
-
- mul_qt_v3(q1, par_vec);
-
- madd_v3_v3fl(par_vec, kink, amplitude);
-
- /* rotate kink vector around strand tangent */
- if (t != 0.f) {
- axis_angle_to_quat(q1, par->vel, t);
- mul_qt_v3(q1, par_vec);
- }
-
- add_v3_v3v3(result, par->co, par_vec);
- break;
- }
- case PART_KINK_RADIAL:
- {
- if (flat > 0.f) {
- float proj[3];
- /* flatten along strand */
- project_v3_v3v3(proj, par_vec, par->vel);
- madd_v3_v3fl(result, proj, flat);
- }
-
- madd_v3_v3fl(result, par_vec, -amplitude * sinf(t));
- break;
- }
- case PART_KINK_WAVE:
- {
- madd_v3_v3fl(result, kink, amplitude * sinf(t));
-
- if (flat > 0.f) {
- float proj[3];
- /* flatten along wave */
- project_v3_v3v3(proj, par_vec, kink);
- madd_v3_v3fl(result, proj, flat);
-
- /* flatten along strand */
- project_v3_v3v3(proj, par_vec, par->vel);
- madd_v3_v3fl(result, proj, flat);
- }
- break;
- }
- case PART_KINK_BRAID:
- {
- float y_vec[3] = {0.f, 1.f, 0.f};
- float z_vec[3] = {0.f, 0.f, 1.f};
- float vec_one[3], state_co[3];
- float inp_y, inp_z, length;
-
- if (par_rot) {
- mul_qt_v3(par_rot, y_vec);
- mul_qt_v3(par_rot, z_vec);
- }
-
- negate_v3(par_vec);
- normalize_v3_v3(vec_one, par_vec);
-
- inp_y = dot_v3v3(y_vec, vec_one);
- inp_z = dot_v3v3(z_vec, vec_one);
-
- if (inp_y > 0.5f) {
- copy_v3_v3(state_co, y_vec);
-
- 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, sinf((float)M_PI / 3.f));
- madd_v3_v3fl(state_co, y_vec, -0.5f);
-
- 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, -sinf((float)M_PI / 3.f));
- madd_v3_v3fl(state_co, y_vec, -0.5f);
-
- 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));
- }
+extern void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], const float par_rot[4], float time, float freq, float shape, float amplitude, float flat,
+ short type, short axis, float obmat[4][4], int smooth_start);
+extern float do_clump(ParticleKey *state, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
+ bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve);
- mul_v3_fl(state_co, amplitude);
- add_v3_v3(state_co, par->co);
- sub_v3_v3v3(par_vec, state->co, state_co);
-
- length = normalize_v3(par_vec);
- mul_v3_fl(par_vec, MIN2(length, amplitude / 2.f));
-
- add_v3_v3v3(state_co, par->co, y_vec);
- add_v3_v3(state_co, z_vec);
- add_v3_v3(state_co, par_vec);
-
- shape = 2.f * (float)M_PI * (1.f + shape);
-
- if (t < shape) {
- shape = t / shape;
- shape = (float)sqrt((double)shape);
- interp_v3_v3v3(result, result, state_co, shape);
- }
- else {
- copy_v3_v3(result, state_co);
- }
- break;
- }
- }
-
- /* blend the start of the kink */
- if (dt < 1.f)
- interp_v3_v3v3(state->co, state->co, result, dt);
- else
- copy_v3_v3(state->co, result);
-}
-
-static float do_clump(ParticleKey *state, ParticleKey *par, float time, float clumpfac, float clumppow, float pa_clump)
-{
- float clump = 0.f;
-
- if (par && clumpfac != 0.0f) {
- float cpow;
-
- if (clumppow < 0.0f)
- cpow = 1.0f + clumppow;
- else
- cpow = 1.0f + 9.0f * clumppow;
-
- if (clumpfac < 0.0f) /* clump roots instead of tips */
- clump = -clumpfac * pa_clump * (float)pow(1.0 - (double)time, (double)cpow);
- else
- clump = clumpfac * pa_clump * (float)pow((double)time, (double)cpow);
-
- interp_v3_v3v3(state->co, state->co, par->co, clump);
- }
-
- return clump;
-}
void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
{
EffectedPoint point;
@@ -2166,12 +1752,14 @@ void precalc_guides(ParticleSimulationData *sim, ListBase *effectors)
}
}
}
-int do_guides(ListBase *effectors, ParticleKey *state, int index, float time)
+
+int do_guides(ParticleSettings *part, ListBase *effectors, ParticleKey *state, int index, float time)
{
+ CurveMapping *clumpcurve = (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) ? part->clumpcurve : NULL;
+ CurveMapping *roughcurve = (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) ? part->roughcurve : NULL;
EffectorCache *eff;
PartDeflect *pd;
Curve *cu;
- ParticleKey key, par;
GuideEffectorData *data;
float effect[3] = {0.0f, 0.0f, 0.0f}, veffect[3] = {0.0f, 0.0f, 0.0f};
@@ -2180,78 +1768,92 @@ int do_guides(ListBase *effectors, ParticleKey *state, int index, float time)
float vec_to_point[3];
if (effectors) for (eff = effectors->first; eff; eff = eff->next) {
- pd = eff->pd;
-
- if (pd->forcefield != PFIELD_GUIDE)
- continue;
-
- data = eff->guide_data + index;
-
- if (data->strength <= 0.0f)
- continue;
-
- guidetime = time / (1.0f - pd->free_end);
-
- if (guidetime > 1.0f)
- continue;
-
- cu = (Curve *)eff->ob->data;
-
- if (pd->flag & PFIELD_GUIDE_PATH_ADD) {
- if (where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
- return 0;
- }
- else {
- if (where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
- return 0;
- }
-
- mul_m4_v3(eff->ob->obmat, guidevec);
- mul_mat3_m4_v3(eff->ob->obmat, guidedir);
-
- normalize_v3(guidedir);
-
- copy_v3_v3(vec_to_point, data->vec_to_point);
-
- if (guidetime != 0.0f) {
- /* curve direction */
- cross_v3_v3v3(temp, eff->guide_dir, guidedir);
- angle = dot_v3v3(eff->guide_dir, guidedir) / (len_v3(eff->guide_dir));
- angle = saacos(angle);
- axis_angle_to_quat(rot2, temp, angle);
- mul_qt_v3(rot2, vec_to_point);
-
- /* curve tilt */
- axis_angle_to_quat(rot2, guidedir, guidevec[3] - eff->guide_loc[3]);
- mul_qt_v3(rot2, vec_to_point);
- }
-
- /* curve taper */
- if (cu->taperobj)
- mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
-
- else { /* curve size*/
- if (cu->flag & CU_PATH_RADIUS) {
- mul_v3_fl(vec_to_point, radius);
- }
+ pd = eff->pd;
+
+ if (pd->forcefield != PFIELD_GUIDE)
+ continue;
+
+ data = eff->guide_data + index;
+
+ if (data->strength <= 0.0f)
+ continue;
+
+ guidetime = time / (1.0f - pd->free_end);
+
+ if (guidetime > 1.0f)
+ continue;
+
+ cu = (Curve *)eff->ob->data;
+
+ if (pd->flag & PFIELD_GUIDE_PATH_ADD) {
+ if (where_on_path(eff->ob, data->strength * guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
+ return 0;
+ }
+ else {
+ if (where_on_path(eff->ob, guidetime, guidevec, guidedir, NULL, &radius, &weight) == 0)
+ return 0;
+ }
+
+ mul_m4_v3(eff->ob->obmat, guidevec);
+ mul_mat3_m4_v3(eff->ob->obmat, guidedir);
+
+ normalize_v3(guidedir);
+
+ copy_v3_v3(vec_to_point, data->vec_to_point);
+
+ if (guidetime != 0.0f) {
+ /* curve direction */
+ cross_v3_v3v3(temp, eff->guide_dir, guidedir);
+ angle = dot_v3v3(eff->guide_dir, guidedir) / (len_v3(eff->guide_dir));
+ angle = saacos(angle);
+ axis_angle_to_quat(rot2, temp, angle);
+ mul_qt_v3(rot2, vec_to_point);
+
+ /* curve tilt */
+ axis_angle_to_quat(rot2, guidedir, guidevec[3] - eff->guide_loc[3]);
+ mul_qt_v3(rot2, vec_to_point);
+ }
+
+ /* curve taper */
+ if (cu->taperobj)
+ mul_v3_fl(vec_to_point, BKE_displist_calc_taper(eff->scene, cu->taperobj, (int)(data->strength * guidetime * 100.0f), 100));
+
+ else { /* curve size*/
+ if (cu->flag & CU_PATH_RADIUS) {
+ mul_v3_fl(vec_to_point, radius);
}
- par.co[0] = par.co[1] = par.co[2] = 0.0f;
+ }
+
+ if (clumpcurve)
+ curvemapping_changed_all(clumpcurve);
+ if (roughcurve)
+ curvemapping_changed_all(roughcurve);
+
+ {
+ ParticleKey key;
+ float par_co[3] = {0.0f, 0.0f, 0.0f};
+ float par_vel[3] = {0.0f, 0.0f, 0.0f};
+ float par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f};
+ float orco_offset[3] = {0.0f, 0.0f, 0.0f};
+
copy_v3_v3(key.co, vec_to_point);
- do_kink(&key, &par, 0, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0);
- do_clump(&key, &par, guidetime, pd->clump_fac, pd->clump_pow, 1.0f);
+ do_kink(&key, par_co, par_vel, par_rot, guidetime, pd->kink_freq, pd->kink_shape, pd->kink_amp, 0.f, pd->kink, pd->kink_axis, 0, 0);
+ do_clump(&key, par_co, guidetime, orco_offset, pd->clump_fac, pd->clump_pow, 1.0f,
+ part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, clumpcurve);
copy_v3_v3(vec_to_point, key.co);
-
- add_v3_v3(vec_to_point, guidevec);
-
- //sub_v3_v3v3(pa_loc, pa_loc, pa_zero);
- madd_v3_v3fl(effect, vec_to_point, data->strength);
- madd_v3_v3fl(veffect, guidedir, data->strength);
- totstrength += data->strength;
-
- if (pd->flag & PFIELD_GUIDE_PATH_WEIGHT)
- totstrength *= weight;
}
-
+
+ add_v3_v3(vec_to_point, guidevec);
+
+ //sub_v3_v3v3(pa_loc, pa_loc, pa_zero);
+ madd_v3_v3fl(effect, vec_to_point, data->strength);
+ madd_v3_v3fl(veffect, guidedir, data->strength);
+ totstrength += data->strength;
+
+ if (pd->flag & PFIELD_GUIDE_PATH_WEIGHT)
+ totstrength *= weight;
+ }
+
if (totstrength != 0.0f) {
if (totstrength > 1.0f)
mul_v3_fl(effect, 1.0f / totstrength);
@@ -2266,41 +1868,7 @@ int do_guides(ListBase *effectors, ParticleKey *state, int index, float time)
}
return 0;
}
-static void do_rough(float *loc, float mat[4][4], float t, float fac, float size, float thres, ParticleKey *state)
-{
- float rough[3];
- float rco[3];
-
- 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);
- rough[0] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2, 0, 2);
- rough[1] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2, 0, 2);
- rough[2] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2, 0, 2);
- madd_v3_v3fl(state->co, mat[0], fac * rough[0]);
- madd_v3_v3fl(state->co, mat[1], fac * rough[1]);
- madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
-}
-static void do_rough_end(float *loc, float mat[4][4], float t, float fac, float shape, ParticleKey *state)
-{
- float rough[2];
- float roughfac;
-
- roughfac = fac * (float)pow((double)t, shape);
- copy_v2_v2(rough, loc);
- rough[0] = -1.0f + 2.0f * rough[0];
- rough[1] = -1.0f + 2.0f * rough[1];
- mul_v2_fl(rough, roughfac);
-
- madd_v3_v3fl(state->co, mat[0], rough[0]);
- madd_v3_v3fl(state->co, mat[1], rough[1]);
-}
static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheKey *ca, int k, int steps, float *UNUSED(rootco), float effector, float UNUSED(dfra), float UNUSED(cfra), float *length, float *vec)
{
float force[3] = {0.0f, 0.0f, 0.0f};
@@ -2332,20 +1900,6 @@ static void do_path_effectors(ParticleSimulationData *sim, int i, ParticleCacheK
if (k < steps)
*length = len_v3(vec);
}
-static int check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *state, float max_length, float *cur_length, float length, float *dvec)
-{
- if (*cur_length + length > max_length) {
- mul_v3_fl(dvec, (max_length - *cur_length) / length);
- add_v3_v3v3(state->co, (state - 1)->co, dvec);
- keys->steps = k;
- /* something over the maximum step value */
- return k = 100000;
- }
- else {
- *cur_length += length;
- return k;
- }
-}
static void offset_child(ChildParticle *cpa, ParticleKey *par, float *par_rot, ParticleKey *child, float flat, float radius)
{
copy_v3_v3(child->co, cpa->fuv);
@@ -2424,49 +1978,15 @@ void psys_find_parents(ParticleSimulationData *sim)
BLI_kdtree_free(tree);
}
-static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3])
+static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene, float cfra, int editupdate)
{
- float cross[3], nstrand[3], vnor[3], blend;
-
- if (!((ma->mode & MA_STR_SURFDIFF) || (ma->strand_surfnor > 0.0f)))
- return;
-
- if (ma->mode & MA_STR_SURFDIFF) {
- cross_v3_v3v3(cross, surfnor, nor);
- cross_v3_v3v3(nstrand, nor, cross);
-
- blend = dot_v3v3(nstrand, surfnor);
- CLAMP(blend, 0.0f, 1.0f);
-
- interp_v3_v3v3(vnor, nstrand, surfnor, blend);
- normalize_v3(vnor);
- }
- else {
- copy_v3_v3(vnor, nor);
- }
-
- if (ma->strand_surfnor > 0.0f) {
- if (ma->strand_surfnor > surfdist) {
- blend = (ma->strand_surfnor - surfdist) / ma->strand_surfnor;
- interp_v3_v3v3(vnor, vnor, surfnor, blend);
- normalize_v3(vnor);
- }
- }
-
- copy_v3_v3(nor, vnor);
-}
-
-static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float cfra, int editupdate)
-{
- ParticleThreadContext *ctx = threads[0].ctx;
-/* Object *ob = ctx->sim.ob; */
- ParticleSystem *psys = ctx->sim.psys;
+ ParticleSystem *psys = sim->psys;
ParticleSettings *part = psys->part;
-/* ParticleEditSettings *pset = &scene->toolsettings->particle; */
int totparent = 0, between = 0;
- int steps = (int)pow(2.0, (double)part->draw_step);
+ int segments = 1 << part->draw_step;
int totchild = psys->totchild;
- int i, seed, totthread = threads[0].tot;
+
+ psys_thread_context_init(ctx, sim);
/*---start figuring out what is actually wanted---*/
if (psys_in_edit_mode(scene, psys)) {
@@ -2475,7 +1995,7 @@ static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float c
if (psys->renderdata == 0 && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0)
totchild = 0;
- steps = (int)pow(2.0, (double)pset->draw_step);
+ segments = 1 << pset->draw_step;
}
if (totchild && part->childtype == PART_CHILD_FACES) {
@@ -2489,28 +2009,22 @@ static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float c
}
if (psys->renderdata)
- steps = (int)pow(2.0, (double)part->ren_step);
+ segments = 1 << part->ren_step;
else {
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
totparent = MIN2(totparent, totchild);
}
- if (totchild == 0) return 0;
-
- /* init random number generator */
- seed = 31415926 + ctx->sim.psys->seed;
-
- if (ctx->editupdate || totchild < 10000)
- totthread = 1;
-
- for (i = 0; i < totthread; i++) {
- threads[i].rng_path = BLI_rng_new(seed);
- threads[i].tot = totthread;
- }
+ if (totchild == 0)
+ return false;
/* fill context values */
ctx->between = between;
- ctx->steps = steps;
+ ctx->segments = segments;
+ if (ELEM(part->kink, PART_KINK_SPIRAL))
+ ctx->extra_segments = max_ii(part->kink_extra_steps, 1);
+ else
+ ctx->extra_segments = 0;
ctx->totchild = totchild;
ctx->totparent = totparent;
ctx->parent_pass = 0;
@@ -2529,31 +2043,36 @@ static int psys_threads_init_path(ParticleThread *threads, Scene *scene, float c
if (psys->part->flag & PART_CHILD_EFFECT)
ctx->vg_effector = psys_cache_vgroup(ctx->dm, psys, PSYS_VG_EFFECTOR);
- /* set correct ipo timing */
-#if 0 // XXX old animation system
- if (part->flag & PART_ABS_TIME && part->ipo) {
- calc_ipo(part->ipo, cfra);
- execute_ipo((ID *)part, part->ipo);
- }
-#endif // XXX old animation system
+ /* prepare curvemapping tables */
+ if ((part->child_flag & PART_CHILD_USE_CLUMP_CURVE) && part->clumpcurve)
+ curvemapping_changed_all(part->clumpcurve);
+ if ((part->child_flag & PART_CHILD_USE_ROUGH_CURVE) && part->roughcurve)
+ curvemapping_changed_all(part->roughcurve);
- return 1;
+ return true;
+}
+
+static void psys_task_init_path(ParticleTask *task, ParticleSimulationData *sim)
+{
+ /* init random number generator */
+ int seed = 31415926 + sim->psys->seed;
+
+ task->rng_path = BLI_rng_new(seed);
}
/* note: this function must be thread safe, except for branching! */
-static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle *cpa, ParticleCacheKey *child_keys, int i)
+static void psys_thread_create_path(ParticleTask *task, struct ChildParticle *cpa, ParticleCacheKey *child_keys, int i)
{
- ParticleThreadContext *ctx = thread->ctx;
+ ParticleThreadContext *ctx = task->ctx;
Object *ob = ctx->sim.ob;
ParticleSystem *psys = ctx->sim.psys;
ParticleSettings *part = psys->part;
ParticleCacheKey **cache = psys->childcache;
- ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.scene, psys) ? psys->edit->pathcache : psys->pathcache;
- ParticleCacheKey *child, *par = NULL, *key[4];
+ ParticleCacheKey **pcache = psys_in_edit_mode(ctx->sim.scene, psys) && psys->edit ? psys->edit->pathcache : psys->pathcache;
+ ParticleCacheKey *child, *key[4];
ParticleTexture ptex;
float *cpa_fuv = 0, *par_rot = 0, rot[4];
- float orco[3], ornor[3], hairmat[4][4], t, dvec[3], off1[4][3], off2[4][3];
- float length, max_length = 1.0f, cur_length = 0.0f;
+ float orco[3], ornor[3], hairmat[4][4], dvec[3], off1[4][3], off2[4][3];
float eff_length, eff_vec[3], weight[4];
int k, cpa_num;
short cpa_from;
@@ -2585,7 +2104,7 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
if (!needupdate)
return;
else
- memset(child_keys, 0, sizeof(*child_keys) * (ctx->steps + 1));
+ memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
}
/* get parent paths */
@@ -2608,14 +2127,14 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
if (part->flag & PART_CHILD_LONG_HAIR) {
/* For long hair use tip distance/root distance as parting factor instead of root to tip angle. */
float d1 = len_v3v3(key[0]->co, key[w]->co);
- float d2 = len_v3v3((key[0] + key[0]->steps - 1)->co, (key[w] + key[w]->steps - 1)->co);
+ float d2 = len_v3v3((key[0] + key[0]->segments - 1)->co, (key[w] + key[w]->segments - 1)->co);
d = d1 > 0.f ? d2 / d1 - 1.f : 10000.f;
}
else {
float v1[3], v2[3];
- sub_v3_v3v3(v1, (key[0] + key[0]->steps - 1)->co, key[0]->co);
- sub_v3_v3v3(v2, (key[w] + key[w]->steps - 1)->co, key[w]->co);
+ sub_v3_v3v3(v1, (key[0] + key[0]->segments - 1)->co, key[0]->co);
+ sub_v3_v3v3(v2, (key[w] + key[w]->segments - 1)->co, key[w]->co);
normalize_v3(v1);
normalize_v3(v2);
@@ -2663,7 +2182,7 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
if (!(psys->edit->points[cpa->parent].flag & PEP_EDIT_RECALC))
return;
- memset(child_keys, 0, sizeof(*child_keys) * (ctx->steps + 1));
+ memset(child_keys, 0, sizeof(*child_keys) * (ctx->segments + 1));
}
/* get the parent path */
@@ -2682,18 +2201,18 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
psys_mat_hair_to_global(ob, ctx->sim.psmd->dm, psys->part->from, pa, hairmat);
}
- child_keys->steps = ctx->steps;
+ child_keys->segments = ctx->segments;
/* get different child parameters from textures & vgroups */
get_child_modifier_parameters(part, ctx, cpa, cpa_from, cpa_num, cpa_fuv, orco, &ptex);
if (ptex.exist < psys_frand(psys, i + 24)) {
- child_keys->steps = -1;
+ child_keys->segments = -1;
return;
}
/* create the child path */
- for (k = 0, child = child_keys; k <= ctx->steps; k++, child++) {
+ for (k = 0, child = child_keys; k <= ctx->segments; k++, child++) {
if (ctx->between) {
int w = 0;
@@ -2711,7 +2230,7 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
/* Fade the effect of rotation for even lengths in the end */
project_v3_v3v3(dvec, off2[w], (key[w] + k)->vel);
- madd_v3_v3fl(off2[w], dvec, -(float)k / (float)ctx->steps);
+ madd_v3_v3fl(off2[w], dvec, -(float)k / (float)ctx->segments);
}
add_v3_v3(off2[w], (key[w] + k)->co);
@@ -2735,14 +2254,14 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
offset_child(cpa, (ParticleKey *)(key[0] + k), par_rot, (ParticleKey *)child, part->childflat, part->childrad);
}
- child->time = (float)k / (float)ctx->steps;
+ child->time = (float)k / (float)ctx->segments;
}
/* apply effectors */
if (part->flag & PART_CHILD_EFFECT) {
- for (k = 0, child = child_keys; k <= ctx->steps; k++, child++) {
+ for (k = 0, child = child_keys; k <= ctx->segments; k++, child++) {
if (k) {
- do_path_effectors(&ctx->sim, cpa->pa[0], child, k, ctx->steps, child_keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec);
+ do_path_effectors(&ctx->sim, cpa->pa[0], child, k, ctx->segments, child_keys->co, ptex.effector, 0.0f, ctx->cfra, &eff_length, eff_vec);
}
else {
sub_v3_v3v3(eff_vec, (child + 1)->co, child->co);
@@ -2751,147 +2270,119 @@ static void psys_thread_create_path(ParticleThread *thread, struct ChildParticle
}
}
- for (k = 0, child = child_keys; k <= ctx->steps; k++, child++) {
- t = (float)k / (float)ctx->steps;
-
- if (ctx->totparent)
- /* this is now threadsafe, virtual parents are calculated before rest of children */
- par = (i >= ctx->totparent) ? cache[cpa->parent] : NULL;
- else if (cpa->parent >= 0)
- par = pcache[cpa->parent];
-
- if (par) {
- if (k) {
- mul_qt_qtqt(rot, (par + k)->rot, par->rot);
- par_rot = rot;
- }
- else {
- par_rot = par->rot;
+ {
+ ParticleData *pa = NULL;
+ ParticleCacheKey *par = NULL;
+ float par_co[3];
+ float par_orco[3];
+
+ if (ctx->totparent) {
+ if (i >= ctx->totparent) {
+ pa = &psys->particles[cpa->parent];
+ /* this is now threadsafe, virtual parents are calculated before rest of children */
+ par = cache[cpa->parent];
}
- par += k;
}
-
- /* apply different deformations to the child path */
- do_child_modifiers(&ctx->sim, &ptex, (ParticleKey *)par, par_rot, cpa, orco, hairmat, (ParticleKey *)child, t);
-
- /* we have to correct velocity because of kink & clump */
- if (k > 1) {
- sub_v3_v3v3((child - 1)->vel, child->co, (child - 2)->co);
- mul_v3_fl((child - 1)->vel, 0.5);
-
- if (ctx->ma && (part->draw_col == PART_DRAW_COL_MAT))
- get_strand_normal(ctx->ma, ornor, cur_length, (child - 1)->vel);
- }
-
- if (k == ctx->steps)
- sub_v3_v3v3(child->vel, child->co, (child - 1)->co);
-
- /* check if path needs to be cut before actual end of data points */
- if (k) {
- sub_v3_v3v3(dvec, child->co, (child - 1)->co);
- length = 1.0f / (float)ctx->steps;
- k = check_path_length(k, child_keys, child, max_length, &cur_length, length, dvec);
- }
- else {
- /* initialize length calculation */
- max_length = ptex.length;
- cur_length = 0.0f;
+ else if (cpa->parent >= 0) {
+ pa = &psys->particles[cpa->parent];
+ par = pcache[cpa->parent];
}
-
- if (ctx->ma && (part->draw_col == PART_DRAW_COL_MAT)) {
- copy_v3_v3(child->col, &ctx->ma->r);
- get_strand_normal(ctx->ma, ornor, cur_length, child->vel);
+
+ if (pa) {
+ ListBase modifiers;
+ BLI_listbase_clear(&modifiers);
+
+ psys_particle_on_emitter(ctx->sim.psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset,
+ par_co, NULL, NULL, NULL, par_orco, NULL);
+
+ psys_apply_child_modifiers(ctx, &modifiers, cpa, &ptex, orco, ornor, hairmat, child_keys, par, par_orco);
}
+ else
+ zero_v3(par_orco);
}
/* Hide virtual parents */
if (i < ctx->totparent)
- child_keys->steps = -1;
+ child_keys->segments = -1;
}
-static void *exec_child_path_cache(void *data)
+static void exec_child_path_cache(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
{
- ParticleThread *thread = (ParticleThread *)data;
- ParticleThreadContext *ctx = thread->ctx;
+ ParticleTask *task = taskdata;
+ ParticleThreadContext *ctx = task->ctx;
ParticleSystem *psys = ctx->sim.psys;
ParticleCacheKey **cache = psys->childcache;
ChildParticle *cpa;
- int i, totchild = ctx->totchild, first = 0;
+ int i;
- if (thread->tot > 1) {
- first = ctx->parent_pass ? 0 : ctx->totparent;
- totchild = ctx->parent_pass ? ctx->totparent : ctx->totchild;
+ cpa = psys->child + task->begin;
+ for (i = task->begin; i < task->end; ++i, ++cpa) {
+ psys_thread_create_path(task, cpa, cache[i], i);
}
-
- cpa = psys->child + first + thread->num;
- for (i = first + thread->num; i < totchild; i += thread->tot, cpa += thread->tot)
- psys_thread_create_path(thread, cpa, cache[i], i);
-
- return 0;
}
void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupdate)
{
- ParticleThread *pthreads;
- ParticleThreadContext *ctx;
- ListBase threads;
- int i, totchild, totparent, totthread;
-
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ ParticleThreadContext ctx;
+ ParticleTask *tasks_parent, *tasks_child;
+ int numtasks_parent, numtasks_child;
+ int i, totchild, totparent;
+
if (sim->psys->flag & PSYS_GLOBAL_HAIR)
return;
-
- pthreads = psys_threads_create(sim);
-
- if (!psys_threads_init_path(pthreads, sim->scene, cfra, editupdate)) {
- psys_threads_free(pthreads);
+
+ /* create a task pool for child path tasks */
+ if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate))
return;
- }
-
- ctx = pthreads[0].ctx;
- totchild = ctx->totchild;
- totparent = ctx->totparent;
-
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, &ctx);
+ totchild = ctx.totchild;
+ totparent = ctx.totparent;
+
if (editupdate && sim->psys->childcache && totchild == sim->psys->totchildcache) {
; /* just overwrite the existing cache */
}
else {
/* clear out old and create new empty path cache */
free_child_path_cache(sim->psys);
- sim->psys->childcache = psys_alloc_path_cache_buffers(&sim->psys->childcachebufs, totchild, ctx->steps + 1);
+
+ sim->psys->childcache = psys_alloc_path_cache_buffers(&sim->psys->childcachebufs, totchild, ctx.segments + ctx.extra_segments + 1);
sim->psys->totchildcache = totchild;
}
-
- totthread = pthreads[0].tot;
-
- if (totthread > 1) {
-
- /* make virtual child parents thread safe by calculating them first */
- if (totparent) {
- BLI_init_threads(&threads, exec_child_path_cache, totthread);
-
- for (i = 0; i < totthread; i++) {
- pthreads[i].ctx->parent_pass = 1;
- BLI_insert_thread(&threads, &pthreads[i]);
- }
-
- BLI_end_threads(&threads);
-
- for (i = 0; i < totthread; i++)
- pthreads[i].ctx->parent_pass = 0;
- }
-
- BLI_init_threads(&threads, exec_child_path_cache, totthread);
-
- for (i = 0; i < totthread; i++)
- BLI_insert_thread(&threads, &pthreads[i]);
-
- BLI_end_threads(&threads);
+
+ /* cache parent paths */
+ ctx.parent_pass = 1;
+ psys_tasks_create(&ctx, totparent, &tasks_parent, &numtasks_parent);
+ for (i = 0; i < numtasks_parent; ++i) {
+ ParticleTask *task = &tasks_parent[i];
+
+ psys_task_init_path(task, sim);
+ BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
}
- else
- exec_child_path_cache(&pthreads[0]);
+ BLI_task_pool_work_and_wait(task_pool);
+
+ /* cache child paths */
+ ctx.parent_pass = 0;
+ psys_tasks_create(&ctx, totchild, &tasks_child, &numtasks_child);
+ for (i = 0; i < numtasks_child; ++i) {
+ ParticleTask *task = &tasks_child[i];
+
+ psys_task_init_path(task, sim);
+ BLI_task_pool_push(task_pool, exec_child_path_cache, task, false, TASK_PRIORITY_LOW);
+ }
+ BLI_task_pool_work_and_wait(task_pool);
- psys_threads_free(pthreads);
+ BLI_task_pool_free(task_pool);
+
+ psys_tasks_free(tasks_parent, numtasks_parent);
+ psys_tasks_free(tasks_child, numtasks_child);
+
+ psys_thread_context_free(&ctx);
}
+
/* figure out incremental rotations along path starting from unit quat */
static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCacheKey *key1, ParticleCacheKey *key2, float *prev_tangent, int i)
{
@@ -2959,7 +2450,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4];
float rotmat[3][3];
int k;
- int steps = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step));
+ int segments = (int)pow(2.0, (double)(psys->renderdata ? part->ren_step : part->draw_step));
int totpart = psys->totpart;
float length, vec[3];
float *vg_effector = NULL;
@@ -2979,7 +2470,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
/* clear out old and create new empty path cache */
psys_free_path_cache(psys, psys->edit);
- cache = psys->pathcache = psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, steps + 1);
+ cache = psys->pathcache = psys_alloc_path_cache_buffers(&psys->pathcachebufs, totpart, segments + 1);
psys->lattice_deform_data = psys_create_lattice_deform_data(sim);
ma = give_current_material(sim->ob, psys->part->omat);
@@ -3014,9 +2505,9 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
pind.bspline = (psys->part->flag & PART_HAIR_BSPLINE);
pind.dm = hair_dm;
- memset(cache[p], 0, sizeof(*cache[p]) * (steps + 1));
+ memset(cache[p], 0, sizeof(*cache[p]) * (segments + 1));
- cache[p]->steps = steps;
+ cache[p]->segments = segments;
/*--get the first data points--*/
init_particle_interpolation(sim->ob, sim->psys, pa, &pind);
@@ -3038,15 +2529,15 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
}
if (birthtime >= dietime) {
- cache[p]->steps = -1;
+ cache[p]->segments = -1;
continue;
}
dietime = birthtime + pa_length * (dietime - birthtime);
/*--interpolate actual path from data points--*/
- for (k = 0, ca = cache[p]; k <= steps; k++, ca++) {
- time = (float)k / (float)steps;
+ for (k = 0, ca = cache[p]; k <= segments; k++, ca++) {
+ time = (float)k / (float)segments;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
do_particle_interpolation(psys, p, pa, t, &pind, &result);
@@ -3061,7 +2552,15 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
copy_v3_v3(ca->col, col);
}
-
+
+ if (part->type == PART_HAIR) {
+ HairKey *hkey;
+
+ for (k = 0, hkey = pa->hair; k < pa->totkey; ++k, ++hkey) {
+ mul_v3_m4v3(hkey->world_co, hairmat, hkey->co);
+ }
+ }
+
/*--modify paths and calculate rotation & velocity--*/
if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
@@ -3074,29 +2573,29 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
sub_v3_v3v3(vec, (cache[p] + 1)->co, cache[p]->co);
length = len_v3(vec);
- for (k = 1, ca = cache[p] + 1; k <= steps; k++, ca++)
- do_path_effectors(sim, p, ca, k, steps, cache[p]->co, effector, dfra, cfra, &length, vec);
+ for (k = 1, ca = cache[p] + 1; k <= segments; k++, ca++)
+ do_path_effectors(sim, p, ca, k, segments, cache[p]->co, effector, dfra, cfra, &length, vec);
}
/* apply guide curves to path data */
if (sim->psys->effectors && (psys->part->flag & PART_CHILD_EFFECT) == 0) {
- for (k = 0, ca = cache[p]; k <= steps; k++, ca++)
+ for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
/* ca is safe to cast, since only co and vel are used */
- do_guides(sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)steps);
+ do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)ca, p, (float)k / (float)segments);
}
/* lattices have to be calculated separately to avoid mixups between effector calculations */
if (psys->lattice_deform_data) {
- for (k = 0, ca = cache[p]; k <= steps; k++, ca++)
+ for (k = 0, ca = cache[p]; k <= segments; k++, ca++)
calc_latt_deform(psys->lattice_deform_data, ca->co, 1.0f);
}
}
/* finally do rotation & velocity */
- for (k = 1, ca = cache[p] + 1; k <= steps; k++, ca++) {
+ for (k = 1, ca = cache[p] + 1; k <= segments; k++, ca++) {
cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
- if (k == steps)
+ if (k == segments)
copy_qt_qt(ca->rot, (ca - 1)->rot);
/* set velocity */
@@ -3105,7 +2604,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra)
if (k == 1)
copy_v3_v3((ca - 1)->vel, ca->vel);
- ca->time = (float)k / (float)steps;
+ ca->time = (float)k / (float)segments;
}
/* First rotation is based on emitting face orientation.
* This is way better than having flipping rotations resulting
@@ -3149,17 +2648,17 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
float t, time = 0.0f, keytime = 0.0f /*, frs_sec */;
float hairmat[4][4], rotmat[3][3], prev_tangent[3] = {0.0f, 0.0f, 0.0f};
int k, i;
- int steps = (int)pow(2.0, (double)pset->draw_step);
+ int segments = 1 << pset->draw_step;
int totpart = edit->totpoint, recalc_set = 0;
float sel_col[3];
float nosel_col[3];
- steps = MAX2(steps, 4);
+ segments = MAX2(segments, 4);
if (!cache || edit->totpoint != edit->totcached) {
/* clear out old and create new empty path cache */
psys_free_path_cache(edit->psys, edit);
- cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, steps + 1);
+ cache = edit->pathcache = psys_alloc_path_cache_buffers(&edit->pathcachebufs, totpart, segments + 1);
/* set flag for update (child particles check this too) */
for (i = 0, point = edit->points; i < totpart; i++, point++)
@@ -3206,9 +2705,9 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
}
- memset(cache[i], 0, sizeof(*cache[i]) * (steps + 1));
+ memset(cache[i], 0, sizeof(*cache[i]) * (segments + 1));
- cache[i]->steps = steps;
+ cache[i]->segments = segments;
/*--get the first data points--*/
init_particle_interpolation(ob, psys, pa, &pind);
@@ -3224,13 +2723,13 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
dietime = pind.dietime;
if (birthtime >= dietime) {
- cache[i]->steps = -1;
+ cache[i]->segments = -1;
continue;
}
/*--interpolate actual path from data points--*/
- for (k = 0, ca = cache[i]; k <= steps; k++, ca++) {
- time = (float)k / (float)steps;
+ for (k = 0, ca = cache[i]; k <= segments; k++, ca++) {
+ time = (float)k / (float)segments;
t = birthtime + time * (dietime - birthtime);
result.time = -t;
do_particle_interpolation(psys, i, pa, t, &pind, &result);
@@ -3243,7 +2742,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
if (k) {
cache_key_incremental_rotation(ca, ca - 1, ca - 2, prev_tangent, k);
- if (k == steps)
+ if (k == segments)
copy_qt_qt(ca->rot, (ca - 1)->rot);
/* set velocity */
@@ -3277,7 +2776,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf
/* at the moment this is only used for weight painting.
* will need to move out of this check if its used elsewhere. */
- t2 = birthtime + ((float)k / (float)steps) * (dietime - birthtime);
+ t2 = birthtime + ((float)k / (float)segments) * (dietime - birthtime);
while (pind.hkey[1]->time < t2) pind.hkey[1]++;
pind.hkey[0] = pind.hkey[1] - 1;
@@ -3581,6 +3080,7 @@ void object_remove_particle_system(Scene *UNUSED(scene), Object *ob)
DAG_relations_tag_update(G.main);
DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
}
+
static void default_particle_settings(ParticleSettings *part)
{
part->type = PART_EMITTER;
@@ -3611,6 +3111,8 @@ static void default_particle_settings(ParticleSettings *part)
part->adapt_pix = 3;
part->kink_axis = 2;
part->kink_amp_clump = 1.f;
+ part->kink_extra_steps = 4;
+ part->clump_noise_size = 1.0f;
part->reactevent = PART_EVENT_DEATH;
part->disp = 100;
part->from = PART_FROM_FACE;
@@ -3678,6 +3180,30 @@ ParticleSettings *psys_new_settings(const char *name, Main *main)
return part;
}
+void BKE_particlesettings_clump_curve_init(ParticleSettings *part)
+{
+ CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ cumap->cm[0].curve[0].x = 0.0f;
+ cumap->cm[0].curve[0].y = 1.0f;
+ cumap->cm[0].curve[1].x = 1.0f;
+ cumap->cm[0].curve[1].y = 1.0f;
+
+ part->clumpcurve = cumap;
+}
+
+void BKE_particlesettings_rough_curve_init(ParticleSettings *part)
+{
+ CurveMapping *cumap = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+
+ cumap->cm[0].curve[0].x = 0.0f;
+ cumap->cm[0].curve[0].y = 1.0f;
+ cumap->cm[0].curve[1].x = 1.0f;
+ cumap->cm[0].curve[1].y = 1.0f;
+
+ part->roughcurve = cumap;
+}
+
ParticleSettings *BKE_particlesettings_copy(ParticleSettings *part)
{
ParticleSettings *partn;
@@ -3689,6 +3215,11 @@ ParticleSettings *BKE_particlesettings_copy(ParticleSettings *part)
partn->effector_weights = MEM_dupallocN(part->effector_weights);
partn->fluid = MEM_dupallocN(part->fluid);
+ if (part->clumpcurve)
+ partn->clumpcurve = curvemapping_copy(part->clumpcurve);
+ if (part->roughcurve)
+ partn->roughcurve = curvemapping_copy(part->roughcurve);
+
partn->boids = boid_copy_settings(part->boids);
for (a = 0; a < MAX_MTEX; a++) {
@@ -3840,7 +3371,7 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
float value, rgba[4], texvec[3];
ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp =
- ptex->gravity = ptex->field = ptex->time = ptex->clump = ptex->kink =
+ ptex->gravity = ptex->field = ptex->time = ptex->clump = ptex->kink_freq = ptex->kink_amp =
ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
ptex->length = 1.0f - part->randlength * psys_frand(psys, child_index + 26);
@@ -3880,21 +3411,23 @@ static void get_cpa_texture(DerivedMesh *dm, ParticleSystem *psys, ParticleSetti
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL);
+ externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false);
if ((event & mtex->mapto) & PAMAP_ROUGH)
ptex->rough1 = ptex->rough2 = ptex->roughe = texture_value_blend(def, ptex->rough1, value, mtex->roughfac, blend);
SET_PARTICLE_TEXTURE(PAMAP_LENGTH, ptex->length, mtex->lengthfac);
SET_PARTICLE_TEXTURE(PAMAP_CLUMP, ptex->clump, mtex->clumpfac);
- SET_PARTICLE_TEXTURE(PAMAP_KINK, ptex->kink, mtex->kinkfac);
+ SET_PARTICLE_TEXTURE(PAMAP_KINK_AMP, ptex->kink_amp, mtex->kinkampfac);
+ SET_PARTICLE_TEXTURE(PAMAP_KINK_FREQ, ptex->kink_freq, mtex->kinkfac);
SET_PARTICLE_TEXTURE(PAMAP_DENS, ptex->exist, mtex->padensfac);
}
}
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_LENGTH, ptex->length);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_CLUMP, ptex->clump);
- CLAMP_PARTICLE_TEXTURE_POS(PAMAP_KINK, ptex->kink);
+ CLAMP_PARTICLE_TEXTURE_POS(PAMAP_KINK_AMP, ptex->kink_amp);
+ CLAMP_PARTICLE_TEXTURE_POS(PAMAP_KINK_FREQ, ptex->kink_freq);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_ROUGH, ptex->rough1);
CLAMP_PARTICLE_TEXTURE_POS(PAMAP_DENS, ptex->exist);
}
@@ -3911,7 +3444,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
/* initialize ptex */
ptex->ivel = ptex->life = ptex->exist = ptex->size = ptex->damp =
- ptex->gravity = ptex->field = ptex->length = ptex->clump = ptex->kink =
+ ptex->gravity = ptex->field = ptex->length = ptex->clump = ptex->kink_freq = ptex->kink_amp =
ptex->effector = ptex->rough1 = ptex->rough2 = ptex->roughe = 1.0f;
ptex->time = (float)(pa - sim->psys->particles) / (float)sim->psys->totpart;
@@ -3961,7 +3494,7 @@ void psys_get_texture(ParticleSimulationData *sim, ParticleData *pa, ParticleTex
break;
}
- externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL);
+ externtex(mtex, texvec, &value, rgba, rgba + 1, rgba + 2, rgba + 3, 0, NULL, false);
if ((event & mtex->mapto) & PAMAP_TIME) {
/* the first time has to set the base value for time regardless of blend mode */
@@ -4065,7 +3598,7 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
if (ctx->vg_clump)
ptex->clump *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_clump);
if (ctx->vg_kink)
- ptex->kink *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
+ ptex->kink_freq *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_kink);
if (ctx->vg_rough1)
ptex->rough1 *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_rough1);
if (ctx->vg_rough2)
@@ -4075,55 +3608,6 @@ static void get_child_modifier_parameters(ParticleSettings *part, ParticleThread
if (ctx->vg_effector)
ptex->effector *= psys_interpolate_value_from_verts(ctx->dm, cpa_from, cpa_num, cpa_fuv, ctx->vg_effector);
}
-static void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, ParticleKey *par, float *par_rot, ChildParticle *cpa, float *orco, float mat[4][4], ParticleKey *state, float t)
-{
- ParticleSettings *part = sim->psys->part;
- int i = cpa - sim->psys->child;
- int guided = 0;
-
- float kink_freq = part->kink_freq;
- float rough1 = part->rough1;
- float rough2 = part->rough2;
- float rough_end = part->rough_end;
-
- if (ptex) {
- kink_freq *= ptex->kink;
- rough1 *= ptex->rough1;
- rough2 *= ptex->rough2;
- rough_end *= ptex->roughe;
- }
-
- if (part->flag & PART_CHILD_EFFECT)
- /* state is safe to cast, since only co and vel are used */
- guided = do_guides(sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
-
- if (guided == 0) {
- float clump = do_clump(state, par, t, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f);
-
- if (kink_freq != 0.f) {
- float kink_amp = part->kink_amp * (1.f - part->kink_amp_clump * clump);
-
- do_kink(state, par, par_rot, t, kink_freq, part->kink_shape,
- kink_amp, part->kink_flat, part->kink, part->kink_axis,
- sim->ob->obmat, sim->psys->part->childtype == PART_CHILD_FACES);
- }
- }
-
- if (rough1 > 0.f)
- do_rough(orco, mat, t, rough1, part->rough1_size, 0.0, state);
-
- if (rough2 > 0.f) {
- float vec[3];
- psys_frand_vec(sim->psys, i + 27, vec);
- do_rough(vec, mat, t, rough2, part->rough2_size, part->rough2_thres, state);
- }
-
- if (rough_end > 0.f) {
- float vec[3];
- psys_frand_vec(sim->psys, i + 27, vec);
- do_rough_end(vec, mat, t, rough_end, part->rough_end_shape, state);
- }
-}
/* get's hair (or keyed) particles state at the "path time" specified in state->time */
void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *state, const bool vel)
{
@@ -4190,7 +3674,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
mul_mat3_m4_v3(hairmat, state->vel);
if (sim->psys->effectors && (part->flag & PART_CHILD_GUIDE) == 0) {
- do_guides(sim->psys->effectors, state, p, state->time);
+ do_guides(sim->psys->part, sim->psys->effectors, state, p, state->time);
/* TODO: proper velocity handling */
}
@@ -4212,6 +3696,8 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
copy_qt_qt(state->rot, result.rot);
}
else {
+ float par_co[3], par_orco[3];
+
cpa = psys->child + p - totpart;
if (state->time < 0.0f)
@@ -4248,6 +3734,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
pa = psys->particles + cpa->parent;
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
if (part->type == PART_HAIR)
psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
else
@@ -4267,8 +3754,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
cpa_num = pa->num;
cpa_fuv = pa->fuv;
-
-
+ psys_particle_on_emitter(psmd, part->from, pa->num, pa->num_dmcache, pa->fuv, pa->foffset, par_co, 0, 0, 0, par_orco, 0);
if (part->type == PART_HAIR) {
psys_particle_on_emitter(psmd, cpa_from, cpa_num, DMCACHE_ISCHILD, cpa_fuv, pa->foffset, co, 0, 0, 0, orco, 0);
psys_mat_hair_to_global(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
@@ -4326,7 +3812,7 @@ void psys_get_particle_on_path(ParticleSimulationData *sim, int p, ParticleKey *
copy_particle_key(&tstate, state, 1);
/* apply different deformations to the child path */
- do_child_modifiers(sim, &ptex, par, par->rot, cpa, orco, hairmat, state, t);
+ do_child_modifiers(sim, &ptex, par->co, par->vel, par->rot, par_orco, cpa, orco, hairmat, state, t);
/* try to estimate correct velocity */
if (vel) {
@@ -4421,6 +3907,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
float mat[4][4];
ParticleKey *key1;
float t = (cfra - pa->time) / pa->lifetime;
+ float par_orco[3] = {0.0f, 0.0f, 0.0f};
key1 = &pa->state;
offset_child(cpa, key1, key1->rot, state, part->childflat, part->childrad);
@@ -4428,7 +3915,7 @@ int psys_get_particle_state(ParticleSimulationData *sim, int p, ParticleKey *sta
CLAMP(t, 0.0f, 1.0f);
unit_m4(mat);
- do_child_modifiers(sim, NULL, key1, key1->rot, cpa, cpa->fuv, mat, state, t);
+ do_child_modifiers(sim, NULL, key1->co, key1->vel, key1->rot, par_orco, cpa, cpa->fuv, mat, state, t);
if (psys->lattice_deform_data)
calc_latt_deform(psys->lattice_deform_data, state->co, 1.0f);
@@ -4556,7 +4043,7 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa
float loc[3], nor[3], vec[3], side[3], len;
float xvec[3] = {-1.0, 0.0, 0.0}, nmat[3][3];
- sub_v3_v3v3(vec, (cache + cache->steps)->co, cache->co);
+ sub_v3_v3v3(vec, (cache + cache->segments)->co, cache->co);
len = normalize_v3(vec);
if (pa == NULL && psys->part->childflat != PART_CHILD_FACES)
@@ -4573,8 +4060,8 @@ void psys_get_dupli_path_transform(ParticleSimulationData *sim, ParticleData *pa
normalize_v3(nor);
/* make sure that we get a proper side vector */
- if (fabsf(dot_v3v3(nor, vec)) > 0.999999) {
- if (fabsf(dot_v3v3(nor, xvec)) > 0.999999) {
+ if (fabsf(dot_v3v3(nor, vec)) > 0.999999f) {
+ if (fabsf(dot_v3v3(nor, xvec)) > 0.999999f) {
nor[0] = 0.0f;
nor[1] = 1.0f;
nor[2] = 0.0f;
diff --git a/source/blender/blenkernel/intern/particle_child.c b/source/blender/blenkernel/intern/particle_child.c
new file mode 100644
index 00000000000..33541c3a7fd
--- /dev/null
+++ b/source/blender/blenkernel/intern/particle_child.c
@@ -0,0 +1,726 @@
+/*
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/particle_child.c
+ * \ingroup bke
+ */
+
+#include "BLI_math.h"
+#include "BLI_noise.h"
+
+#include "DNA_material_types.h"
+
+#include "BKE_colortools.h"
+#include "BKE_particle.h"
+
+struct Material;
+
+void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], const float par_rot[4], float time, float freq, float shape, float amplitude, float flat,
+ short type, short axis, float obmat[4][4], int smooth_start);
+float do_clump(ParticleKey *state, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
+ bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve);
+void do_child_modifiers(ParticleSimulationData *sim,
+ ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
+ ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t);
+
+static void get_strand_normal(Material *ma, const float surfnor[3], float surfdist, float nor[3])
+{
+ float cross[3], nstrand[3], vnor[3], blend;
+
+ if (!((ma->mode & MA_STR_SURFDIFF) || (ma->strand_surfnor > 0.0f)))
+ return;
+
+ if (ma->mode & MA_STR_SURFDIFF) {
+ cross_v3_v3v3(cross, surfnor, nor);
+ cross_v3_v3v3(nstrand, nor, cross);
+
+ blend = dot_v3v3(nstrand, surfnor);
+ CLAMP(blend, 0.0f, 1.0f);
+
+ interp_v3_v3v3(vnor, nstrand, surfnor, blend);
+ normalize_v3(vnor);
+ }
+ else {
+ copy_v3_v3(vnor, nor);
+ }
+
+ if (ma->strand_surfnor > 0.0f) {
+ if (ma->strand_surfnor > surfdist) {
+ blend = (ma->strand_surfnor - surfdist) / ma->strand_surfnor;
+ interp_v3_v3v3(vnor, vnor, surfnor, blend);
+ normalize_v3(vnor);
+ }
+ }
+
+ copy_v3_v3(nor, vnor);
+}
+
+/* ------------------------------------------------------------------------- */
+
+typedef struct ParticlePathIterator {
+ ParticleCacheKey *key;
+ int index;
+ float time;
+
+ ParticleCacheKey *parent_key;
+ float parent_rotation[4];
+} ParticlePathIterator;
+
+static void psys_path_iter_get(ParticlePathIterator *iter, ParticleCacheKey *keys, int totkeys,
+ ParticleCacheKey *parent, int index)
+{
+ BLI_assert(index >= 0 && index < totkeys);
+
+ iter->key = keys + index;
+ iter->index = index;
+ iter->time = (float)index / (float)(totkeys - 1);
+
+ if (parent) {
+ iter->parent_key = parent + index;
+ if (index > 0)
+ mul_qt_qtqt(iter->parent_rotation, iter->parent_key->rot, parent->rot);
+ else
+ copy_qt_qt(iter->parent_rotation, parent->rot);
+ }
+ else {
+ iter->parent_key = NULL;
+ unit_qt(iter->parent_rotation);
+ }
+}
+
+typedef struct ParticlePathModifier {
+ struct ParticlePathModifier *next, *prev;
+
+ void (*apply)(ParticleCacheKey *keys, int totkeys, ParticleCacheKey *parent_keys);
+} ParticlePathModifier;
+
+/* ------------------------------------------------------------------------- */
+
+static void do_kink_spiral_deform(ParticleKey *state, const float dir[3], const float kink[3],
+ float time, float freq, float shape, float amplitude,
+ const float spiral_start[3])
+{
+ float result[3];
+
+ CLAMP(time, 0.f, 1.f);
+
+ copy_v3_v3(result, state->co);
+
+ {
+ /* Creates a logarithmic spiral:
+ * r(theta) = a * exp(b * theta)
+ *
+ * The "density" parameter b is defined by the shape parameter
+ * and goes up to the Golden Spiral for 1.0
+ * http://en.wikipedia.org/wiki/Golden_spiral
+ */
+ const float b = shape * (1.0f + sqrtf(5.0f)) / (float)M_PI * 0.25f;
+ /* angle of the spiral against the curve (rotated opposite to make a smooth transition) */
+ const float start_angle = ((b != 0.0f) ? atanf(1.0f / b) :
+ (float)-M_PI_2) + (b > 0.0f ? -(float)M_PI_2 : (float)M_PI_2);
+
+ float spiral_axis[3], rot[3][3];
+ float vec[3];
+
+ float theta = freq * time * 2.0f * (float)M_PI;
+ float radius = amplitude * expf(b * theta);
+
+ /* a bit more intuitive than using negative frequency for this */
+ if (amplitude < 0.0f)
+ theta = -theta;
+
+ cross_v3_v3v3(spiral_axis, dir, kink);
+ normalize_v3(spiral_axis);
+
+ mul_v3_v3fl(vec, kink, -radius);
+
+ axis_angle_normalized_to_mat3(rot, spiral_axis, theta);
+ mul_m3_v3(rot, vec);
+
+ madd_v3_v3fl(vec, kink, amplitude);
+
+ axis_angle_normalized_to_mat3(rot, spiral_axis, -start_angle);
+ mul_m3_v3(rot, vec);
+
+ add_v3_v3v3(result, spiral_start, vec);
+ }
+
+ copy_v3_v3(state->co, result);
+}
+
+static void do_kink_spiral(ParticleThreadContext *ctx, ParticleTexture *ptex, const float parent_orco[3],
+ ChildParticle *cpa, const float orco[3], float hairmat[4][4],
+ ParticleCacheKey *keys, ParticleCacheKey *parent_keys, int *r_totkeys, float *r_max_length)
+{
+ struct ParticleSettings *part = ctx->sim.psys->part;
+ const int seed = ctx->sim.psys->child_seed + (int)(cpa - ctx->sim.psys->child);
+ const int totkeys = ctx->segments + 1;
+ const int extrakeys = ctx->extra_segments;
+
+ float kink_amp_random = part->kink_amp_random;
+ float kink_amp = part->kink_amp * (1.0f - kink_amp_random * psys_frand(ctx->sim.psys, 93541 + seed));
+ float kink_freq = part->kink_freq;
+ float kink_shape = part->kink_shape;
+ float kink_axis_random = part->kink_axis_random;
+ float rough1 = part->rough1;
+ float rough2 = part->rough2;
+ float rough_end = part->rough_end;
+
+ ParticlePathIterator iter;
+ ParticleCacheKey *key;
+ int k;
+
+ float dir[3];
+ float spiral_start[3] = {0.0f, 0.0f, 0.0f};
+ float spiral_start_time = 0.0f;
+ float spiral_par_co[3] = {0.0f, 0.0f, 0.0f};
+ float spiral_par_vel[3] = {0.0f, 0.0f, 0.0f};
+ float spiral_par_rot[4] = {1.0f, 0.0f, 0.0f, 0.0f};
+ float totlen;
+ float cut_time;
+ int start_index = 0, end_index = 0;
+ float kink_base[3];
+
+ if (ptex) {
+ kink_amp *= ptex->kink_amp;
+ kink_freq *= ptex->kink_freq;
+ rough1 *= ptex->rough1;
+ rough2 *= ptex->rough2;
+ rough_end *= ptex->roughe;
+ }
+
+ cut_time = (totkeys - 1) * ptex->length;
+ zero_v3(spiral_start);
+
+ for (k = 0, key = keys; k < totkeys-1; k++, key++) {
+ if ((float)(k + 1) >= cut_time) {
+ float fac = cut_time - (float)k;
+ ParticleCacheKey *par = parent_keys + k;
+
+ start_index = k + 1;
+ end_index = start_index + extrakeys;
+
+ spiral_start_time = ((float)k + fac) / (float)(totkeys - 1);
+ interp_v3_v3v3(spiral_start, key->co, (key+1)->co, fac);
+
+ interp_v3_v3v3(spiral_par_co, par->co, (par+1)->co, fac);
+ interp_v3_v3v3(spiral_par_vel, par->vel, (par+1)->vel, fac);
+ interp_qt_qtqt(spiral_par_rot, par->rot, (par+1)->rot, fac);
+
+ break;
+ }
+ }
+
+ zero_v3(dir);
+
+ zero_v3(kink_base);
+ kink_base[part->kink_axis] = 1.0f;
+ mul_mat3_m4_v3(ctx->sim.ob->obmat, kink_base);
+
+ for (k = 0, key = keys; k < end_index; k++, key++) {
+ float par_time;
+ float *par_co, *par_vel, *par_rot;
+
+ psys_path_iter_get(&iter, keys, end_index, NULL, k);
+ if (k < start_index) {
+ sub_v3_v3v3(dir, (key+1)->co, key->co);
+ normalize_v3(dir);
+
+ par_time = (float)k / (float)(totkeys - 1);
+ par_co = parent_keys[k].co;
+ par_vel = parent_keys[k].vel;
+ par_rot = parent_keys[k].rot;
+ }
+ else {
+ float spiral_time = (float)(k - start_index) / (float)(extrakeys-1);
+ float kink[3], tmp[3];
+
+ /* use same time value for every point on the spiral */
+ par_time = spiral_start_time;
+ par_co = spiral_par_co;
+ par_vel = spiral_par_vel;
+ par_rot = spiral_par_rot;
+
+ project_v3_v3v3(tmp, kink_base, dir);
+ sub_v3_v3v3(kink, kink_base, tmp);
+ normalize_v3(kink);
+
+ if (kink_axis_random > 0.0f) {
+ float a = kink_axis_random * (psys_frand(ctx->sim.psys, 7112 + seed) * 2.0f - 1.0f) * (float)M_PI;
+ float rot[3][3];
+
+ axis_angle_normalized_to_mat3(rot, dir, a);
+ mul_m3_v3(rot, kink);
+ }
+
+ do_kink_spiral_deform((ParticleKey *)key, dir, kink, spiral_time, kink_freq, kink_shape, kink_amp, spiral_start);
+ }
+
+ /* apply different deformations to the child path */
+ do_child_modifiers(&ctx->sim, ptex, par_co, par_vel, par_rot, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, par_time);
+ }
+
+ totlen = 0.0f;
+ for (k = 0, key = keys; k < end_index-1; k++, key++)
+ totlen += len_v3v3((key+1)->co, key->co);
+
+ *r_totkeys = end_index;
+ *r_max_length = totlen;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static bool check_path_length(int k, ParticleCacheKey *keys, ParticleCacheKey *key, float max_length, float step_length, float *cur_length, float dvec[3])
+{
+ if (*cur_length + step_length > max_length) {
+ sub_v3_v3v3(dvec, key->co, (key-1)->co);
+ mul_v3_fl(dvec, (max_length - *cur_length) / step_length);
+ add_v3_v3v3(key->co, (key-1)->co, dvec);
+ keys->segments = k;
+ /* something over the maximum step value */
+ return false;
+ }
+ else {
+ *cur_length += step_length;
+ return true;
+ }
+}
+
+void psys_apply_child_modifiers(ParticleThreadContext *ctx, struct ListBase *modifiers,
+ ChildParticle *cpa, ParticleTexture *ptex, const float orco[3], const float ornor[3], float hairmat[4][4],
+ ParticleCacheKey *keys, ParticleCacheKey *parent_keys, const float parent_orco[3])
+{
+ struct ParticleSettings *part = ctx->sim.psys->part;
+ struct Material *ma = ctx->ma;
+ const bool draw_col_ma = (part->draw_col == PART_DRAW_COL_MAT);
+ const bool use_length_check = !ELEM(part->kink, PART_KINK_SPIRAL);
+
+ ParticlePathModifier *mod;
+ ParticleCacheKey *key;
+ int totkeys, k;
+ float max_length;
+
+#if 0 /* TODO for the future: use true particle modifiers that work on the whole curve */
+ for (mod = modifiers->first; mod; mod = mod->next) {
+ mod->apply(keys, totkeys, parent_keys);
+ }
+#else
+ (void)modifiers;
+ (void)mod;
+
+ if (part->kink == PART_KINK_SPIRAL) {
+ do_kink_spiral(ctx, ptex, parent_orco, cpa, orco, hairmat, keys, parent_keys, &totkeys, &max_length);
+ keys->segments = totkeys - 1;
+ }
+ else {
+ ParticlePathIterator iter;
+
+ totkeys = ctx->segments + 1;
+ max_length = ptex->length;
+
+ for (k = 0, key = keys; k < totkeys; k++, key++) {
+ ParticleKey *par;
+
+ psys_path_iter_get(&iter, keys, totkeys, parent_keys, k);
+ par = (ParticleKey *)iter.parent_key;
+
+ /* apply different deformations to the child path */
+ do_child_modifiers(&ctx->sim, ptex, par->co, par->vel, iter.parent_rotation, parent_orco, cpa, orco, hairmat, (ParticleKey *)key, iter.time);
+ }
+ }
+
+ {
+ const float step_length = 1.0f / (float)(totkeys - 1);
+
+ float cur_length = 0.0f;
+
+ /* we have to correct velocity because of kink & clump */
+ for (k = 0, key = keys; k < totkeys; ++k, ++key) {
+ if (k >= 2) {
+ sub_v3_v3v3((key-1)->vel, key->co, (key-2)->co);
+ mul_v3_fl((key-1)->vel, 0.5);
+
+ if (ma && draw_col_ma)
+ get_strand_normal(ma, ornor, cur_length, (key-1)->vel);
+ }
+ if (k == totkeys-1) {
+ /* last key */
+ sub_v3_v3v3(key->vel, key->co, (key-1)->co);
+ }
+
+ if (use_length_check && k > 1) {
+ float dvec[3];
+ /* check if path needs to be cut before actual end of data points */
+ if (!check_path_length(k, keys, key, max_length, step_length, &cur_length, dvec))
+ break;
+ }
+
+ if (ma && draw_col_ma) {
+ copy_v3_v3(key->col, &ma->r);
+ get_strand_normal(ma, ornor, cur_length, key->vel);
+ }
+ }
+ }
+#endif
+}
+
+/* ------------------------------------------------------------------------- */
+
+void do_kink(ParticleKey *state, const float par_co[3], const float par_vel[3], const float par_rot[4], float time, float freq, float shape,
+ float amplitude, float flat, short type, short axis, float obmat[4][4], int smooth_start)
+{
+ float kink[3] = {1.f, 0.f, 0.f}, par_vec[3], q1[4] = {1.f, 0.f, 0.f, 0.f};
+ float t, dt = 1.f, result[3];
+
+ if (ELEM(type, PART_KINK_NO, PART_KINK_SPIRAL))
+ return;
+
+ CLAMP(time, 0.f, 1.f);
+
+ if (shape != 0.0f && !ELEM(type, PART_KINK_BRAID)) {
+ if (shape < 0.0f)
+ time = (float)pow(time, 1.f + shape);
+ else
+ time = (float)pow(time, 1.f / (1.f - shape));
+ }
+
+ t = time * freq * (float)M_PI;
+
+ if (smooth_start) {
+ dt = fabsf(t);
+ /* smooth the beginning of kink */
+ CLAMP(dt, 0.f, (float)M_PI);
+ dt = sinf(dt / 2.f);
+ }
+
+ if (!ELEM(type, PART_KINK_RADIAL)) {
+ float temp[3];
+
+ kink[axis] = 1.f;
+
+ if (obmat)
+ mul_mat3_m4_v3(obmat, kink);
+
+ mul_qt_v3(par_rot, kink);
+
+ /* make sure kink is normal to strand */
+ project_v3_v3v3(temp, kink, par_vel);
+ sub_v3_v3(kink, temp);
+ normalize_v3(kink);
+ }
+
+ copy_v3_v3(result, state->co);
+ sub_v3_v3v3(par_vec, par_co, state->co);
+
+ switch (type) {
+ case PART_KINK_CURL:
+ {
+ float curl_offset[3];
+
+ /* rotate kink vector around strand tangent */
+ mul_v3_v3fl(curl_offset, kink, amplitude);
+ axis_angle_to_quat(q1, par_vel, t);
+ mul_qt_v3(q1, curl_offset);
+
+ interp_v3_v3v3(par_vec, state->co, par_co, flat);
+ add_v3_v3v3(result, par_vec, curl_offset);
+ break;
+ }
+ case PART_KINK_RADIAL:
+ {
+ if (flat > 0.f) {
+ float proj[3];
+ /* flatten along strand */
+ project_v3_v3v3(proj, par_vec, par_vel);
+ madd_v3_v3fl(result, proj, flat);
+ }
+
+ madd_v3_v3fl(result, par_vec, -amplitude * sinf(t));
+ break;
+ }
+ case PART_KINK_WAVE:
+ {
+ madd_v3_v3fl(result, kink, amplitude * sinf(t));
+
+ if (flat > 0.f) {
+ float proj[3];
+ /* flatten along wave */
+ project_v3_v3v3(proj, par_vec, kink);
+ madd_v3_v3fl(result, proj, flat);
+
+ /* flatten along strand */
+ project_v3_v3v3(proj, par_vec, par_vel);
+ madd_v3_v3fl(result, proj, flat);
+ }
+ break;
+ }
+ case PART_KINK_BRAID:
+ {
+ float y_vec[3] = {0.f, 1.f, 0.f};
+ float z_vec[3] = {0.f, 0.f, 1.f};
+ float vec_one[3], state_co[3];
+ float inp_y, inp_z, length;
+
+ if (par_rot) {
+ mul_qt_v3(par_rot, y_vec);
+ mul_qt_v3(par_rot, z_vec);
+ }
+
+ negate_v3(par_vec);
+ normalize_v3_v3(vec_one, par_vec);
+
+ inp_y = dot_v3v3(y_vec, vec_one);
+ inp_z = dot_v3v3(z_vec, vec_one);
+
+ if (inp_y > 0.5f) {
+ copy_v3_v3(state_co, y_vec);
+
+ 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, sinf((float)M_PI / 3.f));
+ madd_v3_v3fl(state_co, y_vec, -0.5f);
+
+ 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, -sinf((float)M_PI / 3.f));
+ madd_v3_v3fl(state_co, y_vec, -0.5f);
+
+ 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);
+ add_v3_v3(state_co, par_co);
+ sub_v3_v3v3(par_vec, state->co, state_co);
+
+ length = normalize_v3(par_vec);
+ mul_v3_fl(par_vec, MIN2(length, amplitude / 2.f));
+
+ add_v3_v3v3(state_co, par_co, y_vec);
+ add_v3_v3(state_co, z_vec);
+ add_v3_v3(state_co, par_vec);
+
+ shape = 2.f * (float)M_PI * (1.f + shape);
+
+ if (t < shape) {
+ shape = t / shape;
+ shape = (float)sqrt((double)shape);
+ interp_v3_v3v3(result, result, state_co, shape);
+ }
+ else {
+ copy_v3_v3(result, state_co);
+ }
+ break;
+ }
+ }
+
+ /* blend the start of the kink */
+ if (dt < 1.f)
+ interp_v3_v3v3(state->co, state->co, result, dt);
+ else
+ copy_v3_v3(state->co, result);
+}
+
+static float do_clump_level(float result[3], const float co[3], const float par_co[3], float time,
+ float clumpfac, float clumppow, float pa_clump, CurveMapping *clumpcurve)
+{
+ float clump = 0.0f;
+
+ if (clumpcurve) {
+ clump = pa_clump * (1.0f - CLAMPIS(curvemapping_evaluateF(clumpcurve, 0, time), 0.0f, 1.0f));
+
+ interp_v3_v3v3(result, co, par_co, clump);
+ }
+ else if (clumpfac != 0.0f) {
+ float cpow;
+
+ if (clumppow < 0.0f)
+ cpow = 1.0f + clumppow;
+ else
+ cpow = 1.0f + 9.0f * clumppow;
+
+ if (clumpfac < 0.0f) /* clump roots instead of tips */
+ clump = -clumpfac * pa_clump * (float)pow(1.0 - (double)time, (double)cpow);
+ else
+ clump = clumpfac * pa_clump * (float)pow((double)time, (double)cpow);
+
+ interp_v3_v3v3(result, co, par_co, clump);
+ }
+
+ return clump;
+}
+
+float do_clump(ParticleKey *state, const float par_co[3], float time, const float orco_offset[3], float clumpfac, float clumppow, float pa_clump,
+ bool use_clump_noise, float clump_noise_size, CurveMapping *clumpcurve)
+{
+ float clump;
+
+ if (use_clump_noise && clump_noise_size != 0.0f) {
+ float center[3], noisevec[3];
+ float da[4], pa[12];
+
+ mul_v3_v3fl(noisevec, orco_offset, 1.0f / clump_noise_size);
+ voronoi(noisevec[0], noisevec[1], noisevec[2], da, pa, 1.0f, 0);
+ mul_v3_fl(&pa[0], clump_noise_size);
+ add_v3_v3v3(center, par_co, &pa[0]);
+
+ do_clump_level(state->co, state->co, center, time, clumpfac, clumppow, pa_clump, clumpcurve);
+ }
+
+ clump = do_clump_level(state->co, state->co, par_co, time, clumpfac, clumppow, pa_clump, clumpcurve);
+
+ return clump;
+}
+
+static void do_rough(const float loc[3], float mat[4][4], float t, float fac, float size, float thres, ParticleKey *state)
+{
+ float rough[3];
+ float rco[3];
+
+ 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);
+ rough[0] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2, 0, 2);
+ rough[1] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2, 0, 2);
+ rough[2] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2, 0, 2);
+
+ madd_v3_v3fl(state->co, mat[0], fac * rough[0]);
+ madd_v3_v3fl(state->co, mat[1], fac * rough[1]);
+ madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
+}
+
+static void do_rough_end(const float loc[3], float mat[4][4], float t, float fac, float shape, ParticleKey *state)
+{
+ float rough[2];
+ float roughfac;
+
+ roughfac = fac * (float)pow((double)t, shape);
+ copy_v2_v2(rough, loc);
+ rough[0] = -1.0f + 2.0f * rough[0];
+ rough[1] = -1.0f + 2.0f * rough[1];
+ mul_v2_fl(rough, roughfac);
+
+ madd_v3_v3fl(state->co, mat[0], rough[0]);
+ madd_v3_v3fl(state->co, mat[1], rough[1]);
+}
+
+static void do_rough_curve(const float loc[3], float mat[4][4], float time, float fac, float size, CurveMapping *roughcurve, ParticleKey *state)
+{
+ float rough[3];
+ float rco[3];
+
+ if (!roughcurve)
+ return;
+
+ fac *= CLAMPIS(curvemapping_evaluateF(roughcurve, 0, time), 0.0f, 1.0f);
+
+ copy_v3_v3(rco, loc);
+ mul_v3_fl(rco, time);
+ rough[0] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[0], rco[1], rco[2], 2, 0, 2);
+ rough[1] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[1], rco[2], rco[0], 2, 0, 2);
+ rough[2] = -1.0f + 2.0f * BLI_gTurbulence(size, rco[2], rco[0], rco[1], 2, 0, 2);
+
+ madd_v3_v3fl(state->co, mat[0], fac * rough[0]);
+ madd_v3_v3fl(state->co, mat[1], fac * rough[1]);
+ madd_v3_v3fl(state->co, mat[2], fac * rough[2]);
+}
+
+void do_child_modifiers(ParticleSimulationData *sim, ParticleTexture *ptex, const float par_co[3], const float par_vel[3], const float par_rot[4], const float par_orco[3],
+ ChildParticle *cpa, const float orco[3], float mat[4][4], ParticleKey *state, float t)
+{
+ ParticleSettings *part = sim->psys->part;
+ CurveMapping *clumpcurve = (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) ? part->clumpcurve : NULL;
+ CurveMapping *roughcurve = (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) ? part->roughcurve : NULL;
+ int i = cpa - sim->psys->child;
+ int guided = 0;
+
+ float kink_amp = part->kink_amp;
+ float kink_amp_clump = part->kink_amp_clump;
+ float kink_freq = part->kink_freq;
+ float rough1 = part->rough1;
+ float rough2 = part->rough2;
+ float rough_end = part->rough_end;
+ const bool smooth_start = (sim->psys->part->childtype == PART_CHILD_FACES);
+
+ if (ptex) {
+ kink_amp *= ptex->kink_amp;
+ kink_freq *= ptex->kink_freq;
+ rough1 *= ptex->rough1;
+ rough2 *= ptex->rough2;
+ rough_end *= ptex->roughe;
+ }
+
+ if (part->flag & PART_CHILD_EFFECT)
+ /* state is safe to cast, since only co and vel are used */
+ guided = do_guides(sim->psys->part, sim->psys->effectors, (ParticleKey *)state, cpa->parent, t);
+
+ if (guided == 0) {
+ float orco_offset[3];
+ float clump;
+
+ sub_v3_v3v3(orco_offset, orco, par_orco);
+ clump = do_clump(state, par_co, t, orco_offset, part->clumpfac, part->clumppow, ptex ? ptex->clump : 1.f,
+ part->child_flag & PART_CHILD_USE_CLUMP_NOISE, part->clump_noise_size, clumpcurve);
+
+ if (kink_freq != 0.f) {
+ kink_amp *= (1.f - kink_amp_clump * clump);
+
+ do_kink(state, par_co, par_vel, par_rot, t, kink_freq, part->kink_shape,
+ kink_amp, part->kink_flat, part->kink, part->kink_axis,
+ sim->ob->obmat, smooth_start);
+ }
+ }
+
+ if (roughcurve) {
+ do_rough_curve(orco, mat, t, rough1, part->rough1_size, roughcurve, state);
+ }
+ else {
+ if (rough1 > 0.f)
+ do_rough(orco, mat, t, rough1, part->rough1_size, 0.0, state);
+
+ if (rough2 > 0.f) {
+ float vec[3];
+ psys_frand_vec(sim->psys, i + 27, vec);
+ do_rough(vec, mat, t, rough2, part->rough2_size, part->rough2_thres, state);
+ }
+
+ if (rough_end > 0.f) {
+ float vec[3];
+ psys_frand_vec(sim->psys, i + 27, vec);
+ do_rough_end(vec, mat, t, rough_end, part->rough_end_shape, state);
+ }
+ }
+}
diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c
new file mode 100644
index 00000000000..6cc42e85a12
--- /dev/null
+++ b/source/blender/blenkernel/intern/particle_distribute.c
@@ -0,0 +1,1419 @@
+/*
+ * ***** 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) 2007 by Janne Karhu.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Raul Fernandez Hernandez (Farsthary),
+ * Stephen Swhitehorn,
+ * Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/blenkernel/intern/particle_distribute.c
+ * \ingroup bke
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_jitter.h"
+#include "BLI_kdtree.h"
+#include "BLI_math.h"
+#include "BLI_rand.h"
+#include "BLI_sort.h"
+#include "BLI_task.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_scene_types.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+
+static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot);
+
+static void alloc_child_particles(ParticleSystem *psys, int tot)
+{
+ if (psys->child) {
+ /* only re-allocate if we have to */
+ if (psys->part->childtype && psys->totchild == tot) {
+ memset(psys->child, 0, tot*sizeof(ChildParticle));
+ return;
+ }
+
+ MEM_freeN(psys->child);
+ psys->child=NULL;
+ psys->totchild=0;
+ }
+
+ if (psys->part->childtype) {
+ psys->totchild= tot;
+ if (psys->totchild)
+ psys->child= MEM_callocN(psys->totchild*sizeof(ChildParticle), "child_particles");
+ }
+}
+
+static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, ParticleSystem *psys)
+{
+ ChildParticle *cpa = NULL;
+ int i, p;
+ int child_nbr= psys_get_child_number(scene, psys);
+ int totpart= psys_get_tot_child(scene, psys);
+
+ alloc_child_particles(psys, totpart);
+
+ cpa = psys->child;
+ for (i=0; i<child_nbr; i++) {
+ for (p=0; p<psys->totpart; p++,cpa++) {
+ float length=2.0;
+ cpa->parent=p;
+
+ /* create even spherical distribution inside unit sphere */
+ while (length>=1.0f) {
+ cpa->fuv[0]=2.0f*BLI_frand()-1.0f;
+ cpa->fuv[1]=2.0f*BLI_frand()-1.0f;
+ cpa->fuv[2]=2.0f*BLI_frand()-1.0f;
+ length=len_v3(cpa->fuv);
+ }
+
+ cpa->num=-1;
+ }
+ }
+ /* dmcache must be updated for parent particles if children from faces is used */
+ psys_calc_dmcache(ob, finaldm, psys);
+}
+static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
+{
+ ParticleData *pa=NULL;
+ float min[3], max[3], delta[3], d;
+ MVert *mv, *mvert = dm->getVertDataArray(dm,0);
+ int totvert=dm->getNumVerts(dm), from=psys->part->from;
+ int i, j, k, p, res=psys->part->grid_res, size[3], axis;
+
+ /* find bounding box of dm */
+ if (totvert > 0) {
+ mv=mvert;
+ copy_v3_v3(min, mv->co);
+ copy_v3_v3(max, mv->co);
+ mv++;
+ for (i = 1; i < totvert; i++, mv++) {
+ minmax_v3v3_v3(min, max, mv->co);
+ }
+ }
+ else {
+ zero_v3(min);
+ zero_v3(max);
+ }
+
+ sub_v3_v3v3(delta, max, min);
+
+ /* determine major axis */
+ axis = axis_dominant_v3_single(delta);
+
+ d = delta[axis]/(float)res;
+
+ size[axis] = res;
+ size[(axis+1)%3] = (int)ceil(delta[(axis+1)%3]/d);
+ size[(axis+2)%3] = (int)ceil(delta[(axis+2)%3]/d);
+
+ /* float errors grrr.. */
+ size[(axis+1)%3] = MIN2(size[(axis+1)%3],res);
+ size[(axis+2)%3] = MIN2(size[(axis+2)%3],res);
+
+ size[0] = MAX2(size[0], 1);
+ size[1] = MAX2(size[1], 1);
+ size[2] = MAX2(size[2], 1);
+
+ /* no full offset for flat/thin objects */
+ min[0]+= d < delta[0] ? d/2.f : delta[0]/2.f;
+ min[1]+= d < delta[1] ? d/2.f : delta[1]/2.f;
+ min[2]+= d < delta[2] ? d/2.f : delta[2]/2.f;
+
+ for (i=0,p=0,pa=psys->particles; i<res; i++) {
+ for (j=0; j<res; j++) {
+ for (k=0; k<res; k++,p++,pa++) {
+ pa->fuv[0] = min[0] + (float)i*d;
+ pa->fuv[1] = min[1] + (float)j*d;
+ pa->fuv[2] = min[2] + (float)k*d;
+ pa->flag |= PARS_UNEXIST;
+ pa->hair_index = 0; /* abused in volume calculation */
+ }
+ }
+ }
+
+ /* enable particles near verts/edges/faces/inside surface */
+ if (from==PART_FROM_VERT) {
+ float vec[3];
+
+ pa=psys->particles;
+
+ min[0] -= d/2.0f;
+ min[1] -= d/2.0f;
+ min[2] -= d/2.0f;
+
+ for (i=0,mv=mvert; i<totvert; i++,mv++) {
+ sub_v3_v3v3(vec,mv->co,min);
+ vec[0]/=delta[0];
+ vec[1]/=delta[1];
+ vec[2]/=delta[2];
+ pa[((int)(vec[0] * (size[0] - 1)) * res +
+ (int)(vec[1] * (size[1] - 1))) * res +
+ (int)(vec[2] * (size[2] - 1))].flag &= ~PARS_UNEXIST;
+ }
+ }
+ else if (ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
+ float co1[3], co2[3];
+
+ MFace *mface= NULL, *mface_array;
+ float v1[3], v2[3], v3[3], v4[4], lambda;
+ int a, a1, a2, a0mul, a1mul, a2mul, totface;
+ int amax= from==PART_FROM_FACE ? 3 : 1;
+
+ totface=dm->getNumTessFaces(dm);
+ mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);
+
+ for (a=0; a<amax; a++) {
+ if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; }
+ else if (a==1) { a0mul=res; a1mul=1; a2mul=res*res; }
+ else { a0mul=1; a1mul=res*res; a2mul=res; }
+
+ for (a1=0; a1<size[(a+1)%3]; a1++) {
+ for (a2=0; a2<size[(a+2)%3]; a2++) {
+ mface= mface_array;
+
+ pa = psys->particles + a1*a1mul + a2*a2mul;
+ copy_v3_v3(co1, pa->fuv);
+ co1[a] -= d < delta[a] ? d/2.f : delta[a]/2.f;
+ copy_v3_v3(co2, co1);
+ co2[a] += delta[a] + 0.001f*d;
+ co1[a] -= 0.001f*d;
+
+ /* lets intersect the faces */
+ for (i=0; i<totface; i++,mface++) {
+ copy_v3_v3(v1, mvert[mface->v1].co);
+ copy_v3_v3(v2, mvert[mface->v2].co);
+ copy_v3_v3(v3, mvert[mface->v3].co);
+
+ if (isect_axial_line_tri_v3(a, co1, co2, v2, v3, v1, &lambda)) {
+ if (from==PART_FROM_FACE)
+ (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
+ else /* store number of intersections */
+ (pa+(int)(lambda*size[a])*a0mul)->hair_index++;
+ }
+ else if (mface->v4) {
+ copy_v3_v3(v4, mvert[mface->v4].co);
+
+ if (isect_axial_line_tri_v3(a, co1, co2, v4, v1, v3, &lambda)) {
+ if (from==PART_FROM_FACE)
+ (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
+ else
+ (pa+(int)(lambda*size[a])*a0mul)->hair_index++;
+ }
+ }
+ }
+
+ if (from==PART_FROM_VOLUME) {
+ int in=pa->hair_index%2;
+ if (in) pa->hair_index++;
+ for (i=0; i<size[0]; i++) {
+ if (in || (pa+i*a0mul)->hair_index%2)
+ (pa+i*a0mul)->flag &= ~PARS_UNEXIST;
+ /* odd intersections == in->out / out->in */
+ /* even intersections -> in stays same */
+ in=(in + (pa+i*a0mul)->hair_index) % 2;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (psys->part->flag & PART_GRID_HEXAGONAL) {
+ for (i=0,p=0,pa=psys->particles; i<res; i++) {
+ for (j=0; j<res; j++) {
+ for (k=0; k<res; k++,p++,pa++) {
+ if (j%2)
+ pa->fuv[0] += d/2.f;
+
+ if (k%2) {
+ pa->fuv[0] += d/2.f;
+ pa->fuv[1] += d/2.f;
+ }
+ }
+ }
+ }
+ }
+
+ if (psys->part->flag & PART_GRID_INVERT) {
+ for (i=0; i<size[0]; i++) {
+ for (j=0; j<size[1]; j++) {
+ pa=psys->particles + res*(i*res + j);
+ for (k=0; k<size[2]; k++, pa++) {
+ pa->flag ^= PARS_UNEXIST;
+ }
+ }
+ }
+ }
+
+ if (psys->part->grid_rand > 0.f) {
+ float rfac = d * psys->part->grid_rand;
+ for (p=0,pa=psys->particles; p<psys->totpart; p++,pa++) {
+ if (pa->flag & PARS_UNEXIST)
+ continue;
+
+ pa->fuv[0] += rfac * (psys_frand(psys, p + 31) - 0.5f);
+ pa->fuv[1] += rfac * (psys_frand(psys, p + 32) - 0.5f);
+ pa->fuv[2] += rfac * (psys_frand(psys, p + 33) - 0.5f);
+ }
+ }
+}
+
+/* modified copy from rayshade.c */
+static void hammersley_create(float *out, int n, int seed, float amount)
+{
+ RNG *rng;
+ double p, t, offs[2];
+ int k, kk;
+
+ rng = BLI_rng_new(31415926 + n + seed);
+ offs[0] = BLI_rng_get_double(rng) + (double)amount;
+ offs[1] = BLI_rng_get_double(rng) + (double)amount;
+ BLI_rng_free(rng);
+
+ for (k = 0; k < n; k++) {
+ t = 0;
+ for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1)
+ if (kk & 1) /* kk mod 2 = 1 */
+ t += p;
+
+ out[2*k + 0] = fmod((double)k/(double)n + offs[0], 1.0);
+ out[2*k + 1] = fmod(t + offs[1], 1.0);
+ }
+}
+
+/* almost exact copy of BLI_jitter_init */
+static void init_mv_jit(float *jit, int num, int seed2, float amount)
+{
+ RNG *rng;
+ float *jit2, x, rad1, rad2, rad3;
+ int i, num2;
+
+ if (num==0) return;
+
+ rad1= (float)(1.0f/sqrtf((float)num));
+ rad2= (float)(1.0f/((float)num));
+ rad3= (float)sqrtf((float)num)/((float)num);
+
+ rng = BLI_rng_new(31415926 + num + seed2);
+ x= 0;
+ num2 = 2 * num;
+ for (i=0; i<num2; i+=2) {
+
+ jit[i] = x + amount*rad1*(0.5f - BLI_rng_get_float(rng));
+ jit[i+1] = i/(2.0f*num) + amount*rad1*(0.5f - BLI_rng_get_float(rng));
+
+ jit[i]-= (float)floor(jit[i]);
+ jit[i+1]-= (float)floor(jit[i+1]);
+
+ x+= rad3;
+ x -= (float)floor(x);
+ }
+
+ jit2= MEM_mallocN(12 + 2*sizeof(float)*num, "initjit");
+
+ for (i=0 ; i<4 ; i++) {
+ BLI_jitterate1((float (*)[2])jit, (float (*)[2])jit2, num, rad1);
+ BLI_jitterate1((float (*)[2])jit, (float (*)[2])jit2, num, rad1);
+ BLI_jitterate2((float (*)[2])jit, (float (*)[2])jit2, num, rad2);
+ }
+ MEM_freeN(jit2);
+ BLI_rng_free(rng);
+}
+
+static void psys_uv_to_w(float u, float v, int quad, float *w)
+{
+ float vert[4][3], co[3];
+
+ if (!quad) {
+ if (u+v > 1.0f)
+ v= 1.0f-v;
+ else
+ u= 1.0f-u;
+ }
+
+ vert[0][0] = 0.0f; vert[0][1] = 0.0f; vert[0][2] = 0.0f;
+ vert[1][0] = 1.0f; vert[1][1] = 0.0f; vert[1][2] = 0.0f;
+ vert[2][0] = 1.0f; vert[2][1] = 1.0f; vert[2][2] = 0.0f;
+
+ co[0] = u;
+ co[1] = v;
+ co[2] = 0.0f;
+
+ if (quad) {
+ vert[3][0] = 0.0f; vert[3][1] = 1.0f; vert[3][2] = 0.0f;
+ interp_weights_poly_v3( w,vert, 4, co);
+ }
+ else {
+ interp_weights_poly_v3( w,vert, 3, co);
+ w[3] = 0.0f;
+ }
+}
+
+/* Find the index in "sum" array before "value" is crossed. */
+static int distribute_binary_search(float *sum, int n, float value)
+{
+ int mid, low=0, high=n;
+
+ if (value == 0.f)
+ return 0;
+
+ while (low <= high) {
+ mid= (low + high)/2;
+
+ if (sum[mid] < value && value <= sum[mid+1])
+ return mid;
+
+ if (sum[mid] >= value)
+ high= mid - 1;
+ else if (sum[mid] < value)
+ low= mid + 1;
+ else
+ return mid;
+ }
+
+ return low;
+}
+
+/* the max number if calls to rng_* funcs within psys_thread_distribute_particle
+ * be sure to keep up to date if this changes */
+#define PSYS_RND_DIST_SKIP 2
+
+/* note: this function must be thread safe, for from == PART_FROM_CHILD */
+#define ONLY_WORKING_WITH_PA_VERTS 0
+static void distribute_from_verts_exec(ParticleTask *thread, ParticleData *pa, int p)
+{
+ ParticleThreadContext *ctx= thread->ctx;
+ int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+
+ /* TODO_PARTICLE - use original index */
+ pa->num= ctx->index[p];
+ pa->fuv[0] = 1.0f;
+ pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
+
+#if ONLY_WORKING_WITH_PA_VERTS
+ if (ctx->tree) {
+ KDTreeNearest ptn[3];
+ int w, maxw;
+
+ psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
+ BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
+ maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
+
+ for (w=0; w<maxw; w++) {
+ pa->verts[w]=ptn->num;
+ }
+ }
+#endif
+
+ if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_rng_skip(thread->rng, rng_skip_tot);
+}
+
+static void distribute_from_faces_exec(ParticleTask *thread, ParticleData *pa, int p) {
+ ParticleThreadContext *ctx= thread->ctx;
+ DerivedMesh *dm= ctx->dm;
+ float randu, randv;
+ int distr= ctx->distr;
+ int i;
+ int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+
+ MFace *mface;
+
+ pa->num = i = ctx->index[p];
+ mface = dm->getTessFaceData(dm,i,CD_MFACE);
+
+ switch (distr) {
+ case PART_DISTR_JIT:
+ if (ctx->jitlevel == 1) {
+ if (mface->v4)
+ psys_uv_to_w(0.5f, 0.5f, mface->v4, pa->fuv);
+ else
+ psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
+ }
+ else {
+ ctx->jitoff[i] = fmod(ctx->jitoff[i],(float)ctx->jitlevel);
+ if (!isnan(ctx->jitoff[i])) {
+ psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mface->v4, pa->fuv);
+ ctx->jitoff[i]++;
+ }
+ }
+ break;
+ case PART_DISTR_RAND:
+ randu= BLI_rng_get_float(thread->rng);
+ randv= BLI_rng_get_float(thread->rng);
+ rng_skip_tot -= 2;
+
+ psys_uv_to_w(randu, randv, mface->v4, pa->fuv);
+ break;
+ }
+ pa->foffset= 0.0f;
+
+ if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_rng_skip(thread->rng, rng_skip_tot);
+}
+
+static void distribute_from_volume_exec(ParticleTask *thread, ParticleData *pa, int p) {
+ ParticleThreadContext *ctx= thread->ctx;
+ DerivedMesh *dm= ctx->dm;
+ float *v1, *v2, *v3, *v4, nor[3], co1[3], co2[3];
+ float cur_d, min_d, randu, randv;
+ int distr= ctx->distr;
+ int i, intersect, tot;
+ int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+
+ MFace *mface;
+ MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
+
+ pa->num = i = ctx->index[p];
+ mface = dm->getTessFaceData(dm,i,CD_MFACE);
+
+ switch (distr) {
+ case PART_DISTR_JIT:
+ if (ctx->jitlevel == 1) {
+ if (mface->v4)
+ psys_uv_to_w(0.5f, 0.5f, mface->v4, pa->fuv);
+ else
+ psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
+ }
+ else {
+ ctx->jitoff[i] = fmod(ctx->jitoff[i],(float)ctx->jitlevel);
+ if (!isnan(ctx->jitoff[i])) {
+ psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mface->v4, pa->fuv);
+ ctx->jitoff[i]++;
+ }
+ }
+ break;
+ case PART_DISTR_RAND:
+ randu= BLI_rng_get_float(thread->rng);
+ randv= BLI_rng_get_float(thread->rng);
+ rng_skip_tot -= 2;
+
+ psys_uv_to_w(randu, randv, mface->v4, pa->fuv);
+ break;
+ }
+ pa->foffset= 0.0f;
+
+ /* experimental */
+ tot=dm->getNumTessFaces(dm);
+
+ psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0);
+
+ normalize_v3(nor);
+ mul_v3_fl(nor,-100.0);
+
+ add_v3_v3v3(co2,co1,nor);
+
+ min_d=2.0;
+ intersect=0;
+
+ for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
+ if (i==pa->num) continue;
+
+ v1=mvert[mface->v1].co;
+ v2=mvert[mface->v2].co;
+ v3=mvert[mface->v3].co;
+
+ if (isect_line_tri_v3(co1, co2, v2, v3, v1, &cur_d, 0)) {
+ if (cur_d<min_d) {
+ min_d=cur_d;
+ pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ intersect=1;
+ }
+ }
+ if (mface->v4) {
+ v4=mvert[mface->v4].co;
+
+ if (isect_line_tri_v3(co1, co2, v4, v1, v3, &cur_d, 0)) {
+ if (cur_d<min_d) {
+ min_d=cur_d;
+ pa->foffset=cur_d*50.0f; /* to the middle of volume */
+ intersect=1;
+ }
+ }
+ }
+ }
+ if (intersect==0)
+ pa->foffset=0.0;
+ else {
+ switch (distr) {
+ case PART_DISTR_JIT:
+ pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)];
+ break;
+ case PART_DISTR_RAND:
+ pa->foffset *= BLI_frand();
+ break;
+ }
+ }
+
+ if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_rng_skip(thread->rng, rng_skip_tot);
+}
+
+static void distribute_children_exec(ParticleTask *thread, ChildParticle *cpa, int p) {
+ ParticleThreadContext *ctx= thread->ctx;
+ Object *ob= ctx->sim.ob;
+ DerivedMesh *dm= ctx->dm;
+ float orco1[3], co1[3], nor1[3];
+ float randu, randv;
+ int cfrom= ctx->cfrom;
+ int i;
+ int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
+
+ MFace *mf;
+
+ if (ctx->index[p] < 0) {
+ cpa->num=0;
+ cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3]=0.0f;
+ cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
+ return;
+ }
+
+ mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);
+
+ randu= BLI_rng_get_float(thread->rng);
+ randv= BLI_rng_get_float(thread->rng);
+ rng_skip_tot -= 2;
+
+ psys_uv_to_w(randu, randv, mf->v4, cpa->fuv);
+
+ cpa->num = ctx->index[p];
+
+ if (ctx->tree) {
+ KDTreeNearest ptn[10];
+ int w,maxw;//, do_seams;
+ float maxd /*, mind,dd */, totw= 0.0f;
+ int parent[10];
+ float pweight[10];
+
+ psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL);
+ BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
+ maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
+
+ maxd=ptn[maxw-1].dist;
+ /* mind=ptn[0].dist; */ /* UNUSED */
+
+ /* the weights here could be done better */
+ for (w=0; w<maxw; w++) {
+ parent[w]=ptn[w].index;
+ pweight[w]=(float)pow(2.0,(double)(-6.0f*ptn[w].dist/maxd));
+ }
+ for (;w<10; w++) {
+ parent[w]=-1;
+ pweight[w]=0.0f;
+ }
+
+ for (w=0,i=0; w<maxw && i<4; w++) {
+ if (parent[w]>=0) {
+ cpa->pa[i]=parent[w];
+ cpa->w[i]=pweight[w];
+ totw+=pweight[w];
+ i++;
+ }
+ }
+ for (;i<4; i++) {
+ cpa->pa[i]=-1;
+ cpa->w[i]=0.0f;
+ }
+
+ if (totw > 0.0f) {
+ for (w = 0; w < 4; w++) {
+ cpa->w[w] /= totw;
+ }
+ }
+
+ cpa->parent=cpa->pa[0];
+ }
+
+ if (rng_skip_tot > 0) /* should never be below zero */
+ BLI_rng_skip(thread->rng, rng_skip_tot);
+}
+
+static void exec_distribute_parent(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ ParticleTask *task = taskdata;
+ ParticleSystem *psys= task->ctx->sim.psys;
+ ParticleData *pa;
+ int p;
+
+ pa= psys->particles + task->begin;
+ switch (psys->part->from) {
+ case PART_FROM_FACE:
+ for (p = task->begin; p < task->end; ++p, ++pa)
+ distribute_from_faces_exec(task, pa, p);
+ break;
+ case PART_FROM_VOLUME:
+ for (p = task->begin; p < task->end; ++p, ++pa)
+ distribute_from_volume_exec(task, pa, p);
+ break;
+ case PART_FROM_VERT:
+ for (p = task->begin; p < task->end; ++p, ++pa)
+ distribute_from_verts_exec(task, pa, p);
+ break;
+ }
+}
+
+static void exec_distribute_child(TaskPool *UNUSED(pool), void *taskdata, int UNUSED(threadid))
+{
+ ParticleTask *task = taskdata;
+ ParticleSystem *psys = task->ctx->sim.psys;
+ ChildParticle *cpa;
+ int p;
+
+ /* RNG skipping at the beginning */
+ cpa = psys->child;
+ for (p = 0; p < task->begin; ++p, ++cpa) {
+ if (task->ctx->skip) /* simplification skip */
+ BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
+
+ BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP);
+ }
+
+ for (; p < task->end; ++p, ++cpa) {
+ if (task->ctx->skip) /* simplification skip */
+ BLI_rng_skip(task->rng, PSYS_RND_DIST_SKIP * task->ctx->skip[p]);
+
+ distribute_children_exec(task, cpa, p);
+ }
+}
+
+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];
+ int index2 = orig_index[*(const int *)p2];
+
+ if (index1 < index2)
+ return -1;
+ else if (index1 == index2) {
+ /* this pointer comparison appears to make qsort stable for glibc,
+ * and apparently on solaris too, makes the renders reproducible */
+ if (p1 < p2)
+ return -1;
+ else if (p1 == p2)
+ return 0;
+ else
+ return 1;
+ }
+ else
+ return 1;
+}
+
+static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from)
+{
+ if (from == PART_FROM_CHILD) {
+ ChildParticle *cpa;
+ int p, totchild = psys_get_tot_child(scene, psys);
+
+ if (psys->child && totchild) {
+ for (p=0,cpa=psys->child; p<totchild; p++,cpa++) {
+ cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3] = 0.0;
+ cpa->foffset= 0.0f;
+ cpa->parent=0;
+ cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
+ cpa->num= -1;
+ }
+ }
+ }
+ else {
+ PARTICLE_P;
+ LOOP_PARTICLES {
+ pa->fuv[0] = pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
+ pa->foffset= 0.0f;
+ pa->num= -1;
+ }
+ }
+}
+
+/* Creates a distribution of coordinates on a DerivedMesh */
+/* This is to denote functionality that does not yet work with mesh - only derived mesh */
+static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, ParticleSimulationData *sim, int from)
+{
+ Scene *scene = sim->scene;
+ DerivedMesh *finaldm = sim->psmd->dm;
+ Object *ob = sim->ob;
+ ParticleSystem *psys= sim->psys;
+ ParticleData *pa=0, *tpars= 0;
+ ParticleSettings *part;
+ ParticleSeam *seams= 0;
+ KDTree *tree=0;
+ DerivedMesh *dm= NULL;
+ float *jit= NULL;
+ int i, p=0;
+ int cfrom=0;
+ int totelem=0, totpart, *particle_element=0, children=0, totseam=0;
+ int jitlevel= 1, distr;
+ 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 (ELEM(NULL, ob, psys, psys->part))
+ return 0;
+
+ part=psys->part;
+ totpart=psys->totpart;
+ if (totpart==0)
+ return 0;
+
+ if (!finaldm->deformedOnly && !finaldm->getTessFaceDataArray(finaldm, CD_ORIGINDEX)) {
+ printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
+// XXX error("Can't paint with the current modifier stack, disable destructive modifiers");
+ return 0;
+ }
+
+ psys_thread_context_init(ctx, sim);
+
+ /* First handle special cases */
+ if (from == PART_FROM_CHILD) {
+ /* Simple children */
+ if (part->childtype != PART_CHILD_FACES) {
+ BLI_srandom(31415926 + psys->seed + psys->child_seed);
+ distribute_simple_children(scene, ob, finaldm, psys);
+ return 0;
+ }
+ }
+ else {
+ /* Grid distribution */
+ if (part->distr==PART_DISTR_GRID && from != PART_FROM_VERT) {
+ BLI_srandom(31415926 + psys->seed);
+ dm= CDDM_from_mesh((Mesh*)ob->data);
+ DM_ensure_tessface(dm);
+ distribute_grid(dm,psys);
+ dm->release(dm);
+ return 0;
+ }
+ }
+
+ /* Create trees and original coordinates if needed */
+ if (from == PART_FROM_CHILD) {
+ distr=PART_DISTR_RAND;
+ BLI_srandom(31415926 + psys->seed + psys->child_seed);
+ dm= finaldm;
+
+ /* BMESH ONLY */
+ DM_ensure_tessface(dm);
+
+ children=1;
+
+ tree=BLI_kdtree_new(totpart);
+
+ for (p=0,pa=psys->particles; p<totpart; p++,pa++) {
+ psys_particle_on_dm(dm,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco,NULL);
+ BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco, 1, 1);
+ BLI_kdtree_insert(tree, p, orco);
+ }
+
+ BLI_kdtree_balance(tree);
+
+ totpart = psys_get_tot_child(scene, psys);
+ cfrom = from = PART_FROM_FACE;
+ }
+ else {
+ distr = part->distr;
+ BLI_srandom(31415926 + psys->seed);
+
+ if (psys->part->use_modifier_stack)
+ dm = finaldm;
+ else
+ dm= CDDM_from_mesh((Mesh*)ob->data);
+
+ /* BMESH ONLY, for verts we don't care about tessfaces */
+ if (from != PART_FROM_VERT) {
+ DM_ensure_tessface(dm);
+ }
+
+ /* we need orco for consistent distributions */
+ if (!CustomData_has_layer(&dm->vertData, CD_ORCO))
+ DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob));
+
+ if (from == PART_FROM_VERT) {
+ MVert *mv= dm->getVertDataArray(dm, CD_MVERT);
+ float (*orcodata)[3] = dm->getVertDataArray(dm, CD_ORCO);
+ int totvert = dm->getNumVerts(dm);
+
+ tree=BLI_kdtree_new(totvert);
+
+ for (p=0; p<totvert; p++) {
+ if (orcodata) {
+ copy_v3_v3(co,orcodata[p]);
+ BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co, 1, 1);
+ }
+ else
+ copy_v3_v3(co,mv[p].co);
+ BLI_kdtree_insert(tree, p, co);
+ }
+
+ BLI_kdtree_balance(tree);
+ }
+ }
+
+ /* Get total number of emission elements and allocate needed arrays */
+ totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm);
+
+ if (totelem == 0) {
+ distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0);
+
+ if (G.debug & G_DEBUG)
+ fprintf(stderr,"Particle distribution error: Nothing to emit from!\n");
+
+ if (dm != finaldm) dm->release(dm);
+
+ BLI_kdtree_free(tree);
+
+ return 0;
+ }
+
+ element_weight = MEM_callocN(sizeof(float)*totelem, "particle_distribution_weights");
+ particle_element= MEM_callocN(sizeof(int)*totpart, "particle_distribution_indexes");
+ element_sum = MEM_callocN(sizeof(float)*(totelem+1), "particle_distribution_sum");
+ jitter_offset = MEM_callocN(sizeof(float)*totelem, "particle_distribution_jitoff");
+
+ /* Calculate weights from face areas */
+ if ((part->flag&PART_EDISTR || children) && from != PART_FROM_VERT) {
+ MVert *v1, *v2, *v3, *v4;
+ float totarea=0.f, co1[3], co2[3], co3[3], co4[3];
+ float (*orcodata)[3];
+
+ orcodata= dm->getVertDataArray(dm, CD_ORCO);
+
+ for (i=0; i<totelem; i++) {
+ MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
+
+ if (orcodata) {
+ copy_v3_v3(co1, orcodata[mf->v1]);
+ copy_v3_v3(co2, orcodata[mf->v2]);
+ copy_v3_v3(co3, orcodata[mf->v3]);
+ BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co1, 1, 1);
+ BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co2, 1, 1);
+ BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co3, 1, 1);
+ if (mf->v4) {
+ copy_v3_v3(co4, orcodata[mf->v4]);
+ BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co4, 1, 1);
+ }
+ }
+ else {
+ v1= (MVert*)dm->getVertData(dm,mf->v1,CD_MVERT);
+ v2= (MVert*)dm->getVertData(dm,mf->v2,CD_MVERT);
+ v3= (MVert*)dm->getVertData(dm,mf->v3,CD_MVERT);
+ copy_v3_v3(co1, v1->co);
+ copy_v3_v3(co2, v2->co);
+ copy_v3_v3(co3, v3->co);
+ if (mf->v4) {
+ v4= (MVert*)dm->getVertData(dm,mf->v4,CD_MVERT);
+ copy_v3_v3(co4, v4->co);
+ }
+ }
+
+ cur = mf->v4 ? area_quad_v3(co1, co2, co3, co4) : area_tri_v3(co1, co2, co3);
+
+ if (cur > maxweight)
+ maxweight = cur;
+
+ element_weight[i] = cur;
+ totarea += cur;
+ }
+
+ for (i=0; i<totelem; i++)
+ element_weight[i] /= totarea;
+
+ maxweight /= totarea;
+ }
+ else {
+ float min=1.0f/(float)(MIN2(totelem,totpart));
+ for (i=0; i<totelem; i++)
+ element_weight[i]=min;
+ maxweight=min;
+ }
+
+ /* Calculate weights from vgroup */
+ vweight = psys_cache_vgroup(dm,psys,PSYS_VG_DENSITY);
+
+ if (vweight) {
+ if (from==PART_FROM_VERT) {
+ for (i=0;i<totelem; i++)
+ element_weight[i]*=vweight[i];
+ }
+ else { /* PART_FROM_FACE / PART_FROM_VOLUME */
+ for (i=0;i<totelem; i++) {
+ MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
+ tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
+
+ if (mf->v4) {
+ tweight += vweight[mf->v4];
+ tweight /= 4.0f;
+ }
+ else {
+ tweight /= 3.0f;
+ }
+
+ element_weight[i]*=tweight;
+ }
+ }
+ MEM_freeN(vweight);
+ }
+
+ /* Calculate total weight of all elements */
+ totweight= 0.0f;
+ for (i=0;i<totelem; i++)
+ totweight += element_weight[i];
+
+ inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f);
+
+ /* Calculate cumulative weights */
+ element_sum[0] = 0.0f;
+ for (i=0; i<totelem; i++)
+ element_sum[i+1] = element_sum[i] + element_weight[i] * inv_totweight;
+
+ /* Finally assign elements to particles */
+ if ((part->flag&PART_TRAND) || (part->simplify_flag&PART_SIMPLIFY_ENABLE)) {
+ float pos;
+
+ for (p=0; p<totpart; p++) {
+ /* In theory element_sum[totelem] should be 1.0, but due to float errors this is not necessarily always true, so scale pos accordingly. */
+ pos= BLI_frand() * element_sum[totelem];
+ particle_element[p] = distribute_binary_search(element_sum, totelem, pos);
+ particle_element[p] = MIN2(totelem-1, particle_element[p]);
+ jitter_offset[particle_element[p]] = pos;
+ }
+ }
+ else {
+ double step, pos;
+
+ step= (totpart < 2) ? 0.5 : 1.0/(double)totpart;
+ pos= 1e-6; /* tiny offset to avoid zero weight face */
+ i= 0;
+
+ for (p=0; p<totpart; p++, pos+=step) {
+ while ((i < totelem) && (pos > (double)element_sum[i + 1]))
+ i++;
+
+ particle_element[p] = MIN2(totelem-1, i);
+
+ /* avoid zero weight face */
+ if (p == totpart-1 && element_weight[particle_element[p]] == 0.0f)
+ particle_element[p] = particle_element[p-1];
+
+ jitter_offset[particle_element[p]] = pos;
+ }
+ }
+
+ MEM_freeN(element_sum);
+
+ /* For hair, sort by origindex (allows optimization's in rendering), */
+ /* however with virtual parents the children need to be in random order. */
+ if (part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents!=0.0f)) {
+ int *orig_index = NULL;
+
+ if (from == PART_FROM_VERT) {
+ if (dm->numVertData)
+ orig_index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+ }
+ else {
+ if (dm->numTessFaceData)
+ orig_index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ }
+
+ if (orig_index) {
+ BLI_qsort_r(particle_element, totpart, sizeof(int), distribute_compare_orig_index, orig_index);
+ }
+ }
+
+ /* Create jittering if needed */
+ if (distr==PART_DISTR_JIT && ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
+ jitlevel= part->userjit;
+
+ if (jitlevel == 0) {
+ jitlevel= totpart/totelem;
+ if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */
+ if (jitlevel<3) jitlevel= 3;
+ }
+
+ jit= MEM_callocN((2+ jitlevel*2)*sizeof(float), "jit");
+
+ /* for small amounts of particles we use regular jitter since it looks
+ * a bit better, for larger amounts we switch to hammersley sequence
+ * because it is much faster */
+ if (jitlevel < 25)
+ init_mv_jit(jit, jitlevel, psys->seed, part->jitfac);
+ else
+ hammersley_create(jit, jitlevel+1, psys->seed, part->jitfac);
+ BLI_array_randomize(jit, 2*sizeof(float), jitlevel, psys->seed); /* for custom jit or even distribution */
+ }
+
+ /* Setup things for threaded distribution */
+ ctx->tree= tree;
+ ctx->seams= seams;
+ ctx->totseam= totseam;
+ ctx->sim.psys= psys;
+ ctx->index= particle_element;
+ ctx->jit= jit;
+ ctx->jitlevel= jitlevel;
+ ctx->jitoff= jitter_offset;
+ ctx->weight= element_weight;
+ ctx->maxweight= maxweight;
+ ctx->cfrom= cfrom;
+ ctx->distr= distr;
+ ctx->dm= dm;
+ ctx->tpars= tpars;
+
+ if (children) {
+ totpart= psys_render_simplify_distribution(ctx, totpart);
+ alloc_child_particles(psys, totpart);
+ }
+
+ return 1;
+}
+
+static void psys_task_init_distribute(ParticleTask *task, ParticleSimulationData *sim)
+{
+ /* init random number generator */
+ int seed = 31415926 + sim->psys->seed;
+
+ task->rng = BLI_rng_new(seed);
+}
+
+static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
+{
+ TaskScheduler *task_scheduler;
+ TaskPool *task_pool;
+ ParticleThreadContext ctx;
+ ParticleTask *tasks;
+ DerivedMesh *finaldm = sim->psmd->dm;
+ int i, totpart, numtasks;
+
+ /* create a task pool for distribution tasks */
+ if (!psys_thread_context_init_distribute(&ctx, sim, from))
+ return;
+
+ task_scheduler = BLI_task_scheduler_get();
+ task_pool = BLI_task_pool_create(task_scheduler, &ctx);
+
+ totpart = (from == PART_FROM_CHILD ? sim->psys->totchild : sim->psys->totpart);
+ psys_tasks_create(&ctx, totpart, &tasks, &numtasks);
+ for (i = 0; i < numtasks; ++i) {
+ ParticleTask *task = &tasks[i];
+
+ psys_task_init_distribute(task, sim);
+ if (from == PART_FROM_CHILD)
+ BLI_task_pool_push(task_pool, exec_distribute_child, task, false, TASK_PRIORITY_LOW);
+ else
+ BLI_task_pool_push(task_pool, exec_distribute_parent, task, false, TASK_PRIORITY_LOW);
+ }
+ BLI_task_pool_work_and_wait(task_pool);
+
+ BLI_task_pool_free(task_pool);
+
+ psys_calc_dmcache(sim->ob, finaldm, sim->psys);
+
+ if (ctx.dm != finaldm)
+ ctx.dm->release(ctx.dm);
+
+ psys_tasks_free(tasks, numtasks);
+
+ psys_thread_context_free(&ctx);
+}
+
+/* ready for future use, to emit particles without geometry */
+static void distribute_particles_on_shape(ParticleSimulationData *sim, int UNUSED(from))
+{
+ distribute_invalid(sim->scene, sim->psys, 0);
+
+ fprintf(stderr,"Shape emission not yet possible!\n");
+}
+
+void distribute_particles(ParticleSimulationData *sim, int from)
+{
+ PARTICLE_PSMD;
+ int distr_error=0;
+
+ if (psmd) {
+ if (psmd->dm)
+ distribute_particles_on_dm(sim, from);
+ else
+ distr_error=1;
+ }
+ else
+ distribute_particles_on_shape(sim, from);
+
+ if (distr_error) {
+ distribute_invalid(sim->scene, sim->psys, from);
+
+ fprintf(stderr,"Particle distribution error!\n");
+ }
+}
+
+/* ======== Simplify ======== */
+
+static float psys_render_viewport_falloff(double rate, float dist, float width)
+{
+ return pow(rate, dist / width);
+}
+
+static float psys_render_projected_area(ParticleSystem *psys, const float center[3], float area, double vprate, float *viewport)
+{
+ ParticleRenderData *data = psys->renderdata;
+ float co[4], view[3], ortho1[3], ortho2[3], w, dx, dy, radius;
+
+ /* transform to view space */
+ copy_v3_v3(co, center);
+ co[3] = 1.0f;
+ mul_m4_v4(data->viewmat, co);
+
+ /* compute two vectors orthogonal to view vector */
+ normalize_v3_v3(view, co);
+ ortho_basis_v3v3_v3(ortho1, ortho2, view);
+
+ /* compute on screen minification */
+ w = co[2] * data->winmat[2][3] + data->winmat[3][3];
+ dx = data->winx * ortho2[0] * data->winmat[0][0];
+ dy = data->winy * ortho2[1] * data->winmat[1][1];
+ w = sqrtf(dx * dx + dy * dy) / w;
+
+ /* w squared because we are working with area */
+ area = area * w * w;
+
+ /* viewport of the screen test */
+
+ /* project point on screen */
+ mul_m4_v4(data->winmat, co);
+ if (co[3] != 0.0f) {
+ co[0] = 0.5f * data->winx * (1.0f + co[0] / co[3]);
+ co[1] = 0.5f * data->winy * (1.0f + co[1] / co[3]);
+ }
+
+ /* screen space radius */
+ radius = sqrtf(area / (float)M_PI);
+
+ /* make smaller using fallof once over screen edge */
+ *viewport = 1.0f;
+
+ if (co[0] + radius < 0.0f)
+ *viewport *= psys_render_viewport_falloff(vprate, -(co[0] + radius), data->winx);
+ else if (co[0] - radius > data->winx)
+ *viewport *= psys_render_viewport_falloff(vprate, (co[0] - radius) - data->winx, data->winx);
+
+ if (co[1] + radius < 0.0f)
+ *viewport *= psys_render_viewport_falloff(vprate, -(co[1] + radius), data->winy);
+ else if (co[1] - radius > data->winy)
+ *viewport *= psys_render_viewport_falloff(vprate, (co[1] - radius) - data->winy, data->winy);
+
+ return area;
+}
+
+/* BMESH_TODO, for orig face data, we need to use MPoly */
+static int psys_render_simplify_distribution(ParticleThreadContext *ctx, int tot)
+{
+ DerivedMesh *dm = ctx->dm;
+ Mesh *me = (Mesh *)(ctx->sim.ob->data);
+ MFace *mf, *mface;
+ MVert *mvert;
+ ParticleRenderData *data;
+ ParticleRenderElem *elems, *elem;
+ ParticleSettings *part = ctx->sim.psys->part;
+ float *facearea, (*facecenter)[3], size[3], fac, powrate, scaleclamp;
+ float co1[3], co2[3], co3[3], co4[3], lambda, arearatio, t, area, viewport;
+ double vprate;
+ int *facetotvert;
+ int a, b, totorigface, totface, newtot, skipped;
+
+ /* double lookup */
+ const int *index_mf_to_mpoly;
+ const int *index_mp_to_orig;
+
+ if (part->ren_as != PART_DRAW_PATH || !(part->draw & PART_DRAW_REN_STRAND))
+ return tot;
+ if (!ctx->sim.psys->renderdata)
+ return tot;
+
+ data = ctx->sim.psys->renderdata;
+ if (data->timeoffset)
+ return 0;
+ if (!(part->simplify_flag & PART_SIMPLIFY_ENABLE))
+ return tot;
+
+ mvert = dm->getVertArray(dm);
+ mface = dm->getTessFaceArray(dm);
+ totface = dm->getNumTessFaces(dm);
+ totorigface = me->totpoly;
+
+ if (totface == 0 || totorigface == 0)
+ return tot;
+
+ index_mf_to_mpoly = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+ index_mp_to_orig = dm->getPolyDataArray(dm, CD_ORIGINDEX);
+ if (index_mf_to_mpoly == NULL) {
+ index_mp_to_orig = NULL;
+ }
+
+ facearea = MEM_callocN(sizeof(float) * totorigface, "SimplifyFaceArea");
+ facecenter = MEM_callocN(sizeof(float[3]) * totorigface, "SimplifyFaceCenter");
+ facetotvert = MEM_callocN(sizeof(int) * totorigface, "SimplifyFaceArea");
+ elems = MEM_callocN(sizeof(ParticleRenderElem) * totorigface, "SimplifyFaceElem");
+
+ if (data->elems)
+ MEM_freeN(data->elems);
+
+ data->do_simplify = true;
+ data->elems = elems;
+ data->index_mf_to_mpoly = index_mf_to_mpoly;
+ data->index_mp_to_orig = index_mp_to_orig;
+
+ /* compute number of children per original face */
+ for (a = 0; a < tot; a++) {
+ b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
+ if (b != ORIGINDEX_NONE) {
+ elems[b].totchild++;
+ }
+ }
+
+ /* compute areas and centers of original faces */
+ for (mf = mface, a = 0; a < totface; a++, mf++) {
+ b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, a) : a;
+
+ if (b != ORIGINDEX_NONE) {
+ copy_v3_v3(co1, mvert[mf->v1].co);
+ copy_v3_v3(co2, mvert[mf->v2].co);
+ copy_v3_v3(co3, mvert[mf->v3].co);
+
+ add_v3_v3(facecenter[b], co1);
+ add_v3_v3(facecenter[b], co2);
+ add_v3_v3(facecenter[b], co3);
+
+ if (mf->v4) {
+ copy_v3_v3(co4, mvert[mf->v4].co);
+ add_v3_v3(facecenter[b], co4);
+ facearea[b] += area_quad_v3(co1, co2, co3, co4);
+ facetotvert[b] += 4;
+ }
+ else {
+ facearea[b] += area_tri_v3(co1, co2, co3);
+ facetotvert[b] += 3;
+ }
+ }
+ }
+
+ for (a = 0; a < totorigface; a++)
+ if (facetotvert[a] > 0)
+ mul_v3_fl(facecenter[a], 1.0f / facetotvert[a]);
+
+ /* for conversion from BU area / pixel area to reference screen size */
+ BKE_mesh_texspace_get(me, 0, 0, size);
+ fac = ((size[0] + size[1] + size[2]) / 3.0f) / part->simplify_refsize;
+ fac = fac * fac;
+
+ powrate = log(0.5f) / log(part->simplify_rate * 0.5f);
+ if (part->simplify_flag & PART_SIMPLIFY_VIEWPORT)
+ vprate = pow(1.0f - part->simplify_viewport, 5.0);
+ else
+ vprate = 1.0;
+
+ /* set simplification parameters per original face */
+ for (a = 0, elem = elems; a < totorigface; a++, elem++) {
+ area = psys_render_projected_area(ctx->sim.psys, facecenter[a], facearea[a], vprate, &viewport);
+ arearatio = fac * area / facearea[a];
+
+ if ((arearatio < 1.0f || viewport < 1.0f) && elem->totchild) {
+ /* lambda is percentage of elements to keep */
+ lambda = (arearatio < 1.0f) ? powf(arearatio, powrate) : 1.0f;
+ lambda *= viewport;
+
+ lambda = MAX2(lambda, 1.0f / elem->totchild);
+
+ /* compute transition region */
+ t = part->simplify_transition;
+ elem->t = (lambda - t < 0.0f) ? lambda : (lambda + t > 1.0f) ? 1.0f - lambda : t;
+ elem->reduce = 1;
+
+ /* scale at end and beginning of the transition region */
+ 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 = sqrtf(elem->scalemin);
+ elem->scalemax = sqrtf(elem->scalemax);
+
+ /* clamp scaling */
+ scaleclamp = (float)min_ii(elem->totchild, 10);
+ elem->scalemin = MIN2(scaleclamp, elem->scalemin);
+ elem->scalemax = MIN2(scaleclamp, elem->scalemax);
+
+ /* extend lambda to include transition */
+ lambda = lambda + elem->t;
+ if (lambda > 1.0f)
+ lambda = 1.0f;
+ }
+ else {
+ lambda = arearatio;
+
+ elem->scalemax = 1.0f; //sqrt(lambda);
+ elem->scalemin = 1.0f; //sqrt(lambda);
+ elem->reduce = 0;
+ }
+
+ elem->lambda = lambda;
+ elem->scalemin = sqrtf(elem->scalemin);
+ elem->scalemax = sqrtf(elem->scalemax);
+ elem->curchild = 0;
+ }
+
+ MEM_freeN(facearea);
+ MEM_freeN(facecenter);
+ MEM_freeN(facetotvert);
+
+ /* move indices and set random number skipping */
+ ctx->skip = MEM_callocN(sizeof(int) * tot, "SimplificationSkip");
+
+ skipped = 0;
+ for (a = 0, newtot = 0; a < tot; a++) {
+ b = (index_mf_to_mpoly) ? DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig, ctx->index[a]) : ctx->index[a];
+
+ if (b != ORIGINDEX_NONE) {
+ if (elems[b].curchild++ < ceil(elems[b].lambda * elems[b].totchild)) {
+ ctx->index[newtot] = ctx->index[a];
+ ctx->skip[newtot] = skipped;
+ skipped = 0;
+ newtot++;
+ }
+ else skipped++;
+ }
+ else skipped++;
+ }
+
+ for (a = 0, elem = elems; a < totorigface; a++, elem++)
+ elem->curchild = 0;
+
+ return newtot;
+}
diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c
index 2a71cf2780f..dcae5972c61 100644
--- a/source/blender/blenkernel/intern/particle_system.c
+++ b/source/blender/blenkernel/intern/particle_system.c
@@ -69,6 +69,7 @@
#include "BLI_kdtree.h"
#include "BLI_kdopbvh.h"
#include "BLI_sort.h"
+#include "BLI_task.h"
#include "BLI_threads.h"
#include "BLI_linklist.h"
@@ -281,7 +282,7 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart)
}
}
-static int get_psys_child_number(struct Scene *scene, ParticleSystem *psys)
+int psys_get_child_number(Scene *scene, ParticleSystem *psys)
{
int nbr;
@@ -296,30 +297,9 @@ static int get_psys_child_number(struct Scene *scene, ParticleSystem *psys)
return get_render_child_particle_number(&scene->r, nbr);
}
-static int get_psys_tot_child(struct Scene *scene, ParticleSystem *psys)
+int psys_get_tot_child(Scene *scene, ParticleSystem *psys)
{
- return psys->totpart*get_psys_child_number(scene, psys);
-}
-
-static void alloc_child_particles(ParticleSystem *psys, int tot)
-{
- if (psys->child) {
- /* only re-allocate if we have to */
- if (psys->part->childtype && psys->totchild == tot) {
- memset(psys->child, 0, tot*sizeof(ChildParticle));
- return;
- }
-
- MEM_freeN(psys->child);
- psys->child=NULL;
- psys->totchild=0;
- }
-
- if (psys->part->childtype) {
- psys->totchild= tot;
- if (psys->totchild)
- psys->child= MEM_callocN(psys->totchild*sizeof(ChildParticle), "child_particles");
- }
+ return psys->totpart*psys_get_child_number(scene, psys);
}
/************************************************/
@@ -449,1053 +429,60 @@ void psys_calc_dmcache(Object *ob, DerivedMesh *dm, ParticleSystem *psys)
}
}
-static void distribute_simple_children(Scene *scene, Object *ob, DerivedMesh *finaldm, ParticleSystem *psys)
-{
- ChildParticle *cpa = NULL;
- int i, p;
- int child_nbr= get_psys_child_number(scene, psys);
- int totpart= get_psys_tot_child(scene, psys);
-
- alloc_child_particles(psys, totpart);
-
- cpa = psys->child;
- for (i=0; i<child_nbr; i++) {
- for (p=0; p<psys->totpart; p++,cpa++) {
- float length=2.0;
- cpa->parent=p;
-
- /* create even spherical distribution inside unit sphere */
- while (length>=1.0f) {
- cpa->fuv[0]=2.0f*BLI_frand()-1.0f;
- cpa->fuv[1]=2.0f*BLI_frand()-1.0f;
- cpa->fuv[2]=2.0f*BLI_frand()-1.0f;
- length=len_v3(cpa->fuv);
- }
-
- cpa->num=-1;
- }
- }
- /* dmcache must be updated for parent particles if children from faces is used */
- psys_calc_dmcache(ob, finaldm, psys);
-}
-static void distribute_grid(DerivedMesh *dm, ParticleSystem *psys)
-{
- ParticleData *pa=NULL;
- float min[3], max[3], delta[3], d;
- MVert *mv, *mvert = dm->getVertDataArray(dm,0);
- int totvert=dm->getNumVerts(dm), from=psys->part->from;
- int i, j, k, p, res=psys->part->grid_res, size[3], axis;
-
- /* find bounding box of dm */
- if (totvert > 0) {
- mv=mvert;
- copy_v3_v3(min, mv->co);
- copy_v3_v3(max, mv->co);
- mv++;
- for (i = 1; i < totvert; i++, mv++) {
- minmax_v3v3_v3(min, max, mv->co);
- }
- }
- else {
- zero_v3(min);
- zero_v3(max);
- }
-
- sub_v3_v3v3(delta, max, min);
-
- /* determine major axis */
- axis = axis_dominant_v3_single(delta);
-
- d = delta[axis]/(float)res;
-
- size[axis] = res;
- size[(axis+1)%3] = (int)ceil(delta[(axis+1)%3]/d);
- size[(axis+2)%3] = (int)ceil(delta[(axis+2)%3]/d);
-
- /* float errors grrr.. */
- size[(axis+1)%3] = MIN2(size[(axis+1)%3],res);
- size[(axis+2)%3] = MIN2(size[(axis+2)%3],res);
-
- size[0] = MAX2(size[0], 1);
- size[1] = MAX2(size[1], 1);
- size[2] = MAX2(size[2], 1);
-
- /* no full offset for flat/thin objects */
- min[0]+= d < delta[0] ? d/2.f : delta[0]/2.f;
- min[1]+= d < delta[1] ? d/2.f : delta[1]/2.f;
- min[2]+= d < delta[2] ? d/2.f : delta[2]/2.f;
-
- for (i=0,p=0,pa=psys->particles; i<res; i++) {
- for (j=0; j<res; j++) {
- for (k=0; k<res; k++,p++,pa++) {
- pa->fuv[0] = min[0] + (float)i*d;
- pa->fuv[1] = min[1] + (float)j*d;
- pa->fuv[2] = min[2] + (float)k*d;
- pa->flag |= PARS_UNEXIST;
- pa->hair_index = 0; /* abused in volume calculation */
- }
- }
- }
-
- /* enable particles near verts/edges/faces/inside surface */
- if (from==PART_FROM_VERT) {
- float vec[3];
-
- pa=psys->particles;
-
- min[0] -= d/2.0f;
- min[1] -= d/2.0f;
- min[2] -= d/2.0f;
-
- for (i=0,mv=mvert; i<totvert; i++,mv++) {
- sub_v3_v3v3(vec,mv->co,min);
- vec[0]/=delta[0];
- vec[1]/=delta[1];
- vec[2]/=delta[2];
- pa[((int)(vec[0] * (size[0] - 1)) * res +
- (int)(vec[1] * (size[1] - 1))) * res +
- (int)(vec[2] * (size[2] - 1))].flag &= ~PARS_UNEXIST;
- }
- }
- else if (ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
- float co1[3], co2[3];
-
- MFace *mface= NULL, *mface_array;
- float v1[3], v2[3], v3[3], v4[4], lambda;
- int a, a1, a2, a0mul, a1mul, a2mul, totface;
- int amax= from==PART_FROM_FACE ? 3 : 1;
-
- totface=dm->getNumTessFaces(dm);
- mface=mface_array=dm->getTessFaceDataArray(dm,CD_MFACE);
-
- for (a=0; a<amax; a++) {
- if (a==0) { a0mul=res*res; a1mul=res; a2mul=1; }
- else if (a==1) { a0mul=res; a1mul=1; a2mul=res*res; }
- else { a0mul=1; a1mul=res*res; a2mul=res; }
-
- for (a1=0; a1<size[(a+1)%3]; a1++) {
- for (a2=0; a2<size[(a+2)%3]; a2++) {
- mface= mface_array;
-
- pa = psys->particles + a1*a1mul + a2*a2mul;
- copy_v3_v3(co1, pa->fuv);
- co1[a] -= d < delta[a] ? d/2.f : delta[a]/2.f;
- copy_v3_v3(co2, co1);
- co2[a] += delta[a] + 0.001f*d;
- co1[a] -= 0.001f*d;
-
- /* lets intersect the faces */
- for (i=0; i<totface; i++,mface++) {
- copy_v3_v3(v1, mvert[mface->v1].co);
- copy_v3_v3(v2, mvert[mface->v2].co);
- copy_v3_v3(v3, mvert[mface->v3].co);
-
- if (isect_axial_line_tri_v3(a, co1, co2, v2, v3, v1, &lambda)) {
- if (from==PART_FROM_FACE)
- (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
- else /* store number of intersections */
- (pa+(int)(lambda*size[a])*a0mul)->hair_index++;
- }
- else if (mface->v4) {
- copy_v3_v3(v4, mvert[mface->v4].co);
-
- if (isect_axial_line_tri_v3(a, co1, co2, v4, v1, v3, &lambda)) {
- if (from==PART_FROM_FACE)
- (pa+(int)(lambda*size[a])*a0mul)->flag &= ~PARS_UNEXIST;
- else
- (pa+(int)(lambda*size[a])*a0mul)->hair_index++;
- }
- }
- }
-
- if (from==PART_FROM_VOLUME) {
- int in=pa->hair_index%2;
- if (in) pa->hair_index++;
- for (i=0; i<size[0]; i++) {
- if (in || (pa+i*a0mul)->hair_index%2)
- (pa+i*a0mul)->flag &= ~PARS_UNEXIST;
- /* odd intersections == in->out / out->in */
- /* even intersections -> in stays same */
- in=(in + (pa+i*a0mul)->hair_index) % 2;
- }
- }
- }
- }
- }
- }
-
- if (psys->part->flag & PART_GRID_HEXAGONAL) {
- for (i=0,p=0,pa=psys->particles; i<res; i++) {
- for (j=0; j<res; j++) {
- for (k=0; k<res; k++,p++,pa++) {
- if (j%2)
- pa->fuv[0] += d/2.f;
-
- if (k%2) {
- pa->fuv[0] += d/2.f;
- pa->fuv[1] += d/2.f;
- }
- }
- }
- }
- }
-
- if (psys->part->flag & PART_GRID_INVERT) {
- for (i=0; i<size[0]; i++) {
- for (j=0; j<size[1]; j++) {
- pa=psys->particles + res*(i*res + j);
- for (k=0; k<size[2]; k++, pa++) {
- pa->flag ^= PARS_UNEXIST;
- }
- }
- }
- }
-
- if (psys->part->grid_rand > 0.f) {
- float rfac = d * psys->part->grid_rand;
- for (p=0,pa=psys->particles; p<psys->totpart; p++,pa++) {
- if (pa->flag & PARS_UNEXIST)
- continue;
-
- pa->fuv[0] += rfac * (psys_frand(psys, p + 31) - 0.5f);
- pa->fuv[1] += rfac * (psys_frand(psys, p + 32) - 0.5f);
- pa->fuv[2] += rfac * (psys_frand(psys, p + 33) - 0.5f);
- }
- }
-}
-
-/* modified copy from rayshade.c */
-static void hammersley_create(float *out, int n, int seed, float amount)
-{
- RNG *rng;
- double p, t, offs[2];
- int k, kk;
-
- rng = BLI_rng_new(31415926 + n + seed);
- offs[0] = BLI_rng_get_double(rng) + (double)amount;
- offs[1] = BLI_rng_get_double(rng) + (double)amount;
- BLI_rng_free(rng);
-
- for (k = 0; k < n; k++) {
- t = 0;
- for (p = 0.5, kk = k; kk; p *= 0.5, kk >>= 1)
- if (kk & 1) /* kk mod 2 = 1 */
- t += p;
-
- out[2*k + 0] = fmod((double)k/(double)n + offs[0], 1.0);
- out[2*k + 1] = fmod(t + offs[1], 1.0);
- }
-}
-
-/* almost exact copy of BLI_jitter_init */
-static void init_mv_jit(float *jit, int num, int seed2, float amount)
-{
- RNG *rng;
- float *jit2, x, rad1, rad2, rad3;
- int i, num2;
-
- if (num==0) return;
-
- rad1= (float)(1.0f/sqrtf((float)num));
- rad2= (float)(1.0f/((float)num));
- rad3= (float)sqrtf((float)num)/((float)num);
-
- rng = BLI_rng_new(31415926 + num + seed2);
- x= 0;
- num2 = 2 * num;
- for (i=0; i<num2; i+=2) {
-
- jit[i] = x + amount*rad1*(0.5f - BLI_rng_get_float(rng));
- jit[i+1] = i/(2.0f*num) + amount*rad1*(0.5f - BLI_rng_get_float(rng));
-
- jit[i]-= (float)floor(jit[i]);
- jit[i+1]-= (float)floor(jit[i+1]);
-
- x+= rad3;
- x -= (float)floor(x);
- }
-
- jit2= MEM_mallocN(12 + 2*sizeof(float)*num, "initjit");
-
- for (i=0 ; i<4 ; i++) {
- BLI_jitterate1((float (*)[2])jit, (float (*)[2])jit2, num, rad1);
- BLI_jitterate1((float (*)[2])jit, (float (*)[2])jit2, num, rad1);
- BLI_jitterate2((float (*)[2])jit, (float (*)[2])jit2, num, rad2);
- }
- MEM_freeN(jit2);
- BLI_rng_free(rng);
-}
-
-static void psys_uv_to_w(float u, float v, int quad, float *w)
-{
- float vert[4][3], co[3];
-
- if (!quad) {
- if (u+v > 1.0f)
- v= 1.0f-v;
- else
- u= 1.0f-u;
- }
-
- vert[0][0] = 0.0f; vert[0][1] = 0.0f; vert[0][2] = 0.0f;
- vert[1][0] = 1.0f; vert[1][1] = 0.0f; vert[1][2] = 0.0f;
- vert[2][0] = 1.0f; vert[2][1] = 1.0f; vert[2][2] = 0.0f;
-
- co[0] = u;
- co[1] = v;
- co[2] = 0.0f;
-
- if (quad) {
- vert[3][0] = 0.0f; vert[3][1] = 1.0f; vert[3][2] = 0.0f;
- interp_weights_poly_v3( w,vert, 4, co);
- }
- else {
- interp_weights_poly_v3( w,vert, 3, co);
- w[3] = 0.0f;
- }
-}
-
-/* Find the index in "sum" array before "value" is crossed. */
-static int distribute_binary_search(float *sum, int n, float value)
-{
- int mid, low=0, high=n;
-
- if (value == 0.f)
- return 0;
-
- while (low <= high) {
- mid= (low + high)/2;
-
- if (sum[mid] < value && value <= sum[mid+1])
- return mid;
-
- if (sum[mid] >= value)
- high= mid - 1;
- else if (sum[mid] < value)
- low= mid + 1;
- else
- return mid;
- }
-
- return low;
-}
-
-/* the max number if calls to rng_* funcs within psys_thread_distribute_particle
- * be sure to keep up to date if this changes */
-#define PSYS_RND_DIST_SKIP 2
-
-/* note: this function must be thread safe, for from == PART_FROM_CHILD */
-#define ONLY_WORKING_WITH_PA_VERTS 0
-static void distribute_threads_exec(ParticleThread *thread, ParticleData *pa, ChildParticle *cpa, int p)
-{
- ParticleThreadContext *ctx= thread->ctx;
- Object *ob= ctx->sim.ob;
- DerivedMesh *dm= ctx->dm;
- float *v1, *v2, *v3, *v4, nor[3], orco1[3], co1[3], co2[3], nor1[3];
- float cur_d, min_d, randu, randv;
- int from= ctx->from;
- int cfrom= ctx->cfrom;
- int distr= ctx->distr;
- int i, intersect, tot;
- int rng_skip_tot= PSYS_RND_DIST_SKIP; /* count how many rng_* calls wont need skipping */
-
- if (from == PART_FROM_VERT) {
- /* TODO_PARTICLE - use original index */
- pa->num= ctx->index[p];
- pa->fuv[0] = 1.0f;
- pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
-
-#if ONLY_WORKING_WITH_PA_VERTS
- if (ctx->tree) {
- KDTreeNearest ptn[3];
- int w, maxw;
-
- psys_particle_on_dm(ctx->dm,from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co1,0,0,0,orco1,0);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
- maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
-
- for (w=0; w<maxw; w++) {
- pa->verts[w]=ptn->num;
- }
- }
-#endif
- }
- else if (from == PART_FROM_FACE || from == PART_FROM_VOLUME) {
- MFace *mface;
-
- pa->num = i = ctx->index[p];
- mface = dm->getTessFaceData(dm,i,CD_MFACE);
-
- switch (distr) {
- case PART_DISTR_JIT:
- if (ctx->jitlevel == 1) {
- if (mface->v4)
- psys_uv_to_w(0.5f, 0.5f, mface->v4, pa->fuv);
- else
- psys_uv_to_w(1.0f / 3.0f, 1.0f / 3.0f, mface->v4, pa->fuv);
- }
- else {
- ctx->jitoff[i] = fmod(ctx->jitoff[i],(float)ctx->jitlevel);
- if (!isnan(ctx->jitoff[i])) {
- psys_uv_to_w(ctx->jit[2*(int)ctx->jitoff[i]], ctx->jit[2*(int)ctx->jitoff[i]+1], mface->v4, pa->fuv);
- ctx->jitoff[i]++;
- }
- }
- break;
- case PART_DISTR_RAND:
- randu= BLI_rng_get_float(thread->rng);
- randv= BLI_rng_get_float(thread->rng);
- rng_skip_tot -= 2;
-
- psys_uv_to_w(randu, randv, mface->v4, pa->fuv);
- break;
- }
- pa->foffset= 0.0f;
-
- /* experimental */
- if (from==PART_FROM_VOLUME) {
- MVert *mvert=dm->getVertDataArray(dm,CD_MVERT);
-
- tot=dm->getNumTessFaces(dm);
-
- psys_interpolate_face(mvert,mface,0,0,pa->fuv,co1,nor,0,0,0,0);
-
- normalize_v3(nor);
- mul_v3_fl(nor,-100.0);
-
- add_v3_v3v3(co2,co1,nor);
-
- min_d=2.0;
- intersect=0;
-
- for (i=0,mface=dm->getTessFaceDataArray(dm,CD_MFACE); i<tot; i++,mface++) {
- if (i==pa->num) continue;
-
- v1=mvert[mface->v1].co;
- v2=mvert[mface->v2].co;
- v3=mvert[mface->v3].co;
-
- if (isect_line_tri_v3(co1, co2, v2, v3, v1, &cur_d, 0)) {
- if (cur_d<min_d) {
- min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
- intersect=1;
- }
- }
- if (mface->v4) {
- v4=mvert[mface->v4].co;
-
- if (isect_line_tri_v3(co1, co2, v4, v1, v3, &cur_d, 0)) {
- if (cur_d<min_d) {
- min_d=cur_d;
- pa->foffset=cur_d*50.0f; /* to the middle of volume */
- intersect=1;
- }
- }
- }
- }
- if (intersect==0)
- pa->foffset=0.0;
- else {
- switch (distr) {
- case PART_DISTR_JIT:
- pa->foffset *= ctx->jit[p % (2 * ctx->jitlevel)];
- break;
- case PART_DISTR_RAND:
- pa->foffset *= BLI_frand();
- break;
- }
- }
- }
- }
- else if (from == PART_FROM_CHILD) {
- MFace *mf;
-
- if (ctx->index[p] < 0) {
- cpa->num=0;
- cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3]=0.0f;
- cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
- return;
- }
-
- mf= dm->getTessFaceData(dm, ctx->index[p], CD_MFACE);
-
- randu= BLI_rng_get_float(thread->rng);
- randv= BLI_rng_get_float(thread->rng);
- rng_skip_tot -= 2;
-
- psys_uv_to_w(randu, randv, mf->v4, cpa->fuv);
-
- cpa->num = ctx->index[p];
-
- if (ctx->tree) {
- KDTreeNearest ptn[10];
- int w,maxw;//, do_seams;
- float maxd /*, mind,dd */, totw= 0.0f;
- int parent[10];
- float pweight[10];
-
- psys_particle_on_dm(dm,cfrom,cpa->num,DMCACHE_ISCHILD,cpa->fuv,cpa->foffset,co1,nor1,NULL,NULL,orco1,NULL);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco1, 1, 1);
- maxw = BLI_kdtree_find_nearest_n(ctx->tree,orco1,ptn,3);
-
- maxd=ptn[maxw-1].dist;
- /* mind=ptn[0].dist; */ /* UNUSED */
-
- /* the weights here could be done better */
- for (w=0; w<maxw; w++) {
- parent[w]=ptn[w].index;
- pweight[w]=(float)pow(2.0,(double)(-6.0f*ptn[w].dist/maxd));
- }
- for (;w<10; w++) {
- parent[w]=-1;
- pweight[w]=0.0f;
- }
-
- for (w=0,i=0; w<maxw && i<4; w++) {
- if (parent[w]>=0) {
- cpa->pa[i]=parent[w];
- cpa->w[i]=pweight[w];
- totw+=pweight[w];
- i++;
- }
- }
- for (;i<4; i++) {
- cpa->pa[i]=-1;
- cpa->w[i]=0.0f;
- }
-
- if (totw>0.0f) for (w=0; w<4; w++)
- cpa->w[w]/=totw;
-
- cpa->parent=cpa->pa[0];
- }
- }
-
- if (rng_skip_tot > 0) /* should never be below zero */
- BLI_rng_skip(thread->rng, rng_skip_tot);
-}
-
-static void *distribute_threads_exec_cb(void *data)
+/* threaded child particle distribution and path caching */
+void psys_thread_context_init(ParticleThreadContext *ctx, ParticleSimulationData *sim)
{
- ParticleThread *thread= (ParticleThread*)data;
- ParticleSystem *psys= thread->ctx->sim.psys;
- ParticleData *pa;
- ChildParticle *cpa;
- int p, totpart;
-
- if (thread->ctx->from == PART_FROM_CHILD) {
- totpart= psys->totchild;
- cpa= psys->child;
-
- for (p=0; p<totpart; p++, cpa++) {
- if (thread->ctx->skip) /* simplification skip */
- BLI_rng_skip(thread->rng, PSYS_RND_DIST_SKIP * thread->ctx->skip[p]);
-
- if ((p+thread->num) % thread->tot == 0)
- distribute_threads_exec(thread, NULL, cpa, p);
- else /* thread skip */
- BLI_rng_skip(thread->rng, PSYS_RND_DIST_SKIP);
- }
- }
- else {
- totpart= psys->totpart;
- pa= psys->particles + thread->num;
- for (p=thread->num; p<totpart; p+=thread->tot, pa+=thread->tot)
- distribute_threads_exec(thread, pa, NULL, p);
- }
-
- return 0;
+ memset(ctx, 0, sizeof(ParticleThreadContext));
+ ctx->sim = *sim;
+ ctx->dm = ctx->sim.psmd->dm;
+ ctx->ma = give_current_material(sim->ob, sim->psys->part->omat);
}
-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];
- int index2 = orig_index[*(const int *)p2];
-
- if (index1 < index2)
- return -1;
- else if (index1 == index2) {
- /* this pointer comparison appears to make qsort stable for glibc,
- * and apparently on solaris too, makes the renders reproducible */
- if (p1 < p2)
- return -1;
- else if (p1 == p2)
- return 0;
- else
- return 1;
- }
- else
- return 1;
-}
+#define MAX_PARTICLES_PER_TASK 256 /* XXX arbitrary - maybe use at least number of points instead for better balancing? */
-static void distribute_invalid(Scene *scene, ParticleSystem *psys, int from)
+BLI_INLINE int ceil_ii(int a, int b)
{
- if (from == PART_FROM_CHILD) {
- ChildParticle *cpa;
- int p, totchild = get_psys_tot_child(scene, psys);
-
- if (psys->child && totchild) {
- for (p=0,cpa=psys->child; p<totchild; p++,cpa++) {
- cpa->fuv[0]=cpa->fuv[1]=cpa->fuv[2]=cpa->fuv[3] = 0.0;
- cpa->foffset= 0.0f;
- cpa->parent=0;
- cpa->pa[0]=cpa->pa[1]=cpa->pa[2]=cpa->pa[3]=0;
- cpa->num= -1;
- }
- }
- }
- else {
- PARTICLE_P;
- LOOP_PARTICLES {
- pa->fuv[0] = pa->fuv[1] = pa->fuv[2] = pa->fuv[3] = 0.0;
- pa->foffset= 0.0f;
- pa->num= -1;
- }
- }
+ return (a + b - 1) / b;
}
-/* Creates a distribution of coordinates on a DerivedMesh */
-/* This is to denote functionality that does not yet work with mesh - only derived mesh */
-static int distribute_threads_init_data(ParticleThread *threads, Scene *scene, DerivedMesh *finaldm, int from)
+void psys_tasks_create(ParticleThreadContext *ctx, int totpart, ParticleTask **r_tasks, int *r_numtasks)
{
- ParticleThreadContext *ctx= threads[0].ctx;
- Object *ob= ctx->sim.ob;
- ParticleSystem *psys= ctx->sim.psys;
- ParticleData *pa=0, *tpars= 0;
- ParticleSettings *part;
- ParticleSeam *seams= 0;
- KDTree *tree=0;
- DerivedMesh *dm= NULL;
- float *jit= NULL;
- int i, seed, p=0, totthread= threads[0].tot;
- int cfrom=0;
- int totelem=0, totpart, *particle_element=0, children=0, totseam=0;
- int jitlevel= 1, distr;
- 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 (ELEM(NULL, ob, psys, psys->part))
- return 0;
-
- part=psys->part;
- totpart=psys->totpart;
- if (totpart==0)
- return 0;
-
- if (!finaldm->deformedOnly && !finaldm->getTessFaceDataArray(finaldm, CD_ORIGINDEX)) {
- printf("Can't create particles with the current modifier stack, disable destructive modifiers\n");
-// XXX error("Can't paint with the current modifier stack, disable destructive modifiers");
- return 0;
- }
-
- /* First handle special cases */
- if (from == PART_FROM_CHILD) {
- /* Simple children */
- if (part->childtype != PART_CHILD_FACES) {
- BLI_srandom(31415926 + psys->seed + psys->child_seed);
- distribute_simple_children(scene, ob, finaldm, psys);
- return 0;
- }
- }
- else {
- /* Grid distribution */
- if (part->distr==PART_DISTR_GRID && from != PART_FROM_VERT) {
- BLI_srandom(31415926 + psys->seed);
- dm= CDDM_from_mesh((Mesh*)ob->data);
- DM_ensure_tessface(dm);
- distribute_grid(dm,psys);
- dm->release(dm);
- return 0;
- }
- }
+ ParticleTask *tasks;
+ int numtasks = ceil_ii(totpart, MAX_PARTICLES_PER_TASK);
+ float particles_per_task = (float)totpart / (float)numtasks, p, pnext;
+ int i;
- /* Create trees and original coordinates if needed */
- if (from == PART_FROM_CHILD) {
- distr=PART_DISTR_RAND;
- BLI_srandom(31415926 + psys->seed + psys->child_seed);
- dm= finaldm;
-
- /* BMESH ONLY */
- DM_ensure_tessface(dm);
-
- children=1;
-
- tree=BLI_kdtree_new(totpart);
-
- for (p=0,pa=psys->particles; p<totpart; p++,pa++) {
- psys_particle_on_dm(dm,part->from,pa->num,pa->num_dmcache,pa->fuv,pa->foffset,co,nor,0,0,orco,NULL);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &orco, 1, 1);
- BLI_kdtree_insert(tree, p, orco);
- }
-
- BLI_kdtree_balance(tree);
-
- totpart = get_psys_tot_child(scene, psys);
- cfrom = from = PART_FROM_FACE;
- }
- else {
- distr = part->distr;
- BLI_srandom(31415926 + psys->seed);
-
- if (psys->part->use_modifier_stack)
- dm = finaldm;
- else
- dm= CDDM_from_mesh((Mesh*)ob->data);
-
- /* BMESH ONLY, for verts we don't care about tessfaces */
- if (from != PART_FROM_VERT) {
- DM_ensure_tessface(dm);
- }
-
- /* we need orco for consistent distributions */
- if (!CustomData_has_layer(&dm->vertData, CD_ORCO))
- DM_add_vert_layer(dm, CD_ORCO, CD_ASSIGN, BKE_mesh_orco_verts_get(ob));
-
- if (from == PART_FROM_VERT) {
- MVert *mv= dm->getVertDataArray(dm, CD_MVERT);
- float (*orcodata)[3] = dm->getVertDataArray(dm, CD_ORCO);
- int totvert = dm->getNumVerts(dm);
-
- tree=BLI_kdtree_new(totvert);
-
- for (p=0; p<totvert; p++) {
- if (orcodata) {
- copy_v3_v3(co,orcodata[p]);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co, 1, 1);
- }
- else
- copy_v3_v3(co,mv[p].co);
- BLI_kdtree_insert(tree, p, co);
- }
-
- BLI_kdtree_balance(tree);
- }
- }
-
- /* Get total number of emission elements and allocate needed arrays */
- totelem = (from == PART_FROM_VERT) ? dm->getNumVerts(dm) : dm->getNumTessFaces(dm);
-
- if (totelem == 0) {
- distribute_invalid(scene, psys, children ? PART_FROM_CHILD : 0);
-
- if (G.debug & G_DEBUG)
- fprintf(stderr,"Particle distribution error: Nothing to emit from!\n");
-
- if (dm != finaldm) dm->release(dm);
-
- BLI_kdtree_free(tree);
-
- return 0;
- }
-
- element_weight = MEM_callocN(sizeof(float)*totelem, "particle_distribution_weights");
- particle_element= MEM_callocN(sizeof(int)*totpart, "particle_distribution_indexes");
- element_sum = MEM_callocN(sizeof(float)*(totelem+1), "particle_distribution_sum");
- jitter_offset = MEM_callocN(sizeof(float)*totelem, "particle_distribution_jitoff");
-
- /* Calculate weights from face areas */
- if ((part->flag&PART_EDISTR || children) && from != PART_FROM_VERT) {
- MVert *v1, *v2, *v3, *v4;
- float totarea=0.f, co1[3], co2[3], co3[3], co4[3];
- float (*orcodata)[3];
-
- orcodata= dm->getVertDataArray(dm, CD_ORCO);
-
- for (i=0; i<totelem; i++) {
- MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
-
- if (orcodata) {
- copy_v3_v3(co1, orcodata[mf->v1]);
- copy_v3_v3(co2, orcodata[mf->v2]);
- copy_v3_v3(co3, orcodata[mf->v3]);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co1, 1, 1);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co2, 1, 1);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co3, 1, 1);
- if (mf->v4) {
- copy_v3_v3(co4, orcodata[mf->v4]);
- BKE_mesh_orco_verts_transform((Mesh*)ob->data, &co4, 1, 1);
- }
- }
- else {
- v1= (MVert*)dm->getVertData(dm,mf->v1,CD_MVERT);
- v2= (MVert*)dm->getVertData(dm,mf->v2,CD_MVERT);
- v3= (MVert*)dm->getVertData(dm,mf->v3,CD_MVERT);
- copy_v3_v3(co1, v1->co);
- copy_v3_v3(co2, v2->co);
- copy_v3_v3(co3, v3->co);
- if (mf->v4) {
- v4= (MVert*)dm->getVertData(dm,mf->v4,CD_MVERT);
- copy_v3_v3(co4, v4->co);
- }
- }
-
- cur = mf->v4 ? area_quad_v3(co1, co2, co3, co4) : area_tri_v3(co1, co2, co3);
-
- if (cur > maxweight)
- maxweight = cur;
-
- element_weight[i] = cur;
- totarea += cur;
- }
-
- for (i=0; i<totelem; i++)
- element_weight[i] /= totarea;
-
- maxweight /= totarea;
- }
- else {
- float min=1.0f/(float)(MIN2(totelem,totpart));
- for (i=0; i<totelem; i++)
- element_weight[i]=min;
- maxweight=min;
- }
-
- /* Calculate weights from vgroup */
- vweight = psys_cache_vgroup(dm,psys,PSYS_VG_DENSITY);
-
- if (vweight) {
- if (from==PART_FROM_VERT) {
- for (i=0;i<totelem; i++)
- element_weight[i]*=vweight[i];
- }
- else { /* PART_FROM_FACE / PART_FROM_VOLUME */
- for (i=0;i<totelem; i++) {
- MFace *mf=dm->getTessFaceData(dm,i,CD_MFACE);
- tweight = vweight[mf->v1] + vweight[mf->v2] + vweight[mf->v3];
-
- if (mf->v4) {
- tweight += vweight[mf->v4];
- tweight /= 4.0f;
- }
- else {
- tweight /= 3.0f;
- }
-
- element_weight[i]*=tweight;
- }
- }
- MEM_freeN(vweight);
- }
-
- /* Calculate total weight of all elements */
- totweight= 0.0f;
- for (i=0;i<totelem; i++)
- totweight += element_weight[i];
-
- inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f);
-
- /* Calculate cumulative weights */
- element_sum[0] = 0.0f;
- for (i=0; i<totelem; i++)
- element_sum[i+1] = element_sum[i] + element_weight[i] * inv_totweight;
+ tasks = MEM_callocN(sizeof(ParticleTask) * numtasks, "ParticleThread");
+ *r_numtasks = numtasks;
+ *r_tasks = tasks;
- /* Finally assign elements to particles */
- if ((part->flag&PART_TRAND) || (part->simplify_flag&PART_SIMPLIFY_ENABLE)) {
- float pos;
-
- for (p=0; p<totpart; p++) {
- /* In theory element_sum[totelem] should be 1.0, but due to float errors this is not necessarily always true, so scale pos accordingly. */
- pos= BLI_frand() * element_sum[totelem];
- particle_element[p] = distribute_binary_search(element_sum, totelem, pos);
- particle_element[p] = MIN2(totelem-1, particle_element[p]);
- jitter_offset[particle_element[p]] = pos;
- }
- }
- else {
- double step, pos;
-
- step= (totpart < 2) ? 0.5 : 1.0/(double)totpart;
- pos= 1e-6; /* tiny offset to avoid zero weight face */
- i= 0;
-
- for (p=0; p<totpart; p++, pos+=step) {
- while ((i < totelem) && (pos > (double)element_sum[i + 1]))
- i++;
-
- particle_element[p] = MIN2(totelem-1, i);
-
- /* avoid zero weight face */
- if (p == totpart-1 && element_weight[particle_element[p]] == 0.0f)
- particle_element[p] = particle_element[p-1];
-
- jitter_offset[particle_element[p]] = pos;
- }
- }
-
- MEM_freeN(element_sum);
-
- /* For hair, sort by origindex (allows optimization's in rendering), */
- /* however with virtual parents the children need to be in random order. */
- if (part->type == PART_HAIR && !(part->childtype==PART_CHILD_FACES && part->parents!=0.0f)) {
- int *orig_index = NULL;
-
- if (from == PART_FROM_VERT) {
- if (dm->numVertData)
- orig_index = dm->getVertDataArray(dm, CD_ORIGINDEX);
- }
- else {
- if (dm->numTessFaceData)
- orig_index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
- }
-
- if (orig_index) {
- BLI_qsort_r(particle_element, totpart, sizeof(int), distribute_compare_orig_index, orig_index);
- }
- }
-
- /* Create jittering if needed */
- if (distr==PART_DISTR_JIT && ELEM(from,PART_FROM_FACE,PART_FROM_VOLUME)) {
- jitlevel= part->userjit;
+ p = 0.0f;
+ for (i = 0; i < numtasks; i++, p = pnext) {
+ pnext = p + particles_per_task;
- if (jitlevel == 0) {
- jitlevel= totpart/totelem;
- if (part->flag & PART_EDISTR) jitlevel*= 2; /* looks better in general, not very scietific */
- if (jitlevel<3) jitlevel= 3;
- }
-
- jit= MEM_callocN((2+ jitlevel*2)*sizeof(float), "jit");
-
- /* for small amounts of particles we use regular jitter since it looks
- * a bit better, for larger amounts we switch to hammersley sequence
- * because it is much faster */
- if (jitlevel < 25)
- init_mv_jit(jit, jitlevel, psys->seed, part->jitfac);
- else
- hammersley_create(jit, jitlevel+1, psys->seed, part->jitfac);
- BLI_array_randomize(jit, 2*sizeof(float), jitlevel, psys->seed); /* for custom jit or even distribution */
- }
-
- /* Setup things for threaded distribution */
- ctx->tree= tree;
- ctx->seams= seams;
- ctx->totseam= totseam;
- ctx->sim.psys= psys;
- ctx->index= particle_element;
- ctx->jit= jit;
- ctx->jitlevel= jitlevel;
- ctx->jitoff= jitter_offset;
- ctx->weight= element_weight;
- ctx->maxweight= maxweight;
- ctx->from= (children) ? PART_FROM_CHILD : from;
- ctx->cfrom= cfrom;
- ctx->distr= distr;
- ctx->dm= dm;
- ctx->tpars= tpars;
-
- if (children) {
- totpart= psys_render_simplify_distribution(ctx, totpart);
- alloc_child_particles(psys, totpart);
- }
-
- if (!children || psys->totchild < 10000)
- totthread= 1;
-
- seed= 31415926 + ctx->sim.psys->seed;
- for (i=0; i<totthread; i++) {
- threads[i].rng= BLI_rng_new(seed);
- threads[i].tot= totthread;
+ tasks[i].ctx = ctx;
+ tasks[i].begin = (int)p;
+ tasks[i].end = min_ii((int)pnext, totpart);
}
-
- return 1;
}
-static void distribute_particles_on_dm(ParticleSimulationData *sim, int from)
+void psys_tasks_free(ParticleTask *tasks, int numtasks)
{
- DerivedMesh *finaldm = sim->psmd->dm;
- ListBase threads;
- ParticleThread *pthreads;
- ParticleThreadContext *ctx;
- int i, totthread;
-
- pthreads= psys_threads_create(sim);
-
- if (!distribute_threads_init_data(pthreads, sim->scene, finaldm, from)) {
- psys_threads_free(pthreads);
- return;
- }
-
- totthread= pthreads[0].tot;
- if (totthread > 1) {
- BLI_init_threads(&threads, distribute_threads_exec_cb, totthread);
-
- for (i=0; i<totthread; i++)
- BLI_insert_thread(&threads, &pthreads[i]);
-
- BLI_end_threads(&threads);
- }
- else
- distribute_threads_exec_cb(&pthreads[0]);
-
- psys_calc_dmcache(sim->ob, finaldm, sim->psys);
-
- ctx= pthreads[0].ctx;
- if (ctx->dm != finaldm)
- ctx->dm->release(ctx->dm);
-
- psys_threads_free(pthreads);
-}
-
-/* ready for future use, to emit particles without geometry */
-static void distribute_particles_on_shape(ParticleSimulationData *sim, int UNUSED(from))
-{
- distribute_invalid(sim->scene, sim->psys, 0);
-
- fprintf(stderr,"Shape emission not yet possible!\n");
-}
-
-static void distribute_particles(ParticleSimulationData *sim, int from)
-{
- PARTICLE_PSMD;
- int distr_error=0;
-
- if (psmd) {
- if (psmd->dm)
- distribute_particles_on_dm(sim, from);
- else
- distr_error=1;
- }
- else
- distribute_particles_on_shape(sim, from);
-
- if (distr_error) {
- distribute_invalid(sim->scene, sim->psys, from);
-
- fprintf(stderr,"Particle distribution error!\n");
- }
-}
-
-/* threaded child particle distribution and path caching */
-ParticleThread *psys_threads_create(ParticleSimulationData *sim)
-{
- ParticleThread *threads;
- ParticleThreadContext *ctx;
- int i, totthread = BKE_scene_num_threads(sim->scene);
+ int i;
- threads= MEM_callocN(sizeof(ParticleThread)*totthread, "ParticleThread");
- ctx= MEM_callocN(sizeof(ParticleThreadContext), "ParticleThreadContext");
-
- ctx->sim = *sim;
- ctx->dm= ctx->sim.psmd->dm;
- ctx->ma= give_current_material(sim->ob, sim->psys->part->omat);
-
- memset(threads, 0, sizeof(ParticleThread)*totthread);
-
- for (i=0; i<totthread; i++) {
- threads[i].ctx= ctx;
- threads[i].num= i;
- threads[i].tot= totthread;
+ /* threads */
+ for (i = 0; i < numtasks; ++i) {
+ if (tasks[i].rng)
+ BLI_rng_free(tasks[i].rng);
+ if (tasks[i].rng_path)
+ BLI_rng_free(tasks[i].rng_path);
}
- return threads;
+ MEM_freeN(tasks);
}
-void psys_threads_free(ParticleThread *threads)
+void psys_thread_context_free(ParticleThreadContext *ctx)
{
- ParticleThreadContext *ctx= threads[0].ctx;
- int i, totthread= threads[0].tot;
-
/* path caching */
if (ctx->vg_length)
MEM_freeN(ctx->vg_length);
@@ -1524,17 +511,6 @@ void psys_threads_free(ParticleThread *threads)
if (ctx->seams) MEM_freeN(ctx->seams);
//if (ctx->vertpart) MEM_freeN(ctx->vertpart);
BLI_kdtree_free(ctx->tree);
-
- /* threads */
- for (i=0; i<totthread; i++) {
- if (threads[i].rng)
- BLI_rng_free(threads[i].rng);
- if (threads[i].rng_path)
- BLI_rng_free(threads[i].rng_path);
- }
-
- MEM_freeN(ctx);
- MEM_freeN(threads);
}
static void initialize_particle_texture(ParticleSimulationData *sim, ParticleData *pa, int p)
@@ -3098,7 +2074,7 @@ static void basic_integrate(ParticleSimulationData *sim, int p, float dfra, floa
tkey.time=pa->state.time;
if (part->type != PART_HAIR) {
- if (do_guides(sim->psys->effectors, &tkey, p, time)) {
+ if (do_guides(sim->psys->part, sim->psys->effectors, &tkey, p, time)) {
copy_v3_v3(pa->state.co,tkey.co);
/* guides don't produce valid velocity */
sub_v3_v3v3(pa->state.vel, tkey.co, pa->prev_state.co);
@@ -3893,7 +2869,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
Base *base;
int distr=0, alloc=0, skip=0;
- if ((psys->part->childtype && psys->totchild != get_psys_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET)
+ if ((psys->part->childtype && psys->totchild != psys_get_tot_child(sim->scene, psys)) || psys->recalc&PSYS_RECALC_RESET)
alloc=1;
if (alloc || psys->recalc&PSYS_RECALC_CHILD || (psys->vgroup[PSYS_VG_DENSITY] && (sim->ob && sim->ob->mode & OB_MODE_WEIGHT_PAINT)))
@@ -3903,7 +2879,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
if (alloc)
realloc_particles(sim, sim->psys->totpart);
- if (get_psys_tot_child(sim->scene, psys)) {
+ if (psys_get_tot_child(sim->scene, psys)) {
/* don't generate children while computing the hair keys */
if (!(psys->part->type == PART_HAIR) || (psys->flag & PSYS_HAIR_DONE)) {
distribute_particles(sim, PART_FROM_CHILD);
@@ -3964,125 +2940,235 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra)
psys_free_path_cache(psys, NULL);
}
-static void do_hair_dynamics(ParticleSimulationData *sim)
+static bool psys_hair_use_simulation(ParticleData *pa, float max_length)
{
- ParticleSystem *psys = sim->psys;
- DerivedMesh *dm = psys->hair_in_dm;
- MVert *mvert = NULL;
- MEdge *medge = NULL;
- MDeformVert *dvert = NULL;
+ /* Minimum segment length relative to average length.
+ * Hairs with segments below this length will be excluded from the simulation,
+ * because otherwise the solver will become unstable.
+ * The hair system should always make sure the hair segments have reasonable length ratios,
+ * but this can happen in old files when e.g. cutting hair.
+ */
+ const float min_length = 0.1f * max_length;
+
HairKey *key;
- PARTICLE_P;
- int totpoint = 0;
- int totedge;
int k;
- float hairmat[4][4];
- float (*deformedVerts)[3];
-
- 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;
+
+ if (pa->totkey < 2)
+ return false;
+
+ for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) {
+ float length = len_v3v3(key->co, (key-1)->co);
+ if (length < min_length)
+ return false;
}
+
+ return true;
+}
- /* create a dm from hair vertices */
- LOOP_PARTICLES
- totpoint += pa->totkey;
-
- totedge = totpoint;
- totpoint += psys->totpart;
-
- if (dm && (totpoint != dm->getNumVerts(dm) || totedge != dm->getNumEdges(dm))) {
- dm->release(dm);
- dm = psys->hair_in_dm = NULL;
+static MDeformVert *hair_set_pinning(MDeformVert *dvert, float weight)
+{
+ if (dvert) {
+ if (!dvert->totweight) {
+ dvert->dw = MEM_callocN(sizeof(MDeformWeight), "deformWeight");
+ dvert->totweight = 1;
+ }
+
+ dvert->dw->weight = weight;
+ dvert++;
}
+ return dvert;
+}
+static void hair_create_input_dm(ParticleSimulationData *sim, int totpoint, int totedge, DerivedMesh **r_dm, ClothHairData **r_hairdata)
+{
+ ParticleSystem *psys = sim->psys;
+ ParticleSettings *part = psys->part;
+ DerivedMesh *dm;
+ ClothHairData *hairdata;
+ MVert *mvert;
+ MEdge *medge;
+ MDeformVert *dvert;
+ HairKey *key;
+ PARTICLE_P;
+ int k, hair_index;
+ float hairmat[4][4];
+ float max_length;
+ float hair_radius;
+
+ dm = *r_dm;
if (!dm) {
- dm = psys->hair_in_dm = CDDM_new(totpoint, totedge, 0, 0, 0);
+ *r_dm = dm = CDDM_new(totpoint, totedge, 0, 0, 0);
DM_add_vert_layer(dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
}
-
mvert = CDDM_get_verts(dm);
medge = CDDM_get_edges(dm);
dvert = DM_get_vert_data_layer(dm, CD_MDEFORMVERT);
-
+
+ hairdata = *r_hairdata;
+ if (!hairdata) {
+ *r_hairdata = hairdata = MEM_mallocN(sizeof(ClothHairData) * totpoint, "hair data");
+ }
+
+ /* calculate maximum segment length */
+ max_length = 0.0f;
+ LOOP_PARTICLES {
+ for (k=1, key=pa->hair+1; k<pa->totkey; k++,key++) {
+ float length = len_v3v3(key->co, (key-1)->co);
+ if (max_length < length)
+ max_length = length;
+ }
+ }
+
psys->clmd->sim_parms->vgroup_mass = 1;
-
+
+ /* XXX placeholder for more flexible future hair settings */
+ hair_radius = part->size;
+
/* make vgroup for pin roots etc.. */
- psys->particles->hair_index = 1;
+ hair_index = 1;
LOOP_PARTICLES {
- if (p)
- pa->hair_index = (pa-1)->hair_index + (pa-1)->totkey + 1;
-
+ float root_mat[4][4];
+ float bending_stiffness;
+ bool use_hair;
+
+ pa->hair_index = hair_index;
+ use_hair = psys_hair_use_simulation(pa, max_length);
+
psys_mat_hair_to_object(sim->ob, sim->psmd->dm, psys->part->from, pa, hairmat);
-
+ mul_m4_m4m4(root_mat, sim->ob->obmat, hairmat);
+ normalize_m4(root_mat);
+
+ bending_stiffness = CLAMPIS(1.0f - part->bending_random * psys_frand(psys, p + 666), 0.0f, 1.0f);
+
for (k=0, key=pa->hair; k<pa->totkey; k++,key++) {
+ ClothHairData *hair;
+ float *co, *co_next;
+
+ co = key->co;
+ co_next = (key+1)->co;
/* create fake root before actual root to resist bending */
if (k==0) {
- float temp[3];
- sub_v3_v3v3(temp, key->co, (key+1)->co);
- copy_v3_v3(mvert->co, key->co);
- add_v3_v3v3(mvert->co, mvert->co, temp);
+ hair = &psys->clmd->hairdata[pa->hair_index - 1];
+ copy_v3_v3(hair->loc, root_mat[3]);
+ copy_m3_m4(hair->rot, root_mat);
+
+ hair->radius = hair_radius;
+ hair->bending_stiffness = bending_stiffness;
+
+ add_v3_v3v3(mvert->co, co, co);
+ sub_v3_v3(mvert->co, co_next);
mul_m4_v3(hairmat, mvert->co);
- mvert++;
-
+
medge->v1 = pa->hair_index - 1;
medge->v2 = pa->hair_index;
+
+ dvert = hair_set_pinning(dvert, 1.0f);
+
+ mvert++;
medge++;
-
- if (dvert) {
- if (!dvert->totweight) {
- dvert->dw = MEM_callocN(sizeof(MDeformWeight), "deformWeight");
- dvert->totweight = 1;
- }
-
- dvert->dw->weight = 1.0f;
- dvert++;
- }
}
-
- copy_v3_v3(mvert->co, key->co);
+
+ /* store root transform in cloth data */
+ hair = &psys->clmd->hairdata[pa->hair_index + k];
+ copy_v3_v3(hair->loc, root_mat[3]);
+ copy_m3_m4(hair->rot, root_mat);
+
+ hair->radius = hair_radius;
+ hair->bending_stiffness = bending_stiffness;
+
+ copy_v3_v3(mvert->co, co);
mul_m4_v3(hairmat, mvert->co);
- mvert++;
if (k) {
medge->v1 = pa->hair_index + k - 1;
medge->v2 = pa->hair_index + k;
- medge++;
- }
-
- if (dvert) {
- if (!dvert->totweight) {
- dvert->dw = MEM_callocN(sizeof(MDeformWeight), "deformWeight");
- dvert->totweight = 1;
- }
- /* roots should be 1.0, the rest can be anything from 0.0 to 1.0 */
- dvert->dw->weight = key->weight;
- dvert++;
}
+
+ /* roots and disabled hairs should be 1.0, the rest can be anything from 0.0 to 1.0 */
+ if (use_hair)
+ dvert = hair_set_pinning(dvert, key->weight);
+ else
+ dvert = hair_set_pinning(dvert, 1.0f);
+
+ mvert++;
+ if (k)
+ medge++;
}
+
+ hair_index += pa->totkey + 1;
}
+}
+static void do_hair_dynamics(ParticleSimulationData *sim)
+{
+ ParticleSystem *psys = sim->psys;
+ PARTICLE_P;
+ EffectorWeights *clmd_effweights;
+ int totpoint;
+ int totedge;
+ float (*deformedVerts)[3];
+ bool realloc_roots;
+
+ 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;
+ psys->clmd->coll_parms->flags |= CLOTH_COLLSETTINGS_FLAG_POINTS;
+ }
+
+ /* count simulated points */
+ totpoint = 0;
+ totedge = 0;
+ LOOP_PARTICLES {
+ /* "out" dm contains all hairs */
+ totedge += pa->totkey;
+ totpoint += pa->totkey + 1; /* +1 for virtual root point */
+ }
+
+ realloc_roots = false; /* whether hair root info array has to be reallocated */
+ if (psys->hair_in_dm) {
+ DerivedMesh *dm = psys->hair_in_dm;
+ if (totpoint != dm->getNumVerts(dm) || totedge != dm->getNumEdges(dm)) {
+ dm->release(dm);
+ psys->hair_in_dm = NULL;
+ realloc_roots = true;
+ }
+ }
+
+ if (!psys->hair_in_dm || !psys->clmd->hairdata || realloc_roots) {
+ if (psys->clmd->hairdata) {
+ MEM_freeN(psys->clmd->hairdata);
+ psys->clmd->hairdata = NULL;
+ }
+ }
+
+ hair_create_input_dm(sim, totpoint, totedge, &psys->hair_in_dm, &psys->clmd->hairdata);
+
if (psys->hair_out_dm)
psys->hair_out_dm->release(psys->hair_out_dm);
-
+
psys->clmd->point_cache = psys->pointcache;
+ /* for hair sim we replace the internal cloth effector weights temporarily
+ * to use the particle settings
+ */
+ clmd_effweights = psys->clmd->sim_parms->effector_weights;
psys->clmd->sim_parms->effector_weights = psys->part->effector_weights;
-
- deformedVerts = MEM_mallocN(sizeof(*deformedVerts) * dm->getNumVerts(dm), "do_hair_dynamics vertexCos");
- psys->hair_out_dm = CDDM_copy(dm);
+
+ deformedVerts = MEM_mallocN(sizeof(*deformedVerts) * psys->hair_in_dm->getNumVerts(psys->hair_in_dm), "do_hair_dynamics vertexCos");
+ psys->hair_out_dm = CDDM_copy(psys->hair_in_dm);
psys->hair_out_dm->getVertCos(psys->hair_out_dm, deformedVerts);
-
- clothModifier_do(psys->clmd, sim->scene, sim->ob, dm, deformedVerts);
-
+
+ clothModifier_do(psys->clmd, sim->scene, sim->ob, psys->hair_in_dm, deformedVerts);
+
CDDM_apply_vert_coords(psys->hair_out_dm, deformedVerts);
-
+
MEM_freeN(deformedVerts);
-
- psys->clmd->sim_parms->effector_weights = NULL;
+
+ /* restore cloth effector weights */
+ psys->clmd->sim_parms->effector_weights = clmd_effweights;
}
static void hair_step(ParticleSimulationData *sim, float cfra)
{
@@ -4473,7 +3559,7 @@ static void update_children(ParticleSimulationData *sim)
/* don't generate children while growing hair - waste of time */
psys_free_children(sim->psys);
else if (sim->psys->part->childtype) {
- if (sim->psys->totchild != get_psys_tot_child(sim->scene, sim->psys))
+ if (sim->psys->totchild != psys_get_tot_child(sim->scene, sim->psys))
distribute_particles(sim, PART_FROM_CHILD);
else {
/* Children are up to date, nothing to do. */
diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c
index bd953890443..5e07437d426 100644
--- a/source/blender/blenkernel/intern/pbvh.c
+++ b/source/blender/blenkernel/intern/pbvh.c
@@ -281,7 +281,7 @@ static int map_insert_vert(PBVH *bvh, GHash *map,
/* Find vertices used by the faces in this node and update the draw buffers */
static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
{
- GHashIterator *iter;
+ GHashIterator gh_iter;
GHash *map;
int i, j, totface;
bool has_visible = false;
@@ -314,22 +314,17 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node)
"bvh node vert indices");
/* Build the vertex list, unique verts first */
- for (iter = BLI_ghashIterator_new(map), i = 0;
- BLI_ghashIterator_done(iter) == false;
- BLI_ghashIterator_step(iter), ++i)
- {
- void *value = BLI_ghashIterator_getValue(iter);
+ GHASH_ITER (gh_iter, map) {
+ void *value = BLI_ghashIterator_getValue(&gh_iter);
int ndx = GET_INT_FROM_POINTER(value);
if (ndx < 0)
ndx = -ndx + node->uniq_verts - 1;
node->vert_indices[ndx] =
- GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(iter));
+ GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
}
- BLI_ghashIterator_free(iter);
-
for (i = 0; i < totface; ++i) {
MFace *f = bvh->faces + node->prim_indices[i];
int sides = f->v4 ? 4 : 3;
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 75301471fca..a9780ef50d3 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -774,7 +774,7 @@ static int ptcache_smoke_read(PTCacheFile *pf, void *smoke_v)
/* version header */
ptcache_file_read(pf, version, 4, sizeof(char));
- if (strncmp(version, SMOKE_CACHE_VERSION, 4))
+ if (!STREQLEN(version, SMOKE_CACHE_VERSION, 4))
{
/* reset file pointer */
fseek(pf->fp, -4, SEEK_CUR);
@@ -956,7 +956,7 @@ static int ptcache_dynamicpaint_read(PTCacheFile *pf, void *dp_v)
/* version header */
ptcache_file_read(pf, version, 1, sizeof(char) * 4);
- if (strncmp(version, DPAINT_CACHE_VERSION, 4)) {
+ if (!STREQLEN(version, DPAINT_CACHE_VERSION, 4)) {
printf("Dynamic Paint: Invalid cache version: '%c%c%c%c'!\n", UNPACK4(version));
return 0;
}
@@ -1710,7 +1710,7 @@ static int ptcache_file_header_begin_read(PTCacheFile *pf)
if (fread(bphysics, sizeof(char), 8, pf->fp) != 8)
error = 1;
- if (!error && strncmp(bphysics, "BPHYSICS", 8))
+ if (!error && !STREQLEN(bphysics, "BPHYSICS", 8))
error = 1;
if (!error && !fread(&typeflag, sizeof(unsigned int), 1, pf->fp))
@@ -2386,7 +2386,7 @@ static int ptcache_write_needed(PTCacheID *pid, int cfra, int *overwrite)
PointCache *cache = pid->cache;
int ofra = 0, efra = cache->endframe;
- /* allways start from scratch on the first frame */
+ /* always start from scratch on the first frame */
if (cfra && cfra == cache->startframe) {
BKE_ptcache_id_clear(pid, PTCACHE_CLEAR_ALL, cfra);
cache->state.flag &= ~PTC_STATE_REDO_NEEDED;
@@ -2512,7 +2512,7 @@ void BKE_ptcache_id_clear(PTCacheID *pid, int mode, unsigned int cfra)
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
- if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
+ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
if (mode == PTCACHE_CLEAR_ALL) {
pid->cache->state.last_exact = MIN2(pid->cache->startframe, 0);
BLI_join_dirfile(path_full, sizeof(path_full), path, de->d_name);
@@ -2656,7 +2656,7 @@ void BKE_ptcache_id_time(PTCacheID *pid, Scene *scene, float cfra, int *startfra
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
- if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
+ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
/* read the number of the file */
unsigned int frame, len2 = (int)strlen(de->d_name);
char num[7];
@@ -2827,7 +2827,7 @@ void BKE_ptcache_remove(void)
return;
while ((de = readdir(dir)) != NULL) {
- if ( strcmp(de->d_name, ".")==0 || strcmp(de->d_name, "..")==0) {
+ if (FILENAME_IS_CURRPAR(de->d_name)) {
/* do nothing */
}
else if (strstr(de->d_name, PTCACHE_EXT)) { /* do we have the right extension?*/
@@ -2976,7 +2976,7 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
- if (strncmp(old_filename, de->d_name, len ) == 0) { /* do we have the right prefix */
+ if (STREQLEN(old_filename, de->d_name, len)) { /* do we have the right prefix */
/* read the number of the file */
int frame, len2 = (int)strlen(de->d_name);
char num[7];
@@ -3031,7 +3031,7 @@ void BKE_ptcache_load_external(PTCacheID *pid)
while ((de = readdir(dir)) != NULL) {
if (strstr(de->d_name, ext)) { /* do we have the right extension?*/
- if (strncmp(filename, de->d_name, len ) == 0) { /* do we have the right prefix */
+ if (STREQLEN(filename, de->d_name, len)) { /* do we have the right prefix */
/* read the number of the file */
int frame, len2 = (int)strlen(de->d_name);
char num[7];
diff --git a/source/blender/blenkernel/intern/property.c b/source/blender/blenkernel/intern/property.c
index bb04d548a44..100df5fd121 100644
--- a/source/blender/blenkernel/intern/property.c
+++ b/source/blender/blenkernel/intern/property.c
@@ -131,60 +131,6 @@ bProperty *BKE_bproperty_new(int type)
return prop;
}
-/* used by BKE_bproperty_unique() only */
-static bProperty *bproperty_get(bProperty *first, bProperty *self, const char *name)
-{
- bProperty *p;
- for (p = first; p; p = p->next) {
- if (p != self && (strcmp(p->name, name) == 0))
- return p;
- }
- return NULL;
-}
-void BKE_bproperty_unique(bProperty *first, bProperty *prop, int force)
-{
- bProperty *p;
-
- /* set the first if its not set */
- if (first == NULL) {
- first = prop;
- while (first->prev) {
- first = first->prev;
- }
- }
-
- if (force) {
- /* change other names to make them unique */
- while ((p = bproperty_get(first, prop, prop->name))) {
- BKE_bproperty_unique(first, p, 0);
- }
- }
- else {
- /* change our own name until its unique */
- if (bproperty_get(first, prop, prop->name)) {
- /* there is a collision */
- char new_name[sizeof(prop->name)];
- char base_name[sizeof(prop->name)];
- char num[sizeof(prop->name)];
- int i = 0;
-
- /* strip numbers */
- BLI_strncpy(base_name, prop->name, sizeof(base_name));
- for (i = strlen(base_name) - 1; (i >= 0 && isdigit(base_name[i])); i--) {
- base_name[i] = '\0';
- }
- i = 0;
-
- do { /* ensure we have enough chars for the new number in the name */
- const size_t num_len = BLI_snprintf(num, sizeof(num), "%d", i++);
- BLI_snprintf(new_name, sizeof(prop->name),
- "%.*s%s", (int)(sizeof(prop->name) - num_len), base_name, num);
- } while (bproperty_get(first, prop, new_name));
-
- BLI_strncpy(prop->name, new_name, sizeof(prop->name));
- }
- }
-}
bProperty *BKE_bproperty_object_get(Object *ob, const char *name)
{
diff --git a/source/blender/blenkernel/intern/rigidbody.c b/source/blender/blenkernel/intern/rigidbody.c
index 4bd3b6bd8dd..92db7165c6d 100644
--- a/source/blender/blenkernel/intern/rigidbody.c
+++ b/source/blender/blenkernel/intern/rigidbody.c
@@ -438,6 +438,10 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
new_shape = rigidbody_get_shape_trimesh_from_mesh(ob);
break;
}
+ /* use box shape if we can't fall back to old shape */
+ if (new_shape == NULL && rbo->physics_shape == NULL) {
+ new_shape = RB_shape_new_box(size[0], size[1], size[2]);
+ }
/* assign new collision shape if creation was successful */
if (new_shape) {
if (rbo->physics_shape)
@@ -445,11 +449,6 @@ static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
rbo->physics_shape = new_shape;
RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo));
}
- /* use box shape if we can't fall back to old shape */
- else if (rbo->physics_shape == NULL) {
- rbo->shape = RB_SHAPE_BOX;
- rigidbody_validate_sim_shape(ob, true);
- }
}
/* --------------------- */
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index 13e9b7fb0c4..f94f7cd8f0b 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -689,6 +689,12 @@ Scene *BKE_scene_add(Main *bmain, const char *name)
BLI_strncpy(sce->sequencer_colorspace_settings.name, colorspace_name,
sizeof(sce->sequencer_colorspace_settings.name));
+ /* Safe Areas */
+ copy_v2_fl2(sce->safe_areas.title, 3.5f / 100.0f, 3.5f / 100.0f);
+ copy_v2_fl2(sce->safe_areas.action, 10.0f / 100.0f, 5.0f / 100.0f);
+ copy_v2_fl2(sce->safe_areas.title_center, 17.5f / 100.0f, 5.0f / 100.0f);
+ copy_v2_fl2(sce->safe_areas.action_center, 15.0f / 100.0f, 5.0f / 100.0f);
+
return sce;
}
@@ -1636,9 +1642,9 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
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)))
+ ((obedit->id.flag & LIB_ID_RECALC_ALL) ||
+ (mesh->id.flag & LIB_ID_RECALC_ALL)))
{
if (check_rendered_viewport_visible(bmain)) {
BMesh *bm = mesh->edit_btmesh->bm;
@@ -1997,7 +2003,7 @@ void BKE_scene_disable_color_management(Scene *scene)
bool BKE_scene_check_color_management_enabled(const Scene *scene)
{
- return strcmp(scene->display_settings.display_device, "None") != 0;
+ return !STREQ(scene->display_settings.display_device, "None");
}
bool BKE_scene_check_rigidbody_active(const Scene *scene)
diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c
index ad4ed5a0b99..c9dba38b713 100644
--- a/source/blender/blenkernel/intern/screen.c
+++ b/source/blender/blenkernel/intern/screen.c
@@ -46,6 +46,7 @@
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
+#include "BLI_rect.h"
#include "BKE_idprop.h"
#include "BKE_screen.h"
@@ -137,7 +138,7 @@ void BKE_spacetype_register(SpaceType *st)
BLI_addtail(&spacetypes, st);
}
-int BKE_spacetype_exists(int spaceid)
+bool BKE_spacetype_exists(int spaceid)
{
return BKE_spacetype_from_id(spaceid) != NULL;
}
@@ -419,16 +420,17 @@ ScrArea *BKE_screen_find_area_from_space(struct bScreen *sc, SpaceLink *sl)
return sa;
}
-/* note, using this function is generally a last resort, you really want to be
+/**
+ * \note Using this function is generally a last resort, you really want to be
* using the context when you can - campbell
- * -1 for any type */
+ */
ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short min)
{
ScrArea *sa, *big = NULL;
int size, maxsize = 0;
for (sa = sc->areabase.first; sa; sa = sa->next) {
- if ((spacetype == -1) || sa->spacetype == spacetype) {
+ if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
if (min <= sa->winx && min <= sa->winy) {
size = sa->winx * sa->winy;
if (size > maxsize) {
@@ -442,6 +444,22 @@ ScrArea *BKE_screen_find_big_area(bScreen *sc, const int spacetype, const short
return big;
}
+ScrArea *BKE_screen_find_area_xy(bScreen *sc, const int spacetype, int x, int y)
+{
+ ScrArea *sa, *sa_found = NULL;
+
+ for (sa = sc->areabase.first; sa; sa = sa->next) {
+ if (BLI_rcti_isect_pt(&sa->totrct, x, y)) {
+ if ((spacetype == SPACE_TYPE_ANY) || (sa->spacetype == spacetype)) {
+ sa_found = sa;
+ }
+ break;
+ }
+ }
+ return sa_found;
+}
+
+
/**
* Utility function to get the active layer to use when adding new objects.
*/
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index b43e481d97d..83287fe7725 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -1290,6 +1290,7 @@ typedef struct SeqIndexBuildContext {
int tc_flags;
int size_flags;
int quality;
+ bool overwrite;
Main *bmain;
Scene *scene;
@@ -1329,7 +1330,7 @@ static double seq_rendersize_to_scale_factor(int size)
return 0.25;
}
-static void seq_open_anim_file(Sequence *seq)
+static void seq_open_anim_file(Sequence *seq, bool openfile)
{
char name[FILE_MAX];
StripProxy *proxy;
@@ -1342,8 +1343,14 @@ static void seq_open_anim_file(Sequence *seq)
seq->strip->dir, seq->strip->stripdata->name);
BLI_path_abs(name, G.main->name);
- seq->anim = openanim(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
- seq->streamindex, seq->strip->colorspace_settings.name);
+ if (openfile) {
+ seq->anim = openanim(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
+ else {
+ seq->anim = openanim_noload(name, IB_rect | ((seq->flag & SEQ_FILTERY) ? IB_animdeinterlace : 0),
+ seq->streamindex, seq->strip->colorspace_settings.name);
+ }
if (seq->anim == NULL) {
return;
@@ -1457,7 +1464,7 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
return NULL;
}
- seq_open_anim_file(seq);
+ seq_open_anim_file(seq, true);
frameno = IMB_anim_index_get_frame_index(seq->anim, seq->strip->proxy->tc, frameno);
@@ -1481,7 +1488,8 @@ static ImBuf *seq_proxy_fetch(const SeqRenderData *context, Sequence *seq, int c
}
}
-static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, int cfra, int proxy_render_size)
+static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, int cfra,
+ int proxy_render_size, const bool overwrite)
{
char name[PROXY_MAXFILE];
int quality;
@@ -1493,6 +1501,10 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
return;
}
+ if (!overwrite && BLI_exists(name)) {
+ return;
+ }
+
ibuf_tmp = seq_render_strip(context, seq, cfra);
rectx = (proxy_render_size * ibuf_tmp->x) / 100;
@@ -1526,7 +1538,7 @@ static void seq_proxy_build_frame(const SeqRenderData *context, Sequence *seq, i
IMB_freeImBuf(ibuf);
}
-SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq)
+SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *scene, Sequence *seq, struct GSet *file_list)
{
SeqIndexBuildContext *context;
Sequence *nseq;
@@ -1546,6 +1558,7 @@ SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *sc
context->tc_flags = nseq->strip->proxy->build_tc_flags;
context->size_flags = nseq->strip->proxy->build_size_flags;
context->quality = nseq->strip->proxy->quality;
+ context->overwrite = (nseq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) == 0;
context->bmain = bmain;
context->scene = scene;
@@ -1553,11 +1566,12 @@ SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *sc
context->seq = nseq;
if (nseq->type == SEQ_TYPE_MOVIE) {
- seq_open_anim_file(nseq);
+ seq_open_anim_file(nseq, true);
if (nseq->anim) {
context->index_context = IMB_anim_index_rebuild_context(nseq->anim,
- context->tc_flags, context->size_flags, context->quality);
+ context->tc_flags, context->size_flags, context->quality,
+ context->overwrite, file_list);
}
}
@@ -1566,6 +1580,7 @@ SeqIndexBuildContext *BKE_sequencer_proxy_rebuild_context(Main *bmain, Scene *sc
void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, short *do_update, float *progress)
{
+ const bool overwrite = context->overwrite;
SeqRenderData render_context;
Sequence *seq = context->seq;
Scene *scene = context->scene;
@@ -1602,16 +1617,16 @@ void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context, short *stop, sho
for (cfra = seq->startdisp + seq->startstill; cfra < seq->enddisp - seq->endstill; cfra++) {
if (context->size_flags & IMB_PROXY_25) {
- seq_proxy_build_frame(&render_context, seq, cfra, 25);
+ seq_proxy_build_frame(&render_context, seq, cfra, 25, overwrite);
}
if (context->size_flags & IMB_PROXY_50) {
- seq_proxy_build_frame(&render_context, seq, cfra, 50);
+ seq_proxy_build_frame(&render_context, seq, cfra, 50, overwrite);
}
if (context->size_flags & IMB_PROXY_75) {
- seq_proxy_build_frame(&render_context, seq, cfra, 75);
+ seq_proxy_build_frame(&render_context, seq, cfra, 75, overwrite);
}
if (context->size_flags & IMB_PROXY_100) {
- seq_proxy_build_frame(&render_context, seq, cfra, 100);
+ seq_proxy_build_frame(&render_context, seq, cfra, 100, overwrite);
}
*progress = (float) (cfra - seq->startdisp - seq->startstill) / (seq->enddisp - seq->endstill - seq->startdisp - seq->startstill);
@@ -1635,6 +1650,22 @@ void BKE_sequencer_proxy_rebuild_finish(SeqIndexBuildContext *context, bool stop
MEM_freeN(context);
}
+void BKE_sequencer_proxy_set(struct Sequence *seq, bool value)
+{
+ if (value) {
+ seq->flag |= SEQ_USE_PROXY;
+ if (seq->strip->proxy == NULL) {
+ seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
+ seq->strip->proxy->quality = 90;
+ seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
+ seq->strip->proxy->build_size_flags = SEQ_PROXY_IMAGE_SIZE_25;
+ }
+ }
+ else {
+ seq->flag ^= SEQ_USE_PROXY;
+ }
+}
+
/*********************** color balance *************************/
static StripColorBalance calc_cb(StripColorBalance *cb_)
@@ -2609,7 +2640,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context, Sequence *seq
* When rendering from command line renderer is called from main thread, in this
* case it's always safe to render scene here
*/
- if (!is_thread_main || is_rendering == false || is_background) {
+ if (!is_thread_main || is_rendering == false || is_background || context->eval_ctx->mode == DAG_EVAL_RENDER) {
if (re == NULL)
re = RE_NewRender(scene->id.name);
@@ -2755,15 +2786,22 @@ static ImBuf *do_render_strip_uncached(const SeqRenderData *context, Sequence *s
case SEQ_TYPE_MOVIE:
{
- seq_open_anim_file(seq);
+ seq_open_anim_file(seq, false);
if (seq->anim) {
+ IMB_Proxy_Size proxy_size = seq_rendersize_to_proxysize(context->preview_render_size);
IMB_anim_set_preseek(seq->anim, seq->anim_preseek);
ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
- seq_rendersize_to_proxysize(context->preview_render_size));
+ proxy_size);
+ /* fetching for requested proxy size failed, try fetching the original instead */
+ if (!ibuf && proxy_size != IMB_PROXY_NONE) {
+ ibuf = IMB_anim_absolute(seq->anim, nr + seq->anim_startofs,
+ seq->strip->proxy ? seq->strip->proxy->tc : IMB_TC_RECORD_RUN,
+ IMB_PROXY_NONE);
+ }
if (ibuf) {
BKE_sequencer_imbuf_to_sequencer_space(context->scene, ibuf, false);
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c
index d91818615f3..2ff81cd5394 100644
--- a/source/blender/blenkernel/intern/shrinkwrap.c
+++ b/source/blender/blenkernel/intern/shrinkwrap.c
@@ -89,7 +89,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc)
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) if(calc->numVerts > BKE_MESH_OMP_LIMIT)
+#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];
@@ -394,7 +394,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) if(calc->numVerts > BKE_MESH_OMP_LIMIT)
+#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];
diff --git a/source/blender/blenkernel/intern/smoke.c b/source/blender/blenkernel/intern/smoke.c
index a996da5915e..b6453fe8fb1 100644
--- a/source/blender/blenkernel/intern/smoke.c
+++ b/source/blender/blenkernel/intern/smoke.c
@@ -2131,6 +2131,9 @@ static void update_flowsfluids(Scene *scene, Object *ob, SmokeDomainSettings *sd
if (sfs->source == MOD_SMOKE_FLOW_SOURCE_PARTICLES) {
/* emit_from_particles() updates timestep internally */
emit_from_particles(collob, sds, sfs, &em_temp, scene, sdt);
+ if (!(sfs->flags & MOD_SMOKE_FLOW_USE_PART_SIZE)) {
+ hires_multiplier = 1;
+ }
}
else { /* MOD_SMOKE_FLOW_SOURCE_MESH */
/* update flow object frame */
diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c
index 88720d5fcb7..25ac3c91b7f 100644
--- a/source/blender/blenkernel/intern/sound.c
+++ b/source/blender/blenkernel/intern/sound.c
@@ -118,9 +118,10 @@ void BKE_sound_free(bSound *sound)
sound_free_waveform(sound);
- if (sound->mutex) {
- BLI_mutex_free(sound->mutex);
- sound->mutex = NULL;
+ if (sound->spinlock) {
+ BLI_spin_end(sound->spinlock);
+ MEM_freeN(sound->spinlock);
+ sound->spinlock = NULL;
}
#endif /* WITH_AUDASPACE */
@@ -687,8 +688,7 @@ void sound_free_waveform(bSound *sound)
void sound_read_waveform(bSound *sound, short *stop)
{
AUD_SoundInfo info = AUD_getInfo(sound->playback_handle);
- SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform),
- "SoundWaveform");
+ SoundWaveform *waveform = MEM_mallocN(sizeof(SoundWaveform), "SoundWaveform");
if (info.length > 0) {
int length = info.length * SOUND_WAVE_SAMPLES_PER_SECOND;
@@ -710,18 +710,18 @@ void sound_read_waveform(bSound *sound, short *stop)
MEM_freeN(waveform->data);
}
MEM_freeN(waveform);
- BLI_mutex_lock(sound->mutex);
+ BLI_spin_lock(sound->spinlock);
sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING;
- BLI_mutex_unlock(sound->mutex);
+ BLI_spin_unlock(sound->spinlock);
return;
}
sound_free_waveform(sound);
- BLI_mutex_lock(sound->mutex);
+ BLI_spin_lock(sound->spinlock);
sound->waveform = waveform;
sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING;
- BLI_mutex_unlock(sound->mutex);
+ BLI_spin_unlock(sound->spinlock);
}
void sound_update_scene(Main *bmain, struct Scene *scene)
diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c
index 961a66f853b..9519c7b25a1 100644
--- a/source/blender/blenkernel/intern/subsurf_ccg.c
+++ b/source/blender/blenkernel/intern/subsurf_ccg.c
@@ -1871,64 +1871,6 @@ static void ccgDM_drawFacesSolid(DerivedMesh *dm, float (*partial_redraw_planes)
}
}
-static void ccgdm_draw_attrib_vertex(DMVertexAttribs *attribs, int a, int index, int vert)
-{
- const float zero[4] = {0.0f, 0.0f, 0.0f, 0.0f};
- int b;
-
- /* orco texture coordinates */
- if (attribs->totorco) {
- /*const*/ float (*array)[3] = attribs->orco.array;
- const float *orco = (array) ? array[index] : zero;
-
- if (attribs->orco.gl_texco)
- glTexCoord3fv(orco);
- else
- glVertexAttrib3fvARB(attribs->orco.gl_index, orco);
- }
-
- /* uv texture coordinates */
- for (b = 0; b < attribs->tottface; b++) {
- const float *uv;
-
- if (attribs->tface[b].array) {
- MTFace *tf = &attribs->tface[b].array[a];
- uv = tf->uv[vert];
- }
- else {
- uv = zero;
- }
-
- if (attribs->tface[b].gl_texco)
- glTexCoord2fv(uv);
- else
- glVertexAttrib2fvARB(attribs->tface[b].gl_index, uv);
- }
-
- /* vertex colors */
- for (b = 0; b < attribs->totmcol; b++) {
- GLubyte col[4];
-
- if (attribs->mcol[b].array) {
- MCol *cp = &attribs->mcol[b].array[a * 4 + vert];
- col[0] = cp->b; col[1] = cp->g; col[2] = cp->r; col[3] = cp->a;
- }
- else {
- col[0] = 0; col[1] = 0; col[2] = 0; col[3] = 0;
- }
-
- glVertexAttrib4ubvARB(attribs->mcol[b].gl_index, col);
- }
-
- /* tangent for normal mapping */
- if (attribs->tottang) {
- /*const*/ float (*array)[4] = attribs->tang.array;
- const float *tang = (array) ? array[a * 4 + vert] : zero;
-
- glVertexAttrib4fvARB(attribs->tang.gl_index, tang);
- }
-}
-
/* Only used by non-editmesh types */
static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
DMSetMaterial setMaterial,
@@ -1959,7 +1901,7 @@ static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
else \
index = 0; \
- ccgdm_draw_attrib_vertex(&attribs, a, index, vert); \
+ DM_draw_attrib_vertex(&attribs, a, index, vert); \
} (void)0
totface = ccgSubSurf_getNumFaces(ss);
@@ -2130,7 +2072,7 @@ static void ccgDM_drawMappedFacesMat(DerivedMesh *dm,
index = getFaceIndex(ss, f, S, x + dx, y + dy, edgeSize, gridSize); \
else \
index = 0; \
- ccgdm_draw_attrib_vertex(&attribs, a, index, vert); \
+ DM_draw_attrib_vertex(&attribs, a, index, vert); \
} (void)0
totface = ccgSubSurf_getNumFaces(ss);
@@ -3523,6 +3465,7 @@ static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
ccgdm->dm.calcNormals = ccgDM_calcNormals;
ccgdm->dm.calcLoopNormals = CDDM_calc_loop_normals;
+ ccgdm->dm.calcLoopNormalsSpaceArray = CDDM_calc_loop_normals_spacearr;
ccgdm->dm.recalcTessellation = ccgDM_recalcTessellation;
ccgdm->dm.getVertCos = ccgdm_getVertCos;
diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c
index 3a311bfb23b..c5a8cbe68b2 100644
--- a/source/blender/blenkernel/intern/text.c
+++ b/source/blender/blenkernel/intern/text.c
@@ -508,10 +508,14 @@ void BKE_text_unlink(Main *bmain, Text *text)
bNodeTree *ntree;
bNode *node;
Material *mat;
+ Lamp *la;
+ Tex *te;
+ World *wo;
+ FreestyleLineStyle *linestyle;
Scene *sce;
SceneRenderLayer *srl;
FreestyleModuleConfig *module;
- short update;
+ bool update;
for (ob = bmain->object.first; ob; ob = ob->id.next) {
/* game controllers */
@@ -563,23 +567,97 @@ void BKE_text_unlink(Main *bmain, Text *text)
}
/* nodes */
+ for (la = bmain->lamp.first; la; la = la->id.next) {
+ ntree = la->nodetree;
+ if (!ntree)
+ continue;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == NODE_FRAME) {
+ if ((Text *)node->id == text) {
+ node->id = NULL;
+ }
+ }
+ }
+ }
+
+ for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) {
+ ntree = linestyle->nodetree;
+ if (!ntree)
+ continue;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == NODE_FRAME) {
+ if ((Text *)node->id == text) {
+ node->id = NULL;
+ }
+ }
+ }
+ }
+
for (mat = bmain->mat.first; mat; mat = mat->id.next) {
ntree = mat->nodetree;
if (!ntree)
continue;
for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
+ if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
+ if ((Text *)node->id == text) {
+ node->id = NULL;
+ }
+ }
+ }
+ }
+
+ for (te = bmain->tex.first; te; te = te->id.next) {
+ ntree = te->nodetree;
+ if (!ntree)
+ continue;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == NODE_FRAME) {
+ if ((Text *)node->id == text) {
+ node->id = NULL;
+ }
+ }
+ }
+ }
+
+ for (wo = bmain->world.first; wo; wo = wo->id.next) {
+ ntree = wo->nodetree;
+ if (!ntree)
+ continue;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == NODE_FRAME) {
+ if ((Text *)node->id == text) {
+ node->id = NULL;
+ }
+ }
+ }
+ }
+
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ ntree = sce->nodetree;
+ if (!ntree)
+ continue;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (node->type == NODE_FRAME) {
Text *ntext = (Text *)node->id;
if (ntext == text) node->id = NULL;
}
}
+
+ /* Freestyle (while looping oer the scene) */
+ for (srl = sce->r.layers.first; srl; srl = srl->next) {
+ for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
+ if (module->script == text)
+ module->script = NULL;
+ }
+ }
}
-
+
for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) {
for (node = ntree->nodes.first; node; node = node->next) {
- if (node->type == SH_NODE_SCRIPT) {
- Text *ntext = (Text *)node->id;
- if (ntext == text) node->id = NULL;
+ if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) {
+ if ((Text *)node->id == text) {
+ node->id = NULL;
+ }
}
}
}
@@ -600,16 +678,6 @@ void BKE_text_unlink(Main *bmain, Text *text)
}
}
- /* Freestyle */
- for (sce = bmain->scene.first; sce; sce = sce->id.next) {
- for (srl = sce->r.layers.first; srl; srl = srl->next) {
- for (module = srl->freestyleConfig.modules.first; module; module = module->next) {
- if (module->script == text)
- module->script = NULL;
- }
- }
- }
-
text->id.us = 0;
}
@@ -617,7 +685,7 @@ void BKE_text_clear(Text *text) /* called directly from rna */
{
int oldstate;
- oldstate = txt_get_undostate( );
+ oldstate = txt_get_undostate();
txt_set_undostate(1);
txt_sel_all(text);
txt_delete_sel(text);
@@ -2740,7 +2808,7 @@ void txt_unindent(Text *text)
while (true) {
bool changed = false;
- if (strncmp(text->curl->line, remove, indentlen) == 0) {
+ if (STREQLEN(text->curl->line, remove, indentlen)) {
if (num == 0)
unindented_first = true;
text->curl->len -= indentlen;
diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c
index dce6584bdfe..6c4cbcf9316 100644
--- a/source/blender/blenkernel/intern/texture.c
+++ b/source/blender/blenkernel/intern/texture.c
@@ -349,7 +349,11 @@ bool do_colorband(const ColorBand *coba, float in, float out[4])
CBData left, right;
/* we're looking for first pos > in */
- for (a = 0; a < coba->tot; a++, cbd1++) if (cbd1->pos > in) break;
+ for (a = 0; a < coba->tot; a++, cbd1++) {
+ if (cbd1->pos > in) {
+ break;
+ }
+ }
if (a == coba->tot) {
cbd2 = cbd1 - 1;
@@ -745,6 +749,7 @@ void default_mtex(MTex *mtex)
mtex->lengthfac = 1.0f;
mtex->clumpfac = 1.0f;
mtex->kinkfac = 1.0f;
+ mtex->kinkampfac = 1.0f;
mtex->roughfac = 1.0f;
mtex->padensfac = 1.0f;
mtex->lifefac = 1.0f;
@@ -755,7 +760,7 @@ void default_mtex(MTex *mtex)
mtex->fieldfac = 1.0f;
mtex->normapspace = MTEX_NSPACE_TANGENT;
mtex->brush_map_mode = MTEX_MAP_MODE_TILED;
- mtex->random_angle = 2.0f * M_PI;
+ mtex->random_angle = 2.0f * (float)M_PI;
mtex->brush_angle_mode = 0;
}
@@ -1629,7 +1634,7 @@ void BKE_texture_get_value(Scene *scene, Tex *texture, float *tex_co, TexResult
}
/* no node textures for now */
- result_type = multitex_ext_safe(texture, tex_co, texres, NULL, do_color_manage);
+ result_type = multitex_ext_safe(texture, tex_co, texres, NULL, do_color_manage, false);
/* if the texture gave an RGB value, we assume it didn't give a valid
* intensity, since this is in the context of modifiers don't use perceptual color conversion.
diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c
index d580c184a8b..0037002f6d8 100644
--- a/source/blender/blenkernel/intern/tracking.c
+++ b/source/blender/blenkernel/intern/tracking.c
@@ -721,7 +721,7 @@ MovieTrackingTrack *BKE_tracking_track_get_named(MovieTracking *tracking, MovieT
MovieTrackingTrack *track = tracksbase->first;
while (track) {
- if (!strcmp(track->name, name))
+ if (STREQ(track->name, name))
return track;
track = track->next;
@@ -1267,7 +1267,7 @@ MovieTrackingPlaneTrack *BKE_tracking_plane_track_get_named(MovieTracking *track
plane_track;
plane_track = plane_track->next)
{
- if (!strcmp(plane_track->name, name)) {
+ if (STREQ(plane_track->name, name)) {
return plane_track;
}
}
@@ -1563,7 +1563,7 @@ MovieTrackingObject *BKE_tracking_object_get_named(MovieTracking *tracking, cons
MovieTrackingObject *object = tracking->objects.first;
while (object) {
- if (!strcmp(object->name, name))
+ if (STREQ(object->name, name))
return object;
object = object->next;
diff --git a/source/blender/blenkernel/intern/tracking_auto.c b/source/blender/blenkernel/intern/tracking_auto.c
index 22a380ea835..4cb3f2ca493 100644
--- a/source/blender/blenkernel/intern/tracking_auto.c
+++ b/source/blender/blenkernel/intern/tracking_auto.c
@@ -373,7 +373,7 @@ bool BKE_autotrack_context_step(AutoTrackContext *context)
bool ok = false;
int track;
-#pragma omp parallel for if(context->num_tracks > 1)
+#pragma omp parallel for if (context->num_tracks > 1)
for (track = 0; track < context->num_tracks; ++track) {
AutoTrackOptions *options = &context->options[track];
libmv_Marker libmv_current_marker,
diff --git a/source/blender/blenkernel/intern/writeavi.c b/source/blender/blenkernel/intern/writeavi.c
index 8a6a0438b84..85eac1f21ed 100644
--- a/source/blender/blenkernel/intern/writeavi.c
+++ b/source/blender/blenkernel/intern/writeavi.c
@@ -253,7 +253,7 @@ static void end_avi(void)
}
#endif /* WITH_AVI */
-/* similar to BKE_makepicstring() */
+/* similar to BKE_image_path_from_imformat() */
void BKE_movie_filepath_get(char *string, RenderData *rd)
{
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index 9737ef429cb..128a5da9b68 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -469,8 +469,8 @@ static int ffmpeg_proprty_valid(AVCodecContext *c, const char *prop_name, IDProp
{
int valid = 1;
- if (strcmp(prop_name, "video") == 0) {
- if (strcmp(curr->name, "bf") == 0) {
+ if (STREQ(prop_name, "video")) {
+ if (STREQ(curr->name, "bf")) {
/* flash codec doesn't support b frames */
valid &= c->codec_id != AV_CODEC_ID_FLV1;
}
@@ -624,9 +624,9 @@ static AVStream *alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
if ((of->oformat->flags & AVFMT_GLOBALHEADER)
#if 0
- || !strcmp(of->oformat->name, "mp4")
- || !strcmp(of->oformat->name, "mov")
- || !strcmp(of->oformat->name, "3gp")
+ || STREQ(of->oformat->name, "mp4")
+ || STREQ(of->oformat->name, "mov")
+ || STREQ(of->oformat->name, "3gp")
#endif
)
{
diff --git a/source/blender/blenkernel/intern/writeframeserver.c b/source/blender/blenkernel/intern/writeframeserver.c
index 746b99ffb52..ae6b19fb019 100644
--- a/source/blender/blenkernel/intern/writeframeserver.c
+++ b/source/blender/blenkernel/intern/writeframeserver.c
@@ -214,7 +214,7 @@ static int handle_request(RenderData *rd, char *req)
*p = 0;
- if (strcmp(path, "/index.html") == 0 || strcmp(path, "/") == 0) {
+ if (STREQ(path, "/index.html") || STREQ(path, "/")) {
safe_puts(index_page);
return -1;
}
@@ -226,7 +226,7 @@ static int handle_request(RenderData *rd, char *req)
write_ppm = 1;
return atoi(path + 12);
}
- if (strcmp(path, "/info.txt") == 0) {
+ if (STREQ(path, "/info.txt")) {
char buf[4096];
sprintf(buf,
@@ -250,7 +250,7 @@ static int handle_request(RenderData *rd, char *req)
safe_puts(buf);
return -1;
}
- if (strcmp(path, "/close.txt") == 0) {
+ if (STREQ(path, "/close.txt")) {
safe_puts(good_bye);
G.is_break = true; /* Abort render */
return -1;
diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h
index 49d072ddfdc..4981b163cdf 100644
--- a/source/blender/blenlib/BLI_kdopbvh.h
+++ b/source/blender/blenlib/BLI_kdopbvh.h
@@ -105,6 +105,10 @@ int BLI_bvhtree_find_nearest(BVHTree *tree, const float co[3], BVHTreeNearest *n
int BLI_bvhtree_ray_cast(BVHTree *tree, const float co[3], const float dir[3], float radius, BVHTreeRayHit *hit,
BVHTree_RayCastCallback callback, void *userdata);
+/* Calls the callback for every ray intersection */
+int BLI_bvhtree_ray_cast_all(BVHTree *tree, const float co[3], const float dir[3], float radius,
+ BVHTree_RayCastCallback callback, void *userdata);
+
float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], const float light_end[3], float pos[3]);
/* range query */
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index 2bc23c8a72d..daa7db8e3cf 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -42,10 +42,13 @@
#endif
#ifndef M_PI
-#define M_PI 3.14159265358979323846
+#define M_PI 3.14159265358979323846 /* pi */
#endif
#ifndef M_PI_2
-#define M_PI_2 1.57079632679489661923
+#define M_PI_2 1.57079632679489661923 /* pi/2 */
+#endif
+#ifndef M_PI_4
+#define M_PI_4 0.78539816339744830962 /* pi/4 */
#endif
#ifndef M_SQRT2
#define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
@@ -60,22 +63,22 @@
#define M_SQRT1_3 0.57735026918962576450 /* 1/sqrt(3) */
#endif
#ifndef M_1_PI
-#define M_1_PI 0.318309886183790671538
+#define M_1_PI 0.318309886183790671538 /* 1/pi */
#endif
#ifndef M_E
-#define M_E 2.7182818284590452354
+#define M_E 2.7182818284590452354 /* e */
#endif
#ifndef M_LOG2E
-#define M_LOG2E 1.4426950408889634074
+#define M_LOG2E 1.4426950408889634074 /* log_2 e */
#endif
#ifndef M_LOG10E
-#define M_LOG10E 0.43429448190325182765
+#define M_LOG10E 0.43429448190325182765 /* log_10 e */
#endif
#ifndef M_LN2
-#define M_LN2 0.69314718055994530942
+#define M_LN2 0.69314718055994530942 /* log_e 2 */
#endif
#ifndef M_LN10
-#define M_LN10 2.30258509299404568402
+#define M_LN10 2.30258509299404568402 /* log_e 10 */
#endif
#if defined(__GNUC__)
diff --git a/source/blender/blenlib/BLI_math_color.h b/source/blender/blenlib/BLI_math_color.h
index 5c14ac55492..560ebe3d390 100644
--- a/source/blender/blenlib/BLI_math_color.h
+++ b/source/blender/blenlib/BLI_math_color.h
@@ -141,6 +141,10 @@ void xyz_to_lab(float x, float y, float z, float *l, float *a, float *b);
MINLINE int compare_rgb_uchar(const unsigned char a[3], const unsigned char b[3], const int limit);
+MINLINE float dither_random_value(float s, float t);
+MINLINE void float_to_byte_dither_v3(unsigned char b[3], const float f[3], float dither, float s, float t);
+
+
#define rgba_char_args_set_fl(col, r, g, b, a) \
rgba_char_args_set(col, (r) * 255, (g) * 255, (b) * 255, (a) * 255)
diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h
index 905889a33d7..fbd026f7617 100644
--- a/source/blender/blenlib/BLI_math_rotation.h
+++ b/source/blender/blenlib/BLI_math_rotation.h
@@ -119,6 +119,11 @@ void mat4_to_axis_angle(float axis[3], float *angle, float M[4][4]);
void axis_angle_to_mat3_single(float R[3][3], const char axis, const float angle);
void angle_to_mat2(float R[2][2], const float angle);
+/****************************** Exponential Map ******************************/
+void quat_to_expmap(float expmap[3], const float q[4]);
+void quat_normalized_to_expmap(float expmap[3], const float q[4]);
+void expmap_to_quat(float r[4], const float expmap[3]);
+
/******************************** XYZ Eulers *********************************/
void eul_to_quat(float quat[4], const float eul[3]);
diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h
index 4455e72cf45..0f437b7fc38 100644
--- a/source/blender/blenlib/BLI_math_vector.h
+++ b/source/blender/blenlib/BLI_math_vector.h
@@ -290,6 +290,8 @@ MINLINE void normal_float_to_short_v3(short r[3], const float n[3]);
void minmax_v3v3_v3(float min[3], float max[3], const float vec[3]);
void minmax_v2v2_v2(float min[2], float max[2], const float vec[2]);
+void minmax_v3v3_v3_array(float r_min[3], float r_max[3], float (*vec_arr)[3], int nbr);
+
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist);
void dist_ensure_v2_v2fl(float v1[2], const float v2[2], const float dist);
diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h
index bade390d056..7103f8a7597 100644
--- a/source/blender/blenlib/BLI_path_util.h
+++ b/source/blender/blenlib/BLI_path_util.h
@@ -108,6 +108,8 @@ void BLI_cleanup_dir(const char *relabase, char *dir) ATTR_NONNULL(2);
/* doesn't touch trailing slash */
void BLI_cleanup_path(const char *relabase, char *path) ATTR_NONNULL(2);
+void BLI_filename_make_safe(char *fname) ATTR_NONNULL(1);
+
/* go back one directory */
bool BLI_parent_dir(char *path) ATTR_NONNULL();
@@ -163,6 +165,15 @@ void BLI_string_to_utf8(char *original, char *utf_8, const char *code);
# define FILE_MAX 1024
#endif
+/* Parent and current dir helpers. */
+#define FILENAME_PARENT ".."
+#define FILENAME_CURRENT "."
+
+/* Avoid calling strcmp on one or two chars! */
+#define FILENAME_IS_PARENT(_n) (((_n)[0] == '.') && ((_n)[1] == '.') && ((_n)[2] == '\0'))
+#define FILENAME_IS_CURRENT(_n) (((_n)[0] == '.') && ((_n)[1] == '\0'))
+#define FILENAME_IS_CURRPAR(_n) (((_n)[0] == '.') && (((_n)[1] == '\0') || (((_n)[1] == '.') && ((_n)[2] == '\0'))))
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/blenlib/PIL_time.h b/source/blender/blenlib/PIL_time.h
index 158559fa3d9..6e347339980 100644
--- a/source/blender/blenlib/PIL_time.h
+++ b/source/blender/blenlib/PIL_time.h
@@ -37,7 +37,7 @@
extern "C" {
#endif
-extern
+extern
/** Return an indication of time, expressed as
* seconds since some fixed point. Successive calls
* are guaranteed to generate values greater than or
@@ -45,6 +45,12 @@ extern
*/
double PIL_check_seconds_timer(void);
+extern
+/**
+ * int version of #PIL_check_seconds_timer
+ */
+long int PIL_check_seconds_timer_i(void);
+
/**
* Platform-independent sleep function.
* \param ms Number of milliseconds to sleep
diff --git a/source/blender/blenlib/intern/BLI_args.c b/source/blender/blenlib/intern/BLI_args.c
index 49a3c466727..9faf6c93447 100644
--- a/source/blender/blenlib/intern/BLI_args.c
+++ b/source/blender/blenlib/intern/BLI_args.c
@@ -100,7 +100,7 @@ static bool keycmp(const void *a, const void *b)
return (BLI_strcasecmp(ka->arg, kb->arg) != 0);
}
else {
- return (strcmp(ka->arg, kb->arg) != 0);
+ return (!STREQ(ka->arg, kb->arg));
}
}
else {
diff --git a/source/blender/blenlib/intern/BLI_ghash.c b/source/blender/blenlib/intern/BLI_ghash.c
index c87b60f08db..5360ea744a1 100644
--- a/source/blender/blenlib/intern/BLI_ghash.c
+++ b/source/blender/blenlib/intern/BLI_ghash.c
@@ -771,7 +771,7 @@ unsigned int BLI_ghashutil_strhash_p(const void *ptr)
}
bool BLI_ghashutil_strcmp(const void *a, const void *b)
{
- return (strcmp(a, b) != 0);
+ return (!STREQ(a, b));
}
GHashPair *BLI_ghashutil_pairalloc(const void *first, const void *second)
diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c
index b76b925e6cc..e4504bcaab1 100644
--- a/source/blender/blenlib/intern/BLI_kdopbvh.c
+++ b/source/blender/blenlib/intern/BLI_kdopbvh.c
@@ -1468,6 +1468,42 @@ static void dfs_raycast(BVHRayCastData *data, BVHNode *node)
}
}
+static void dfs_raycast_all(BVHRayCastData *data, BVHNode *node)
+{
+ int i;
+
+ /* ray-bv is really fast.. and simple tests revealed its worth to test it
+ * before calling the ray-primitive functions */
+ /* XXX: temporary solution for particles until fast_ray_nearest_hit supports ray.radius */
+ float dist = (data->ray.radius == 0.0f) ? fast_ray_nearest_hit(data, node) : ray_nearest_hit(data, node->bv);
+
+ if (node->totnode == 0) {
+ if (data->callback) {
+ data->hit.index = -1;
+ data->hit.dist = FLT_MAX;
+ data->callback(data->userdata, node->index, &data->ray, &data->hit);
+ }
+ else {
+ data->hit.index = node->index;
+ data->hit.dist = dist;
+ madd_v3_v3v3fl(data->hit.co, data->ray.origin, data->ray.direction, dist);
+ }
+ }
+ else {
+ /* pick loop direction to dive into the tree (based on ray direction and split axis) */
+ if (data->ray_dot_axis[node->main_axis] > 0.0f) {
+ for (i = 0; i != node->totnode; i++) {
+ dfs_raycast_all(data, node->children[i]);
+ }
+ }
+ else {
+ for (i = node->totnode - 1; i >= 0; i--) {
+ dfs_raycast_all(data, node->children[i]);
+ }
+ }
+ }
+}
+
#if 0
static void iterative_raycast(BVHRayCastData *data, BVHNode *node)
{
@@ -1573,6 +1609,48 @@ float BLI_bvhtree_bb_raycast(const float bv[6], const float light_start[3], cons
}
+int BLI_bvhtree_ray_cast_all(BVHTree *tree, const float co[3], const float dir[3], float radius,
+ BVHTree_RayCastCallback callback, void *userdata)
+{
+ int i;
+ BVHRayCastData data;
+ BVHNode *root = tree->nodes[tree->totleaf];
+
+ data.tree = tree;
+
+ data.callback = callback;
+ data.userdata = userdata;
+
+ copy_v3_v3(data.ray.origin, co);
+ copy_v3_v3(data.ray.direction, dir);
+ data.ray.radius = radius;
+
+ normalize_v3(data.ray.direction);
+
+ for (i = 0; i < 3; i++) {
+ data.ray_dot_axis[i] = dot_v3v3(data.ray.direction, KDOP_AXES[i]);
+ data.idot_axis[i] = 1.0f / data.ray_dot_axis[i];
+
+ if (fabsf(data.ray_dot_axis[i]) < FLT_EPSILON) {
+ data.ray_dot_axis[i] = 0.0;
+ }
+ data.index[2 * i] = data.idot_axis[i] < 0.0f ? 1 : 0;
+ data.index[2 * i + 1] = 1 - data.index[2 * i];
+ data.index[2 * i] += 2 * i;
+ data.index[2 * i + 1] += 2 * i;
+ }
+
+
+ data.hit.index = -1;
+ data.hit.dist = FLT_MAX;
+
+ if (root) {
+ dfs_raycast_all(&data, root);
+ }
+
+ return data.hit.index;
+}
+
/**
* Range Query - as request by broken :P
*
diff --git a/source/blender/blenlib/intern/boxpack2d.c b/source/blender/blenlib/intern/boxpack2d.c
index bae56444f37..2db52cbda60 100644
--- a/source/blender/blenlib/intern/boxpack2d.c
+++ b/source/blender/blenlib/intern/boxpack2d.c
@@ -32,6 +32,9 @@
#include "BLI_utildefines.h"
#include "BLI_boxpack2d.h" /* own include */
+#include "BLI_sort.h" /* qsort_r */
+#define qsort_r BLI_qsort_r
+
#include "BLI_strict_flags.h"
#ifdef __GNUC__
@@ -226,18 +229,20 @@ static int box_areasort(const void *p1, const void *p2)
* sorts from lower left to top right It uses the current box's width and height
* as offsets when sorting, this has the result of not placing boxes outside
* the bounds of the existing backed area where possible
- * */
-static float box_width;
-static float box_height;
-static BoxVert *vertarray;
+ */
+struct VertSortContext {
+ BoxVert *vertarray;
+ float box_width, box_height;
+};
-static int vertex_sort(const void *p1, const void *p2)
+static int vertex_sort(const void *p1, const void *p2, void *vs_ctx_p)
{
- BoxVert *v1, *v2;
+ const struct VertSortContext *vs_ctx = vs_ctx_p;
+ const BoxVert *v1, *v2;
float a1, a2;
- v1 = vertarray + ((const int *)p1)[0];
- v2 = vertarray + ((const int *)p2)[0];
+ v1 = &vs_ctx->vertarray[*((const unsigned int *)p1)];
+ v2 = &vs_ctx->vertarray[*((const unsigned int *)p2)];
#ifdef USE_FREE_STRIP
/* push free verts to the end so we can strip */
@@ -246,8 +251,8 @@ static int vertex_sort(const void *p1, const void *p2)
else if (UNLIKELY(v2->free == 0)) return -1;
#endif
- a1 = max_ff(v1->x + box_width, v1->y + box_height);
- a2 = max_ff(v2->x + box_width, v2->y + box_height);
+ a1 = max_ff(v1->x + vs_ctx->box_width, v1->y + vs_ctx->box_height);
+ a2 = max_ff(v2->x + vs_ctx->box_width, v2->y + vs_ctx->box_height);
#ifdef USE_PACK_BIAS
a1 += v1->bias;
@@ -285,6 +290,8 @@ void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x,
BoxPack *box, *box_test; /*current box and another for intersection tests*/
BoxVert *vert; /* the current vert */
+ struct VertSortContext vs_ctx;
+
if (!len) {
*r_tot_x = tot_x;
*r_tot_y = tot_y;
@@ -295,9 +302,11 @@ void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x,
qsort(boxarray, (size_t)len, sizeof(BoxPack), box_areasort);
/* add verts to the boxes, these are only used internally */
- vert = vertarray = MEM_mallocN((size_t)len * 4 * sizeof(BoxVert), "BoxPack Verts");
+ vert = MEM_mallocN((size_t)len * 4 * sizeof(BoxVert), "BoxPack Verts");
vertex_pack_indices = MEM_mallocN((size_t)len * 3 * sizeof(int), "BoxPack Indices");
+ vs_ctx.vertarray = vert;
+
for (box = boxarray, box_index = 0, i = 0; box_index < len; box_index++, box++) {
vert->blb = vert->brb = vert->tlb =
@@ -371,16 +380,16 @@ void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x,
/* Main boxpacking loop */
for (box_index = 1; box_index < len; box_index++, box++) {
- /* These static floatds are used for sorting */
- box_width = box->w;
- box_height = box->h;
+ /* These floats are used for sorting re-sorting */
+ vs_ctx.box_width = box->w;
+ vs_ctx.box_height = box->h;
- qsort(vertex_pack_indices, (size_t)verts_pack_len, sizeof(int), vertex_sort);
+ qsort_r(vertex_pack_indices, (size_t)verts_pack_len, sizeof(int), vertex_sort, &vs_ctx);
#ifdef USE_FREE_STRIP
/* strip free vertices */
i = verts_pack_len - 1;
- while ((i != 0) && vertarray[vertex_pack_indices[i]].free == 0) {
+ while ((i != 0) && vs_ctx.vertarray[vertex_pack_indices[i]].free == 0) {
i--;
}
verts_pack_len = i + 1;
@@ -391,7 +400,7 @@ void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x,
isect = true;
for (i = 0; i < verts_pack_len && isect; i++) {
- vert = vertarray + vertex_pack_indices[i];
+ vert = &vs_ctx.vertarray[vertex_pack_indices[i]];
/* printf("\ttesting vert %i %i %i %f %f\n", i,
* vert->free, verts_pack_len, vert->x, vert->y); */
@@ -661,5 +670,5 @@ void BLI_box_pack_2d(BoxPack *boxarray, const unsigned int len, float *r_tot_x,
box->v[0] = box->v[1] = box->v[2] = box->v[3] = NULL;
}
MEM_freeN(vertex_pack_indices);
- MEM_freeN(vertarray);
+ MEM_freeN(vs_ctx.vertarray);
}
diff --git a/source/blender/blenlib/intern/dynlib.c b/source/blender/blenlib/intern/dynlib.c
index b66eda4f141..e916b01e859 100644
--- a/source/blender/blenlib/intern/dynlib.c
+++ b/source/blender/blenlib/intern/dynlib.c
@@ -43,6 +43,8 @@ struct DynamicLibrary {
#ifdef WIN32
+#define _WIN32_WINNT 0x501 /* Windows XP or newer */
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "utf_winfunc.h"
#include "utfconv.h"
diff --git a/source/blender/blenlib/intern/fileops.c b/source/blender/blenlib/intern/fileops.c
index 62e1b6e4cbf..d6fe5e52b95 100644
--- a/source/blender/blenlib/intern/fileops.c
+++ b/source/blender/blenlib/intern/fileops.c
@@ -316,7 +316,7 @@ static bool delete_recursive(const char *dir)
while (i--) {
char file[8];
BLI_split_file_part(fl->path, file, sizeof(file));
- if (STREQ(file, ".") || STREQ(file, "..")) {
+ if (FILENAME_IS_CURRPAR(file)) {
/* Skip! */
}
else if (S_ISDIR(fl->type)) {
@@ -584,7 +584,7 @@ static int recursive_operation(const char *startfrom, const char *startto,
for (i = 0; i < n; i++) {
const struct dirent * const dirent = dirlist[i];
- if (!strcmp(dirent->d_name, ".") || !strcmp(dirent->d_name, ".."))
+ if (FILENAME_IS_CURRPAR(dirent->d_name))
continue;
join_dirfile_alloc(&from_path, &from_alloc_len, from, dirent->d_name);
diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c
index bd3e1e0bbb0..d52c09790f9 100644
--- a/source/blender/blenlib/intern/listbase.c
+++ b/source/blender/blenlib/intern/listbase.c
@@ -474,7 +474,7 @@ void *BLI_findstring(const ListBase *listbase, const char *id, const int offset)
for (link = listbase->first; link; link = link->next) {
id_iter = ((const char *)link) + offset;
- if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0) {
+ if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
return link;
}
}
@@ -494,7 +494,7 @@ void *BLI_rfindstring(const ListBase *listbase, const char *id, const int offset
for (link = listbase->last; link; link = link->prev) {
id_iter = ((const char *)link) + offset;
- if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0) {
+ if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
return link;
}
}
@@ -515,7 +515,7 @@ void *BLI_findstring_ptr(const ListBase *listbase, const char *id, const int off
/* exact copy of BLI_findstring(), except for this line */
id_iter = *((const char **)(((const char *)link) + offset));
- if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0) {
+ if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
return link;
}
}
@@ -536,7 +536,7 @@ void *BLI_rfindstring_ptr(const ListBase *listbase, const char *id, const int of
/* exact copy of BLI_rfindstring(), except for this line */
id_iter = *((const char **)(((const char *)link) + offset));
- if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0) {
+ if (id[0] == id_iter[0] && STREQ(id, id_iter)) {
return link;
}
}
@@ -600,7 +600,7 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs
while (link) {
id_iter = ((const char *)link) + offset;
- if (id[0] == id_iter[0] && strcmp(id, id_iter) == 0)
+ if (id[0] == id_iter[0] && STREQ(id, id_iter))
return i;
i++;
link = link->next;
diff --git a/source/blender/blenlib/intern/math_color_inline.c b/source/blender/blenlib/intern/math_color_inline.c
index 9233749d5df..dc62d04ad55 100644
--- a/source/blender/blenlib/intern/math_color_inline.c
+++ b/source/blender/blenlib/intern/math_color_inline.c
@@ -31,6 +31,8 @@
#include "BLI_math_color.h"
#include "BLI_utildefines.h"
+#include "math.h"
+
#ifndef __MATH_COLOR_INLINE_C__
#define __MATH_COLOR_INLINE_C__
@@ -269,6 +271,24 @@ MINLINE int compare_rgb_uchar(const unsigned char col_a[3], const unsigned char
return 0;
}
+MINLINE float dither_random_value(float s, float t)
+{
+ static float vec[2] = {12.9898f, 78.233f};
+ float value;
+
+ value = sinf(s * vec[0] + t * vec[1]) * 43758.5453f;
+ return value - floorf(value);
+}
+
+MINLINE void float_to_byte_dither_v3(unsigned char b[3], const float f[3], float dither, float s, float t)
+{
+ float dither_value = dither_random_value(s, t) * 0.005f * dither;
+
+ b[0] = FTOCHAR(dither_value + f[0]);
+ b[1] = FTOCHAR(dither_value + f[1]);
+ b[2] = FTOCHAR(dither_value + f[2]);
+}
+
/**************** Alpha Transformations *****************/
MINLINE void premul_to_straight_v4_v4(float straight[4], const float premul[4])
diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c
index 3ac031d7b90..3d5d47bc2e0 100644
--- a/source/blender/blenlib/intern/math_rotation.c
+++ b/source/blender/blenlib/intern/math_rotation.c
@@ -1016,6 +1016,40 @@ void angle_to_mat2(float mat[2][2], const float angle)
mat[1][1] = angle_cos;
}
+/****************************** Exponential Map ******************************/
+
+void quat_normalized_to_expmap(float expmap[3], const float q[4])
+{
+ float angle;
+ BLI_ASSERT_UNIT_QUAT(q);
+
+ /* Obtain axis/angle representation. */
+ quat_to_axis_angle(expmap, &angle, q);
+
+ /* Convert to exponential map. */
+ mul_v3_fl(expmap, angle);
+}
+
+void quat_to_expmap(float expmap[3], const float q[4])
+{
+ float q_no[4];
+ normalize_qt_qt(q_no, q);
+ quat_normalized_to_expmap(expmap, q_no);
+}
+
+void expmap_to_quat(float r[4], const float expmap[3])
+{
+ float axis[3];
+ float angle;
+
+ /* Obtain axis/angle representation. */
+ angle = normalize_v3_v3(axis, expmap);
+ angle = angle_wrap_rad(angle);
+
+ /* Convert to quaternion. */
+ axis_angle_to_quat(r, axis, angle);
+}
+
/******************************** XYZ Eulers *********************************/
/* XYZ order */
diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c
index 887ec7d4d2c..d065fa7e5a7 100644
--- a/source/blender/blenlib/intern/math_vector.c
+++ b/source/blender/blenlib/intern/math_vector.c
@@ -757,6 +757,13 @@ void minmax_v2v2_v2(float min[2], float max[2], const float vec[2])
if (max[1] < vec[1]) max[1] = vec[1];
}
+void minmax_v3v3_v3_array(float r_min[3], float r_max[3], float (*vec_arr)[3], int nbr)
+{
+ while (nbr--) {
+ minmax_v3v3_v3(r_min, r_max, *vec_arr++);
+ }
+}
+
/** ensure \a v1 is \a dist from \a v2 */
void dist_ensure_v3_v3fl(float v1[3], const float v2[3], const float dist)
{
diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c
index 3fff22218e2..fb4c31d5cdf 100644
--- a/source/blender/blenlib/intern/path_util.c
+++ b/source/blender/blenlib/intern/path_util.c
@@ -346,7 +346,7 @@ void BLI_cleanup_path(const char *relabase, char *path)
/* Note
* memmove(start, eind, strlen(eind) + 1);
* is the same as
- * strcpy( start, eind );
+ * strcpy(start, eind);
* except strcpy should not be used because there is overlap,
* so use memmove's slightly more obscure syntax - Campbell
*/
@@ -428,6 +428,23 @@ void BLI_cleanup_file(const char *relabase, char *path)
BLI_del_slash(path);
}
+
+/**
+ * Make given name safe to be used in paths.
+ *
+ * For now, simply replaces reserved chars (as listed in
+ * http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
+ * by underscores ('_').
+ */
+void BLI_filename_make_safe(char *fname)
+{
+ const char *invalid = "/\\?%*:|\"<>. ";
+
+ for (; *fname && (fname = strpbrk(fname, invalid)); fname++) {
+ *fname = '_';
+ }
+}
+
/**
* Does path begin with the special "//" prefix that Blender uses to indicate
* a path relative to the .blend file.
@@ -1099,9 +1116,9 @@ void BLI_make_exist(char *dir)
a = strlen(dir);
- for (BLI_join_dirfile(par_path, sizeof(par_path), dir, "..");
+ for (BLI_join_dirfile(par_path, sizeof(par_path), dir, FILENAME_PARENT);
!(BLI_is_dir(dir) && BLI_exists(par_path));
- BLI_join_dirfile(par_path, sizeof(par_path), dir, ".."))
+ BLI_join_dirfile(par_path, sizeof(par_path), dir, FILENAME_PARENT))
{
a--;
while (dir[a] != SEP) {
@@ -1352,9 +1369,7 @@ bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext)
ssize_t a;
/* first check the extension is already there */
- if ( (ext_len <= path_len) &&
- (strcmp(path + (path_len - ext_len), ext) == 0))
- {
+ if ((ext_len <= path_len) && (STREQ(path + (path_len - ext_len), ext))) {
return true;
}
diff --git a/source/blender/blenlib/intern/polyfill2d_beautify.c b/source/blender/blenlib/intern/polyfill2d_beautify.c
index 7914b7cb39b..ba71f52b530 100644
--- a/source/blender/blenlib/intern/polyfill2d_beautify.c
+++ b/source/blender/blenlib/intern/polyfill2d_beautify.c
@@ -237,7 +237,10 @@ static void polyedge_beauty_cost_update_single(
{
/* recalculate edge */
const float cost = polyedge_rotate_beauty_calc(coords, tris, e);
- if (cost < 0.0f) {
+ /* We can get cases where both choices generate very small negative costs, which leads to infinite loop.
+ * Anyway, costs above that are not worth recomputing, maybe we could even optimize it to a smaller limit?
+ * See T43578. */
+ if (cost < -FLT_EPSILON) {
eheap_table[i] = BLI_heap_insert(eheap, cost, e);
}
else {
diff --git a/source/blender/blenlib/intern/rand.c b/source/blender/blenlib/intern/rand.c
index 7657cec8cfd..a03b236b5c6 100644
--- a/source/blender/blenlib/intern/rand.c
+++ b/source/blender/blenlib/intern/rand.c
@@ -33,6 +33,7 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <time.h>
#include "MEM_guardedalloc.h"
diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c
index 4c5268562ad..38a15ab0a6d 100644
--- a/source/blender/blenlib/intern/storage.c
+++ b/source/blender/blenlib/intern/storage.c
@@ -135,10 +135,10 @@ static int bli_compare(struct direntry *entry1, struct direntry *entry2)
/* OK, now we know their S_IFMT fields are the same, go on to a name comparison */
/* make sure "." and ".." are always first */
- if (strcmp(entry1->relname, ".") == 0) return (-1);
- if (strcmp(entry2->relname, ".") == 0) return (1);
- if (strcmp(entry1->relname, "..") == 0) return (-1);
- if (strcmp(entry2->relname, "..") == 0) return (1);
+ if (FILENAME_IS_CURRENT(entry1->relname)) return (-1);
+ if (FILENAME_IS_CURRENT(entry2->relname)) return (1);
+ if (FILENAME_IS_PARENT(entry1->relname)) return (-1);
+ if (FILENAME_IS_PARENT(entry2->relname)) return (1);
return (BLI_natstrcmp(entry1->relname, entry2->relname));
}
diff --git a/source/blender/blenlib/intern/system.c b/source/blender/blenlib/intern/system.c
index 51b8efbb79f..d83077e0e78 100644
--- a/source/blender/blenlib/intern/system.c
+++ b/source/blender/blenlib/intern/system.c
@@ -115,7 +115,7 @@ void BLI_system_backtrace(FILE *fp)
symbolinfo->SizeOfStruct = sizeof(SYMBOL_INFO);
for (i = 0; i < nframes; i++) {
- SymFromAddr(process, ( DWORD64 )( stack[ i ] ), 0, symbolinfo);
+ SymFromAddr(process, (DWORD64)(stack[i]), 0, symbolinfo);
fprintf(fp, "%u: %s - 0x%0X\n", nframes - i - 1, symbolinfo->Name, symbolinfo->Address);
}
diff --git a/source/blender/blenlib/intern/time.c b/source/blender/blenlib/intern/time.c
index 078fc2c295b..a0fb78cd193 100644
--- a/source/blender/blenlib/intern/time.c
+++ b/source/blender/blenlib/intern/time.c
@@ -33,6 +33,9 @@
#include "PIL_time.h"
#ifdef WIN32
+
+#define _WIN32_WINNT 0x501 /* Windows XP or newer */
+#define WIN32_LEAN_AND_MEAN
#include <windows.h>
double PIL_check_seconds_timer(void)
@@ -70,6 +73,11 @@ double PIL_check_seconds_timer(void)
}
}
+long int PIL_check_seconds_timer_i(void)
+{
+ return (long int)PIL_check_seconds_timer();
+}
+
void PIL_sleep_ms(int ms)
{
Sleep(ms);
@@ -90,6 +98,16 @@ double PIL_check_seconds_timer(void)
return ((double) tv.tv_sec + tv.tv_usec / 1000000.0);
}
+long int PIL_check_seconds_timer_i(void)
+{
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+
+ return tv.tv_sec;
+}
+
void PIL_sleep_ms(int ms)
{
if (ms >= 1000) {
diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h
index 4b7b9cecb17..7a6107a974a 100644
--- a/source/blender/blenloader/BLO_readfile.h
+++ b/source/blender/blenloader/BLO_readfile.h
@@ -61,9 +61,7 @@ typedef struct BlendFileData {
struct Main *main;
struct UserDef *user;
- int winpos;
int fileflags;
- int displaymode;
int globalf;
char filename[1024]; /* 1024 = FILE_MAX */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index d31167976ed..6f26ec73f90 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -115,6 +115,7 @@
#include "BKE_armature.h"
#include "BKE_brush.h"
+#include "BKE_cloth.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -778,7 +779,7 @@ static void decode_blender_header(FileData *fd)
readsize = fd->read(fd, header, sizeof(header));
if (readsize == sizeof(header)) {
- if (strncmp(header, "BLENDER", 7) == 0) {
+ if (STREQLEN(header, "BLENDER", 7)) {
int remove_this_endian_test = 1;
fd->flags |= FD_FLAGS_FILE_OK;
@@ -1183,7 +1184,7 @@ bool BLO_is_a_library(const char *path, char *dir, char *group)
/* now we know that we are in a blend file and it is safe to
* assume that gp actually points to a group */
- if (strcmp("Screen", gp) != 0)
+ if (!STREQ("Screen", gp))
BLI_strncpy(group, gp, BLO_GROUP_MAX);
}
return 1;
@@ -3751,6 +3752,13 @@ static void direct_link_particlesettings(FileData *fd, ParticleSettings *part)
direct_link_partdeflect(part->pd);
direct_link_partdeflect(part->pd2);
+ part->clumpcurve = newdataadr(fd, part->clumpcurve);
+ if (part->clumpcurve)
+ direct_link_curvemapping(fd, part->clumpcurve);
+ part->roughcurve = newdataadr(fd, part->roughcurve);
+ if (part->roughcurve)
+ direct_link_curvemapping(fd, part->roughcurve);
+
part->effector_weights = newdataadr(fd, part->effector_weights);
if (!part->effector_weights)
part->effector_weights = BKE_add_effector_weights(part->eff_group);
@@ -3867,6 +3875,7 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
if (psys->clmd) {
psys->clmd = newdataadr(fd, psys->clmd);
psys->clmd->clothObject = NULL;
+ psys->clmd->hairdata = NULL;
psys->clmd->sim_parms= newdataadr(fd, psys->clmd->sim_parms);
psys->clmd->coll_parms= newdataadr(fd, psys->clmd->coll_parms);
@@ -3876,8 +3885,12 @@ static void direct_link_particlesystems(FileData *fd, ListBase *particles)
if (psys->clmd->sim_parms->presets > 10)
psys->clmd->sim_parms->presets = 0;
}
+ if (psys->clmd->coll_parms) {
+ psys->clmd->coll_parms->flags |= CLOTH_COLLSETTINGS_FLAG_POINTS;
+ }
psys->hair_in_dm = psys->hair_out_dm = NULL;
+ psys->clmd->solver_result = NULL;
psys->clmd->point_cache = psys->pointcache;
}
@@ -4472,7 +4485,7 @@ 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) {
+ else if (act->type == ACT_MOUSE) {
/* bMouseActuator *moa= act->data; */
}
}
@@ -4592,6 +4605,7 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
ClothModifierData *clmd = (ClothModifierData *)md;
clmd->clothObject = NULL;
+ clmd->hairdata = NULL;
clmd->sim_parms= newdataadr(fd, clmd->sim_parms);
clmd->coll_parms= newdataadr(fd, clmd->coll_parms);
@@ -4611,6 +4625,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
clmd->sim_parms->effector_weights = BKE_add_effector_weights(NULL);
}
}
+
+ clmd->solver_result = NULL;
}
else if (md->type == eModifierType_Fluidsim) {
FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
@@ -4765,6 +4781,11 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
BLI_endian_switch_int32_array(hmd->indexar, hmd->totindex);
}
+
+ hmd->curfalloff = newdataadr(fd, hmd->curfalloff);
+ if (hmd->curfalloff) {
+ direct_link_curvemapping(fd, hmd->curfalloff);
+ }
}
else if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;
@@ -5197,6 +5218,8 @@ static void lib_link_scene(FileData *fd, Main *main)
sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
+ sce->toolsettings->particle.shape_object = newlibadr(fd, sce->id.lib, sce->toolsettings->particle.shape_object);
+
for (base = sce->base.first; base; base = next) {
next = base->next;
@@ -5943,7 +5966,7 @@ typedef enum ePointerUserMode {
static bool restore_pointer(ID *id, ID *newid, ePointerUserMode user)
{
- if (strcmp(newid->name + 2, id->name + 2) == 0) {
+ if (STREQ(newid->name + 2, id->name + 2)) {
if (newid->lib == id->lib) {
if (user == USER_ONE) {
if (newid->us == 0) {
@@ -6804,9 +6827,10 @@ static void direct_link_sound(FileData *fd, bSound *sound)
sound->waveform = NULL;
}
- if (sound->mutex)
- sound->mutex = BLI_mutex_alloc();
-
+ if (sound->spinlock) {
+ sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
+ BLI_spin_init(sound->spinlock);
+ }
/* clear waveform loading flag */
sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING;
@@ -7521,9 +7545,7 @@ static BHead *read_global(BlendFileData *bfd, FileData *fd, BHead *bhead)
bfd->main->build_commit_timestamp = fg->build_commit_timestamp;
BLI_strncpy(bfd->main->build_hash, fg->build_hash, sizeof(bfd->main->build_hash));
- bfd->winpos = fg->winpos;
bfd->fileflags = fg->fileflags;
- bfd->displaymode = fg->displaymode;
bfd->globalf = fg->globalf;
BLI_strncpy(bfd->filename, fg->filename, sizeof(bfd->filename));
@@ -9033,7 +9055,7 @@ static ID *append_named_part(Main *mainl, FileData *fd, const char *idname, cons
if (bhead->code == idcode) {
const char *idname_test= bhead_id_name(fd, bhead);
- if (strcmp(idname_test + 2, idname) == 0) {
+ if (STREQ(idname_test + 2, idname)) {
found = 1;
id = is_yet_read(fd, mainl, bhead);
if (id == NULL) {
@@ -9154,7 +9176,7 @@ static void append_id_part(FileData *fd, Main *mainvar, ID *id, ID **r_id)
for (bhead = blo_firstbhead(fd); bhead; bhead = blo_nextbhead(fd, bhead)) {
if (bhead->code == GS(id->name)) {
- if (strcmp(id->name, bhead_id_name(fd, bhead))==0) {
+ if (STREQ(id->name, bhead_id_name(fd, bhead))) {
id->flag &= ~LIB_READ;
id->flag |= LIB_NEED_EXPAND;
// printf("read lib block %s\n", id->name);
diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c
index 8eb54c30cb1..8e485f17ef8 100644
--- a/source/blender/blenloader/intern/versioning_250.c
+++ b/source/blender/blenloader/intern/versioning_250.c
@@ -325,7 +325,7 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
SpaceNla *snla = (SpaceNla *)sl;
memcpy(&ar->v2d, &snla->v2d, sizeof(View2D));
- ar->v2d.tot.ymin = (float)(-sa->winy)/3.0f;
+ ar->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
ar->v2d.tot.ymax = 0.0f;
ar->v2d.scroll |= (V2D_SCROLL_BOTTOM|V2D_SCROLL_SCALE_HORIZONTAL);
@@ -340,8 +340,8 @@ static void area_add_window_regions(ScrArea *sa, SpaceLink *sl, ListBase *lb)
/* we totally reinit the view for the Action Editor, as some old instances had some weird cruft set */
ar->v2d.tot.xmin = -20.0f;
- ar->v2d.tot.ymin = (float)(-sa->winy)/3.0f;
- ar->v2d.tot.xmax = (float)((sa->winx > 120)? (sa->winx) : 120);
+ ar->v2d.tot.ymin = (float)(-sa->winy) / 3.0f;
+ ar->v2d.tot.xmax = (float)((sa->winx > 120) ? (sa->winx) : 120);
ar->v2d.tot.ymax = 0.0f;
ar->v2d.cur = ar->v2d.tot;
diff --git a/source/blender/blenloader/intern/versioning_260.c b/source/blender/blenloader/intern/versioning_260.c
index 7e5127aa407..10526a191d2 100644
--- a/source/blender/blenloader/intern/versioning_260.c
+++ b/source/blender/blenloader/intern/versioning_260.c
@@ -1883,7 +1883,7 @@ void blo_do_versions_260(FileData *fd, Library *UNUSED(lib), Main *main)
SEQ_END
if (scene->r.bake_samples == 0)
- scene->r.bake_samples = 256;
+ scene->r.bake_samples = 256;
if (scene->world) {
World *world = blo_do_versions_newlibadr(fd, scene->id.lib, scene->world);
diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c
index 0ff953e7420..468f56c9c0b 100644
--- a/source/blender/blenloader/intern/versioning_270.c
+++ b/source/blender/blenloader/intern/versioning_270.c
@@ -526,11 +526,114 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
br->mtex.brush_angle_mode |= MTEX_ANGLE_RANDOM;
br->mask_mtex.brush_angle_mode |= MTEX_ANGLE_RANDOM;
}
- br->mtex.random_angle = 2.0f * M_PI;
- br->mask_mtex.random_angle = 2.0f * M_PI;
+ br->mtex.random_angle = 2.0 * M_PI;
+ br->mask_mtex.random_angle = 2.0 * M_PI;
}
#undef BRUSH_RAKE
#undef BRUSH_RANDOM_ROTATION
}
+
+ /* Customizable Safe Areas */
+ if (!MAIN_VERSION_ATLEAST(main, 273, 2)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "Scene", "DisplaySafeAreas", "safe_areas")) {
+ Scene *scene;
+
+ for (scene = main->scene.first; scene; scene = scene->id.next) {
+ copy_v2_fl2(scene->safe_areas.title, 3.5f / 100.0f, 3.5f / 100.0f);
+ copy_v2_fl2(scene->safe_areas.action, 10.0f / 100.0f, 5.0f / 100.0f);
+ copy_v2_fl2(scene->safe_areas.title_center, 17.5f / 100.0f, 5.0f / 100.0f);
+ copy_v2_fl2(scene->safe_areas.action_center, 15.0f / 100.0f, 5.0f / 100.0f);
+ }
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 273, 3)) {
+ ParticleSettings *part;
+ for (part = main->particle.first; part; part = part->id.next) {
+ if (part->clumpcurve)
+ part->child_flag |= PART_CHILD_USE_CLUMP_CURVE;
+ if (part->roughcurve)
+ part->child_flag |= PART_CHILD_USE_ROUGH_CURVE;
+ }
+ }
+
+ if (!MAIN_VERSION_ATLEAST(main, 273, 6)) {
+ if (!DNA_struct_elem_find(fd->filesdna, "ClothSimSettings", "float", "bending_damping")) {
+ Object *ob;
+ ModifierData *md;
+ for (ob = main->object.first; ob; ob = ob->id.next) {
+ for (md = ob->modifiers.first; md; md = md->next) {
+ if (md->type == eModifierType_Cloth) {
+ ClothModifierData *clmd = (ClothModifierData *)md;
+ clmd->sim_parms->bending_damping = 0.5f;
+ }
+ else if (md->type == eModifierType_ParticleSystem) {
+ ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
+ if (pmd->psys->clmd) {
+ pmd->psys->clmd->sim_parms->bending_damping = 0.5f;
+ }
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "float", "clump_noise_size")) {
+ ParticleSettings *part;
+ for (part = main->particle.first; part; part = part->id.next) {
+ part->clump_noise_size = 1.0f;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "ParticleSettings", "int", "kink_extra_steps")) {
+ ParticleSettings *part;
+ for (part = main->particle.first; part; part = part->id.next) {
+ part->kink_extra_steps = 4;
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "MTex", "float", "kinkampfac")) {
+ ParticleSettings *part;
+ for (part = main->particle.first; part; part = part->id.next) {
+ int a;
+ for (a = 0; a < MAX_MTEX; a++) {
+ MTex *mtex = part->mtex[a];
+ if (mtex) {
+ mtex->kinkampfac = 1.0f;
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "HookModifierData", "char", "flag")) {
+ 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_Hook) {
+ HookModifierData *hmd = (HookModifierData *)md;
+ hmd->falloff_type = eHook_Falloff_InvSquare;
+ }
+ }
+ }
+ }
+
+ if (!DNA_struct_elem_find(fd->filesdna, "NodePlaneTrackDeformData", "char", "flag")) {
+ FOREACH_NODETREE(main, ntree, id) {
+ if (ntree->type == NTREE_COMPOSIT) {
+ bNode *node;
+ for (node = ntree->nodes.first; node; node = node->next) {
+ if (ELEM(node->type, CMP_NODE_PLANETRACKDEFORM)) {
+ NodePlaneTrackDeformData *data = node->storage;
+ data->flag = 0;
+ data->motion_blur_samples = 16;
+ data->motion_blur_shutter = 0.5f;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END
+ }
+ }
}
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index 27e49522be4..7d276ed5ed7 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -1301,7 +1301,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
Object *ob;
for (vf = main->vfont.first; vf; vf = vf->id.next) {
- if (strcmp(vf->name + strlen(vf->name)-6, ".Bfont") == 0) {
+ if (STREQ(vf->name + strlen(vf->name)-6, ".Bfont")) {
strcpy(vf->name, FO_BUILTIN_NAME);
}
}
@@ -2185,8 +2185,8 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
cam->flag |= CAM_SHOWPASSEPARTOUT;
/* make sure old cameras have title safe on */
- if (!(cam->flag & CAM_SHOWTITLESAFE))
- cam->flag |= CAM_SHOWTITLESAFE;
+ if (!(cam->flag & CAM_SHOW_SAFE_MARGINS))
+ cam->flag |= CAM_SHOW_SAFE_MARGINS;
/* set an appropriate camera passepartout alpha */
if (!(cam->passepartalpha))
@@ -2316,7 +2316,7 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
if (main->versionfile == 241) {
Image *ima;
for (ima = main->image.first; ima; ima = ima->id.next)
- if (strcmp(ima->name, "Compositor") == 0) {
+ if (STREQ(ima->name, "Compositor")) {
strcpy(ima->id.name + 2, "Viewer Node");
strcpy(ima->name, "Viewer Node");
}
@@ -2504,11 +2504,11 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *main)
ima->gen_x = 256; ima->gen_y = 256;
ima->gen_type = 1;
- if (0 == strncmp(ima->id.name + 2, "Viewer Node", sizeof(ima->id.name) - 2)) {
+ if (STREQLEN(ima->id.name + 2, "Viewer Node", sizeof(ima->id.name) - 2)) {
ima->source = IMA_SRC_VIEWER;
ima->type = IMA_TYPE_COMPOSITE;
}
- if (0 == strncmp(ima->id.name + 2, "Render Result", sizeof(ima->id.name) - 2)) {
+ if (STREQLEN(ima->id.name + 2, "Render Result", sizeof(ima->id.name) - 2)) {
ima->source = IMA_SRC_VIEWER;
ima->type = IMA_TYPE_R_RESULT;
}
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index f4c08149e05..9d20d154b7c 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -909,16 +909,39 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree)
write_node_socket_interface(wd, ntree, sock);
}
-static void current_screen_compat(Main *mainvar, bScreen **screen)
+/**
+ * Take care using 'use_active_win', since we wont want the currently active window
+ * to change which scene renders (currently only used for undo).
+ */
+static void current_screen_compat(Main *mainvar, bScreen **r_screen, bool use_active_win)
{
wmWindowManager *wm;
- wmWindow *window;
+ wmWindow *window = NULL;
/* find a global current screen in the first open window, to have
* a reasonable default for reading in older versions */
wm = mainvar->wm.first;
- window = (wm) ? wm->windows.first : NULL;
- *screen = (window) ? window->screen : NULL;
+
+ if (wm) {
+ if (use_active_win) {
+ /* write the active window into the file, needed for multi-window undo T43424 */
+ for (window = wm->windows.first; window; window = window->next) {
+ if (window->active) {
+ break;
+ }
+ }
+
+ /* fallback */
+ if (window == NULL) {
+ window = wm->windows.first;
+ }
+ }
+ else {
+ window = wm->windows.first;
+ }
+ }
+
+ *r_screen = (window) ? window->screen : NULL;
}
typedef struct RenderInfo {
@@ -937,7 +960,7 @@ static void write_renderinfo(WriteData *wd, Main *mainvar)
RenderInfo data;
/* XXX in future, handle multiple windows with multiple screens? */
- current_screen_compat(mainvar, &curscreen);
+ current_screen_compat(mainvar, &curscreen, false);
if (curscreen) curscene = curscreen->scene;
for (sce= mainvar->scene.first; sce; sce= sce->id.next) {
@@ -1062,6 +1085,11 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase)
writestruct(wd, DATA, "PartDeflect", 1, part->pd2);
writestruct(wd, DATA, "EffectorWeights", 1, part->effector_weights);
+ if (part->clumpcurve)
+ write_curvemapping(wd, part->clumpcurve);
+ if (part->roughcurve)
+ write_curvemapping(wd, part->roughcurve);
+
dw = part->dupliweights.first;
for (; dw; dw=dw->next) {
/* update indices */
@@ -1434,6 +1462,10 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
if (md->type==eModifierType_Hook) {
HookModifierData *hmd = (HookModifierData*) md;
+ if (hmd->curfalloff) {
+ write_curvemapping(wd, hmd->curfalloff);
+ }
+
writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar);
}
else if (md->type==eModifierType_Cloth) {
@@ -3387,22 +3419,21 @@ static void write_linestyles(WriteData *wd, ListBase *idbase)
* - for undofile, curscene needs to be saved */
static void write_global(WriteData *wd, int fileflags, Main *mainvar)
{
+ const bool is_undo = (wd->current != NULL);
FileGlobal fg;
bScreen *screen;
char subvstr[8];
/* prevent mem checkers from complaining */
- fg.pads= 0;
+ memset(fg.pad, 0, sizeof(fg.pad));
memset(fg.filename, 0, sizeof(fg.filename));
memset(fg.build_hash, 0, sizeof(fg.build_hash));
- current_screen_compat(mainvar, &screen);
+ current_screen_compat(mainvar, &screen, is_undo);
/* XXX still remap G */
fg.curscreen= screen;
fg.curscene= screen ? screen->scene : NULL;
- fg.displaymode= G.displaymode;
- fg.winpos= G.winpos;
/* prevent to save this, is not good convention, and feature with concerns... */
fg.fileflags= (fileflags & ~G_FILE_FLAGS_RUNTIME);
diff --git a/source/blender/bmesh/CMakeLists.txt b/source/blender/bmesh/CMakeLists.txt
index 23737866bf2..80adb595ac9 100644
--- a/source/blender/bmesh/CMakeLists.txt
+++ b/source/blender/bmesh/CMakeLists.txt
@@ -43,6 +43,7 @@ set(SRC
operators/bmo_bisect_plane.c
operators/bmo_bridge.c
operators/bmo_connect.c
+ operators/bmo_connect_concave.c
operators/bmo_connect_nonplanar.c
operators/bmo_connect_pair.c
operators/bmo_create.c
diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c
index ee35d8cd1d2..8aa64906019 100644
--- a/source/blender/bmesh/intern/bmesh_marking.c
+++ b/source/blender/bmesh/intern/bmesh_marking.c
@@ -41,6 +41,7 @@
#include "BLI_listbase.h"
#include "bmesh.h"
+#include "bmesh_structure.h"
static void recount_totsels(BMesh *bm)
{
@@ -69,6 +70,69 @@ static void recount_totsels(BMesh *bm)
}
}
+/** \name BMesh helper functions for selection flushing.
+ * \{ */
+
+static bool bm_vert_is_edge_select_any_other(BMVert *v, BMEdge *e_first)
+{
+ BMEdge *e_iter = e_first;
+
+ /* start by stepping over the current edge */
+ while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first) {
+ if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#if 0
+static bool bm_vert_is_edge_select_any(BMVert *v)
+{
+ if (v->e) {
+ BMEdge *e_iter, *e_first;
+ e_iter = e_first = v->e;
+ do {
+ if (BM_elem_flag_test(e_iter, BM_ELEM_SELECT)) {
+ return true;
+ }
+ } while ((e_iter = bmesh_disk_edge_next(e_iter, v)) != e_first);
+ }
+ return false;
+}
+#endif
+
+static bool bm_edge_is_face_select_any_other(BMLoop *l_first)
+{
+ BMLoop *l_iter = l_first;
+
+ /* start by stepping over the current face */
+ while ((l_iter = l_iter->radial_next) != l_first) {
+ if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+#if 0
+static bool bm_edge_is_face_select_any(BMEdge *e)
+{
+ if (e->l) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e->l;
+ do {
+ if (BM_elem_flag_test(l_iter->f, BM_ELEM_SELECT)) {
+ return true;
+ }
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ return false;
+}
+#endif
+
+/** \} */
+
/**
* \brief Select Mode Clean
*
@@ -341,8 +405,8 @@ void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
if (select) {
if (!BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- bm->totvertsel += 1;
BM_elem_flag_enable(v, BM_ELEM_SELECT);
+ bm->totvertsel += 1;
}
}
else {
@@ -367,39 +431,27 @@ void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
}
if (select) {
- if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) bm->totedgesel += 1;
-
- BM_elem_flag_enable(e, BM_ELEM_SELECT);
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(e, BM_ELEM_SELECT);
+ bm->totedgesel += 1;
+ }
BM_vert_select_set(bm, e->v1, true);
BM_vert_select_set(bm, e->v2, true);
}
else {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) bm->totedgesel -= 1;
- BM_elem_flag_disable(e, BM_ELEM_SELECT);
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_disable(e, BM_ELEM_SELECT);
+ bm->totedgesel -= 1;
+ }
if ((bm->selectmode & SCE_SELECT_VERTEX) == 0) {
- BMIter iter;
- BMVert *verts[2] = {e->v1, e->v2};
- BMEdge *e2;
int i;
/* check if the vert is used by a selected edge */
for (i = 0; i < 2; i++) {
- bool deselect = true;
-
- for (e2 = BM_iter_new(&iter, bm, BM_EDGES_OF_VERT, verts[i]); e2; e2 = BM_iter_step(&iter)) {
- if (e2 == e) {
- continue;
- }
-
- if (BM_elem_flag_test(e2, BM_ELEM_SELECT)) {
- deselect = false;
- break;
- }
- }
-
- if (deselect) {
- BM_vert_select_set(bm, verts[i], false);
+ BMVert *v = *((&e->v1) + i);
+ if (bm_vert_is_edge_select_any_other(v, e) == false) {
+ BM_vert_select_set(bm, v, false);
}
}
}
@@ -430,10 +482,10 @@ void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
if (select) {
if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- bm->totfacesel++;
+ BM_elem_flag_enable(f, BM_ELEM_SELECT);
+ bm->totfacesel += 1;
}
- BM_elem_flag_enable(f, BM_ELEM_SELECT);
l_iter = l_first = BM_FACE_FIRST_LOOP(f);
do {
BM_vert_select_set(bm, l_iter->v, true);
@@ -441,42 +493,80 @@ void BM_face_select_set(BMesh *bm, BMFace *f, const bool select)
} while ((l_iter = l_iter->next) != l_first);
}
else {
- BMIter liter;
- BMLoop *l;
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) bm->totfacesel -= 1;
- BM_elem_flag_disable(f, BM_ELEM_SELECT);
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_elem_flag_disable(f, BM_ELEM_SELECT);
+ bm->totfacesel -= 1;
+ }
/* flush down to edges */
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- BMIter fiter;
- BMFace *f2;
- BM_ITER_ELEM (f2, &fiter, l->e, BM_FACES_OF_EDGE) {
- if (BM_elem_flag_test(f2, BM_ELEM_SELECT))
- break;
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ /* vertex flushing is handled below */
+ if (bm_edge_is_face_select_any_other(l_iter) == false) {
+ BM_edge_select_set_noflush(bm, l_iter->e, false);
}
+ } while ((l_iter = l_iter->next) != l_first);
- if (!f2) {
- BM_edge_select_set(bm, l->e, false);
+ /* flush down to verts */
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (bm_vert_is_edge_select_any_other(l_iter->v, l_iter->e) == false) {
+ BM_vert_select_set(bm, l_iter->v, false);
}
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+}
+
+/** \name Non flushing versions element selection.
+ * \{ */
+
+void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, const bool select)
+{
+ BLI_assert(e->head.htype == BM_EDGE);
+
+ if (BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ return;
+ }
+
+ if (select) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(e, BM_ELEM_SELECT);
+ bm->totedgesel += 1;
}
+ }
+ else {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_disable(e, BM_ELEM_SELECT);
+ bm->totedgesel -= 1;
+ }
+ }
+}
- /* flush down to verts */
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- BMIter eiter;
- BMEdge *e;
- BM_ITER_ELEM (e, &eiter, l->v, BM_EDGES_OF_VERT) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT))
- break;
- }
+void BM_face_select_set_noflush(BMesh *bm, BMFace *f, const bool select)
+{
+ BLI_assert(f->head.htype == BM_FACE);
- if (!e) {
- BM_vert_select_set(bm, l->v, false);
- }
+ if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
+ return;
+ }
+
+ if (select) {
+ if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_elem_flag_enable(f, BM_ELEM_SELECT);
+ bm->totfacesel += 1;
+ }
+ }
+ else {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ BM_elem_flag_disable(f, BM_ELEM_SELECT);
+ bm->totfacesel -= 1;
}
}
}
+/** \} */
+
/**
* Select Mode Set
*
diff --git a/source/blender/bmesh/intern/bmesh_marking.h b/source/blender/bmesh/intern/bmesh_marking.h
index 9e0c0923164..15f972c6435 100644
--- a/source/blender/bmesh/intern/bmesh_marking.h
+++ b/source/blender/bmesh/intern/bmesh_marking.h
@@ -59,6 +59,10 @@ void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select);
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select);
void BM_face_select_set(BMesh *bm, BMFace *f, const bool select);
+/* lower level functions which don't do flushing */
+void BM_edge_select_set_noflush(BMesh *bm, BMEdge *e, const bool select);
+void BM_face_select_set_noflush(BMesh *bm, BMFace *e, const bool select);
+
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode);
void BM_mesh_select_mode_clean(BMesh *bm);
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index b16ea42304a..9a2869b64ef 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -34,10 +34,12 @@
#include "BLI_linklist_stack.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
+#include "BLI_stack.h"
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_editmesh.h"
+#include "BKE_mesh.h"
#include "BKE_multires.h"
#include "intern/bmesh_private.h"
@@ -438,7 +440,8 @@ void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*
static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float split_angle,
float (*r_lnos)[3])
{
- BMIter eiter;
+ BMIter eiter, viter;
+ BMVert *v;
BMEdge *e;
int i;
@@ -450,15 +453,18 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const flo
{
char htype = BM_LOOP;
- if (vnos) {
- htype |= BM_VERT;
- }
if (fnos) {
htype |= BM_FACE;
}
BM_mesh_elem_index_ensure(bm, htype);
}
+ /* Clear all vertices' tags (means they are all smooth for now). */
+ BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
+ BM_elem_index_set(v, i); /* set_inline */
+ BM_elem_flag_disable(v, BM_ELEM_TAG);
+ }
+
/* This first loop checks which edges are actually smooth, and pre-populate lnos with vnos (as if they were
* all smooth).
*/
@@ -481,13 +487,13 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const flo
* 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.
+ * 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(e, BM_ELEM_SMOOTH) &&
+ BM_elem_flag_test(l_a->f, BM_ELEM_SMOOTH) &&
+ BM_elem_flag_test(l_b->f, BM_ELEM_SMOOTH) &&
l_a->v != l_b->v)
{
const float *no;
@@ -499,20 +505,40 @@ static void bm_mesh_edges_sharp_tag(BMesh *bm, const float (*vnos)[3], const flo
no = vnos ? vnos[BM_elem_index_get(l_b->v)] : l_b->v->no;
copy_v3_v3(r_lnos[BM_elem_index_get(l_b)], no);
}
+ else {
+ /* Sharp edge, tag its verts as such. */
+ BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
+ }
+ }
+ else {
+ /* Sharp edge, tag its verts as such. */
+ BM_elem_flag_enable(e->v1, BM_ELEM_TAG);
+ BM_elem_flag_enable(e->v2, BM_ELEM_TAG);
}
}
- bm->elem_index_dirty &= ~BM_EDGE;
+ bm->elem_index_dirty &= ~(BM_EDGE | BM_VERT);
}
-/* BMesh version of BKE_mesh_normals_loop_split() in mesh_evaluate.c */
-static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const float (*fnos)[3], float (*r_lnos)[3])
+/* BMesh version of BKE_mesh_normals_loop_split() in mesh_evaluate.c
+ * Will use first clnors_data array, and fallback to cd_loop_clnors_offset (use NULL and -1 to not use clnors). */
+static void bm_mesh_loops_calc_normals(
+ BMesh *bm, const float (*vcos)[3], const float (*fnos)[3], float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
{
BMIter fiter;
BMFace *f_curr;
+ const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
+
+ MLoopNorSpaceArray _lnors_spacearr = {NULL};
/* Temp normal stack. */
BLI_SMALLSTACK_DECLARE(normal, float *);
+ /* Temp clnors stack. */
+ BLI_SMALLSTACK_DECLARE(clnors, short *);
+ /* Temp edge vectors stack, only used when computing lnor spacearr. */
+ BLI_Stack *edge_vectors = NULL;
{
char htype = BM_LOOP;
@@ -525,6 +551,15 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
BM_mesh_elem_index_ensure(bm, htype);
}
+ if (!r_lnors_spacearr && has_clnors) {
+ /* We need to compute lnor spacearr if some custom lnor data are given to us! */
+ r_lnors_spacearr = &_lnors_spacearr;
+ }
+ if (r_lnors_spacearr) {
+ BKE_lnor_spacearr_init(r_lnors_spacearr, bm->totloop);
+ edge_vectors = BLI_stack_new(sizeof(float[3]), __func__);
+ }
+
/* We now know edges that can be smoothed (they are tagged), and edges that will be hard (they aren't).
* Now, time to generate the normals.
*/
@@ -533,8 +568,10 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
do {
- if (BM_elem_flag_test_bool(l_curr->e, BM_ELEM_TAG)) {
- /* A smooth edge.
+ if (BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
+ (!r_lnors_spacearr || BM_elem_flag_test(l_curr->v, BM_ELEM_TAG)))
+ {
+ /* A smooth edge, and we are not generating lnors_spacearr, or the related vertex is sharp.
* We skip it because it is either:
* - in the middle of a 'smooth fan' already computed (or that will be as soon as we hit
* one of its ends, i.e. one of its two sharp edges), or...
@@ -542,12 +579,45 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
* are just fine!
*/
}
- else if (!BM_elem_flag_test_bool(l_curr->prev->e, BM_ELEM_TAG)) {
+ else if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
+ !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG))
+ {
/* Simple case (both edges around that vertex are sharp in related polygon),
* this vertex just takes its poly normal.
*/
+ const int l_curr_index = BM_elem_index_get(l_curr);
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);
+ copy_v3_v3(r_lnos[l_curr_index], no);
+
+ /* If needed, generate this (simple!) lnor space. */
+ if (r_lnors_spacearr) {
+ float vec_curr[3], vec_prev[3];
+ MLoopNorSpace *lnor_space = BKE_lnor_space_create(r_lnors_spacearr);
+
+ {
+ const BMVert *v_pivot = l_curr->v;
+ const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
+ const BMVert *v_1 = BM_edge_other_vert(l_curr->e, v_pivot);
+ const float *co_1 = vcos ? vcos[BM_elem_index_get(v_1)] : v_1->co;
+ const BMVert *v_2 = BM_edge_other_vert(l_curr->prev->e, v_pivot);
+ const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
+
+ sub_v3_v3v3(vec_curr, co_1, co_pivot);
+ normalize_v3(vec_curr);
+ sub_v3_v3v3(vec_prev, co_2, co_pivot);
+ normalize_v3(vec_prev);
+ }
+
+ BKE_lnor_space_define(lnor_space, r_lnos[l_curr_index], vec_curr, vec_prev, NULL);
+ /* We know there is only one loop in this space, no need to create a linklist in this case... */
+ BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, l_curr_index, false);
+
+ if (has_clnors) {
+ short (*clnor)[2] = clnors_data ? &clnors_data[l_curr_index] :
+ BM_ELEM_CD_GET_VOID_P(l_curr, cd_loop_clnors_offset);
+ BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor, r_lnos[l_curr_index]);
+ }
+ }
}
/* 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
@@ -567,13 +637,26 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
*/
BMVert *v_pivot = l_curr->v;
BMEdge *e_next;
+ const BMEdge *e_org = l_curr->e;
BMLoop *lfan_pivot, *lfan_pivot_next;
+ int lfan_pivot_index;
float lnor[3] = {0.0f, 0.0f, 0.0f};
- float vec_curr[3], vec_next[3];
+ float vec_curr[3], vec_next[3], vec_org[3];
+
+ /* We validate clnors data on the fly - cheapest way to do! */
+ int clnors_avg[2] = {0, 0};
+ short (*clnor_ref)[2] = NULL;
+ int clnors_nbr = 0;
+ bool clnors_invalid = false;
const float *co_pivot = vcos ? vcos[BM_elem_index_get(v_pivot)] : v_pivot->co;
+ MLoopNorSpace *lnor_space = r_lnors_spacearr ? BKE_lnor_space_create(r_lnors_spacearr) : NULL;
+
+ BLI_assert((edge_vectors == NULL) || BLI_stack_is_empty(edge_vectors));
+
lfan_pivot = l_curr;
+ lfan_pivot_index = BM_elem_index_get(lfan_pivot);
e_next = lfan_pivot->e; /* Current edge here, actually! */
/* Only need to compute previous edge's vector once, then we can just reuse old current one! */
@@ -581,8 +664,13 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
const BMVert *v_2 = BM_edge_other_vert(e_next, v_pivot);
const float *co_2 = vcos ? vcos[BM_elem_index_get(v_2)] : v_2->co;
- sub_v3_v3v3(vec_curr, co_2, co_pivot);
- normalize_v3(vec_curr);
+ sub_v3_v3v3(vec_org, co_2, co_pivot);
+ normalize_v3(vec_org);
+ copy_v3_v3(vec_curr, vec_org);
+
+ if (r_lnors_spacearr) {
+ BLI_stack_push(edge_vectors, vec_org);
+ }
}
while (true) {
@@ -617,12 +705,38 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
const float *no = fnos ? fnos[BM_elem_index_get(f)] : f->no;
/* Accumulate */
madd_v3_v3fl(lnor, no, fac);
+
+ if (has_clnors) {
+ /* Accumulate all clnors, if they are not all equal we have to fix that! */
+ short (*clnor)[2] = clnors_data ? &clnors_data[lfan_pivot_index] :
+ BM_ELEM_CD_GET_VOID_P(lfan_pivot, cd_loop_clnors_offset);
+ if (clnors_nbr) {
+ clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
+ }
+ else {
+ clnor_ref = clnor;
+ }
+ clnors_avg[0] += (*clnor)[0];
+ clnors_avg[1] += (*clnor)[1];
+ clnors_nbr++;
+ /* We store here a pointer to all custom lnors processed. */
+ BLI_SMALLSTACK_PUSH(clnors, (short *)*clnor);
+ }
}
/* We store here a pointer to all loop-normals processed. */
- BLI_SMALLSTACK_PUSH(normal, (float *)r_lnos[BM_elem_index_get(lfan_pivot)]);
+ BLI_SMALLSTACK_PUSH(normal, (float *)r_lnos[lfan_pivot_index]);
+
+ if (r_lnors_spacearr) {
+ /* Assign current lnor space to current 'vertex' loop. */
+ BKE_lnor_space_add_loop(r_lnors_spacearr, lnor_space, lfan_pivot_index, true);
+ if (e_next != e_org) {
+ /* We store here all edges-normalized vectors processed. */
+ BLI_stack_push(edge_vectors, vec_next);
+ }
+ }
- if (!BM_elem_flag_test_bool(e_next, BM_ELEM_TAG)) {
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
/* Next edge is sharp, we have finished with this fan of faces around this vert! */
break;
}
@@ -631,23 +745,105 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
copy_v3_v3(vec_curr, vec_next);
/* Next pivot loop to current one. */
lfan_pivot = lfan_pivot_next;
+ lfan_pivot_index = BM_elem_index_get(lfan_pivot);
}
- /* In case we get a zero normal here, just use vertex normal already set! */
- if (LIKELY(normalize_v3(lnor) != 0.0f)) {
- /* Copy back the final computed normal into all related loop-normals. */
- float *nor;
- while ((nor = BLI_SMALLSTACK_POP(normal))) {
- copy_v3_v3(nor, lnor);
+ {
+ float lnor_len = normalize_v3(lnor);
+
+ /* If we are generating lnor spacearr, we can now define the one for this fan. */
+ if (r_lnors_spacearr) {
+ if (UNLIKELY(lnor_len == 0.0f)) {
+ /* Use vertex normal as fallback! */
+ copy_v3_v3(lnor, r_lnos[lfan_pivot_index]);
+ lnor_len = 1.0f;
+ }
+
+ BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_next, edge_vectors);
+
+ if (has_clnors) {
+ if (clnors_invalid) {
+ short *clnor;
+
+ clnors_avg[0] /= clnors_nbr;
+ clnors_avg[1] /= clnors_nbr;
+ /* Fix/update all clnors of this fan with computed average value. */
+ printf("Invalid clnors in this fan!\n");
+ while ((clnor = BLI_SMALLSTACK_POP(clnors))) {
+ //print_v2("org clnor", clnor);
+ clnor[0] = (short)clnors_avg[0];
+ clnor[1] = (short)clnors_avg[1];
+ }
+ //print_v2("new clnors", clnors_avg);
+ }
+ else {
+ /* We still have to consume the stack! */
+ while (BLI_SMALLSTACK_POP(clnors));
+ }
+ BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
+ }
+ }
+
+ /* In case we get a zero normal here, just use vertex normal already set! */
+ if (LIKELY(lnor_len != 0.0f)) {
+ /* Copy back the final computed normal into all related loop-normals. */
+ float *nor;
+
+ while ((nor = BLI_SMALLSTACK_POP(normal))) {
+ copy_v3_v3(nor, lnor);
+ }
+ }
+ else {
+ /* We still have to consume the stack! */
+ while (BLI_SMALLSTACK_POP(normal));
}
}
- else {
- /* We still have to clear the stack! */
- while (BLI_SMALLSTACK_POP(normal));
+
+ /* Tag related vertex as sharp, to avoid fanning around it again (in case it was a smooth one). */
+ if (r_lnors_spacearr) {
+ BM_elem_flag_enable(l_curr->v, BM_ELEM_TAG);
}
}
} while ((l_curr = l_curr->next) != l_first);
}
+
+ if (r_lnors_spacearr) {
+ BLI_stack_free(edge_vectors);
+ if (r_lnors_spacearr == &_lnors_spacearr) {
+ BKE_lnor_spacearr_free(r_lnors_spacearr);
+ }
+ }
+}
+
+static void bm_mesh_loops_calc_normals_no_autosmooth(
+ BMesh *bm, const float (*vnos)[3], const float (*fnos)[3], float (*r_lnos)[3])
+{
+ BMIter fiter;
+ BMFace *f_curr;
+
+ {
+ char htype = BM_LOOP;
+ if (vnos) {
+ htype |= BM_VERT;
+ }
+ if (fnos) {
+ htype |= BM_FACE;
+ }
+ BM_mesh_elem_index_ensure(bm, htype);
+ }
+
+ BM_ITER_MESH (f_curr, &fiter, bm, BM_FACES_OF_MESH) {
+ BMLoop *l_curr, *l_first;
+ const bool is_face_flat = !BM_elem_flag_test(f_curr, BM_ELEM_SMOOTH);
+
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f_curr);
+ do {
+ const float *no = is_face_flat ? (fnos ? fnos[BM_elem_index_get(f_curr)] : f_curr->no) :
+ (vnos ? vnos[BM_elem_index_get(l_curr->v)] : l_curr->v->no);
+ copy_v3_v3(r_lnos[BM_elem_index_get(l_curr)], no);
+
+ } while ((l_curr = l_curr->next) != l_first);
+ }
}
#if 0 /* Unused currently */
@@ -657,13 +853,24 @@ static void bm_mesh_loops_calc_normals(BMesh *bm, const float (*vcos)[3], const
* Updates the loop normals of a mesh. Assumes vertex and face normals are valid (else call BM_mesh_normals_update()
* first)!
*/
-void BM_mesh_loop_normals_update(BMesh *bm, const float split_angle, float (*r_lnos)[3])
+void BM_mesh_loop_normals_update(
+ BMesh *bm, const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
{
- /* Tag smooth edges and set lnos from vnos when they might be completely smooth... */
- bm_mesh_edges_sharp_tag(bm, NULL, NULL, split_angle, r_lnos);
+ const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
+
+ if (use_split_normals) {
+ /* Tag smooth edges and set lnos from vnos when they might be completely smooth...
+ * When using custom loop normals, disable the angle feature! */
+ bm_mesh_edges_sharp_tag(bm, NULL, NULL, has_clnors ? (float)M_PI : split_angle, r_lnos);
- /* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
- bm_mesh_loops_calc_normals(bm, NULL, NULL, r_lnos);
+ /* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
+ bm_mesh_loops_calc_normals(bm, NULL, NULL, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
+ }
+ else {
+ BLI_assert(!r_lnors_spacearr);
+ bm_mesh_loops_calc_normals_no_autosmooth(bm, NULL, NULL, r_lnos);
+ }
}
#endif
@@ -673,14 +880,25 @@ void BM_mesh_loop_normals_update(BMesh *bm, const float split_angle, float (*r_l
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').
* Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry (splitting edges).
*/
-void BM_loops_calc_normal_vcos(BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*fnos)[3],
- const float split_angle, float (*r_lnos)[3])
+void BM_loops_calc_normal_vcos(
+ BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*fnos)[3],
+ const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
+ MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset)
{
- /* Tag smooth edges and set lnos from vnos when they might be completely smooth... */
- bm_mesh_edges_sharp_tag(bm, vnos, fnos, split_angle, r_lnos);
+ const bool has_clnors = clnors_data || (cd_loop_clnors_offset != -1);
+
+ if (use_split_normals) {
+ /* Tag smooth edges and set lnos from vnos when they might be completely smooth...
+ * When using custom loop normals, disable the angle feature! */
+ bm_mesh_edges_sharp_tag(bm, vnos, fnos, has_clnors ? (float)M_PI : split_angle, r_lnos);
- /* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
- bm_mesh_loops_calc_normals(bm, vcos, fnos, r_lnos);
+ /* Finish computing lnos by accumulating face normals in each fan of faces defined by sharp edges. */
+ bm_mesh_loops_calc_normals(bm, vcos, fnos, r_lnos, r_lnors_spacearr, clnors_data, cd_loop_clnors_offset);
+ }
+ else {
+ BLI_assert(!r_lnors_spacearr);
+ bm_mesh_loops_calc_normals_no_autosmooth(bm, vnos, fnos, r_lnos);
+ }
}
static void UNUSED_FUNCTION(bm_mdisps_space_set)(Object *ob, BMesh *bm, int from, int to)
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index 22e50502aee..bac5da8347e 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -28,6 +28,7 @@
*/
struct BMAllocTemplate;
+struct MLoopNorSpaceArray;
void BM_mesh_elem_toolflags_ensure(BMesh *bm);
void BM_mesh_elem_toolflags_clear(BMesh *bm);
@@ -39,8 +40,10 @@ void BM_mesh_clear(BMesh *bm);
void BM_mesh_normals_update(BMesh *bm);
void BM_verts_calc_normal_vcos(BMesh *bm, const float (*fnos)[3], const float (*vcos)[3], float (*vnos)[3]);
-void BM_loops_calc_normal_vcos(BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*pnos)[3],
- const float split_angle, float (*r_lnos)[3]);
+void BM_loops_calc_normal_vcos(
+ BMesh *bm, const float (*vcos)[3], const float (*vnos)[3], const float (*pnos)[3],
+ const bool use_split_normals, const float split_angle, float (*r_lnos)[3],
+ struct MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2], const int cd_loop_clnors_offset);
void bmesh_edit_begin(BMesh *bm, const BMOpTypeFlag type_flag);
void bmesh_edit_end(BMesh *bm, const BMOpTypeFlag type_flag);
diff --git a/source/blender/bmesh/intern/bmesh_opdefines.c b/source/blender/bmesh/intern/bmesh_opdefines.c
index 114358884b7..d0679b9919a 100644
--- a/source/blender/bmesh/intern/bmesh_opdefines.c
+++ b/source/blender/bmesh/intern/bmesh_opdefines.c
@@ -933,6 +933,28 @@ static BMOpDefine bmo_connect_verts_def = {
};
/*
+ * Connect Verts to form Convex Faces.
+ *
+ * Ensures all faces are convex **faces**.
+ */
+static BMOpDefine bmo_connect_verts_concave_def = {
+ "connect_verts_concave",
+ /* slots_in */
+ {{"faces", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}},
+ {{'\0'}},
+ },
+ /* slots_out */
+ {{"edges.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_EDGE}},
+ {"faces.out", BMO_OP_SLOT_ELEMENT_BUF, {BM_FACE}},
+ {{'\0'}},
+ },
+ bmo_connect_verts_concave_exec,
+ (BMO_OPTYPE_FLAG_UNTAN_MULTIRES |
+ BMO_OPTYPE_FLAG_NORMALS_CALC |
+ BMO_OPTYPE_FLAG_SELECT_FLUSH),
+};
+
+/*
* Connect Verts Across non Planer Faces.
*
* Split faces by connecting edges along non planer **faces**.
@@ -1950,6 +1972,7 @@ const BMOpDefine *bmo_opdefines[] = {
&bmo_collapse_def,
&bmo_collapse_uvs_def,
&bmo_connect_verts_def,
+ &bmo_connect_verts_concave_def,
&bmo_connect_verts_nonplanar_def,
&bmo_connect_vert_pair_def,
&bmo_contextual_create_def,
diff --git a/source/blender/bmesh/intern/bmesh_operators_private.h b/source/blender/bmesh/intern/bmesh_operators_private.h
index 9c1b7085835..979f7d2640a 100644
--- a/source/blender/bmesh/intern/bmesh_operators_private.h
+++ b/source/blender/bmesh/intern/bmesh_operators_private.h
@@ -41,6 +41,7 @@ void bmo_bridge_loops_exec(BMesh *bm, BMOperator *op);
void bmo_collapse_exec(BMesh *bm, BMOperator *op);
void bmo_collapse_uvs_exec(BMesh *bm, BMOperator *op);
void bmo_connect_verts_exec(BMesh *bm, BMOperator *op);
+void bmo_connect_verts_concave_exec(BMesh *bm, BMOperator *op);
void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op);
void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op);
void bmo_contextual_create_exec(BMesh *bm, BMOperator *op);
diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c
index e4aa4bb0c0e..bc06ba2c9b1 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.c
+++ b/source/blender/bmesh/intern/bmesh_polygon.c
@@ -743,7 +743,9 @@ bool BM_face_point_inside_test(BMFace *f, const float co[3])
void BM_face_triangulate(
BMesh *bm, BMFace *f,
BMFace **r_faces_new,
- int *r_faces_new_tot,
+ int *r_faces_new_tot,
+ BMEdge **r_edges_new,
+ int *r_edges_new_tot,
const int quad_method,
const int ngon_method,
const bool use_tag,
@@ -755,6 +757,7 @@ void BM_face_triangulate(
BMLoop *l_iter, *l_first, *l_new;
BMFace *f_new;
int nf_i = 0;
+ int ne_i = 0;
bool use_beauty = (ngon_method == MOD_TRIANGULATE_NGON_BEAUTY);
BLI_assert(BM_face_is_normal_valid(f));
@@ -835,6 +838,9 @@ void BM_face_triangulate(
if (r_faces_new) {
r_faces_new[nf_i++] = f_new;
}
+ if (r_edges_new) {
+ r_edges_new[ne_i++] = l_new->e;
+ }
}
else if (f->len > 4) {
@@ -895,8 +901,7 @@ void BM_face_triangulate(
}
}
- /* we know any edge that we create and _isnt_ */
- if (use_tag) {
+ if (use_tag || r_edges_new) {
/* new faces loops */
l_iter = l_first = l_new;
do {
@@ -906,7 +911,12 @@ void BM_face_triangulate(
bool is_new_edge = (l_iter == l_iter->radial_next);
if (is_new_edge) {
- BM_elem_flag_enable(e, BM_ELEM_TAG);
+ if (use_tag) {
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ if (r_edges_new) {
+ r_edges_new[ne_i++] = e;
+ }
}
/* note, never disable tag's */
} while ((l_iter = l_iter->next) != l_first);
@@ -925,6 +935,10 @@ void BM_face_triangulate(
if (r_faces_new_tot) {
*r_faces_new_tot = nf_i;
}
+
+ if (r_edges_new_tot) {
+ *r_edges_new_tot = ne_i;
+ }
}
/**
diff --git a/source/blender/bmesh/intern/bmesh_polygon.h b/source/blender/bmesh/intern/bmesh_polygon.h
index b25a7dbaa55..9980b59a298 100644
--- a/source/blender/bmesh/intern/bmesh_polygon.h
+++ b/source/blender/bmesh/intern/bmesh_polygon.h
@@ -63,6 +63,8 @@ void BM_face_triangulate(
BMesh *bm, BMFace *f,
BMFace **r_faces_new,
int *r_faces_new_tot,
+ BMEdge **r_edges_new,
+ int *r_edges_new_tot,
const int quad_method, const int ngon_method,
const bool use_tag,
struct MemArena *pf_arena,
diff --git a/source/blender/bmesh/intern/bmesh_queries.c b/source/blender/bmesh/intern/bmesh_queries.c
index f56cf76c41d..4d2361afa3a 100644
--- a/source/blender/bmesh/intern/bmesh_queries.c
+++ b/source/blender/bmesh/intern/bmesh_queries.c
@@ -663,7 +663,7 @@ BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
/**
* Returns edge length
*/
-float BM_edge_calc_length(BMEdge *e)
+float BM_edge_calc_length(const BMEdge *e)
{
return len_v3v3(e->v1->co, e->v2->co);
}
@@ -671,7 +671,7 @@ float BM_edge_calc_length(BMEdge *e)
/**
* Returns edge length squared (for comparisons)
*/
-float BM_edge_calc_length_squared(BMEdge *e)
+float BM_edge_calc_length_squared(const BMEdge *e)
{
return len_squared_v3v3(e->v1->co, e->v2->co);
}
@@ -731,9 +731,9 @@ 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)
+bool BM_vert_is_edge_pair(const BMVert *v)
{
- BMEdge *e = v->e;
+ const BMEdge *e = v->e;
if (e) {
const BMDiskLink *dl = bmesh_disk_edge_link_from_vert(e, v);
return (dl->next == dl->prev);
diff --git a/source/blender/bmesh/intern/bmesh_queries.h b/source/blender/bmesh/intern/bmesh_queries.h
index 5e6d4b5154b..abff55719f5 100644
--- a/source/blender/bmesh/intern/bmesh_queries.h
+++ b/source/blender/bmesh/intern/bmesh_queries.h
@@ -37,8 +37,8 @@ BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_U
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();
+float BM_edge_calc_length(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+float BM_edge_calc_length_squared(const 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();
@@ -70,7 +70,7 @@ int BM_edge_face_count(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL
int BM_vert_face_count(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
BMEdge *BM_vert_other_disk_edge(BMVert *v, BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
-bool BM_vert_is_edge_pair(BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
+bool BM_vert_is_edge_pair(const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
bool BM_vert_is_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();
diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c
new file mode 100644
index 00000000000..a00f65bd10f
--- /dev/null
+++ b/source/blender/bmesh/operators/bmo_connect_concave.c
@@ -0,0 +1,219 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/bmesh/operators/bmo_connect_concave.c
+ * \ingroup bmesh
+ *
+ * Connect vertices so all resulting faces are convex.
+ *
+ * Implementation:
+ *
+ * - triangulate all concave face (tagging convex verts),
+ * - rotate edges (beautify) so edges will connect nearby verts.
+ * - sort long edges (longest first),
+ * put any edges between 2 convex verts last since they often split convex regions.
+ * - merge the sorted edges as long as they don't create convex ngons.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_alloca.h"
+#include "BLI_memarena.h"
+#include "BLI_heap.h"
+#include "BLI_polyfill2d.h"
+#include "BLI_polyfill2d_beautify.h"
+#include "BLI_edgehash.h"
+
+#include "bmesh.h"
+
+#include "intern/bmesh_operators_private.h" /* own include */
+
+#define EDGE_OUT (1 << 0)
+#define FACE_OUT (1 << 1)
+
+static int bm_edge_length_cmp(const void *a_, const void *b_)
+{
+ const BMEdge *e_a = *(const void **)a_;
+ const BMEdge *e_b = *(const void **)b_;
+
+ int e_a_concave = ((BM_elem_flag_test(e_a->v1, BM_ELEM_TAG)) && (BM_elem_flag_test(e_a->v2, BM_ELEM_TAG)));
+ int e_b_concave = ((BM_elem_flag_test(e_b->v1, BM_ELEM_TAG)) && (BM_elem_flag_test(e_b->v2, BM_ELEM_TAG)));
+
+ /* merge edges between concave edges last since these
+ * are most likely to remain and be the main dividers */
+ if (e_a_concave < e_b_concave) return -1;
+ else if (e_a_concave > e_b_concave) return 1;
+ else {
+ /* otherwise shortest edges last */
+ const float e_a_len = BM_edge_calc_length_squared(e_a);
+ const float e_b_len = BM_edge_calc_length_squared(e_b);
+ if (e_a_len < e_b_len) return 1;
+ else if (e_a_len > e_b_len) return -1;
+ else return 0;
+ }
+}
+
+static bool bm_face_split_by_concave(
+ BMesh *bm, BMFace *f_base, const float eps,
+
+ MemArena *pf_arena,
+ struct Heap *pf_heap, struct EdgeHash *pf_ehash)
+{
+ const int f_base_len = f_base->len;
+ int faces_array_tot = f_base->len - 3;
+ int edges_array_tot = f_base->len - 3;
+ BMFace **faces_array = BLI_array_alloca(faces_array, faces_array_tot);
+ BMEdge **edges_array = BLI_array_alloca(edges_array, edges_array_tot);
+ const int quad_method = 0, ngon_method = 0; /* beauty */
+
+ float normal[3];
+ BLI_assert(f_base->len > 3);
+
+ copy_v3_v3(normal, f_base->no);
+
+ BM_face_triangulate(
+ bm, f_base,
+ faces_array, &faces_array_tot,
+ edges_array, &edges_array_tot,
+ quad_method, ngon_method, false,
+ pf_arena,
+ pf_heap, pf_ehash);
+
+ BLI_assert(edges_array_tot <= f_base_len - 3);
+
+ if (faces_array_tot) {
+ int i;
+ for (i = 0; i < faces_array_tot; i++) {
+ BMFace *f = faces_array[i];
+ BMO_elem_flag_enable(bm, f, FACE_OUT);
+ }
+ }
+ BMO_elem_flag_enable(bm, f_base, FACE_OUT);
+
+ if (edges_array_tot) {
+ int i;
+
+ qsort(edges_array, edges_array_tot, sizeof(*edges_array), bm_edge_length_cmp);
+
+ for (i = 0; i < edges_array_tot; i++) {
+ BMLoop *l_pair[2];
+ BMEdge *e = edges_array[i];
+ BMO_elem_flag_enable(bm, e, EDGE_OUT);
+
+ if (BM_edge_is_contiguous(e) &&
+ BM_edge_loop_pair(e, &l_pair[0], &l_pair[1]))
+ {
+ bool ok = true;
+ int j;
+ for (j = 0; j < 2; j++) {
+ BMLoop *l = l_pair[j];
+
+ /* check that merging the edge (on this side)
+ * wouldn't result in a convex face-loop.
+ *
+ * This is the (l->next, l->prev) we would have once joined.
+ */
+ float cross[3];
+ cross_tri_v3(
+ cross,
+ l->v->co,
+ l->radial_next->next->next->v->co,
+ l->prev->v->co
+ );
+
+ if (dot_v3v3(cross, normal) <= eps) {
+ ok = false;
+ break;
+ }
+ }
+
+ if (ok) {
+ BMFace *f_new, *f_pair[2] = {l_pair[0]->f, l_pair[1]->f};
+ f_new = BM_faces_join(bm, f_pair, 2, true);
+ if (f_new) {
+ BMO_elem_flag_enable(bm, f_new, FACE_OUT);
+ }
+ }
+ }
+ }
+ }
+
+ BLI_heap_clear(pf_heap, NULL);
+ BLI_edgehash_clear_ex(pf_ehash, NULL, BLI_POLYFILL_ALLOC_NGON_RESERVE);
+
+ return true;
+}
+
+static bool bm_face_convex_tag_verts(BMFace *f)
+{
+ bool is_concave = false;
+ if (f->len > 3) {
+ const BMLoop *l_iter, *l_first;
+
+ l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_loop_is_convex(l_iter) == false) {
+ is_concave = true;
+ BM_elem_flag_enable(l_iter->v, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_disable(l_iter->v, BM_ELEM_TAG);
+ }
+ } while ((l_iter = l_iter->next) != l_first);
+ }
+ return is_concave;
+}
+
+void bmo_connect_verts_concave_exec(BMesh *bm, BMOperator *op)
+{
+ BMOIter siter;
+ BMFace *f;
+ bool changed = false;
+
+ MemArena *pf_arena;
+ Heap *pf_heap;
+ EdgeHash *pf_ehash;
+
+ pf_arena = BLI_memarena_new(BLI_POLYFILL_ARENA_SIZE, __func__);
+ pf_heap = BLI_heap_new_ex(BLI_POLYFILL_ALLOC_NGON_RESERVE);
+ pf_ehash = BLI_edgehash_new_ex(__func__, BLI_POLYFILL_ALLOC_NGON_RESERVE);
+
+ BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
+ if (f->len > 3 && bm_face_convex_tag_verts(f)) {
+ if (bm_face_split_by_concave(
+ bm, f, FLT_EPSILON,
+ pf_arena, pf_heap, pf_ehash))
+ {
+ changed = true;
+ }
+ }
+ }
+
+ if (changed) {
+ 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, "faces.out", BM_FACE, FACE_OUT);
+ }
+
+ BLI_memarena_free(pf_arena);
+ BLI_heap_free(pf_heap, NULL);
+ BLI_edgehash_free(pf_ehash, NULL);
+}
diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
index 6859ce2060c..c9ce2c5f6b8 100644
--- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c
+++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c
@@ -153,23 +153,11 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op)
{
BMOIter siter;
BMFace *f;
- int totface = 0, totloop = 0;
+ bool changed = false;
BLI_LINKSTACK_DECLARE(fstack, BMFace *);
const float angle_limit = BMO_slot_float_get(op->slots_in, "angle_limit");
-
- BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
- if (f->len > 3) {
- totface += 1;
- totloop += f->len;
- }
- }
-
- if (totface == 0) {
- return;
- }
-
BLI_LINKSTACK_INIT(fstack);
BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) {
@@ -188,11 +176,14 @@ void bmo_connect_verts_nonplanar_exec(BMesh *bm, BMOperator *op)
BLI_LINKSTACK_PUSH(fstack, f_pair[j]);
}
}
+ changed = true;
}
}
BLI_LINKSTACK_FREE(fstack);
- 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, "faces.out", BM_FACE, FACE_OUT);
+ if (changed) {
+ 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, "faces.out", BM_FACE, FACE_OUT);
+ }
}
diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c
index 8cd9ee14bcb..ecb41363761 100644
--- a/source/blender/bmesh/operators/bmo_dissolve.c
+++ b/source/blender/bmesh/operators/bmo_dissolve.c
@@ -475,7 +475,7 @@ void bmo_dissolve_limit_exec(BMesh *bm, BMOperator *op)
{
BMOpSlot *einput = BMO_slot_get(op->slots_in, "edges");
BMOpSlot *vinput = BMO_slot_get(op->slots_in, "verts");
- const float angle_max = (float)M_PI / 2.0f;
+ const float angle_max = M_PI_2;
const float angle_limit = min_ff(angle_max, BMO_slot_float_get(op->slots_in, "angle_limit"));
const bool do_dissolve_boundaries = BMO_slot_bool_get(op->slots_in, "use_dissolve_boundaries");
const BMO_Delimit delimit = BMO_slot_int_get(op->slots_in, "delimit");
diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c
index 88b53b63abb..aa92c3054cd 100644
--- a/source/blender/bmesh/operators/bmo_extrude.c
+++ b/source/blender/bmesh/operators/bmo_extrude.c
@@ -608,10 +608,10 @@ static void calc_solidify_normals(BMesh *bm)
}
else {
/* only one face attached to that edge */
- /* an edge without another attached- the weight on this is
- * undefined, M_PI / 2 is 90d in radians and that seems good enough */
+ /* an edge without another attached- the weight on this is undefined,
+ * M_PI_2 is 90d in radians and that seems good enough */
copy_v3_v3(edge_normal, f1->no);
- mul_v3_fl(edge_normal, M_PI / 2);
+ mul_v3_fl(edge_normal, M_PI_2);
}
add_v3_v3(e->v1->no, edge_normal);
diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c
index 9c8b9ca160d..871bee64c19 100644
--- a/source/blender/bmesh/operators/bmo_removedoubles.c
+++ b/source/blender/bmesh/operators/bmo_removedoubles.c
@@ -529,7 +529,7 @@ static void bmesh_find_doubles_common(BMesh *bm, BMOperator *op,
const float dist = BMO_slot_float_get(op->slots_in, "dist");
const float dist_sq = dist * dist;
- const float dist3 = (M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
+ const float dist3 = ((float)M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
/* Test whether keep_verts arg exists and is non-empty */
if (BMO_slot_exists(op->slots_in, "keep_verts")) {
diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c
index 02462e380b4..5f8438919df 100644
--- a/source/blender/bmesh/operators/bmo_similar.c
+++ b/source/blender/bmesh/operators/bmo_similar.c
@@ -412,10 +412,10 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op)
/* compute the angle between the two edges */
angle = angle_normalized_v3v3(e_ext[i].dir, e_ext[indices[idx]].dir);
- if (angle > (float)(M_PI / 2.0)) /* use the smallest angle between the edges */
+ if (angle > (float)M_PI_2) /* use the smallest angle between the edges */
angle = fabsf(angle - (float)M_PI);
- if (angle / (float)(M_PI / 2.0) <= thresh) {
+ if (angle / (float)M_PI_2 <= thresh) {
BMO_elem_flag_enable(bm, e, EDGE_MARK);
cont = false;
}
diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c
index 8a1569630fa..26b53a21709 100644
--- a/source/blender/bmesh/tools/bmesh_intersect.c
+++ b/source/blender/bmesh/tools/bmesh_intersect.c
@@ -541,7 +541,7 @@ static void bm_isect_tri_tri(
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)) {
+ if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
float ix[3];
interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac);
if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) {
@@ -579,7 +579,7 @@ static void bm_isect_tri_tri(
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)) {
+ if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) {
float ix[3];
interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac);
if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) {
diff --git a/source/blender/bmesh/tools/bmesh_triangulate.c b/source/blender/bmesh/tools/bmesh_triangulate.c
index b76054f270f..404776a0769 100644
--- a/source/blender/bmesh/tools/bmesh_triangulate.c
+++ b/source/blender/bmesh/tools/bmesh_triangulate.c
@@ -64,7 +64,9 @@ static void bm_face_triangulate_mapping(
BLI_assert(face->len > 3);
BM_face_triangulate(
- bm, face, faces_array, &faces_array_tot,
+ bm, face,
+ faces_array, &faces_array_tot,
+ NULL, NULL,
quad_method, ngon_method, use_tag,
pf_arena,
pf_heap, pf_ehash);
@@ -121,7 +123,9 @@ void BM_mesh_triangulate(
if (face->len > 3) {
if (tag_only == false || BM_elem_flag_test(face, BM_ELEM_TAG)) {
BM_face_triangulate(
- bm, face, NULL, NULL,
+ bm, face,
+ NULL, NULL,
+ NULL, NULL,
quad_method, ngon_method, tag_only,
pf_arena,
pf_heap, pf_ehash);
diff --git a/source/blender/collada/AnimationExporter.cpp b/source/blender/collada/AnimationExporter.cpp
index f2c057d32d8..9077db524db 100644
--- a/source/blender/collada/AnimationExporter.cpp
+++ b/source/blender/collada/AnimationExporter.cpp
@@ -76,9 +76,9 @@ void AnimationExporter::operator()(Object *ob)
else
transformName = extract_transform_name(fcu->rna_path);
- if ((!strcmp(transformName, "location") || !strcmp(transformName, "scale")) ||
- (!strcmp(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
- (!strcmp(transformName, "rotation_quaternion")))
+ if ((STREQ(transformName, "location") || STREQ(transformName, "scale")) ||
+ (STREQ(transformName, "rotation_euler") && ob->rotmode == ROT_MODE_EUL) ||
+ (STREQ(transformName, "rotation_quaternion")))
{
dae_animation(ob, fcu, transformName, false);
}
@@ -98,8 +98,8 @@ void AnimationExporter::operator()(Object *ob)
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
- if ((!strcmp(transformName, "color")) || (!strcmp(transformName, "spot_size")) ||
- (!strcmp(transformName, "spot_blend")) || (!strcmp(transformName, "distance")))
+ if ((STREQ(transformName, "color")) || (STREQ(transformName, "spot_size")) ||
+ (STREQ(transformName, "spot_blend")) || (STREQ(transformName, "distance")))
{
dae_animation(ob, fcu, transformName, true);
}
@@ -113,10 +113,10 @@ void AnimationExporter::operator()(Object *ob)
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
- if ((!strcmp(transformName, "lens")) ||
- (!strcmp(transformName, "ortho_scale")) ||
- (!strcmp(transformName, "clip_end")) ||
- (!strcmp(transformName, "clip_start")))
+ if ((STREQ(transformName, "lens")) ||
+ (STREQ(transformName, "ortho_scale")) ||
+ (STREQ(transformName, "clip_end")) ||
+ (STREQ(transformName, "clip_start")))
{
dae_animation(ob, fcu, transformName, true);
}
@@ -134,9 +134,9 @@ void AnimationExporter::operator()(Object *ob)
while (fcu) {
transformName = extract_transform_name(fcu->rna_path);
- if ((!strcmp(transformName, "specular_hardness")) || (!strcmp(transformName, "specular_color")) ||
- (!strcmp(transformName, "diffuse_color")) || (!strcmp(transformName, "alpha")) ||
- (!strcmp(transformName, "ior")))
+ if ((STREQ(transformName, "specular_hardness")) || (STREQ(transformName, "specular_color")) ||
+ (STREQ(transformName, "diffuse_color")) || (STREQ(transformName, "alpha")) ||
+ (STREQ(transformName, "ior")))
{
dae_animation(ob, fcu, transformName, true, ma);
}
@@ -225,7 +225,7 @@ float *AnimationExporter::get_eul_source_for_quat(Object *ob)
while (fcu) {
char *transformName = extract_transform_name(fcu->rna_path);
- if (!strcmp(transformName, "rotation_quaternion") ) {
+ if (STREQ(transformName, "rotation_quaternion") ) {
for (int i = 0; i < fcu->totvert; i++) {
*(quat + (i * 4) + fcu->array_index) = fcu->bezt[i].vec[1][1];
}
@@ -278,17 +278,17 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
bool has_tangents = false;
bool quatRotation = false;
- if (!strcmp(transformName, "rotation_quaternion") ) {
+ if (STREQ(transformName, "rotation_quaternion") ) {
fprintf(stderr, "quaternion rotation curves are not supported. rotation curve will not be exported\n");
quatRotation = true;
return;
}
//axis names for colors
- else if (!strcmp(transformName, "color") ||
- !strcmp(transformName, "specular_color") ||
- !strcmp(transformName, "diffuse_color") ||
- !strcmp(transformName, "alpha"))
+ else if (STREQ(transformName, "color") ||
+ STREQ(transformName, "specular_color") ||
+ STREQ(transformName, "diffuse_color") ||
+ STREQ(transformName, "alpha"))
{
const char *axis_names[] = {"R", "G", "B"};
if (fcu->array_index < 3)
@@ -296,10 +296,10 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
}
//axis names for transforms
- else if (!strcmp(transformName, "location") ||
- !strcmp(transformName, "scale") ||
- !strcmp(transformName, "rotation_euler") ||
- !strcmp(transformName, "rotation_quaternion"))
+ else if (STREQ(transformName, "location") ||
+ STREQ(transformName, "scale") ||
+ STREQ(transformName, "rotation_euler") ||
+ STREQ(transformName, "rotation_quaternion"))
{
const char *axis_names[] = {"X", "Y", "Z"};
if (fcu->array_index < 3)
@@ -357,7 +357,7 @@ void AnimationExporter::dae_animation(Object *ob, FCurve *fcu, char *transformNa
MEM_freeN(eul);
MEM_freeN(eul_axis);
}
- else if (!strcmp(transformName, "lens") && (ob->type == OB_CAMERA)) {
+ else if (STREQ(transformName, "lens") && (ob->type == OB_CAMERA)) {
output_id = create_lens_source_from_fcurve((Camera *) ob->data, COLLADASW::InputSemantic::OUTPUT, fcu, anim_id);
}
else {
@@ -763,7 +763,7 @@ std::string AnimationExporter::create_source_from_fcurve(COLLADASW::InputSemanti
{
std::string source_id = anim_id + get_semantic_suffix(semantic);
- //bool is_angle = !strcmp(fcu->rna_path, "rotation");
+ //bool is_angle = STREQ(fcu->rna_path, "rotation");
bool is_angle = false;
if (strstr(fcu->rna_path, "rotation") || strstr(fcu->rna_path,"spot_size")) is_angle = true;
@@ -1103,13 +1103,13 @@ std::string AnimationExporter::get_light_param_sid(char *rna_path, int tm_type,
if (rna_path) {
char *name = extract_transform_name(rna_path);
- if (!strcmp(name, "color"))
+ if (STREQ(name, "color"))
tm_type = 1;
- else if (!strcmp(name, "spot_size"))
+ else if (STREQ(name, "spot_size"))
tm_type = 2;
- else if (!strcmp(name, "spot_blend"))
+ else if (STREQ(name, "spot_blend"))
tm_type = 3;
- else if (!strcmp(name, "distance"))
+ else if (STREQ(name, "distance"))
tm_type = 4;
else
tm_type = -1;
@@ -1151,13 +1151,13 @@ std::string AnimationExporter::get_camera_param_sid(char *rna_path, int tm_type,
if (rna_path) {
char *name = extract_transform_name(rna_path);
- if (!strcmp(name, "lens"))
+ if (STREQ(name, "lens"))
tm_type = 0;
- else if (!strcmp(name, "ortho_scale"))
+ else if (STREQ(name, "ortho_scale"))
tm_type = 1;
- else if (!strcmp(name, "clip_end"))
+ else if (STREQ(name, "clip_end"))
tm_type = 2;
- else if (!strcmp(name, "clip_start"))
+ else if (STREQ(name, "clip_start"))
tm_type = 3;
else
@@ -1203,23 +1203,23 @@ std::string AnimationExporter::get_transform_sid(char *rna_path, int tm_type, co
if (rna_path) {
char *name = extract_transform_name(rna_path);
- if (!strcmp(name, "rotation_euler"))
+ if (STREQ(name, "rotation_euler"))
tm_type = 0;
- else if (!strcmp(name, "rotation_quaternion"))
+ else if (STREQ(name, "rotation_quaternion"))
tm_type = 1;
- else if (!strcmp(name, "scale"))
+ else if (STREQ(name, "scale"))
tm_type = 2;
- else if (!strcmp(name, "location"))
+ else if (STREQ(name, "location"))
tm_type = 3;
- else if (!strcmp(name, "specular_hardness"))
+ else if (STREQ(name, "specular_hardness"))
tm_type = 4;
- else if (!strcmp(name, "specular_color"))
+ else if (STREQ(name, "specular_color"))
tm_type = 5;
- else if (!strcmp(name, "diffuse_color"))
+ else if (STREQ(name, "diffuse_color"))
tm_type = 6;
- else if (!strcmp(name, "alpha"))
+ else if (STREQ(name, "alpha"))
tm_type = 7;
- else if (!strcmp(name, "ior"))
+ else if (STREQ(name, "ior"))
tm_type = 8;
else
@@ -1311,7 +1311,7 @@ void AnimationExporter::enable_fcurves(bAction *act, char *bone_name)
for (fcu = (FCurve *)act->curves.first; fcu; fcu = fcu->next) {
if (bone_name) {
- if (!strncmp(fcu->rna_path, prefix, strlen(prefix)))
+ if (STREQLEN(fcu->rna_path, prefix, strlen(prefix)))
fcu->flag &= ~FCURVE_DISABLED;
else
fcu->flag |= FCURVE_DISABLED;
@@ -1378,11 +1378,11 @@ void AnimationExporter::find_frames(Object *ob, std::vector<float> &fra, const c
FCurve *fcu = (FCurve *)ob->adt->action->curves.first;
for (; fcu; fcu = fcu->next) {
- if (prefix && strncmp(prefix, fcu->rna_path, strlen(prefix)))
+ if (prefix && !STREQLEN(prefix, fcu->rna_path, strlen(prefix)))
continue;
char *name = extract_transform_name(fcu->rna_path);
- if (!strcmp(name, tm_name)) {
+ if (STREQ(name, tm_name)) {
for (unsigned int i = 0; i < fcu->totvert; i++) {
float f = fcu->bezt[i].vec[1][0];
if (std::find(fra.begin(), fra.end(), f) == fra.end())
diff --git a/source/blender/collada/AnimationImporter.cpp b/source/blender/collada/AnimationImporter.cpp
index 6e2d337a32e..7e937e42787 100644
--- a/source/blender/collada/AnimationImporter.cpp
+++ b/source/blender/collada/AnimationImporter.cpp
@@ -649,7 +649,7 @@ void AnimationImporter:: Assign_float_animations(const COLLADAFW::UniqueId& list
for (iter = animcurves.begin(); iter != animcurves.end(); iter++) {
FCurve *fcu = *iter;
/* All anim_types whose values are to be converted from Degree to Radians can be ORed here */
- if (strcmp("spot_size", anim_type)==0) {
+ if (STREQ("spot_size", anim_type)) {
/* NOTE: Do NOT convert if imported file was made by blender <= 2.69.10
* Reason: old blender versions stored spot_size in radians (was a bug)
*/
diff --git a/source/blender/collada/ArmatureExporter.cpp b/source/blender/collada/ArmatureExporter.cpp
index 5ce62873377..36ab85b9b5b 100644
--- a/source/blender/collada/ArmatureExporter.cpp
+++ b/source/blender/collada/ArmatureExporter.cpp
@@ -181,7 +181,7 @@ void ArmatureExporter::add_bone_node(Bone *bone, Object *ob_arm, Scene *sce,
std::list<Object *>::iterator i = child_objects.begin();
while (i != child_objects.end()) {
- if ((*i)->partype == PARBONE && (0 == strcmp((*i)->parsubstr, bone->name))) {
+ if ((*i)->partype == PARBONE && STREQ((*i)->parsubstr, bone->name)) {
float backup_parinv[4][4];
copy_m4_m4(backup_parinv, (*i)->parentinv);
diff --git a/source/blender/collada/ArmatureImporter.cpp b/source/blender/collada/ArmatureImporter.cpp
index 7ffd300c6de..c2ee6170470 100644
--- a/source/blender/collada/ArmatureImporter.cpp
+++ b/source/blender/collada/ArmatureImporter.cpp
@@ -54,7 +54,7 @@ static EditBone *get_edit_bone(bArmature * armature, char *name) {
EditBone *eBone;
for (eBone = (EditBone *)armature->edbo->first; eBone; eBone = eBone->next) {
- if (!strcmp(name, eBone->name))
+ if (STREQ(name, eBone->name))
return eBone;
}
diff --git a/source/blender/collada/ControllerExporter.cpp b/source/blender/collada/ControllerExporter.cpp
index 25fd9c81535..16c3f68bca4 100644
--- a/source/blender/collada/ControllerExporter.cpp
+++ b/source/blender/collada/ControllerExporter.cpp
@@ -473,7 +473,7 @@ static float get_property(Bone *bone, const char *key, float def)
if (bone->prop) {
IDProperty *property = IDP_GetPropertyFromGroup(bone->prop, key);
if (property) {
- switch(property->type) {
+ switch (property->type) {
case IDP_INT:
result = (float)(IDP_Int(property));
break;
diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp
index 3c35618a4cd..13dc1eda580 100644
--- a/source/blender/collada/EffectExporter.cpp
+++ b/source/blender/collada/EffectExporter.cpp
@@ -133,7 +133,7 @@ void EffectsExporter::writeTextures(COLLADASW::EffectProfile &ep,
if (!ima) return;
// color
- if (t->mapto & (MAP_COL | MAP_COLSPEC)) {
+ if (t->mapto & MAP_COL) {
ep.setDiffuse(createTexture(ima, uvname, sampler), false, "diffuse");
}
// ambient
@@ -141,7 +141,7 @@ void EffectsExporter::writeTextures(COLLADASW::EffectProfile &ep,
ep.setAmbient(createTexture(ima, uvname, sampler), false, "ambient");
}
// specular
- if (t->mapto & MAP_SPEC) {
+ if (t->mapto & (MAP_SPEC | MAP_COLSPEC)) {
ep.setSpecular(createTexture(ima, uvname, sampler), false, "specular");
}
// emission
@@ -263,7 +263,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
COLLADASW::Sampler samplers[MAX_MTEX];
//COLLADASW::Surface surfaces[MAX_MTEX];
//void *samp_surf[MAX_MTEX][2];
- void *samp_surf[MAX_MTEX][1];
+ void *samp_surf[MAX_MTEX];
// image to index to samp_surf map
// samp_surf[index] stores 2 pointers, sampler and surface
@@ -302,7 +302,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
//surfaces[a] = surface;
// store pointers so they can be used later when we create <texture>s
- samp_surf[b][0] = &samplers[a];
+ samp_surf[b] = &samplers[a];
//samp_surf[b][1] = &surfaces[a];
im_samp_map[key] = b;
@@ -349,7 +349,7 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
key + COLLADASW::Sampler::SURFACE_SID_SUFFIX);
sampler.setImageId(key);
samplers[a] = sampler;
- samp_surf[b][0] = &samplers[a];
+ samp_surf[b] = &samplers[a];
im_samp_map[key] = b;
b++;
a++;
@@ -380,19 +380,19 @@ void EffectsExporter::operator()(Material *ma, Object *ob)
key = translate_id(key);
int i = im_samp_map[key];
std::string uvname = strlen(t->uvname) ? t->uvname : active_uv;
- COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i][0];
+ COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i];
writeTextures(ep, key, sampler, t, ima, uvname);
}
std::set<Image *>::iterator uv_t_iter;
int idx;
for (idx = 0, uv_t_iter = uv_textures.begin(); uv_t_iter != uv_textures.end(); uv_t_iter++, idx++ ) {
- if(active_uv_layer>-1 && idx==active_uv_layer) {
+ 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];
+ COLLADASW::Sampler *sampler = (COLLADASW::Sampler *)samp_surf[i];
ep.setDiffuse(createTexture(ima, active_uv, sampler), false, "diffuse");
}
}
diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp
index 854e8abd76d..b271604f839 100644
--- a/source/blender/collada/ErrorHandler.cpp
+++ b/source/blender/collada/ErrorHandler.cpp
@@ -34,6 +34,8 @@
#include <string.h>
+#include "BLI_utildefines.h"
+
//--------------------------------------------------------------------
ErrorHandler::ErrorHandler() : mError(false)
{
@@ -55,13 +57,13 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error)
// Workaround to avoid wrong error
if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_MIN_OCCURS_UNMATCHED) {
- if (strcmp(parserError.getElement(), "effect") == 0) {
+ if (STREQ(parserError.getElement(), "effect")) {
isError = false;
}
}
if (parserError.getErrorType() == GeneratedSaxParser::ParserError::ERROR_VALIDATION_SEQUENCE_PREVIOUS_SIBLING_NOT_PRESENT) {
- if (!((strcmp(parserError.getElement(), "extra") == 0) &&
- (strcmp(parserError.getAdditionalText().c_str(), "sibling: fx_profile_abstract") == 0)))
+ if (!(STREQ(parserError.getElement(), "extra") &&
+ STREQ(parserError.getAdditionalText().c_str(), "sibling: fx_profile_abstract")))
{
isError = false;
}
diff --git a/source/blender/collada/ImageExporter.cpp b/source/blender/collada/ImageExporter.cpp
index 5fd5fab3492..a5c1493208b 100644
--- a/source/blender/collada/ImageExporter.cpp
+++ b/source/blender/collada/ImageExporter.cpp
@@ -89,7 +89,7 @@ void ImagesExporter::export_UV_Image(Image *image, bool use_copies)
// make absolute destination path
BLI_strncpy(export_file, name.c_str(), sizeof(export_file));
- BKE_add_image_extension(export_file, &imageFormat);
+ BKE_image_path_ensure_ext_from_imformat(export_file, &imageFormat);
BLI_join_dirfile(export_path, sizeof(export_path), export_dir, export_file);
diff --git a/source/blender/collada/ImportSettings.cpp b/source/blender/collada/ImportSettings.cpp
index 74607787f25..9483aa1ac76 100644
--- a/source/blender/collada/ImportSettings.cpp
+++ b/source/blender/collada/ImportSettings.cpp
@@ -20,7 +20,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/collada/ExportSettings.cpp
+/** \file blender/collada/ImportSettings.cpp
* \ingroup collada
*/
diff --git a/source/blender/collada/ImportSettings.h b/source/blender/collada/ImportSettings.h
index 51a13da7724..783f58e6bff 100644
--- a/source/blender/collada/ImportSettings.h
+++ b/source/blender/collada/ImportSettings.h
@@ -20,7 +20,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file ExportSettings.h
+/** \file ImportSettings.h
* \ingroup collada
*/
diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp
index a4bf1d28366..02e78b9bc45 100644
--- a/source/blender/collada/MeshImporter.cpp
+++ b/source/blender/collada/MeshImporter.cpp
@@ -227,8 +227,7 @@ void MeshImporter::set_vcol(MLoopCol *mlc, VCOLDataWrapper &vob, int loop_index,
{
COLLADAFW::UIntValuesArray& indices =index_list.getIndices();
int index;
- for(index = 0; index < count; index++,mlc++)
- {
+ for (index = 0; index < count; index++, mlc++) {
int v_index = indices[index+loop_index];
vob.get_vcol(v_index,mlc);
}
@@ -708,8 +707,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, Mesh *me)
mpoly->flag |= ME_SMOOTH;
}
- for(unsigned int vcolor_index = 0 ; vcolor_index < index_list_array_vcolor.getCount();vcolor_index++)
- {
+ for (unsigned int vcolor_index = 0 ; vcolor_index < index_list_array_vcolor.getCount();vcolor_index++) {
COLLADAFW::IndexList& index_list = *index_list_array_vcolor[vcolor_index];
COLLADAFW::String colname = extract_vcolname(index_list.getName());
MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_named(&me->ldata, CD_MLOOPCOL, colname.c_str());
@@ -820,7 +818,7 @@ void MeshImporter::bmeshConversion()
Mesh *me = (*m).second;
BKE_mesh_tessface_clear(me);
BKE_mesh_calc_normals(me);
- //BKE_mesh_validate(me, 1);
+ /* BKE_mesh_validate(me, true, true); */
}
}
}
@@ -1063,7 +1061,7 @@ MTFace *MeshImporter::assign_material_to_geom(COLLADAFW::MaterialBinding cmateri
// set texture face
if (color_texture &&
strlen((color_texture)->uvname) &&
- strcmp(layername, color_texture->uvname) != 0) {
+ !STREQ(layername, color_texture->uvname)) {
texture_face = (MTFace *)CustomData_get_layer_named(&me->fdata, CD_MTFACE,
color_texture->uvname);
strcpy(layername, color_texture->uvname);
diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt
index 4bcdd4d9e34..048c974423f 100644
--- a/source/blender/compositor/CMakeLists.txt
+++ b/source/blender/compositor/CMakeLists.txt
@@ -90,8 +90,6 @@ set(SRC
intern/COM_OpenCLDevice.h
intern/COM_CompositorContext.cpp
intern/COM_CompositorContext.h
- intern/COM_ChannelInfo.cpp
- intern/COM_ChannelInfo.h
intern/COM_SingleThreadedOperation.cpp
intern/COM_SingleThreadedOperation.h
intern/COM_Debug.cpp
diff --git a/source/blender/compositor/COM_defines.h b/source/blender/compositor/COM_defines.h
index b60fffc6a22..9936914d3d8 100644
--- a/source/blender/compositor/COM_defines.h
+++ b/source/blender/compositor/COM_defines.h
@@ -105,7 +105,9 @@ typedef enum OrderOfChunks {
#define COM_RULE_OF_THIRDS_DIVIDER 100.0f
-#define COM_NUMBER_OF_CHANNELS 4
+#define COM_NUM_CHANNELS_VALUE 1
+#define COM_NUM_CHANNELS_VECTOR 3
+#define COM_NUM_CHANNELS_COLOR 4
#define COM_BLUR_BOKEH_PIXELS 512
diff --git a/source/blender/compositor/intern/COM_ChannelInfo.h b/source/blender/compositor/intern/COM_ChannelInfo.h
deleted file mode 100644
index ec78e7e1cb1..00000000000
--- a/source/blender/compositor/intern/COM_ChannelInfo.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2011, Blender Foundation.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * Contributor:
- * Jeroen Bakker
- * Monique Dewanchand
- */
-
-#ifndef _COM_ChannelInfo_h
-#define _COM_ChannelInfo_h
-
-#include <vector>
-#include "BKE_text.h"
-#include <string>
-#include "DNA_node_types.h"
-#include "BLI_rect.h"
-
-using namespace std;
-
-/**
- * @brief List of possible channel types
- * @ingroup Model
- */
-typedef enum ChannelType {
- COM_CT_ColorComponent /** @brief this channel is contains color information. Specific used is determined by channelnumber, and in the future color space */,
- COM_CT_Alpha /** @brief this channel is contains transparency value */,
- COM_CT_Value /** @brief this channel is contains a value */,
- COM_CT_X /** @brief this channel is contains a X value */,
- COM_CT_Y /** @brief this channel is contains a Y value */,
- COM_CT_Z /** @brief this channel is contains a Z value */,
- COM_CT_W /** @brief this channel is contains a W value */,
- COM_CT_UNUSED /** @brief this channel is unused */
-} ChannelType;
-
-/**
- * @brief ChannelInfo holds information about a channel.
- *
- * Channels are transported from node to node via a NodeLink.
- * ChannelInfo holds specific setting of these channels in order that the to-node of the link
- * Can handle specific logic per channel setting.
- *
- * @note currently this is not used, but a future place to implement color spacing and other things.
- * @ingroup Model
- */
-class ChannelInfo {
-private:
- /**
- * @brief the channel number, in the link. [0-3]
- */
- int m_number;
-
- /**
- * @brief type of channel
- */
- ChannelType m_type;
-
- /**
- * @brieg Is this value in this channel premultiplied with its alpha
- * @note only valid if type = ColorComponent;
- */
- bool m_premultiplied;
-
-// /**
-// * Color space of this value.
-// * only valid when type = ColorComponent;
-// */
-// string colorspacename;
-
-public:
- /**
- * @brief creates a new ChannelInfo and set default values
- */
- ChannelInfo();
-
- /**
- * @brief set the index of this channel in the NodeLink
- */
- void setNumber(const int number) { this->m_number = number; }
-
- /**
- * @brief get the index of this channel in the NodeLink
- */
- const int getNumber() const { return this->m_number; }
-
- /**
- * @brief set the type of channel
- */
- void setType(const ChannelType type) { this->m_type = type; }
-
- /**
- * @brief get the type of channel
- */
- const ChannelType getType() const { return this->m_type; }
-
- /**
- * @brief set the premultiplicatioin of this channel
- */
- void setPremultiplied(const bool premultiplied) { this->m_premultiplied = premultiplied; }
-
- /**
- * @brief is this channel premultiplied
- */
- const bool isPremultiplied() const { return this->m_premultiplied; }
-};
-
-
-#endif
diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
index 7c08188db90..0667271f4b1 100644
--- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp
+++ b/source/blender/compositor/intern/COM_ExecutionSystem.cpp
@@ -137,11 +137,15 @@ void ExecutionSystem::execute()
}
unsigned int index;
+ // First allocale all write buffer
for (index = 0; index < this->m_operations.size(); index++) {
NodeOperation *operation = this->m_operations[index];
- operation->setbNodeTree(this->m_context.getbNodeTree());
- operation->initExecution();
+ if (operation->isWriteBufferOperation()) {
+ operation->setbNodeTree(this->m_context.getbNodeTree());
+ operation->initExecution();
+ }
}
+ // Connect read buffers to their write buffers
for (index = 0; index < this->m_operations.size(); index++) {
NodeOperation *operation = this->m_operations[index];
if (operation->isReadBufferOperation()) {
@@ -149,6 +153,14 @@ void ExecutionSystem::execute()
readOperation->updateMemoryBuffer();
}
}
+ // initialize other operations
+ for (index = 0; index < this->m_operations.size(); index++) {
+ NodeOperation *operation = this->m_operations[index];
+ if (!operation->isWriteBufferOperation()) {
+ operation->setbNodeTree(this->m_context.getbNodeTree());
+ operation->initExecution();
+ }
+ }
for (index = 0; index < this->m_groups.size(); index++) {
ExecutionGroup *executionGroup = this->m_groups[index];
executionGroup->setChunksize(this->m_context.getChunksize());
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cpp
index c59ecced93c..37035c50d2c 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.cpp
@@ -27,6 +27,19 @@
using std::min;
using std::max;
+static unsigned int determine_num_channels(DataType datatype)
+{
+ switch (datatype) {
+ case COM_DT_VALUE:
+ return COM_NUM_CHANNELS_VALUE;
+ case COM_DT_VECTOR:
+ return COM_NUM_CHANNELS_VECTOR;
+ case COM_DT_COLOR:
+ default:
+ return COM_NUM_CHANNELS_COLOR;
+ }
+}
+
unsigned int MemoryBuffer::determineBufferSize()
{
return getWidth() * getHeight();
@@ -34,61 +47,62 @@ unsigned int MemoryBuffer::determineBufferSize()
int MemoryBuffer::getWidth() const
{
- return this->m_rect.xmax - this->m_rect.xmin;
+ return this->m_width;
}
int MemoryBuffer::getHeight() const
{
- return this->m_rect.ymax - this->m_rect.ymin;
+ return this->m_height;
}
MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, unsigned int chunkNumber, rcti *rect)
{
BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
+ this->m_width = BLI_rcti_size_x(&this->m_rect);
+ this->m_height = BLI_rcti_size_y(&this->m_rect);
this->m_memoryProxy = memoryProxy;
this->m_chunkNumber = chunkNumber;
- this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * COM_NUMBER_OF_CHANNELS, 16, "COM_MemoryBuffer");
+ this->m_num_channels = determine_num_channels(memoryProxy->getDataType());
+ this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
this->m_state = COM_MB_ALLOCATED;
- this->m_datatype = COM_DT_COLOR;
- this->m_chunkWidth = this->m_rect.xmax - this->m_rect.xmin;
+ this->m_datatype = memoryProxy->getDataType();;
}
MemoryBuffer::MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect)
{
BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
+ this->m_width = BLI_rcti_size_x(&this->m_rect);
+ this->m_height = BLI_rcti_size_y(&this->m_rect);
this->m_memoryProxy = memoryProxy;
this->m_chunkNumber = -1;
- this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * COM_NUMBER_OF_CHANNELS, 16, "COM_MemoryBuffer");
+ this->m_num_channels = determine_num_channels(memoryProxy->getDataType());
+ this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
this->m_state = COM_MB_TEMPORARILY;
- this->m_datatype = COM_DT_COLOR;
- this->m_chunkWidth = this->m_rect.xmax - this->m_rect.xmin;
+ this->m_datatype = memoryProxy->getDataType();
+}
+MemoryBuffer::MemoryBuffer(DataType dataType, rcti *rect)
+{
+ BLI_rcti_init(&this->m_rect, rect->xmin, rect->xmax, rect->ymin, rect->ymax);
+ this->m_width = BLI_rcti_size_x(&this->m_rect);
+ this->m_height = BLI_rcti_size_y(&this->m_rect);
+ this->m_height = this->m_rect.ymax - this->m_rect.ymin;
+ this->m_memoryProxy = NULL;
+ this->m_chunkNumber = -1;
+ this->m_num_channels = determine_num_channels(dataType);
+ this->m_buffer = (float *)MEM_mallocN_aligned(sizeof(float) * determineBufferSize() * this->m_num_channels, 16, "COM_MemoryBuffer");
+ this->m_state = COM_MB_TEMPORARILY;
+ this->m_datatype = dataType;
}
MemoryBuffer *MemoryBuffer::duplicate()
{
MemoryBuffer *result = new MemoryBuffer(this->m_memoryProxy, &this->m_rect);
- memcpy(result->m_buffer, this->m_buffer, this->determineBufferSize() * COM_NUMBER_OF_CHANNELS * sizeof(float));
+ memcpy(result->m_buffer, this->m_buffer, this->determineBufferSize() * this->m_num_channels * sizeof(float));
return result;
}
void MemoryBuffer::clear()
{
- memset(this->m_buffer, 0, this->determineBufferSize() * COM_NUMBER_OF_CHANNELS * sizeof(float));
+ memset(this->m_buffer, 0, this->determineBufferSize() * this->m_num_channels * sizeof(float));
}
-float *MemoryBuffer::convertToValueBuffer()
-{
- const unsigned int size = this->determineBufferSize();
- unsigned int i;
-
- float *result = (float *)MEM_mallocN(sizeof(float) * size, __func__);
-
- const float *fp_src = this->m_buffer;
- float *fp_dst = result;
-
- for (i = 0; i < size; i++, fp_dst++, fp_src += COM_NUMBER_OF_CHANNELS) {
- *fp_dst = *fp_src;
- }
-
- return result;
-}
float MemoryBuffer::getMaximumValue()
{
@@ -98,7 +112,7 @@ float MemoryBuffer::getMaximumValue()
const float *fp_src = this->m_buffer;
- for (i = 0; i < size; i++, fp_src += COM_NUMBER_OF_CHANNELS) {
+ for (i = 0; i < size; i++, fp_src += this->m_num_channels) {
float value = *fp_src;
if (value > result) {
result = value;
@@ -116,7 +130,7 @@ float MemoryBuffer::getMaximumValue(rcti *rect)
BLI_rcti_isect(rect, &this->m_rect, &rect_clamp);
if (!BLI_rcti_is_empty(&rect_clamp)) {
- MemoryBuffer *temp = new MemoryBuffer(NULL, &rect_clamp);
+ MemoryBuffer *temp = new MemoryBuffer(this->m_datatype, &rect_clamp);
temp->copyContentFrom(this);
float result = temp->getMaximumValue();
delete temp;
@@ -152,9 +166,9 @@ void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer)
for (otherY = minY; otherY < maxY; otherY++) {
- otherOffset = ((otherY - otherBuffer->m_rect.ymin) * otherBuffer->m_chunkWidth + minX - otherBuffer->m_rect.xmin) * COM_NUMBER_OF_CHANNELS;
- offset = ((otherY - this->m_rect.ymin) * this->m_chunkWidth + minX - this->m_rect.xmin) * COM_NUMBER_OF_CHANNELS;
- memcpy(&this->m_buffer[offset], &otherBuffer->m_buffer[otherOffset], (maxX - minX) * COM_NUMBER_OF_CHANNELS * sizeof(float));
+ otherOffset = ((otherY - otherBuffer->m_rect.ymin) * otherBuffer->m_width + minX - otherBuffer->m_rect.xmin) * this->m_num_channels;
+ offset = ((otherY - this->m_rect.ymin) * this->m_width + minX - this->m_rect.xmin) * this->m_num_channels;
+ memcpy(&this->m_buffer[offset], &otherBuffer->m_buffer[otherOffset], (maxX - minX) * this->m_num_channels * sizeof(float));
}
}
@@ -163,9 +177,8 @@ void MemoryBuffer::writePixel(int x, int y, const float color[4])
if (x >= this->m_rect.xmin && x < this->m_rect.xmax &&
y >= this->m_rect.ymin && y < this->m_rect.ymax)
{
- const int offset = (this->m_chunkWidth * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * COM_NUMBER_OF_CHANNELS;
- copy_v4_v4(&this->m_buffer[offset], color);
- }
+ const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * this->m_num_channels;
+ memcpy(&this->m_buffer[offset], color, sizeof(float)*this->m_num_channels); }
}
void MemoryBuffer::addPixel(int x, int y, const float color[4])
@@ -173,8 +186,12 @@ void MemoryBuffer::addPixel(int x, int y, const float color[4])
if (x >= this->m_rect.xmin && x < this->m_rect.xmax &&
y >= this->m_rect.ymin && y < this->m_rect.ymax)
{
- const int offset = (this->m_chunkWidth * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * COM_NUMBER_OF_CHANNELS;
- add_v4_v4(&this->m_buffer[offset], color);
+ const int offset = (this->m_width * (y - this->m_rect.ymin) + x - this->m_rect.xmin) * this->m_num_channels;
+ float *dst = &this->m_buffer[offset];
+ const float *src = color;
+ for (int i = 0; i < this->m_num_channels ; i++, dst++, src++) {
+ *dst += *src;
+ }
}
}
@@ -208,8 +225,9 @@ static void read_ewa_pixel_sampled(void *userdata, int x, int y, float result[4]
}
}
-void MemoryBuffer::readEWA(float result[4], const float uv[2], const float derivatives[2][2], PixelSampler sampler)
+void MemoryBuffer::readEWA(float *result, const float uv[2], const float derivatives[2][2], PixelSampler sampler)
{
+ BLI_assert(this->m_datatype == COM_DT_COLOR);
ReadEWAData data;
data.buffer = this;
data.sampler = sampler;
diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.h b/source/blender/compositor/intern/COM_MemoryBuffer.h
index d6ef9cd673e..e0c542108a1 100644
--- a/source/blender/compositor/intern/COM_MemoryBuffer.h
+++ b/source/blender/compositor/intern/COM_MemoryBuffer.h
@@ -83,11 +83,6 @@ private:
unsigned int m_chunkNumber;
/**
- * @brief width of the chunk
- */
- unsigned int m_chunkWidth;
-
- /**
* @brief state of the buffer
*/
MemoryBufferState m_state;
@@ -97,6 +92,15 @@ private:
*/
float *m_buffer;
+ /**
+ * @brief the number of channels of a single value in the buffer.
+ * For value buffers this is 1, vector 3 and color 4
+ */
+ unsigned int m_num_channels;
+
+ int m_width;
+ int m_height;
+
public:
/**
* @brief construct new MemoryBuffer for a chunk
@@ -107,7 +111,12 @@ public:
* @brief construct new temporarily MemoryBuffer for an area
*/
MemoryBuffer(MemoryProxy *memoryProxy, rcti *rect);
-
+
+ /**
+ * @brief construct new temporarily MemoryBuffer for an area
+ */
+ MemoryBuffer(DataType datatype, rcti *rect);
+
/**
* @brief destructor
*/
@@ -117,7 +126,9 @@ public:
* @brief read the ChunkNumber of this MemoryBuffer
*/
unsigned int getChunkNumber() { return this->m_chunkNumber; }
-
+
+ unsigned int get_num_channels() { return this->m_num_channels; }
+
/**
* @brief get the data of this MemoryBuffer
* @note buffer should already be available in memory
@@ -134,8 +145,8 @@ public:
inline void wrap_pixel(int &x, int &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
{
- int w = m_rect.xmax - m_rect.xmin;
- int h = m_rect.ymax - m_rect.ymin;
+ int w = this->m_width;
+ int h = this->m_height;
x = x - m_rect.xmin;
y = y - m_rect.ymin;
@@ -164,7 +175,39 @@ public:
}
}
- inline void read(float result[4], int x, int y,
+ inline void wrap_pixel(float &x, float &y, MemoryBufferExtend extend_x, MemoryBufferExtend extend_y)
+ {
+ float w = (float)this->m_width;
+ float h = (float)this->m_height;
+ x = x - m_rect.xmin;
+ y = y - m_rect.ymin;
+
+ switch (extend_x) {
+ case COM_MB_CLIP:
+ break;
+ case COM_MB_EXTEND:
+ if (x < 0) x = 0.0f;
+ if (x >= w) x = w;
+ break;
+ case COM_MB_REPEAT:
+ x = fmodf(x, w);
+ break;
+ }
+
+ switch (extend_y) {
+ case COM_MB_CLIP:
+ break;
+ case COM_MB_EXTEND:
+ if (y < 0) y = 0.0f;
+ if (y >= h) y = h;
+ break;
+ case COM_MB_REPEAT:
+ y = fmodf(y, h);
+ break;
+ }
+ }
+
+ inline void read(float *result, int x, int y,
MemoryBufferExtend extend_x = COM_MB_CLIP,
MemoryBufferExtend extend_y = COM_MB_CLIP)
{
@@ -172,81 +215,54 @@ public:
bool clip_y = (extend_y == COM_MB_CLIP && (y < m_rect.ymin || y >= m_rect.ymax));
if (clip_x || clip_y) {
/* clip result outside rect is zero */
- zero_v4(result);
+ memset(result, 0, this->m_num_channels * sizeof(float));
}
else {
- wrap_pixel(x, y, extend_x, extend_y);
- const int offset = (this->m_chunkWidth * y + x) * COM_NUMBER_OF_CHANNELS;
- copy_v4_v4(result, &this->m_buffer[offset]);
+ int u = x;
+ int v = y;
+ this->wrap_pixel(u, v, extend_x, extend_y);
+ const int offset = (this->m_width * y + x) * this->m_num_channels;
+ float* buffer = &this->m_buffer[offset];
+ memcpy(result, buffer, sizeof(float) * this->m_num_channels);
}
}
- inline void readNoCheck(float result[4], int x, int y,
+ inline void readNoCheck(float *result, int x, int y,
MemoryBufferExtend extend_x = COM_MB_CLIP,
MemoryBufferExtend extend_y = COM_MB_CLIP)
{
- wrap_pixel(x, y, extend_x, extend_y);
- const int offset = (this->m_chunkWidth * y + x) * COM_NUMBER_OF_CHANNELS;
+ int u = x;
+ int v = y;
- BLI_assert(offset >= 0);
- BLI_assert(offset < this->determineBufferSize() * COM_NUMBER_OF_CHANNELS);
- BLI_assert(!(extend_x == COM_MB_CLIP && (x < m_rect.xmin || x >= m_rect.xmax)) &&
- !(extend_y == COM_MB_CLIP && (y < m_rect.ymin || y >= m_rect.ymax)));
+ this->wrap_pixel(u, v, extend_x, extend_y);
+ const int offset = (this->m_width * v + u) * this->m_num_channels;
+ BLI_assert(offset >= 0);
+ BLI_assert(offset < this->determineBufferSize() * this->m_num_channels);
+ BLI_assert(!(extend_x == COM_MB_CLIP && (u < m_rect.xmin || u >= m_rect.xmax)) &&
+ !(extend_y == COM_MB_CLIP && (v < m_rect.ymin || v >= m_rect.ymax)));
#if 0
/* always true */
BLI_assert((int)(MEM_allocN_len(this->m_buffer) / sizeof(*this->m_buffer)) ==
(int)(this->determineBufferSize() * COM_NUMBER_OF_CHANNELS));
#endif
-
- copy_v4_v4(result, &this->m_buffer[offset]);
+ float *buffer = &this->m_buffer[offset];
+ memcpy(result, buffer, sizeof(float) * this->m_num_channels);
}
void writePixel(int x, int y, const float color[4]);
void addPixel(int x, int y, const float color[4]);
- inline void readBilinear(float result[4], float x, float y,
+ inline void readBilinear(float *result, float x, float y,
MemoryBufferExtend extend_x = COM_MB_CLIP,
MemoryBufferExtend extend_y = COM_MB_CLIP)
{
- int x1 = floor(x);
- int y1 = floor(y);
- int x2 = x1 + 1;
- int y2 = y1 + 1;
- wrap_pixel(x1, y1, extend_x, extend_y);
- wrap_pixel(x2, y2, extend_x, extend_y);
-
- float valuex = x - x1;
- float valuey = y - y1;
- float mvaluex = 1.0f - valuex;
- float mvaluey = 1.0f - valuey;
-
- float color1[4];
- float color2[4];
- float color3[4];
- float color4[4];
-
- read(color1, x1, y1);
- read(color2, x1, y2);
- read(color3, x2, y1);
- read(color4, x2, y2);
-
- color1[0] = color1[0] * mvaluey + color2[0] * valuey;
- color1[1] = color1[1] * mvaluey + color2[1] * valuey;
- color1[2] = color1[2] * mvaluey + color2[2] * valuey;
- color1[3] = color1[3] * mvaluey + color2[3] * valuey;
-
- color3[0] = color3[0] * mvaluey + color4[0] * valuey;
- color3[1] = color3[1] * mvaluey + color4[1] * valuey;
- color3[2] = color3[2] * mvaluey + color4[2] * valuey;
- color3[3] = color3[3] * mvaluey + color4[3] * valuey;
-
- result[0] = color1[0] * mvaluex + color3[0] * valuex;
- result[1] = color1[1] * mvaluex + color3[1] * valuex;
- result[2] = color1[2] * mvaluex + color3[2] * valuex;
- result[3] = color1[3] * mvaluex + color3[3] * valuex;
+ float u = x;
+ float v = y;
+ this->wrap_pixel(u, v, extend_x, extend_y);
+ BLI_bilinear_interpolation_fl(this->m_buffer, result, this->m_width, this->m_height, this->m_num_channels, u - 0.5f, v - 0.5f);
}
- void readEWA(float result[4], const float uv[2], const float derivatives[2][2], PixelSampler sampler);
+ void readEWA(float *result, const float uv[2], const float derivatives[2][2], PixelSampler sampler);
/**
* @brief is this MemoryBuffer a temporarily buffer (based on an area, not on a chunk)
@@ -284,7 +300,6 @@ public:
MemoryBuffer *duplicate();
- float *convertToValueBuffer();
float getMaximumValue();
float getMaximumValue(rcti *rect);
private:
diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cpp b/source/blender/compositor/intern/COM_MemoryProxy.cpp
index 90ca0baea06..1df3e59db62 100644
--- a/source/blender/compositor/intern/COM_MemoryProxy.cpp
+++ b/source/blender/compositor/intern/COM_MemoryProxy.cpp
@@ -23,10 +23,11 @@
#include "COM_MemoryProxy.h"
-MemoryProxy::MemoryProxy()
+MemoryProxy::MemoryProxy(DataType datatype)
{
this->m_writeBufferOperation = NULL;
this->m_executor = NULL;
+ this->m_datatype = datatype;
}
void MemoryProxy::allocate(unsigned int width, unsigned int height)
diff --git a/source/blender/compositor/intern/COM_MemoryProxy.h b/source/blender/compositor/intern/COM_MemoryProxy.h
index 233b035a2d7..b332852088b 100644
--- a/source/blender/compositor/intern/COM_MemoryProxy.h
+++ b/source/blender/compositor/intern/COM_MemoryProxy.h
@@ -63,8 +63,13 @@ private:
*/
MemoryBuffer *m_buffer;
+ /**
+ * @brief datatype of this MemoryProxy
+ */
+ DataType m_datatype;
+
public:
- MemoryProxy();
+ MemoryProxy(DataType type);
/**
* @brief set the ExecutionGroup that can be scheduled to calculate a certain chunk.
@@ -104,6 +109,8 @@ public:
*/
inline MemoryBuffer *getBuffer() { return this->m_buffer; }
+ inline DataType getDataType() { return this->m_datatype; }
+
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("COM:MemoryProxy")
#endif
diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
index fb5bc8fcd9b..74c05c3e62e 100644
--- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
+++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp
@@ -476,7 +476,7 @@ void NodeOperationBuilder::add_input_buffers(NodeOperation *operation, NodeOpera
/* check of other end already has write operation, otherwise add a new one */
WriteBufferOperation *writeoperation = find_attached_write_buffer_operation(output);
if (!writeoperation) {
- writeoperation = new WriteBufferOperation();
+ writeoperation = new WriteBufferOperation(output->getDataType());
writeoperation->setbNodeTree(m_context->getbNodeTree());
addOperation(writeoperation);
@@ -486,7 +486,7 @@ void NodeOperationBuilder::add_input_buffers(NodeOperation *operation, NodeOpera
}
/* add readbuffer op for the input */
- ReadBufferOperation *readoperation = new ReadBufferOperation();
+ ReadBufferOperation *readoperation = new ReadBufferOperation(output->getDataType());
readoperation->setMemoryProxy(writeoperation->getMemoryProxy());
this->addOperation(readoperation);
@@ -519,7 +519,7 @@ void NodeOperationBuilder::add_output_buffers(NodeOperation *operation, NodeOper
/* if no write buffer operation exists yet, create a new one */
if (!writeOperation) {
- writeOperation = new WriteBufferOperation();
+ writeOperation = new WriteBufferOperation(operation->getOutputSocket()->getDataType());
writeOperation->setbNodeTree(m_context->getbNodeTree());
addOperation(writeOperation);
@@ -534,7 +534,7 @@ void NodeOperationBuilder::add_output_buffers(NodeOperation *operation, NodeOper
if (&target->getOperation() == writeOperation)
continue; /* skip existing write op links */
- ReadBufferOperation *readoperation = new ReadBufferOperation();
+ ReadBufferOperation *readoperation = new ReadBufferOperation(operation->getOutputSocket()->getDataType());
readoperation->setMemoryProxy(writeOperation->getMemoryProxy());
addOperation(readoperation);
diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
index c5b663d2aef..5960082c2fd 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.cpp
@@ -24,6 +24,18 @@
#include "COM_WorkScheduler.h"
typedef enum COM_VendorID {NVIDIA = 0x10DE, AMD = 0x1002} COM_VendorID;
+const cl_image_format IMAGE_FORMAT_COLOR = {
+ CL_RGBA,
+ CL_FLOAT
+};
+const cl_image_format IMAGE_FORMAT_VECTOR = {
+ CL_RGB,
+ CL_FLOAT
+};
+const cl_image_format IMAGE_FORMAT_VALUE = {
+ CL_R,
+ CL_FLOAT
+};
OpenCLDevice::OpenCLDevice(cl_context context, cl_device_id device, cl_program program, cl_int vendorId)
{
@@ -72,6 +84,23 @@ cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
return COM_clAttachMemoryBufferToKernelParameter(kernel, parameterIndex, offsetIndex, cleanup, inputMemoryBuffers, (ReadBufferOperation *)reader);
}
+const cl_image_format* OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBuffer)
+{
+ const cl_image_format *imageFormat;
+ int num_channels = memoryBuffer->get_num_channels();
+ if (num_channels == 1) {
+ imageFormat = &IMAGE_FORMAT_VALUE;
+ }
+ else if (num_channels == 3) {
+ imageFormat = &IMAGE_FORMAT_VECTOR;
+ }
+ else {
+ imageFormat = &IMAGE_FORMAT_COLOR;
+ }
+
+ return imageFormat;
+}
+
cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex,
list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers,
ReadBufferOperation *reader)
@@ -80,12 +109,9 @@ cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel,
MemoryBuffer *result = reader->getInputMemoryBuffer(inputMemoryBuffers);
- const cl_image_format imageFormat = {
- CL_RGBA,
- CL_FLOAT
- };
+ const cl_image_format *imageFormat = determineImageFormat(result);
- cl_mem clBuffer = clCreateImage2D(this->m_context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, &imageFormat, result->getWidth(),
+ cl_mem clBuffer = clCreateImage2D(this->m_context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, imageFormat, result->getWidth(),
result->getHeight(), 0, result->getBuffer(), &error);
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 94df2f2b44c..a513954ee0d 100644
--- a/source/blender/compositor/intern/COM_OpenCLDevice.h
+++ b/source/blender/compositor/intern/COM_OpenCLDevice.h
@@ -94,6 +94,12 @@ public:
*/
void execute(WorkPackage *work);
+ /**
+ * @brief determine an image format
+ * @param memorybuffer
+ */
+ static const cl_image_format *determineImageFormat(MemoryBuffer *memoryBuffer);
+
cl_context getContext() { return this->m_context; }
cl_command_queue getQueue() { return this->m_queue; }
diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp
index e1016731c7f..8445dee5ae4 100644
--- a/source/blender/compositor/intern/COM_WorkScheduler.cpp
+++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp
@@ -196,7 +196,7 @@ void WorkScheduler::schedule(ExecutionGroup *group, int chunkNumber)
BLI_thread_queue_push(g_cpuqueue, package);
}
#else
- BLI_thread_queue_push(cpuqueue, package);
+ BLI_thread_queue_push(g_cpuqueue, package);
#endif
#endif
}
diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
index 9b69bc5a46e..379b9f193e8 100644
--- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
+++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp
@@ -54,6 +54,10 @@ void PlaneTrackDeformNode::convertToOperations(NodeConverter &converter, const C
warp_image_operation->setTrackingObject(data->tracking_object);
warp_image_operation->setPlaneTrackName(data->plane_track_name);
warp_image_operation->setFramenumber(frame_number);
+ if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
+ warp_image_operation->setMotionBlurSamples(data->motion_blur_samples);
+ warp_image_operation->setMotionBlurShutter(data->motion_blur_shutter);
+ }
converter.addOperation(warp_image_operation);
converter.mapInputSocket(input_image, warp_image_operation->getInputSocket(0));
@@ -64,6 +68,10 @@ void PlaneTrackDeformNode::convertToOperations(NodeConverter &converter, const C
plane_mask_operation->setTrackingObject(data->tracking_object);
plane_mask_operation->setPlaneTrackName(data->plane_track_name);
plane_mask_operation->setFramenumber(frame_number);
+ if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
+ plane_mask_operation->setMotionBlurSamples(data->motion_blur_samples);
+ plane_mask_operation->setMotionBlurShutter(data->motion_blur_shutter);
+ }
converter.addOperation(plane_mask_operation);
converter.mapOutputSocket(output_plane, plane_mask_operation->getOutputSocket());
diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
index 48c8acfc6a1..17b00af16d8 100644
--- a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
+++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cpp
@@ -73,8 +73,9 @@ void SocketBufferNode::convertToOperations(NodeConverter &converter, const Compo
NodeOutput *output = this->getOutputSocket(0);
NodeInput *input = this->getInputSocket(0);
- WriteBufferOperation *writeOperation = new WriteBufferOperation();
- ReadBufferOperation *readOperation = new ReadBufferOperation();
+ DataType datatype = output->getDataType();
+ WriteBufferOperation *writeOperation = new WriteBufferOperation(datatype);
+ ReadBufferOperation *readOperation = new ReadBufferOperation(datatype);
readOperation->setMemoryProxy(writeOperation->getMemoryProxy());
converter.addOperation(writeOperation);
converter.addOperation(readOperation);
diff --git a/source/blender/compositor/nodes/COM_TextureNode.cpp b/source/blender/compositor/nodes/COM_TextureNode.cpp
index 2ac027ca326..b80ca2fcdbd 100644
--- a/source/blender/compositor/nodes/COM_TextureNode.cpp
+++ b/source/blender/compositor/nodes/COM_TextureNode.cpp
@@ -35,7 +35,7 @@ void TextureNode::convertToOperations(NodeConverter &converter, const Compositor
Tex *texture = (Tex *)editorNode->id;
TextureOperation *operation = new TextureOperation();
const ColorManagedDisplaySettings *displaySettings = context.getDisplaySettings();
- bool sceneColorManage = strcmp(displaySettings->display_device, "None") != 0;
+ bool sceneColorManage = !STREQ(displaySettings->display_device, "None");
operation->setTexture(texture);
operation->setRenderData(context.getRenderData());
operation->setSceneColorManage(sceneColorManage);
diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cpp b/source/blender/compositor/nodes/COM_TranslateNode.cpp
index 990cbe19be2..04dc1d435d3 100644
--- a/source/blender/compositor/nodes/COM_TranslateNode.cpp
+++ b/source/blender/compositor/nodes/COM_TranslateNode.cpp
@@ -57,8 +57,8 @@ void TranslateNode::convertToOperations(NodeConverter &converter, const Composit
converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
if (data->wrap_axis) {
- WriteBufferOperation *writeOperation = new WriteBufferOperation();
- WrapOperation *wrapOperation = new WrapOperation();
+ WriteBufferOperation *writeOperation = new WriteBufferOperation(COM_DT_COLOR);
+ WrapOperation *wrapOperation = new WrapOperation(COM_DT_COLOR);
wrapOperation->setMemoryProxy(writeOperation->getMemoryProxy());
wrapOperation->setWrapping(data->wrap_axis);
diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
index 995c61589cc..b25e2281467 100644
--- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
+++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cpp
@@ -95,7 +95,7 @@ void *AntiAliasOperation::initializeTileData(rcti *rect)
float *input = tile->getBuffer();
char *valuebuffer = (char *)MEM_mallocN(sizeof(char) * size, __func__);
for (int i = 0; i < size; i++) {
- float in = input[i * COM_NUMBER_OF_CHANNELS];
+ float in = input[i];
valuebuffer[i] = FTOCHAR(in);
}
antialias_tagbuf(tile->getWidth(), tile->getHeight(), valuebuffer);
diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
index f5bca5371e6..22f6fc33a0d 100644
--- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cpp
@@ -110,11 +110,11 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data)
int step = getStep();
- int offsetadd = getOffsetAdd();
+ int offsetadd = getOffsetAdd() * COM_NUM_CHANNELS_COLOR;
float m = this->m_bokehDimension / pixelSize;
for (int ny = miny; ny < maxy; ny += step) {
- int bufferindex = ((minx - bufferstartx) * 4) + ((ny - bufferstarty) * 4 * bufferwidth);
+ int bufferindex = ((minx - bufferstartx) * COM_NUM_CHANNELS_COLOR) + ((ny - bufferstarty) * COM_NUM_CHANNELS_COLOR * bufferwidth);
for (int nx = minx; nx < maxx; nx += step) {
float u = this->m_bokehMidX - (nx - x) * m;
float v = this->m_bokehMidY - (ny - y) * m;
diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cpp
index ef331a50dfd..e3438bcbd15 100644
--- a/source/blender/compositor/operations/COM_CompositorOperation.cpp
+++ b/source/blender/compositor/operations/COM_CompositorOperation.cpp
@@ -138,7 +138,7 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int tileNumber)
int y2 = rect->ymax;
int offset = (y1 * this->getWidth() + x1);
int add = (this->getWidth() - (x2 - x1));
- int offset4 = offset * COM_NUMBER_OF_CHANNELS;
+ int offset4 = offset * COM_NUM_CHANNELS_COLOR;
int x;
int y;
bool breaked = false;
@@ -196,14 +196,14 @@ void CompositorOperation::executeRegion(rcti *rect, unsigned int tileNumber)
this->m_depthInput->readSampled(color, input_x, input_y, COM_PS_NEAREST);
zbuffer[offset] = color[0];
- offset4 += COM_NUMBER_OF_CHANNELS;
+ offset4 += COM_NUM_CHANNELS_COLOR;
offset++;
if (isBreaked()) {
breaked = true;
}
}
offset += add;
- offset4 += add * COM_NUMBER_OF_CHANNELS;
+ offset4 += add * COM_NUM_CHANNELS_COLOR;
}
}
diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cpp b/source/blender/compositor/operations/COM_ConvertOperation.cpp
index 1445b78552f..977586acb60 100644
--- a/source/blender/compositor/operations/COM_ConvertOperation.cpp
+++ b/source/blender/compositor/operations/COM_ConvertOperation.cpp
@@ -49,9 +49,9 @@ ConvertValueToColorOperation::ConvertValueToColorOperation() : ConvertBaseOperat
void ConvertValueToColorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- float inputValue[4];
- this->m_inputOperation->readSampled(inputValue, x, y, sampler);
- output[0] = output[1] = output[2] = inputValue[0];
+ float value;
+ this->m_inputOperation->readSampled(&value, x, y, sampler);
+ output[0] = output[1] = output[2] = value;
output[3] = 1.0f;
}
@@ -98,8 +98,9 @@ ConvertColorToVectorOperation::ConvertColorToVectorOperation() : ConvertBaseOper
void ConvertColorToVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- this->m_inputOperation->readSampled(output, x, y, sampler);
-}
+ float color[4];
+ this->m_inputOperation->readSampled(color, x, y, sampler);
+ copy_v3_v3(output, color);}
/* ******** Value to Vector ******** */
@@ -112,12 +113,9 @@ ConvertValueToVectorOperation::ConvertValueToVectorOperation() : ConvertBaseOper
void ConvertValueToVectorOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- float input[4];
- this->m_inputOperation->readSampled(input, x, y, sampler);
- output[0] = input[0];
- output[1] = input[0];
- output[2] = input[0];
- output[3] = 0.0f;
+ float value;
+ this->m_inputOperation->readSampled(&value, x, y, sampler);
+ output[0] = output[1] = output[2] = value;
}
diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
index cbf4ce693d9..6d15ef3395b 100644
--- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
+++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cpp
@@ -82,18 +82,18 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
const int bufferWidth = BLI_rcti_size_x(rect);
int offset;
- this->m_inputProgram->read(inputValue, x, y, NULL);
+ inputBuffer->read(inputValue, x, y);
if (inputValue[0] > sw) {
for (int yi = miny; yi < maxy; yi++) {
const float dy = yi - y;
- offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)) * 4;
+ offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin));
for (int xi = minx; xi < maxx; xi++) {
if (buffer[offset] < sw) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
mindist = min(mindist, dis);
}
- offset += 4;
+ offset ++;
}
}
pixelvalue = -sqrtf(mindist);
@@ -101,15 +101,14 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y,
else {
for (int yi = miny; yi < maxy; yi++) {
const float dy = yi - y;
- offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)) * 4;
+ offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin));
for (int xi = minx; xi < maxx; xi++) {
if (buffer[offset] > sw) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
mindist = min(mindist, dis);
}
- offset += 4;
-
+ offset ++;
}
}
pixelvalue = sqrtf(mindist);
@@ -206,14 +205,14 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void *
for (int yi = miny; yi < maxy; yi++) {
const float dy = yi - y;
- offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)) * 4;
+ offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin));
for (int xi = minx; xi < maxx; xi++) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
if (dis <= mindist) {
value = max(buffer[offset], value);
}
- offset += 4;
+ offset ++;
}
}
output[0] = value;
@@ -280,14 +279,14 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d
for (int yi = miny; yi < maxy; yi++) {
const float dy = yi - y;
- offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin)) * 4;
+ offset = ((yi - rect->ymin) * bufferWidth + (minx - rect->xmin));
for (int xi = minx; xi < maxx; xi++) {
const float dx = xi - x;
const float dis = dx * dx + dy * dy;
if (dis <= mindist) {
value = min(buffer[offset], value);
}
- offset += 4;
+ offset ++;
}
}
output[0] = value;
@@ -383,7 +382,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect)
buf[x] = -FLT_MAX;
}
for (x = xmin; x < xmax; ++x) {
- buf[x - rect->xmin + window - 1] = buffer[4 * (y * width + x)];
+ buf[x - rect->xmin + window - 1] = buffer[(y * width + x)];
}
for (i = 0; i < (bwidth + 3 * half_window) / window; i++) {
@@ -510,7 +509,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect)
buf[x] = FLT_MAX;
}
for (x = xmin; x < xmax; ++x) {
- buf[x - rect->xmin + window - 1] = buffer[4 * (y * width + x)];
+ buf[x - rect->xmin + window - 1] = buffer[(y * width + x)];
}
for (i = 0; i < (bwidth + 3 * half_window) / window; i++) {
diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
index 5006720f091..234a61a4c41 100644
--- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
+++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp
@@ -1270,11 +1270,9 @@ void *DoubleEdgeMaskOperation::initializeTileData(rcti *rect)
MemoryBuffer *innerMask = (MemoryBuffer *)this->m_inputInnerMask->initializeTileData(rect);
MemoryBuffer *outerMask = (MemoryBuffer *)this->m_inputOuterMask->initializeTileData(rect);
float *data = (float *)MEM_mallocN(sizeof(float) * this->getWidth() * this->getHeight(), __func__);
- float *imask = innerMask->convertToValueBuffer();
- float *omask = outerMask->convertToValueBuffer();
+ float *imask = innerMask->getBuffer();
+ float *omask = outerMask->getBuffer();
doDoubleEdgeMask(imask, omask, data);
- MEM_freeN(imask);
- MEM_freeN(omask);
this->m_cachedInstance = data;
}
unlockMutex();
diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
index 705a8c07381..08f520e4271 100644
--- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp
@@ -92,16 +92,16 @@ void *FastGaussianBlurOperation::initializeTileData(rcti *rect)
this->m_sy = this->m_data.sizey * this->m_size / 2.0f;
if ((this->m_sx == this->m_sy) && (this->m_sx > 0.f)) {
- for (c = 0; c < COM_NUMBER_OF_CHANNELS; ++c)
+ for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c)
IIR_gauss(copy, this->m_sx, c, 3);
}
else {
if (this->m_sx > 0.0f) {
- for (c = 0; c < COM_NUMBER_OF_CHANNELS; ++c)
+ for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c)
IIR_gauss(copy, this->m_sx, c, 1);
}
if (this->m_sy > 0.0f) {
- for (c = 0; c < COM_NUMBER_OF_CHANNELS; ++c)
+ for (c = 0; c < COM_NUM_CHANNELS_COLOR; ++c)
IIR_gauss(copy, this->m_sy, c, 2);
}
}
@@ -120,6 +120,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, float sigma, unsign
unsigned int x, y, sz;
unsigned int i;
float *buffer = src->getBuffer();
+ const unsigned int num_channels = src->get_num_channels();
// <0.5 not valid, though can have a possibly useful sort of sharpening effect
if (sigma < 0.5f) return;
@@ -198,31 +199,31 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, float sigma, unsign
int offset;
for (y = 0; y < src_height; ++y) {
const int yx = y * src_width;
- offset = yx * COM_NUMBER_OF_CHANNELS + chan;
+ offset = yx * num_channels + chan;
for (x = 0; x < src_width; ++x) {
X[x] = buffer[offset];
- offset += COM_NUMBER_OF_CHANNELS;
+ offset += num_channels;
}
YVV(src_width);
- offset = yx * COM_NUMBER_OF_CHANNELS + chan;
+ offset = yx * num_channels + chan;
for (x = 0; x < src_width; ++x) {
buffer[offset] = Y[x];
- offset += COM_NUMBER_OF_CHANNELS;
+ offset += num_channels;
}
}
}
if (xy & 2) { // V
int offset;
- const int add = src_width * COM_NUMBER_OF_CHANNELS;
+ const int add = src_width * num_channels;
for (x = 0; x < src_width; ++x) {
- offset = x * COM_NUMBER_OF_CHANNELS + chan;
+ offset = x * num_channels + chan;
for (y = 0; y < src_height; ++y) {
X[y] = buffer[offset];
offset += add;
}
YVV(src_height);
- offset = x * COM_NUMBER_OF_CHANNELS + chan;
+ offset = x * num_channels + chan;
for (y = 0; y < src_height; ++y) {
buffer[offset] = Y[y];
offset += add;
@@ -298,7 +299,7 @@ void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect)
if (this->m_overlay == FAST_GAUSS_OVERLAY_MIN) {
float *src = newBuf->getBuffer();
float *dst = copy->getBuffer();
- for (int i = copy->getWidth() * copy->getHeight(); i != 0; i--, src += COM_NUMBER_OF_CHANNELS, dst += COM_NUMBER_OF_CHANNELS) {
+ for (int i = copy->getWidth() * copy->getHeight(); i != 0; i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) {
if (*src < *dst) {
*dst = *src;
}
@@ -307,7 +308,7 @@ void *FastGaussianBlurValueOperation::initializeTileData(rcti *rect)
else if (this->m_overlay == FAST_GAUSS_OVERLAY_MAX) {
float *src = newBuf->getBuffer();
float *dst = copy->getBuffer();
- for (int i = copy->getWidth() * copy->getHeight(); i != 0; i--, src += COM_NUMBER_OF_CHANNELS, dst += COM_NUMBER_OF_CHANNELS) {
+ for (int i = copy->getWidth() * copy->getHeight(); i != 0; i--, src += COM_NUM_CHANNELS_VALUE, dst += COM_NUM_CHANNELS_VALUE) {
if (*src > *dst) {
*dst = *src;
}
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
index c78347e7b1c..dde57ab640f 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp
@@ -102,15 +102,14 @@ void GaussianAlphaXBlurOperation::executePixel(float output[4], int x, int y, vo
/* *** this is the main part which is different to 'GaussianXBlurOperation' *** */
int step = getStep();
- int offsetadd = getOffsetAdd();
- int bufferindex = ((xmin - bufferstartx) * 4) + ((ymin - bufferstarty) * 4 * bufferwidth);
+ int bufferindex = ((xmin - bufferstartx)) + ((ymin - bufferstarty) * bufferwidth);
/* gauss */
float alpha_accum = 0.0f;
float multiplier_accum = 0.0f;
/* dilate */
- float value_max = finv_test(buffer[(x * 4) + (y * 4 * bufferwidth)], do_invert); /* init with the current color to avoid unneeded lookups */
+ float value_max = finv_test(buffer[(x) + (y * bufferwidth)], do_invert); /* init with the current color to avoid unneeded lookups */
float distfacinv_max = 1.0f; /* 0 to 1 */
for (int nx = xmin; nx < xmax; nx += step) {
@@ -134,7 +133,7 @@ void GaussianAlphaXBlurOperation::executePixel(float output[4], int x, int y, vo
distfacinv_max = multiplier;
}
}
- bufferindex += offsetadd;
+ bufferindex += step;
}
/* blend between the max value and gauss blue - gives nice feather */
diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
index ab97c8b0d13..bb5b3c044af 100644
--- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp
@@ -108,11 +108,11 @@ void GaussianAlphaYBlurOperation::executePixel(float output[4], int x, int y, vo
float multiplier_accum = 0.0f;
/* dilate */
- float value_max = finv_test(buffer[(x * 4) + (y * 4 * bufferwidth)], do_invert); /* init with the current color to avoid unneeded lookups */
+ float value_max = finv_test(buffer[(x) + (y * bufferwidth)], do_invert); /* init with the current color to avoid unneeded lookups */
float distfacinv_max = 1.0f; /* 0 to 1 */
for (int ny = ymin; ny < ymax; ny += step) {
- int bufferindex = ((xmin - bufferstartx) * 4) + ((ny - bufferstarty) * 4 * bufferwidth);
+ int bufferindex = ((xmin - bufferstartx)) + ((ny - bufferstarty) * bufferwidth);
const int index = (ny - y) + this->m_filtersize;
float value = finv_test(buffer[bufferindex], do_invert);
diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
index 441b623b589..dbad51c4329 100644
--- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp
@@ -296,7 +296,7 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y,
int minyr = y - refrady < 0 ? -y : -refrady;
int maxyr = y + refrady > imgy ? imgy - y : refrady;
- float *srcd = buffer + COM_NUMBER_OF_CHANNELS * ( (y + minyr) * imgx + x + minxr);
+ float *srcd = buffer + COM_NUM_CHANNELS_COLOR * ( (y + minyr) * imgx + x + minxr);
gausstabx = m_maintabs[refradx - 1];
gausstabcentx = gausstabx + refradx;
@@ -304,9 +304,9 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y,
gausstabcenty = gausstaby + refrady;
sum = gval = rval = bval = aval = 0.0f;
- for (i = minyr; i < maxyr; i++, srcd += COM_NUMBER_OF_CHANNELS * imgx) {
+ for (i = minyr; i < maxyr; i++, srcd += COM_NUM_CHANNELS_COLOR * imgx) {
src = srcd;
- for (j = minxr; j < maxxr; j++, src += COM_NUMBER_OF_CHANNELS) {
+ for (j = minxr; j < maxxr; j++, src += COM_NUM_CHANNELS_COLOR) {
val = gausstabcenty[i] * gausstabcentx[j];
sum += val;
diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp b/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
index 99c745d7fb0..98919f1b161 100644
--- a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cpp
@@ -49,7 +49,7 @@ MemoryBuffer *GlareBaseOperation::createMemoryBuffer(rcti *rect2)
rect.ymin = 0;
rect.xmax = getWidth();
rect.ymax = getHeight();
- MemoryBuffer *result = new MemoryBuffer(NULL, &rect);
+ MemoryBuffer *result = new MemoryBuffer(COM_DT_COLOR, &rect);
float *data = result->getBuffer();
this->generateGlare(data, tile, this->m_settings);
return result;
diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
index 99a7c5b64c4..04993b08ddf 100644
--- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp
@@ -259,8 +259,8 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
float *kernelBuffer = in2->getBuffer();
float *imageBuffer = in1->getBuffer();
- MemoryBuffer *rdst = new MemoryBuffer(NULL, in1->getRect());
- memset(rdst->getBuffer(), 0, rdst->getWidth() * rdst->getHeight() * COM_NUMBER_OF_CHANNELS * sizeof(float));
+ MemoryBuffer *rdst = new MemoryBuffer(COM_DT_COLOR, in1->getRect());
+ memset(rdst->getBuffer(), 0, rdst->getWidth() * rdst->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float));
// convolution result width & height
w2 = 2 * kernelWidth - 1;
@@ -276,7 +276,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
// normalize convolutor
wt[0] = wt[1] = wt[2] = 0.f;
for (y = 0; y < kernelHeight; y++) {
- colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUMBER_OF_CHANNELS];
+ colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR];
for (x = 0; x < kernelWidth; x++)
add_v3_v3(wt, colp[x]);
}
@@ -284,7 +284,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
if (wt[1] != 0.f) wt[1] = 1.f / wt[1];
if (wt[2] != 0.f) wt[2] = 1.f / wt[2];
for (y = 0; y < kernelHeight; y++) {
- colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUMBER_OF_CHANNELS];
+ colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR];
for (x = 0; x < kernelWidth; x++)
mul_v3_v3(colp[x], wt);
}
@@ -313,7 +313,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
// in2, channel ch -> data1
for (y = 0; y < kernelHeight; y++) {
fp = &data1ch[y * w2];
- colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUMBER_OF_CHANNELS];
+ colp = (fRGB *)&kernelBuffer[y * kernelWidth * COM_NUM_CHANNELS_COLOR];
for (x = 0; x < kernelWidth; x++)
fp[x] = colp[x][ch];
}
@@ -325,7 +325,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
int yy = ybl * ybsz + y;
if (yy >= imageHeight) continue;
fp = &data2[y * w2];
- colp = (fRGB *)&imageBuffer[yy * imageWidth * COM_NUMBER_OF_CHANNELS];
+ colp = (fRGB *)&imageBuffer[yy * imageWidth * COM_NUM_CHANNELS_COLOR];
for (x = 0; x < xbsz; x++) {
int xx = xbl * xbsz + x;
if (xx >= imageWidth) continue;
@@ -349,7 +349,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
const int yy = ybl * ybsz + y - hh;
if ((yy < 0) || (yy >= imageHeight)) continue;
fp = &data2[y * w2];
- colp = (fRGB *)&rdst->getBuffer()[yy * imageWidth * COM_NUMBER_OF_CHANNELS];
+ colp = (fRGB *)&rdst->getBuffer()[yy * imageWidth * COM_NUM_CHANNELS_COLOR];
for (x = 0; x < (int)w2; x++) {
const int xx = xbl * xbsz + x - hw;
if ((xx < 0) || (xx >= imageWidth)) continue;
@@ -364,7 +364,7 @@ static void convolve(float *dst, MemoryBuffer *in1, MemoryBuffer *in2)
MEM_freeN(data2);
MEM_freeN(data1);
- memcpy(dst, rdst->getBuffer(), sizeof(float) * imageWidth * imageHeight * COM_NUMBER_OF_CHANNELS);
+ memcpy(dst, rdst->getBuffer(), sizeof(float) * imageWidth * imageHeight * COM_NUM_CHANNELS_COLOR);
delete(rdst);
}
@@ -381,7 +381,7 @@ void GlareFogGlowOperation::generateGlare(float *data, MemoryBuffer *inputTile,
// make the convolution kernel
rcti kernelRect;
BLI_rcti_init(&kernelRect, 0, sz, 0, sz);
- ckrn = new MemoryBuffer(NULL, &kernelRect);
+ ckrn = new MemoryBuffer(COM_DT_COLOR, &kernelRect);
scale = 0.25f * sqrtf((float)(sz * sz));
diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
index 8854be52ded..69b5bd7d6bf 100644
--- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cpp
@@ -97,7 +97,7 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
}
- memset(tbuf1->getBuffer(), 0, tbuf1->getWidth() * tbuf1->getHeight() * COM_NUMBER_OF_CHANNELS * sizeof(float));
+ memset(tbuf1->getBuffer(), 0, tbuf1->getWidth() * tbuf1->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float));
for (n = 1; n < settings->iter && (!breaked); n++) {
for (y = 0; y < gbuf->getHeight() && (!breaked); y++) {
v = ((float)y + 0.5f) / (float)gbuf->getHeight();
@@ -117,9 +117,9 @@ void GlareGhostOperation::generateGlare(float *data, MemoryBuffer *inputTile, No
}
if (isBreaked()) breaked = true;
}
- memcpy(gbuf->getBuffer(), tbuf1->getBuffer(), tbuf1->getWidth() * tbuf1->getHeight() * COM_NUMBER_OF_CHANNELS * sizeof(float));
+ memcpy(gbuf->getBuffer(), tbuf1->getBuffer(), tbuf1->getWidth() * tbuf1->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float));
}
- memcpy(data, gbuf->getBuffer(), gbuf->getWidth() * gbuf->getHeight() * COM_NUMBER_OF_CHANNELS * sizeof(float));
+ memcpy(data, gbuf->getBuffer(), gbuf->getWidth() * gbuf->getHeight() * COM_NUM_CHANNELS_COLOR * sizeof(float));
delete gbuf;
delete tbuf1;
diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
index 5644ff30ef3..deeb5094bd0 100644
--- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
+++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp
@@ -36,7 +36,7 @@ void GlareStreaksOperation::generateGlare(float *data, MemoryBuffer *inputTile,
bool breaked = false;
MemoryBuffer *tsrc = inputTile->duplicate();
- MemoryBuffer *tdst = new MemoryBuffer(NULL, inputTile->getRect());
+ MemoryBuffer *tdst = new MemoryBuffer(COM_DT_COLOR, inputTile->getRect());
tdst->clear();
memset(data, 0, size4 * sizeof(float));
diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cpp
index 2733c483146..ff0ffe27b42 100644
--- a/source/blender/compositor/operations/COM_ImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_ImageOperation.cpp
@@ -119,10 +119,10 @@ static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sa
nearest_interpolation_color(ibuf, NULL, color, x, y);
break;
case COM_PS_BILINEAR:
- bilinear_interpolation_color(ibuf, NULL, color, x, y);
+ bilinear_interpolation_color(ibuf, NULL, color, x - 0.5f, y - 0.5f);
break;
case COM_PS_BICUBIC:
- bicubic_interpolation_color(ibuf, NULL, color, x, y);
+ bicubic_interpolation_color(ibuf, NULL, color, x - 0.5f, y - 0.5f);
break;
}
}
@@ -133,10 +133,10 @@ static void sampleImageAtLocation(ImBuf *ibuf, float x, float y, PixelSampler sa
nearest_interpolation_color(ibuf, byte_color, NULL, x, y);
break;
case COM_PS_BILINEAR:
- bilinear_interpolation_color(ibuf, byte_color, NULL, x, y);
+ bilinear_interpolation_color(ibuf, byte_color, NULL, x - 0.5f, y - 0.5f);
break;
case COM_PS_BICUBIC:
- bicubic_interpolation_color(ibuf, byte_color, NULL, x, y);
+ bicubic_interpolation_color(ibuf, byte_color, NULL, x - 0.5f, y - 0.5f);
break;
}
rgba_uchar_to_float(color, byte_color);
diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cpp b/source/blender/compositor/operations/COM_InpaintOperation.cpp
index b64c98be0c7..18611c051d3 100644
--- a/source/blender/compositor/operations/COM_InpaintOperation.cpp
+++ b/source/blender/compositor/operations/COM_InpaintOperation.cpp
@@ -83,8 +83,8 @@ float *InpaintSimpleOperation::get_pixel(int x, int y)
ASSERT_XY_RANGE(x, y);
return &this->m_cached_buffer[
- y * width * COM_NUMBER_OF_CHANNELS +
- x * COM_NUMBER_OF_CHANNELS];
+ y * width * COM_NUM_CHANNELS_COLOR +
+ x * COM_NUM_CHANNELS_COLOR];
}
int InpaintSimpleOperation::mdist(int x, int y)
diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
index ddc09ecb483..72c7512cb23 100644
--- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp
@@ -58,7 +58,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
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;
+ int bufferIndex = (y * bufferWidth + cx);
average += buffer[bufferIndex];
count++;
}
@@ -67,7 +67,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data
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;
+ int bufferIndex = (cy * bufferWidth + x);
average += buffer[bufferIndex];
count++;
}
diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
index d9eb7b588a8..d4ba94f240f 100644
--- a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cpp
@@ -62,7 +62,7 @@ void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data
int bufferWidth = inputBuffer->getWidth();
int bufferHeight = inputBuffer->getHeight();
- float value = buffer[(y * bufferWidth + x) * 4];
+ float value = buffer[(y * bufferWidth + x)];
bool ok = false;
int start_x = max_ff(0, x - delta + 1),
@@ -83,7 +83,7 @@ void KeyingClipOperation::executePixel(float output[4], int x, int y, void *data
continue;
}
- int bufferIndex = (cy * bufferWidth + cx) * 4;
+ int bufferIndex = (cy * bufferWidth + cx);
float currentValue = buffer[bufferIndex];
if (fabsf(currentValue - value) < tolerance) {
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp
index 6bf730253e7..bb8fe825c68 100644
--- a/source/blender/compositor/operations/COM_MapUVOperation.cpp
+++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp
@@ -83,11 +83,11 @@ bool MapUVOperation::read_uv(float x, float y, float &r_u, float &r_v, float &r_
return false;
}
else {
- float col[4];
- m_inputUVProgram->readSampled(col, x, y, COM_PS_BILINEAR);
- r_u = col[0] * m_inputColorProgram->getWidth();
- r_v = col[1] * m_inputColorProgram->getHeight();
- r_alpha = col[2];
+ float vector[3];
+ m_inputUVProgram->readSampled(vector, x, y, COM_PS_BILINEAR);
+ r_u = vector[0] * m_inputColorProgram->getWidth();
+ r_v = vector[1] * m_inputColorProgram->getHeight();
+ r_alpha = vector[2];
return true;
}
}
diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cpp b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
index 9a184ae1216..2ed498d1303 100644
--- a/source/blender/compositor/operations/COM_MovieClipOperation.cpp
+++ b/source/blender/compositor/operations/COM_MovieClipOperation.cpp
@@ -103,10 +103,10 @@ void MovieClipBaseOperation::executePixelSampled(float output[4], float x, float
nearest_interpolation_color(ibuf, NULL, output, x, y);
break;
case COM_PS_BILINEAR:
- bilinear_interpolation_color(ibuf, NULL, output, x, y);
+ bilinear_interpolation_color(ibuf, NULL, output, x - 0.5f, y - 0.5f);
break;
case COM_PS_BICUBIC:
- bicubic_interpolation_color(ibuf, NULL, output, x, y);
+ bicubic_interpolation_color(ibuf, NULL, output, x - 0.5f, y - 0.5f);
break;
}
}
diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
index 23fba5a7999..35ab20fb122 100644
--- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
+++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp
@@ -54,10 +54,10 @@ void MultilayerColorOperation::executePixelSampled(float output[4], float x, flo
nearest_interpolation_color(this->m_buffer, NULL, output, x, y);
break;
case COM_PS_BILINEAR:
- bilinear_interpolation_color(this->m_buffer, NULL, output, x, y);
+ bilinear_interpolation_color(this->m_buffer, NULL, output, x - 0.5f, y - 0.5f);
break;
case COM_PS_BICUBIC:
- bicubic_interpolation_color(this->m_buffer, NULL, output, x, y);
+ bicubic_interpolation_color(this->m_buffer, NULL, output, x - 0.5f, y - 0.5f);
break;
}
}
diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cpp b/source/blender/compositor/operations/COM_NormalizeOperation.cpp
index f81b50e6836..e0b5893ffbb 100644
--- a/source/blender/compositor/operations/COM_NormalizeOperation.cpp
+++ b/source/blender/compositor/operations/COM_NormalizeOperation.cpp
@@ -104,7 +104,7 @@ void *NormalizeOperation::initializeTileData(rcti *rect)
if ((value < minv) && (value >= -BLENDER_ZMAX)) {
minv = value;
}
- bc += 4;
+ bc ++;
}
minmult->x = minv;
diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
index 92e8f309ea1..2f92351c00d 100644
--- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp
+++ b/source/blender/compositor/operations/COM_OutputFileOperation.cpp
@@ -140,8 +140,9 @@ void OutputSingleLayerOperation::deinitExecution()
IMB_colormanagement_imbuf_for_write(ibuf, true, false, m_viewSettings, m_displaySettings,
this->m_format);
- BKE_makepicstring(filename, this->m_path, bmain->name, this->m_rd->cfra,
- this->m_format, (this->m_rd->scemode & R_EXTENSION) != 0, true);
+ BKE_image_path_from_imformat(
+ filename, this->m_path, bmain->name, this->m_rd->cfra,
+ this->m_format, (this->m_rd->scemode & R_EXTENSION) != 0, true);
if (0 == BKE_imbuf_write(ibuf, filename, this->m_format))
printf("Cannot save Node File Output to %s\n", filename);
@@ -211,8 +212,9 @@ void OutputOpenExrMultiLayerOperation::deinitExecution()
char filename[FILE_MAX];
void *exrhandle = IMB_exr_get_handle();
- BKE_makepicstring_from_type(filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
- (this->m_rd->scemode & R_EXTENSION) != 0, true);
+ BKE_image_path_from_imtype(
+ filename, this->m_path, bmain->name, this->m_rd->cfra, R_IMF_IMTYPE_MULTILAYER,
+ (this->m_rd->scemode & R_EXTENSION) != 0, true);
BLI_make_existing_file(filename);
for (unsigned int i = 0; i < this->m_layers.size(); ++i) {
diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
index fe272000b6e..fb8730c9fa0 100644
--- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp
@@ -135,7 +135,7 @@ void *PlaneCornerPinMaskOperation::initializeTileData(rcti *rect)
getInputSocketReader(3) };
float corners[4][2];
readCornersFromSockets(rect, readers, corners);
- calculateCorners(corners, true);
+ calculateCorners(corners, true, 0);
m_corners_ready = true;
}
@@ -194,8 +194,7 @@ void *PlaneCornerPinWarpImageOperation::initializeTileData(rcti *rect)
getInputSocketReader(4) };
float corners[4][2];
readCornersFromSockets(rect, readers, corners);
- calculateCorners(corners, true);
- calculatePerspectiveMatrix();
+ calculateCorners(corners, true, 0);
m_corners_ready = true;
}
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
index c507b4cfa98..8133f392ac6 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp
@@ -56,36 +56,38 @@ PlaneDistortWarpImageOperation::PlaneDistortWarpImageOperation() :
this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE);
this->addOutputSocket(COM_DT_COLOR);
this->m_pixelReader = NULL;
+ this->m_motion_blur_samples = 1;
+ this->m_motion_blur_shutter = 0.5f;
this->setComplex(true);
}
-void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2], bool normalized)
+void PlaneDistortWarpImageOperation::calculateCorners(const float corners[4][2],
+ bool normalized,
+ int sample)
{
+ BLI_assert(sample < this->m_motion_blur_samples);
+ const int width = this->m_pixelReader->getWidth();
+ const int height = this->m_pixelReader->getHeight();
+ float frame_corners[4][2] = {{0.0f, 0.0f},
+ {(float) width, 0.0f},
+ {(float) width, (float) height},
+ {0.0f, (float) height}};
+ MotionSample *sample_data = &this->m_samples[sample];
if (normalized) {
for (int i = 0; i < 4; i++) {
- this->m_frameSpaceCorners[i][0] = corners[i][0] * this->getWidth();
- this->m_frameSpaceCorners[i][1] = corners[i][1] * this->getHeight();
+ sample_data->frameSpaceCorners[i][0] = corners[i][0] * this->getWidth();
+ sample_data->frameSpaceCorners[i][1] = corners[i][1] * this->getHeight();
}
}
else {
for (int i = 0; i < 4; i++) {
- this->m_frameSpaceCorners[i][0] = corners[i][0];
- this->m_frameSpaceCorners[i][1] = corners[i][1];
+ sample_data->frameSpaceCorners[i][0] = corners[i][0];
+ sample_data->frameSpaceCorners[i][1] = corners[i][1];
}
}
-}
-
-void PlaneDistortWarpImageOperation::calculatePerspectiveMatrix()
-{
- const int width = this->m_pixelReader->getWidth();
- const int height = this->m_pixelReader->getHeight();
- float frame_corners[4][2] = {{0.0f, 0.0f},
- {(float) width, 0.0f},
- {(float) width, (float) height},
- {0.0f, (float) height}};
- BKE_tracking_homography_between_two_quads(this->m_frameSpaceCorners,
+ BKE_tracking_homography_between_two_quads(sample_data->frameSpaceCorners,
frame_corners,
- this->m_perspectiveMatrix);
+ sample_data->perspectiveMatrix);
}
void PlaneDistortWarpImageOperation::initExecution()
@@ -100,35 +102,47 @@ void PlaneDistortWarpImageOperation::deinitExecution()
void PlaneDistortWarpImageOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- float xy[2] = {x, y};
float uv[2];
float deriv[2][2];
-
- pixelTransform(xy, uv, deriv);
-
- m_pixelReader->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1], COM_PS_BILINEAR);
-}
-
-void PlaneDistortWarpImageOperation::pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2])
-{
- warpCoord(xy[0], xy[1], m_perspectiveMatrix, r_uv, r_deriv);
+ if (this->m_motion_blur_samples == 1) {
+ warpCoord(x, y, this->m_samples[0].perspectiveMatrix, uv, deriv);
+ m_pixelReader->readFiltered(output,
+ uv[0], uv[1],
+ deriv[0], deriv[1],
+ COM_PS_BILINEAR);
+ }
+ else {
+ zero_v4(output);
+ for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ float color[4];
+ warpCoord(x, y, this->m_samples[sample].perspectiveMatrix, uv, deriv);
+ m_pixelReader->readFiltered(color,
+ uv[0], uv[1],
+ deriv[0], deriv[1],
+ COM_PS_BILINEAR);
+ add_v4_v4(output, color);
+ }
+ mul_v4_fl(output, 1.0f / (float)this->m_motion_blur_samples);
+ }
}
bool PlaneDistortWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
- float UVs[4][2];
- float deriv[2][2];
-
- /* TODO(sergey): figure out proper way to do this. */
- warpCoord(input->xmin - 2, input->ymin - 2, this->m_perspectiveMatrix, UVs[0], deriv);
- warpCoord(input->xmax + 2, input->ymin - 2, this->m_perspectiveMatrix, UVs[1], deriv);
- warpCoord(input->xmax + 2, input->ymax + 2, this->m_perspectiveMatrix, UVs[2], deriv);
- warpCoord(input->xmin - 2, input->ymax + 2, this->m_perspectiveMatrix, UVs[3], deriv);
-
float min[2], max[2];
INIT_MINMAX2(min, max);
- for (int i = 0; i < 4; i++) {
- minmax_v2v2_v2(min, max, UVs[i]);
+
+ for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ float UVs[4][2];
+ float deriv[2][2];
+ MotionSample *sample_data = &this->m_samples[sample];
+ /* TODO(sergey): figure out proper way to do this. */
+ warpCoord(input->xmin - 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[0], deriv);
+ warpCoord(input->xmax + 2, input->ymin - 2, sample_data->perspectiveMatrix, UVs[1], deriv);
+ warpCoord(input->xmax + 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[2], deriv);
+ warpCoord(input->xmin - 2, input->ymax + 2, sample_data->perspectiveMatrix, UVs[3], deriv);
+ for (int i = 0; i < 4; i++) {
+ minmax_v2v2_v2(min, max, UVs[i]);
+ }
}
rcti newInput;
@@ -151,20 +165,26 @@ PlaneDistortMaskOperation::PlaneDistortMaskOperation() :
/* Currently hardcoded to 8 samples. */
m_osa = 8;
+ this->m_motion_blur_samples = 1;
+ this->m_motion_blur_shutter = 0.5f;
}
-void PlaneDistortMaskOperation::calculateCorners(const float corners[4][2], bool normalized)
+void PlaneDistortMaskOperation::calculateCorners(const float corners[4][2],
+ bool normalized,
+ int sample)
{
+ BLI_assert(sample < this->m_motion_blur_samples);
+ MotionSample *sample_data = &this->m_samples[sample];
if (normalized) {
for (int i = 0; i < 4; i++) {
- this->m_frameSpaceCorners[i][0] = corners[i][0] * this->getWidth();
- this->m_frameSpaceCorners[i][1] = corners[i][1] * this->getHeight();
+ sample_data->frameSpaceCorners[i][0] = corners[i][0] * this->getWidth();
+ sample_data->frameSpaceCorners[i][1] = corners[i][1] * this->getHeight();
}
}
else {
for (int i = 0; i < 4; i++) {
- this->m_frameSpaceCorners[i][0] = corners[i][0];
- this->m_frameSpaceCorners[i][1] = corners[i][1];
+ sample_data->frameSpaceCorners[i][0] = corners[i][0];
+ sample_data->frameSpaceCorners[i][1] = corners[i][1];
}
}
}
@@ -177,18 +197,44 @@ void PlaneDistortMaskOperation::initExecution()
void PlaneDistortMaskOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
float point[2];
-
int inside_counter = 0;
- for (int sample = 0; sample < this->m_osa; sample++) {
- point[0] = x + this->m_jitter[sample][0];
- point[1] = y + this->m_jitter[sample][1];
-
- if (isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[1], this->m_frameSpaceCorners[2]) ||
- isect_point_tri_v2(point, this->m_frameSpaceCorners[0], this->m_frameSpaceCorners[2], this->m_frameSpaceCorners[3]))
+ if (this->m_motion_blur_samples == 1) {
+ MotionSample *sample_data = &this->m_samples[0];
+ for (int sample = 0; sample < this->m_osa; sample++) {
+ point[0] = x + this->m_jitter[sample][0];
+ point[1] = y + this->m_jitter[sample][1];
+ if (isect_point_tri_v2(point, sample_data->frameSpaceCorners[0],
+ sample_data->frameSpaceCorners[1],
+ sample_data->frameSpaceCorners[2]) ||
+ isect_point_tri_v2(point, sample_data->frameSpaceCorners[0],
+ sample_data->frameSpaceCorners[2],
+ sample_data->frameSpaceCorners[3]))
+ {
+ inside_counter++;
+ }
+ }
+ output[0] = (float)inside_counter / this->m_osa;
+ }
+ else {
+ for (int motion_sample = 0;
+ motion_sample < this->m_motion_blur_samples;
+ ++motion_sample)
{
- inside_counter++;
+ MotionSample *sample_data = &this->m_samples[motion_sample];
+ for (int osa_sample = 0; osa_sample < this->m_osa; ++osa_sample) {
+ point[0] = x + this->m_jitter[osa_sample][0];
+ point[1] = y + this->m_jitter[osa_sample][1];
+ if (isect_point_tri_v2(point, sample_data->frameSpaceCorners[0],
+ sample_data->frameSpaceCorners[1],
+ sample_data->frameSpaceCorners[2]) ||
+ isect_point_tri_v2(point, sample_data->frameSpaceCorners[0],
+ sample_data->frameSpaceCorners[2],
+ sample_data->frameSpaceCorners[3]))
+ {
+ inside_counter++;
+ }
+ }
}
+ output[0] = (float)inside_counter / (this->m_osa * this->m_motion_blur_samples);
}
-
- output[0] = (float) inside_counter / this->m_osa;
}
diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
index ee2874c6b46..fc5dd1ff7d8 100644
--- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.h
@@ -33,43 +33,72 @@
#include "BLI_listbase.h"
#include "BLI_string.h"
+#define PLANE_DISTORT_MAX_SAMPLES 64
class PlaneDistortWarpImageOperation : public NodeOperation {
protected:
+ struct MotionSample {
+ float frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */
+ float perspectiveMatrix[3][3];
+ };
SocketReader *m_pixelReader;
- float m_frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */
- float m_perspectiveMatrix[3][3];
+ MotionSample m_samples[PLANE_DISTORT_MAX_SAMPLES];
+ int m_motion_blur_samples;
+ float m_motion_blur_shutter;
public:
PlaneDistortWarpImageOperation();
- void calculateCorners(const float corners[4][2], bool normalized);
- void calculatePerspectiveMatrix();
+ void calculateCorners(const float corners[4][2],
+ bool normalized,
+ int sample);
void initExecution();
void deinitExecution();
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
- void pixelTransform(const float xy[2], float r_uv[2], float r_deriv[2][2]);
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
+
+ void setMotionBlurSamples(int samples) {
+ BLI_assert(samples <= PLANE_DISTORT_MAX_SAMPLES);
+ this->m_motion_blur_samples = samples;
+ }
+ void setMotionBlurShutter(float shutter) {
+ this->m_motion_blur_shutter = shutter;
+ }
};
class PlaneDistortMaskOperation : public NodeOperation {
protected:
+ struct MotionSample {
+ float frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */
+ };
int m_osa;
+ MotionSample m_samples[PLANE_DISTORT_MAX_SAMPLES];
float m_jitter[32][2];
- float m_frameSpaceCorners[4][2]; /* Corners coordinates in pixel space. */
+ int m_motion_blur_samples;
+ float m_motion_blur_shutter;
public:
PlaneDistortMaskOperation();
-
- void calculateCorners(const float corners[4][2], bool normalized);
-
+
+ void calculateCorners(const float corners[4][2],
+ bool normalized,
+ int sample);
+
void initExecution();
-
+
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
+
+ void setMotionBlurSamples(int samples) {
+ BLI_assert(samples <= PLANE_DISTORT_MAX_SAMPLES);
+ this->m_motion_blur_samples = samples;
+ }
+ void setMotionBlurShutter(float shutter) {
+ this->m_motion_blur_shutter = shutter;
+ }
};
#endif
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
index fec39cbfde0..20a8fa95200 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp
@@ -46,31 +46,29 @@ PlaneTrackCommon::PlaneTrackCommon()
this->m_planeTrackName[0] = '\0';
}
-void PlaneTrackCommon::readCornersFromTrack(float corners[4][2])
+void PlaneTrackCommon::readCornersFromTrack(float corners[4][2], float frame)
{
MovieTracking *tracking;
MovieTrackingObject *object;
if (!this->m_movieClip)
return;
-
+
tracking = &this->m_movieClip->tracking;
-
+
object = BKE_tracking_object_get_named(tracking, this->m_trackingObjectName);
if (object) {
MovieTrackingPlaneTrack *plane_track;
-
plane_track = BKE_tracking_plane_track_get_named(tracking, object, this->m_planeTrackName);
-
if (plane_track) {
MovieTrackingPlaneMarker *plane_marker;
- int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip, this->m_framenumber);
-
+ float clip_framenr =
+ BKE_movieclip_remap_scene_to_clip_frame(this->m_movieClip,
+ frame);
plane_marker = BKE_tracking_plane_marker_get(plane_track, clip_framenr);
- copy_v2_v2(corners[0], plane_marker->corners[0]);
- copy_v2_v2(corners[1], plane_marker->corners[1]);
- copy_v2_v2(corners[2], plane_marker->corners[2]);
- copy_v2_v2(corners[3], plane_marker->corners[3]);
+ BKE_tracking_plane_marker_get_subframe_corners(plane_track,
+ clip_framenr,
+ corners);
}
}
}
@@ -79,14 +77,12 @@ void PlaneTrackCommon::determineResolution(unsigned int resolution[2], unsigned
{
resolution[0] = 0;
resolution[1] = 0;
-
+
if (this->m_movieClip) {
int width, height;
MovieClipUser user = {0};
-
BKE_movieclip_user_set_frame(&user, this->m_framenumber);
BKE_movieclip_get_size(this->m_movieClip, &user, &width, &height);
-
resolution[0] = width;
resolution[1] = height;
}
@@ -98,10 +94,21 @@ void PlaneTrackCommon::determineResolution(unsigned int resolution[2], unsigned
void PlaneTrackMaskOperation::initExecution()
{
PlaneDistortMaskOperation::initExecution();
-
float corners[4][2];
- readCornersFromTrack(corners);
- calculateCorners(corners, true);
+ if (this->m_motion_blur_samples == 1) {
+ readCornersFromTrack(corners, this->m_framenumber);
+ calculateCorners(corners, true, 0);
+ }
+ else {
+ const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter;
+ const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples;
+ float frame_iter = frame;
+ for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ readCornersFromTrack(corners, frame_iter);
+ calculateCorners(corners, true, sample);
+ frame_iter += frame_step;
+ }
+ }
}
/* ******** PlaneTrackWarpImageOperation ******** */
@@ -109,9 +116,20 @@ void PlaneTrackMaskOperation::initExecution()
void PlaneTrackWarpImageOperation::initExecution()
{
PlaneDistortWarpImageOperation::initExecution();
-
+ /* TODO(sergey): De-duplicate with mask operation. */
float corners[4][2];
- readCornersFromTrack(corners);
- calculateCorners(corners, true);
- calculatePerspectiveMatrix();
+ if (this->m_motion_blur_samples == 1) {
+ readCornersFromTrack(corners, this->m_framenumber);
+ calculateCorners(corners, true, 0);
+ }
+ else {
+ const float frame = (float)this->m_framenumber - this->m_motion_blur_shutter;
+ const float frame_step = (this->m_motion_blur_shutter * 2.0f) / this->m_motion_blur_samples;
+ float frame_iter = frame;
+ for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
+ readCornersFromTrack(corners, frame_iter);
+ calculateCorners(corners, true, sample);
+ frame_iter += frame_step;
+ }
+ }
}
diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.h b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
index 3c5dd783542..41761493e12 100644
--- a/source/blender/compositor/operations/COM_PlaneTrackOperation.h
+++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.h
@@ -43,7 +43,7 @@ protected:
/* note: this class is not an operation itself (to prevent virtual inheritance issues)
* implementation classes must make wrappers to use these methods, see below.
*/
- void readCornersFromTrack(float corners[4][2]);
+ void readCornersFromTrack(float corners[4][2], float frame);
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
public:
@@ -68,7 +68,7 @@ public:
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
{
PlaneTrackCommon::determineResolution(resolution, preferredResolution);
-
+
unsigned int temp[2];
NodeOperation::determineResolution(temp, resolution);
}
@@ -81,13 +81,12 @@ public:
PlaneDistortWarpImageOperation(),
PlaneTrackCommon()
{}
-
+
void initExecution();
-
+
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
{
PlaneTrackCommon::determineResolution(resolution, preferredResolution);
-
unsigned int temp[2];
NodeOperation::determineResolution(temp, resolution);
}
diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.cpp b/source/blender/compositor/operations/COM_QualityStepHelper.cpp
index d99d6f28eff..4d9c15f9747 100644
--- a/source/blender/compositor/operations/COM_QualityStepHelper.cpp
+++ b/source/blender/compositor/operations/COM_QualityStepHelper.cpp
@@ -37,15 +37,15 @@ void QualityStepHelper::initExecution(QualityHelper helper)
case COM_QUALITY_HIGH:
default:
this->m_step = 1;
- this->m_offsetadd = 4;
+ this->m_offsetadd = 1;
break;
case COM_QUALITY_MEDIUM:
this->m_step = 2;
- this->m_offsetadd = 8;
+ this->m_offsetadd = 2;
break;
case COM_QUALITY_LOW:
this->m_step = 3;
- this->m_offsetadd = 12;
+ this->m_offsetadd = 3;
break;
}
break;
diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
index 47d5fc6bcca..ad4084a7092 100644
--- a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cpp
@@ -24,9 +24,9 @@
#include "COM_WriteBufferOperation.h"
#include "COM_defines.h"
-ReadBufferOperation::ReadBufferOperation() : NodeOperation()
+ReadBufferOperation::ReadBufferOperation(DataType datatype) : NodeOperation()
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(datatype);
this->m_single_value = false;
this->m_offset = 0;
this->m_buffer = NULL;
@@ -58,11 +58,19 @@ void ReadBufferOperation::executePixelSampled(float output[4], float x, float y,
/* write buffer has a single value stored at (0,0) */
m_buffer->read(output, 0, 0);
}
- else if (sampler == COM_PS_NEAREST) {
- m_buffer->read(output, x, y);
- }
else {
- m_buffer->readBilinear(output, x, y);
+ switch (sampler) {
+ case COM_PS_NEAREST:
+ m_buffer->read(output, x, y);
+ break;
+ case COM_PS_BILINEAR:
+ default:
+ m_buffer->readBilinear(output, x, y);
+ break;
+ case COM_PS_BICUBIC:
+ m_buffer->readBilinear(output, x, y);
+ break;
+ }
}
}
diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.h b/source/blender/compositor/operations/COM_ReadBufferOperation.h
index 569920d51ef..7e5bc55a8ca 100644
--- a/source/blender/compositor/operations/COM_ReadBufferOperation.h
+++ b/source/blender/compositor/operations/COM_ReadBufferOperation.h
@@ -25,6 +25,7 @@
#include "COM_NodeOperation.h"
#include "COM_MemoryProxy.h"
+#include "COM_MemoryBuffer.h"
class ReadBufferOperation : public NodeOperation {
private:
@@ -33,7 +34,7 @@ private:
unsigned int m_offset;
MemoryBuffer *m_buffer;
public:
- ReadBufferOperation();
+ ReadBufferOperation(DataType datetype);
void setMemoryProxy(MemoryProxy *memoryProxy) { this->m_memoryProxy = memoryProxy; }
MemoryProxy *getMemoryProxy() { return this->m_memoryProxy; }
void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]);
diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
index 06f4f6d77cf..4c6d5c24781 100644
--- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp
+++ b/source/blender/compositor/operations/COM_RenderLayersProg.cpp
@@ -104,22 +104,13 @@ void RenderLayersBaseProg::doInterpolation(float output[4], float x, float y, Pi
}
case COM_PS_BILINEAR:
- BLI_bilinear_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y);
+ BLI_bilinear_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x - 0.5f, y - 0.5f);
break;
case COM_PS_BICUBIC:
- BLI_bicubic_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x, y);
+ BLI_bicubic_interpolation_fl(this->m_inputBuffer, output, width, height, this->m_elementsize, x - 0.5f, y - 0.5f);
break;
}
-
- if (this->m_elementsize == 1) {
- output[1] = 0.0f;
- output[2] = 0.0f;
- output[3] = 0.0f;
- }
- else if (this->m_elementsize == 3) {
- output[3] = 1.0f;
- }
}
void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
@@ -145,7 +136,17 @@ void RenderLayersBaseProg::executePixelSampled(float output[4], float x, float y
#endif
if (this->m_inputBuffer == NULL) {
- zero_v4(output);
+ int elemsize = this->m_elementsize;
+ if (elemsize == 1) {
+ output[0] = 0.0f;
+ }
+ else if (elemsize == 3) {
+ zero_v3(output);
+ }
+ else {
+ BLI_assert(elemsize == 4);
+ zero_v4(output);
+ }
}
else {
doInterpolation(output, x, y, sampler);
@@ -204,15 +205,12 @@ void RenderLayersAlphaProg::executePixelSampled(float output[4], float x, float
float *inputBuffer = this->getInputBuffer();
if (inputBuffer == NULL) {
- zero_v4(output);
+ output[0] = 0.0f;
}
else {
float temp[4];
doInterpolation(temp, x, y, sampler);
output[0] = temp[3];
- output[1] = 0.0f;
- output[2] = 0.0f;
- output[3] = 0.0f;
}
}
@@ -227,7 +225,7 @@ RenderLayersColorOperation::RenderLayersColorOperation() : RenderLayersBaseProg(
RenderLayersCyclesOperation::RenderLayersCyclesOperation(int pass) : RenderLayersBaseProg(pass, 3)
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_VECTOR);
}
/* ******** Render Layers Depth Operation ******** */
@@ -245,16 +243,10 @@ void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float
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;
}
else {
unsigned int offset = (iy * this->getWidth() + ix);
output[0] = inputBuffer[offset];
- output[1] = 0.0f;
- output[2] = 0.0f;
- output[3] = 0.0f;
}
}
@@ -262,21 +254,21 @@ void RenderLayersDepthProg::executePixelSampled(float output[4], float x, float
RenderLayersDiffuseOperation::RenderLayersDiffuseOperation() : RenderLayersBaseProg(SCE_PASS_DIFFUSE, 3)
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_VECTOR);
}
/* ******** Render Layers Emit Operation ******** */
RenderLayersEmitOperation::RenderLayersEmitOperation() : RenderLayersBaseProg(SCE_PASS_EMIT, 3)
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_VECTOR);
}
/* ******** Render Layers Environment Operation ******** */
RenderLayersEnvironmentOperation::RenderLayersEnvironmentOperation() : RenderLayersBaseProg(SCE_PASS_ENVIRONMENT, 3)
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_VECTOR);
}
/* ******** Render Layers Image Operation ******** */
@@ -290,7 +282,7 @@ RenderLayersColorProg::RenderLayersColorProg() : RenderLayersBaseProg(SCE_PASS_C
RenderLayersIndirectOperation::RenderLayersIndirectOperation() : RenderLayersBaseProg(SCE_PASS_INDIRECT, 3)
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_VECTOR);
}
/* ******** Render Layers Material Index Operation ******** */
@@ -325,28 +317,28 @@ RenderLayersObjectIndexOperation::RenderLayersObjectIndexOperation() : RenderLay
RenderLayersReflectionOperation::RenderLayersReflectionOperation() : RenderLayersBaseProg(SCE_PASS_REFLECT, 3)
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_VECTOR);
}
/* ******** Render Layers Refraction Operation ******** */
RenderLayersRefractionOperation::RenderLayersRefractionOperation() : RenderLayersBaseProg(SCE_PASS_REFRACT, 3)
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_VECTOR);
}
/* ******** Render Layers Shadow Operation ******** */
RenderLayersShadowOperation::RenderLayersShadowOperation() : RenderLayersBaseProg(SCE_PASS_SHADOW, 3)
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_VECTOR);
}
/* ******** Render Layers Specular Operation ******** */
RenderLayersSpecularOperation::RenderLayersSpecularOperation() : RenderLayersBaseProg(SCE_PASS_SPEC, 3)
{
- this->addOutputSocket(COM_DT_COLOR);
+ this->addOutputSocket(COM_DT_VECTOR);
}
/* ******** Render Layers Speed Operation ******** */
diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cpp b/source/blender/compositor/operations/COM_SetVectorOperation.cpp
index 17212d78e15..769eaf1d2ed 100644
--- a/source/blender/compositor/operations/COM_SetVectorOperation.cpp
+++ b/source/blender/compositor/operations/COM_SetVectorOperation.cpp
@@ -33,7 +33,6 @@ void SetVectorOperation::executePixelSampled(float output[4], float x, float y,
output[0] = this->m_x;
output[1] = this->m_y;
output[2] = this->m_z;
- output[3] = this->m_w;
}
void SetVectorOperation::determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2])
diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
index 12b04c386f2..0ca687ea162 100644
--- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
+++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cpp
@@ -135,7 +135,7 @@ struct BufferLineAccumulator {
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);
+ float *iter = input->getBuffer() + COM_NUM_CHANNELS_COLOR * (x + input->getWidth() * y);
return iter;
}
@@ -159,7 +159,7 @@ struct BufferLineAccumulator {
zero_v4(output);
if ((int)(co[0] - source[0]) == 0 && (int)(co[1] - source[1]) == 0) {
- copy_v4_v4(output, input->getBuffer() + COM_NUMBER_OF_CHANNELS * ((int)source[0] + input->getWidth() * (int)source[1]));
+ copy_v4_v4(output, input->getBuffer() + COM_NUM_CHANNELS_COLOR * ((int)source[0] + input->getWidth() * (int)source[1]));
return;
}
@@ -198,7 +198,7 @@ struct BufferLineAccumulator {
/* decrement u */
x -= fxu;
y -= fyu;
- buffer -= (fxu + fyu * buffer_width) * COM_NUMBER_OF_CHANNELS;
+ buffer -= (fxu + fyu * buffer_width) * COM_NUM_CHANNELS_COLOR;
/* decrement v (in steps of dv < 1) */
v_local -= dv;
@@ -207,7 +207,7 @@ struct BufferLineAccumulator {
x -= fxv;
y -= fyv;
- buffer -= (fxv + fyv * buffer_width) * COM_NUMBER_OF_CHANNELS;
+ buffer -= (fxv + fyv * buffer_width) * COM_NUM_CHANNELS_COLOR;
}
}
diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cpp
index ede767cbff7..1b0485afb8d 100644
--- a/source/blender/compositor/operations/COM_TextureOperation.cpp
+++ b/source/blender/compositor/operations/COM_TextureOperation.cpp
@@ -77,12 +77,9 @@ void TextureBaseOperation::determineResolution(unsigned int resolution[2], unsig
void TextureAlphaOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
- TextureBaseOperation::executePixelSampled(output, x, y, sampler);
- output[0] = output[3];
- output[1] = 0.0f;
- output[2] = 0.0f;
- output[3] = 0.0f;
-}
+ float color[4];
+ TextureBaseOperation::executePixelSampled(color, x, y, sampler);
+ output[0] = color[3];}
void TextureBaseOperation::executePixelSampled(float output[4], float x, float y, PixelSampler sampler)
{
@@ -103,7 +100,7 @@ void TextureBaseOperation::executePixelSampled(float output[4], float x, float y
vec[1] = textureSize[1] * (v + textureOffset[1]);
vec[2] = textureSize[2] * textureOffset[2];
- retval = multitex_ext(this->m_texture, vec, NULL, NULL, 0, &texres, m_pool, m_sceneColorManage);
+ retval = multitex_ext(this->m_texture, vec, NULL, NULL, 0, &texres, m_pool, m_sceneColorManage, false);
if (texres.talpha)
output[3] = texres.ta;
@@ -124,18 +121,23 @@ MemoryBuffer *TextureBaseOperation::createMemoryBuffer(rcti *rect2)
{
int height = getHeight();
int width = getWidth();
+ DataType datatype = this->getOutputSocket()->getDataType();
+ int add = 4;
+ if (datatype == COM_DT_VALUE) {
+ add = 1;
+ }
rcti rect;
rect.xmin = 0;
rect.ymin = 0;
rect.xmax = width;
rect.ymax = height;
- MemoryBuffer *result = new MemoryBuffer(NULL, &rect);
+ MemoryBuffer *result = new MemoryBuffer(datatype, &rect);
float *data = result->getBuffer();
for (int y = 0; y < height; y++) {
- for (int x = 0; x < width; x++, data += 4) {
+ for (int x = 0; x < width; x++, data += add) {
this->executePixelSampled(data, x, y, COM_PS_NEAREST);
}
}
diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
index 4b81001fdab..4809efd7436 100644
--- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp
@@ -137,30 +137,33 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y,
copy_v4_fl(multiplier_accum, 1.0f);
float size_center = tempSize[0] * scalar;
- const int addXStep = QualityStepHelper::getStep() * COM_NUMBER_OF_CHANNELS;
-
+ const int addXStepValue = QualityStepHelper::getStep();
+ const int addYStepValue = addXStepValue;
+ const int addXStepColor = addXStepValue * COM_NUM_CHANNELS_COLOR;
+
if (size_center > this->m_threshold) {
- for (int ny = miny; ny < maxy; ny += QualityStepHelper::getStep()) {
+ for (int ny = miny; ny < maxy; ny += addYStepValue) {
float dy = ny - y;
- int offsetNy = ny * inputSizeBuffer->getWidth() * COM_NUMBER_OF_CHANNELS;
- int offsetNxNy = offsetNy + (minx * COM_NUMBER_OF_CHANNELS);
- for (int nx = minx; nx < maxx; nx += QualityStepHelper::getStep()) {
+ int offsetValueNy = ny * inputSizeBuffer->getWidth();
+ int offsetValueNxNy = offsetValueNy + (minx);
+ int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR;
+ for (int nx = minx; nx < maxx; nx += addXStepValue) {
if (nx != x || ny != y) {
- float size = min(inputSizeFloatBuffer[offsetNxNy] * scalar, size_center);
+ float size = min(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center);
if (size > this->m_threshold) {
float dx = nx - x;
if (size > fabsf(dx) && size > fabsf(dy)) {
float uv[2] = {
- (float)(COM_BLUR_BOKEH_PIXELS / 2) + (dx / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1),
- (float)(COM_BLUR_BOKEH_PIXELS / 2) + (dy / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1)};
- inputBokehBuffer->readNoCheck(bokeh, uv[0], uv[1]);
- madd_v4_v4v4(color_accum, bokeh, &inputProgramFloatBuffer[offsetNxNy]);
+ (float)(COM_BLUR_BOKEH_PIXELS / 2) + (dx / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1),
+ (float)(COM_BLUR_BOKEH_PIXELS / 2) + (dy / size) * (float)((COM_BLUR_BOKEH_PIXELS / 2) - 1)};
+ inputBokehBuffer->read(bokeh, uv[0], uv[1]);
+ madd_v4_v4v4(color_accum, bokeh, &inputProgramFloatBuffer[offsetColorNxNy]);
add_v4_v4(multiplier_accum, bokeh);
}
}
}
- offsetNxNy += addXStep;
- }
+ offsetColorNxNy += addXStepColor;
+ offsetValueNxNy += addXStepValue; }
}
}
diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
index f5890157440..8dc06ef07d7 100644
--- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cpp
@@ -57,7 +57,7 @@ void VectorBlurOperation::initExecution()
void VectorBlurOperation::executePixel(float output[4], int x, int y, void *data)
{
float *buffer = (float *) data;
- int index = (y * this->getWidth() + x) * COM_NUMBER_OF_CHANNELS;
+ int index = (y * this->getWidth() + x) * COM_NUM_CHANNELS_COLOR;
copy_v4_v4(output, &buffer[index]);
}
@@ -108,14 +108,12 @@ bool VectorBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBuff
void VectorBlurOperation::generateVectorBlur(float *data, MemoryBuffer *inputImage, MemoryBuffer *inputSpeed, MemoryBuffer *inputZ)
{
- float *zbuf = inputZ->convertToValueBuffer();
NodeBlurData blurdata;
blurdata.samples = this->m_settings->samples / QualityStepHelper::getStep();
blurdata.maxspeed = this->m_settings->maxspeed;
blurdata.minspeed = this->m_settings->minspeed;
blurdata.curved = this->m_settings->curved;
blurdata.fac = this->m_settings->fac;
- RE_zbuf_accumulate_vecblur(&blurdata, this->getWidth(), this->getHeight(), data, inputImage->getBuffer(), inputSpeed->getBuffer(), zbuf);
- MEM_freeN((void *)zbuf);
+ RE_zbuf_accumulate_vecblur(&blurdata, this->getWidth(), this->getHeight(), data, inputImage->getBuffer(), inputSpeed->getBuffer(), inputZ->getBuffer());
return;
}
diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp b/source/blender/compositor/operations/COM_VectorCurveOperation.cpp
index fedc8c6db7d..dfdc54012a8 100644
--- a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp
+++ b/source/blender/compositor/operations/COM_VectorCurveOperation.cpp
@@ -51,7 +51,6 @@ void VectorCurveOperation::executePixelSampled(float output[4], float x, float y
this->m_inputProgram->readSampled(input, x, y, sampler);
curvemapping_evaluate_premulRGBF(this->m_curveMapping, output, input);
- output[3] = input[3];
}
void VectorCurveOperation::deinitExecution()
diff --git a/source/blender/compositor/operations/COM_WrapOperation.cpp b/source/blender/compositor/operations/COM_WrapOperation.cpp
index c30361d1df8..7fbef453a13 100644
--- a/source/blender/compositor/operations/COM_WrapOperation.cpp
+++ b/source/blender/compositor/operations/COM_WrapOperation.cpp
@@ -23,7 +23,7 @@
#include "COM_WrapOperation.h"
-WrapOperation::WrapOperation() : ReadBufferOperation()
+WrapOperation::WrapOperation(DataType datatype) : ReadBufferOperation(datatype)
{
this->m_wrappingType = CMP_NODE_WRAP_NONE;
}
diff --git a/source/blender/compositor/operations/COM_WrapOperation.h b/source/blender/compositor/operations/COM_WrapOperation.h
index 33ea1280564..92c93565691 100644
--- a/source/blender/compositor/operations/COM_WrapOperation.h
+++ b/source/blender/compositor/operations/COM_WrapOperation.h
@@ -29,7 +29,7 @@ class WrapOperation : public ReadBufferOperation {
private:
int m_wrappingType;
public:
- WrapOperation();
+ WrapOperation(DataType datetype);
bool determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output);
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
index 832864b399d..fccff2a33bf 100644
--- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
+++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cpp
@@ -25,10 +25,10 @@
#include <stdio.h>
#include "COM_OpenCLDevice.h"
-WriteBufferOperation::WriteBufferOperation() : NodeOperation()
+WriteBufferOperation::WriteBufferOperation(DataType datatype) : NodeOperation()
{
- this->addInputSocket(COM_DT_COLOR);
- this->m_memoryProxy = new MemoryProxy();
+ this->addInputSocket(datatype);
+ this->m_memoryProxy = new MemoryProxy(datatype);
this->m_memoryProxy->setWriteBufferOperation(this);
this->m_memoryProxy->setExecutor(NULL);
}
@@ -61,6 +61,7 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber)
{
MemoryBuffer *memoryBuffer = this->m_memoryProxy->getBuffer();
float *buffer = memoryBuffer->getBuffer();
+ const int num_channels = memoryBuffer->get_num_channels();
if (this->m_input->isComplex()) {
void *data = this->m_input->initializeTileData(rect);
int x1 = rect->xmin;
@@ -71,10 +72,10 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber)
int y;
bool breaked = false;
for (y = y1; y < y2 && (!breaked); y++) {
- int offset4 = (y * memoryBuffer->getWidth() + x1) * COM_NUMBER_OF_CHANNELS;
+ int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels;
for (x = x1; x < x2; x++) {
this->m_input->read(&(buffer[offset4]), x, y, data);
- offset4 += COM_NUMBER_OF_CHANNELS;
+ offset4 += num_channels;
}
if (isBreaked()) {
breaked = true;
@@ -96,10 +97,10 @@ void WriteBufferOperation::executeRegion(rcti *rect, unsigned int tileNumber)
int y;
bool breaked = false;
for (y = y1; y < y2 && (!breaked); y++) {
- int offset4 = (y * memoryBuffer->getWidth() + x1) * COM_NUMBER_OF_CHANNELS;
+ int offset4 = (y * memoryBuffer->getWidth() + x1) * num_channels;
for (x = x1; x < x2; x++) {
this->m_input->readSampled(&(buffer[offset4]), x, y, COM_PS_NEAREST);
- offset4 += COM_NUMBER_OF_CHANNELS;
+ offset4 += num_channels;
}
if (isBreaked()) {
breaked = true;
@@ -126,12 +127,9 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, rcti *rect,
const unsigned int outputBufferWidth = outputBuffer->getWidth();
const unsigned int outputBufferHeight = outputBuffer->getHeight();
- const cl_image_format imageFormat = {
- CL_RGBA,
- CL_FLOAT
- };
+ const cl_image_format *imageFormat = device->determineImageFormat(outputBuffer);
- cl_mem clOutputBuffer = clCreateImage2D(device->getContext(), CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, &imageFormat, outputBufferWidth, outputBufferHeight, 0, outputFloatBuffer, &error);
+ cl_mem clOutputBuffer = clCreateImage2D(device->getContext(), CL_MEM_WRITE_ONLY | CL_MEM_USE_HOST_PTR, imageFormat, outputBufferWidth, outputBufferHeight, 0, outputFloatBuffer, &error);
if (error != CL_SUCCESS) { printf("CLERROR[%d]: %s\n", error, clewErrorString(error)); }
// STEP 2
diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.h b/source/blender/compositor/operations/COM_WriteBufferOperation.h
index 96466df979c..9220cb179c6 100644
--- a/source/blender/compositor/operations/COM_WriteBufferOperation.h
+++ b/source/blender/compositor/operations/COM_WriteBufferOperation.h
@@ -35,7 +35,7 @@ class WriteBufferOperation : public NodeOperation {
bool m_single_value; /* single value stored in buffer */
NodeOperation *m_input;
public:
- WriteBufferOperation();
+ WriteBufferOperation(DataType datatype);
~WriteBufferOperation();
MemoryProxy *getMemoryProxy() { return this->m_memoryProxy; }
void executePixelSampled(float output[4], float x, float y, PixelSampler sampler);
diff --git a/source/blender/datatoc/datatoc_icon_split.py b/source/blender/datatoc/datatoc_icon_split.py
index 55f0a5c5f6a..aae907ec340 100755
--- a/source/blender/datatoc/datatoc_icon_split.py
+++ b/source/blender/datatoc/datatoc_icon_split.py
@@ -63,7 +63,7 @@ def image_from_file(filepath):
try:
import bpy
- except:
+ except ImportError:
bpy = None
if bpy is not None:
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c
index d76eba93640..37c40052275 100644
--- a/source/blender/editors/animation/anim_channels_defines.c
+++ b/source/blender/editors/animation/anim_channels_defines.c
@@ -61,6 +61,7 @@
#include "RNA_access.h"
+#include "BKE_animsys.h"
#include "BKE_curve.h"
#include "BKE_key.h"
#include "BKE_nla.h"
@@ -3519,6 +3520,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
/* step 5) draw name ............................................... */
/* TODO: when renaming, we might not want to draw this, especially if name happens to be longer than channel */
if (acf->name) {
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
char name[ANIM_CHAN_NAME_SIZE]; /* hopefully this will be enough! */
/* set text color */
@@ -3532,7 +3534,7 @@ void ANIM_channel_draw(bAnimContext *ac, bAnimListElem *ale, float yminc, float
acf->name(ale, name);
offset += 3;
- UI_draw_string(offset, ytext, name);
+ UI_fontstyle_draw_simple(fstyle, offset, ytext, name);
/* draw red underline if channel is disabled */
if ((ale->type == ANIMTYPE_FCURVE) && (ale->flag & FCURVE_DISABLED)) {
@@ -3688,6 +3690,7 @@ static void achannel_nlatrack_solo_widget_cb(bContext *C, void *adt_poin, void *
static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poin)
{
ID *id = (ID *)id_poin;
+ AnimData *adt = BKE_animdata_from_id(id);
FCurve *fcu = (FCurve *)fcu_poin;
ReportList *reports = CTX_wm_reports(C);
@@ -3698,9 +3701,8 @@ static void achannel_setting_slider_cb(bContext *C, void *id_poin, void *fcu_poi
bool done = false;
float cfra;
- /* get current frame */
- // NOTE: this will do for now...
- cfra = (float)CFRA;
+ /* get current frame and apply NLA-mapping to it (if applicable) */
+ cfra = BKE_nla_tweakedit_remap(adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
/* get flags for keyframing */
flag = ANIM_get_keyframing_flags(scene, 1);
@@ -3737,9 +3739,8 @@ static void achannel_setting_slider_shapekey_cb(bContext *C, void *key_poin, voi
bool done = false;
float cfra;
- /* get current frame */
- // NOTE: this will do for now...
- cfra = (float)CFRA;
+ /* get current frame and apply NLA-mapping to it (if applicable) */
+ cfra = BKE_nla_tweakedit_remap(key->adt, (float)CFRA, NLATIME_CONVERT_UNMAP);
/* get flags for keyframing */
flag = ANIM_get_keyframing_flags(scene, 1);
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 2d7656642d3..0e052279796 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -59,6 +59,7 @@
/* Draw current frame number in a little green box beside the current frame indicator */
static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const bool time)
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float xscale, yscale, x, y;
char numstr[32] = " t"; /* t is the character to start replacing from */
int slen;
@@ -78,7 +79,8 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const
else {
BLI_timecode_string_from_time_simple(&numstr[4], sizeof(numstr) - 4, 1, cfra);
}
- slen = UI_fontstyle_string_width(numstr) - 1;
+
+ slen = UI_fontstyle_string_width(fstyle, numstr) - 1;
/* get starting coordinates for drawing */
x = cfra * xscale;
@@ -90,7 +92,7 @@ static void draw_cfra_number(Scene *scene, View2D *v2d, const float cfra, const
/* draw current frame number - black text */
UI_ThemeColor(TH_TEXT);
- UI_draw_string(x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr);
+ UI_fontstyle_draw_simple(fstyle, x - 0.25f * U.widget_unit, y + 0.15f * U.widget_unit, numstr);
/* restore view transform */
glScalef(xscale, 1.0, 1.0);
diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c
index b6c7a4aa5a0..140b7e0b117 100644
--- a/source/blender/editors/animation/anim_markers.c
+++ b/source/blender/editors/animation/anim_markers.c
@@ -317,7 +317,7 @@ void debug_markers_print_list(ListBase *markers)
/* function to draw markers */
static void draw_marker(
- View2D *v2d, TimeMarker *marker, int cfra, int flag,
+ View2D *v2d, const uiFontStyle *fstyle, TimeMarker *marker, int cfra, int flag,
/* avoid re-calculating each time */
const float ypixels, const float xscale, const float yscale)
{
@@ -399,13 +399,14 @@ static void draw_marker(
}
#endif
- UI_draw_string(x, y, marker->name);
+ UI_fontstyle_draw_simple(fstyle, x, y, marker->name);
}
}
/* Draw Scene-Markers in time window */
void ED_markers_draw(const bContext *C, int flag)
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
ListBase *markers = ED_context_get_markers(C);
View2D *v2d;
TimeMarker *marker;
@@ -455,7 +456,7 @@ void ED_markers_draw(const bContext *C, int flag)
if ((marker->frame >= v2d_clip_range_x[0]) &&
(marker->frame <= v2d_clip_range_x[1]))
{
- draw_marker(v2d, marker, scene->r.cfra, flag,
+ draw_marker(v2d, fstyle, marker, scene->r.cfra, flag,
ypixels, xscale, yscale);
}
}
@@ -1056,7 +1057,7 @@ static void select_timeline_marker_frame(ListBase *markers, int frame, bool exte
}
BLI_LISTBASE_CIRCULAR_FORWARD_BEGIN (markers, marker, marker_first) {
- /* this way a not-extend select will allways give 1 selected marker */
+ /* this way a not-extend select will always give 1 selected marker */
if (marker->frame == frame) {
marker->flag ^= SELECT;
break;
diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c
index 8ede1a0ad76..bcdad1c93ad 100644
--- a/source/blender/editors/animation/fmodifier_ui.c
+++ b/source/blender/editors/animation/fmodifier_ui.c
@@ -130,6 +130,7 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s
switch (data->mode) {
case FCM_GENERATOR_POLYNOMIAL: /* polynomial expression */
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
float *cp = NULL;
char xval[32];
unsigned int i;
@@ -147,11 +148,12 @@ static void draw_modifier__generator(uiLayout *layout, ID *id, FModifier *fcm, s
/* calculate maximum width of label for "x^n" labels */
if (data->arraysize > 2) {
BLI_snprintf(xval, sizeof(xval), "x^%u", data->arraysize);
- maxXWidth = UI_fontstyle_string_width(xval) + 0.5 * UI_UNIT_X; /* XXX: UI_fontstyle_string_width is not accurate */
+ /* XXX: UI_fontstyle_string_width is not accurate */
+ maxXWidth = UI_fontstyle_string_width(fstyle, xval) + 0.5 * UI_UNIT_X;
}
else {
/* basic size (just "x") */
- maxXWidth = UI_fontstyle_string_width("x") + 0.5 * UI_UNIT_X;
+ maxXWidth = UI_fontstyle_string_width(fstyle, "x") + 0.5 * UI_UNIT_X;
}
/* draw controls for each coefficient and a + sign at end of row */
diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c
index 439b3b94974..ee1bfdff0bd 100644
--- a/source/blender/editors/animation/keyframes_edit.c
+++ b/source/blender/editors/animation/keyframes_edit.c
@@ -785,7 +785,8 @@ static short mirror_bezier_cframe(KeyframeEditData *ked, BezTriple *bezt)
static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
if (bezt->f2 & SELECT) {
- mirror_bezier_yaxis_ex(bezt, 0.0f);
+ /* Yes, names are inverted, we are mirroring accross y axis, hence along x axis... */
+ mirror_bezier_xaxis_ex(bezt, 0.0f);
}
return 0;
@@ -794,7 +795,8 @@ static short mirror_bezier_yaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
static short mirror_bezier_xaxis(KeyframeEditData *UNUSED(ked), BezTriple *bezt)
{
if (bezt->f2 & SELECT) {
- mirror_bezier_xaxis_ex(bezt, 0.0f);
+ /* Yes, names are inverted, we are mirroring accross x axis, hence along y axis... */
+ mirror_bezier_yaxis_ex(bezt, 0.0f);
}
return 0;
@@ -814,7 +816,7 @@ static short mirror_bezier_value(KeyframeEditData *ked, BezTriple *bezt)
{
/* value to mirror over is stored in the custom data -> first float value slot */
if (bezt->f2 & SELECT) {
- mirror_bezier_xaxis_ex(bezt, ked->f1);
+ mirror_bezier_yaxis_ex(bezt, ked->f1);
}
return 0;
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 7ac11c1cd06..932a00d1687 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -641,7 +641,7 @@ static void flip_names(tAnimCopybufItem *aci, char **name)
str_iter = *name = MEM_mallocN(sizeof(char) * (prefix_l + postfix_l + length + 1), "flipped_path");
BLI_strncpy(str_iter, aci->rna_path, prefix_l + 1);
- str_iter += prefix_l ;
+ str_iter += prefix_l;
BLI_strncpy(str_iter, bname_new, length + 1);
str_iter += length;
BLI_strncpy(str_iter, str_end, postfix_l + 1);
@@ -663,14 +663,14 @@ static tAnimCopybufItem *pastebuf_match_path_full(FCurve *fcu, const short from_
if ((from_single) || (aci->array_index == fcu->array_index)) {
char *name = NULL;
flip_names(aci, &name);
- if (strcmp(name, fcu->rna_path) == 0) {
+ if (STREQ(name, fcu->rna_path)) {
MEM_freeN(name);
break;
}
MEM_freeN(name);
}
}
- else if (to_simple || (strcmp(aci->rna_path, fcu->rna_path) == 0)) {
+ else if (to_simple || STREQ(aci->rna_path, fcu->rna_path)) {
if ((from_single) || (aci->array_index == fcu->array_index)) {
break;
}
@@ -711,7 +711,7 @@ static tAnimCopybufItem *pastebuf_match_path_property(FCurve *fcu, const short f
int len_path = strlen(fcu->rna_path);
if (len_id <= len_path) {
/* note, paths which end with "] will fail with this test - Animated ID Props */
- if (strcmp(identifier, fcu->rna_path + (len_path - len_id)) == 0) {
+ if (STREQ(identifier, fcu->rna_path + (len_path - len_id))) {
if ((from_single) || (aci->array_index == fcu->array_index))
break;
}
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index a5c0eee8d3b..4b9a629183e 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -556,7 +556,7 @@ KeyingSet *ANIM_builtin_keyingset_get_named(KeyingSet *prevKS, const char name[]
/* loop over KeyingSets checking names */
for (ks = first; ks; ks = ks->next) {
- if (strcmp(name, ks->idname) == 0)
+ if (STREQ(name, ks->idname))
return ks;
}
@@ -603,7 +603,7 @@ void ANIM_keyingset_info_unregister(Main *bmain, KeyingSetInfo *ksi)
ksn = ks->next;
/* remove if matching typeinfo name */
- if (strcmp(ks->typeinfo, ksi->idname) == 0) {
+ if (STREQ(ks->typeinfo, ksi->idname)) {
Scene *scene;
BKE_keyingset_free(ks);
BLI_remlink(&builtin_keyingsets, ks);
@@ -914,6 +914,37 @@ short ANIM_validate_keyingset(bContext *C, ListBase *dsources, KeyingSet *ks)
return 0;
}
+/* Determine which keying flags apply based on the override flags */
+static short keyingset_apply_keying_flags(const short base_flags, const short overrides, const short own_flags)
+{
+ short result = 0;
+
+ /* The logic for whether a keying flag applies is as follows:
+ * - If the flag in question is set in "overrides", that means that the
+ * status of that flag in "own_flags" is used
+ * - If however the flag isn't set, then its value in "base_flags" is used
+ * instead (i.e. no override)
+ */
+#define APPLY_KEYINGFLAG_OVERRIDE(kflag) \
+ if (overrides & kflag) { \
+ result |= (own_flags & kflag); \
+ } \
+ else { \
+ result |= (base_flags & kflag); \
+ }
+
+ /* Apply the flags one by one...
+ * (See rna_def_common_keying_flags() for the supported flags)
+ */
+ APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_NEEDED)
+ APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_MATRIX)
+ APPLY_KEYINGFLAG_OVERRIDE(INSERTKEY_XYZ2RGB)
+
+#undef APPLY_KEYINGFLAG_OVERRIDE
+
+ return result;
+}
+
/* Given a KeyingSet and context info (if required), modify keyframes for the channels specified
* by the KeyingSet. This takes into account many of the different combinations of using KeyingSets.
* Returns the number of channels that keyframes were added to
@@ -923,7 +954,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
Scene *scene = CTX_data_scene(C);
ReportList *reports = CTX_wm_reports(C);
KS_Path *ksp;
- int kflag = 0, success = 0;
+ const short base_kflags = ANIM_get_keyframing_flags(scene, 1);
+ short kflag = 0, success = 0;
const char *groupname = NULL;
/* sanity checks */
@@ -932,11 +964,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
/* get flags to use */
if (mode == MODIFYKEY_MODE_INSERT) {
- /* use KeyingSet's flags as base */
- kflag = ks->keyingflag;
-
- /* supplement with info from the context */
- kflag |= ANIM_get_keyframing_flags(scene, 1);
+ /* use context settings as base */
+ kflag = keyingset_apply_keying_flags(base_kflags, ks->keyingoverride, ks->keyingflag);
}
else if (mode == MODIFYKEY_MODE_DELETE)
kflag = 0;
@@ -962,8 +991,8 @@ int ANIM_apply_keyingset(bContext *C, ListBase *dsources, bAction *act, KeyingSe
continue;
}
- /* since keying settings can be defined on the paths too, extend the path before using it */
- kflag2 = (kflag | ksp->keyingflag);
+ /* since keying settings can be defined on the paths too, apply the settings for this path first */
+ kflag2 = keyingset_apply_keying_flags(kflag, ksp->keyingoverride, ksp->keyingflag);
/* get pointer to name of group to add channels to */
if (ksp->groupmode == KSP_GROUP_NONE)
diff --git a/source/blender/editors/armature/armature_add.c b/source/blender/editors/armature/armature_add.c
index eba1bc4d78d..22aaeccc4a8 100644
--- a/source/blender/editors/armature/armature_add.c
+++ b/source/blender/editors/armature/armature_add.c
@@ -270,7 +270,7 @@ static EditBone *get_named_editbone(ListBase *edbo, const char *name)
if (name) {
for (eBone = edbo->first; eBone; eBone = eBone->next) {
- if (!strcmp(name, eBone->name))
+ if (STREQ(name, eBone->name))
return eBone;
}
}
diff --git a/source/blender/editors/armature/armature_edit.c b/source/blender/editors/armature/armature_edit.c
index 7f7843a6d1d..88c52989c07 100644
--- a/source/blender/editors/armature/armature_edit.c
+++ b/source/blender/editors/armature/armature_edit.c
@@ -38,6 +38,8 @@
#include "MEM_guardedalloc.h"
+#include "BLF_translation.h"
+
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -236,28 +238,49 @@ float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const bool
return roll;
}
-
+/* note, ranges arithmatic is used below */
typedef enum eCalcRollTypes {
- CALC_ROLL_X = 0,
- CALC_ROLL_Y = 1,
- CALC_ROLL_Z = 2,
-
- CALC_ROLL_TAN_X = 3,
- CALC_ROLL_TAN_Z = 4,
-
- CALC_ROLL_ACTIVE = 5,
- CALC_ROLL_VIEW = 6,
- CALC_ROLL_CURSOR = 7,
+ /* pos */
+ CALC_ROLL_POS_X = 0,
+ CALC_ROLL_POS_Y,
+ CALC_ROLL_POS_Z,
+
+ CALC_ROLL_TAN_POS_X,
+ CALC_ROLL_TAN_POS_Z,
+
+ /* neg */
+ CALC_ROLL_NEG_X,
+ CALC_ROLL_NEG_Y,
+ CALC_ROLL_NEG_Z,
+
+ CALC_ROLL_TAN_NEG_X,
+ CALC_ROLL_TAN_NEG_Z,
+
+ /* no sign */
+ CALC_ROLL_ACTIVE,
+ CALC_ROLL_VIEW,
+ CALC_ROLL_CURSOR,
} eCalcRollTypes;
static EnumPropertyItem prop_calc_roll_types[] = {
- {CALC_ROLL_TAN_X, "X", 0, "Local X Tangent", ""},
- {CALC_ROLL_TAN_Z, "Z", 0, "Local Z Tangent", ""},
+ {0, "", 0, N_("Positive"), ""},
+ {CALC_ROLL_TAN_POS_X, "POS_X", 0, "Local +X Tangent", ""},
+ {CALC_ROLL_TAN_POS_Z, "POS_Z", 0, "Local +Z Tangent", ""},
+
+ {CALC_ROLL_POS_X, "GLOBAL_POS_X", 0, "Global +X Axis", ""},
+ {CALC_ROLL_POS_Y, "GLOBAL_POS_Y", 0, "Global +Y Axis", ""},
+ {CALC_ROLL_POS_Z, "GLOBAL_POS_Z", 0, "Global +Z Axis", ""},
- {CALC_ROLL_X, "GLOBAL_X", 0, "Global X Axis", ""},
- {CALC_ROLL_Y, "GLOBAL_Y", 0, "Global Y Axis", ""},
- {CALC_ROLL_Z, "GLOBAL_Z", 0, "Global Z Axis", ""},
+ {0, "", 0, N_("Negative"), ""},
+ {CALC_ROLL_TAN_NEG_X, "NEG_X", 0, "Local -X Tangent", ""},
+ {CALC_ROLL_TAN_NEG_Z, "NEG_Z", 0, "Local -Z Tangent", ""},
+
+ {CALC_ROLL_NEG_X, "GLOBAL_NEG_X", 0, "Global -X Axis", ""},
+ {CALC_ROLL_NEG_Y, "GLOBAL_NEG_Y", 0, "Global -Y Axis", ""},
+ {CALC_ROLL_NEG_Z, "GLOBAL_NEG_Z", 0, "Global -Z Axis", ""},
+
+ {0, "", 0, N_("Other"), ""},
{CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
{CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
{CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
@@ -268,15 +291,22 @@ static EnumPropertyItem prop_calc_roll_types[] = {
static int armature_calc_roll_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_edit_object(C);
- const short type = RNA_enum_get(op->ptr, "type");
+ eCalcRollTypes type = RNA_enum_get(op->ptr, "type");
const bool axis_only = RNA_boolean_get(op->ptr, "axis_only");
- const bool axis_flip = RNA_boolean_get(op->ptr, "axis_flip");
+ /* axis_flip when matching the active bone never makes sense */
+ bool axis_flip = ((type >= CALC_ROLL_ACTIVE) ? RNA_boolean_get(op->ptr, "axis_flip") :
+ (type >= CALC_ROLL_TAN_NEG_X) ? true : false);
float imat[3][3];
bArmature *arm = ob->data;
EditBone *ebone;
+ if ((type >= CALC_ROLL_NEG_X) && (type <= CALC_ROLL_TAN_NEG_Z)) {
+ type -= (CALC_ROLL_ACTIVE - CALC_ROLL_NEG_X);
+ axis_flip = true;
+ }
+
copy_m3_m4(imat, ob->obmat);
invert_m3(imat);
@@ -302,7 +332,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
}
}
}
- else if (ELEM(type, CALC_ROLL_TAN_X, CALC_ROLL_TAN_Z)) {
+ else if (ELEM(type, CALC_ROLL_TAN_POS_X, CALC_ROLL_TAN_POS_Z)) {
for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
if (ebone->parent) {
bool is_edit = (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone));
@@ -323,7 +353,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
sub_v3_v3v3(dir_b, ebone_other->head, ebone_other->tail);
normalize_v3(dir_b);
- if (type == CALC_ROLL_TAN_Z) {
+ if (type == CALC_ROLL_TAN_POS_Z) {
cross_v3_v3v3(vec, dir_a, dir_b);
}
else {
@@ -374,7 +404,7 @@ static int armature_calc_roll_exec(bContext *C, wmOperator *op)
copy_v3_v3(vec, mat[2]);
}
else { /* Axis */
- assert(type >= 0 && type <= 5);
+ assert(type <= 5);
if (type < 3) vec[type] = 1.0f;
else vec[type - 2] = -1.0f;
mul_m3_v3(imat, vec);
@@ -423,7 +453,7 @@ void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_X, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, CALC_ROLL_TAN_POS_X, "Type", "");
RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align");
}
diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c
index 9afc45955bd..a8b5f888597 100644
--- a/source/blender/editors/armature/armature_naming.c
+++ b/source/blender/editors/armature/armature_naming.c
@@ -141,7 +141,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
char oldname[MAXBONENAME];
/* names better differ! */
- if (strncmp(oldnamep, newnamep, MAXBONENAME)) {
+ if (!STREQLEN(oldnamep, newnamep, MAXBONENAME)) {
/* we alter newname string... so make copy */
BLI_strncpy(newname, newnamep, MAXBONENAME);
@@ -219,7 +219,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
if (ob->parent && (ob->parent->data == arm)) {
if (ob->partype == PARBONE) {
/* bone name in object */
- if (!strcmp(ob->parsubstr, oldname))
+ if (STREQ(ob->parsubstr, oldname))
BLI_strncpy(ob->parsubstr, newname, MAXBONENAME);
}
}
@@ -267,6 +267,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
/* Fix all animdata that may refer to this bone - we can't just do the ones attached to objects, since
* other ID-blocks may have drivers referring to this bone [#29822]
*/
+ // XXX: the ID here is for armatures, but most bone drivers are actually on the object instead...
{
BKE_all_animdata_fix_paths_rename(&arm->id, "pose.bones", oldname, newname);
@@ -284,7 +285,7 @@ void ED_armature_bone_rename(bArmature *arm, const char *oldnamep, const char *n
if (sl->spacetype == SPACE_VIEW3D) {
View3D *v3d = (View3D *)sl;
if (v3d->ob_centre && v3d->ob_centre->data == arm) {
- if (!strcmp(v3d->ob_centre_bone, oldname)) {
+ if (STREQ(v3d->ob_centre_bone, oldname)) {
BLI_strncpy(v3d->ob_centre_bone, newname, MAXBONENAME);
}
}
diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c
index 3e226c39c8c..53989dd783c 100644
--- a/source/blender/editors/armature/armature_relations.c
+++ b/source/blender/editors/armature/armature_relations.c
@@ -29,20 +29,26 @@
* \ingroup edarmature
*/
+#include "MEM_guardedalloc.h"
+
+#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BLI_blenlib.h"
+#include "BLI_ghash.h"
#include "BLI_math.h"
#include "BLF_translation.h"
#include "BKE_action.h"
+#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
+#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_report.h"
@@ -98,33 +104,122 @@ static void joined_armature_fix_links_constraints(
/* action constraint? (pose constraints only) */
if (con->type == CONSTRAINT_TYPE_ACTION) {
- bActionConstraint *data = con->data; // XXX old animation system
- bAction *act;
- bActionChannel *achan;
+ bActionConstraint *data = con->data;
if (data->act) {
- act = data->act;
+ BKE_action_fix_paths_rename(&tarArm->id, data->act, "pose.bones[",
+ pchan->name, curbone->name, 0, 0, false);
+ }
+ }
+
+ }
+}
+
+/* userdata for joined_armature_fix_animdata_cb() */
+typedef struct tJoinArmature_AdtFixData {
+ Object *srcArm;
+ Object *tarArm;
+
+ GHash *names_map;
+} tJoinArmature_AdtFixData;
- for (achan = act->chanbase.first; achan; achan = achan->next) {
- if (STREQ(achan->name, pchan->name)) {
- BLI_strncpy(achan->name, curbone->name, sizeof(achan->name));
+/* Callback to pass to void BKE_animdata_main_cb() for fixing driver ID's to point to the new ID */
+/* FIXME: For now, we only care about drivers here. When editing rigs, it's very rare to have animation
+ * on the rigs being edited already, so it should be safe to skip these.
+ */
+static void joined_armature_fix_animdata_cb(ID *id, AnimData *adt, void *user_data)
+{
+ tJoinArmature_AdtFixData *afd = (tJoinArmature_AdtFixData *)user_data;
+ ID *src_id = &afd->srcArm->id;
+ ID *dst_id = &afd->tarArm->id;
+
+ GHashIterator gh_iter;
+ FCurve *fcu;
+
+ /* Fix paths - If this is the target object, it will have some "dirty" paths */
+ if (id == src_id) {
+ /* Fix drivers */
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ /* skip driver if it doesn't affect the bones */
+ if (strstr(fcu->rna_path, "pose.bones[") == NULL) {
+ continue;
+ }
+
+ // FIXME: this is too crude... it just does everything!
+ GHASH_ITER(gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed; this still means there will be some waste if there aren't many drivers/keys */
+ if (!STREQ(old_name, new_name) && strstr(fcu->rna_path, old_name)) {
+ fcu->rna_path = BKE_animsys_fix_rna_path_rename(id, fcu->rna_path, "pose.bones",
+ old_name, new_name, 0, 0, false);
+
+ /* we don't want to apply a second remapping on this driver now,
+ * so stop trying names, but keep fixing drivers
+ */
+ break;
+ }
+ }
+ }
+ }
+
+
+ /* Driver targets */
+ for (fcu = adt->drivers.first; fcu; fcu = fcu->next) {
+ ChannelDriver *driver = fcu->driver;
+ DriverVar *dvar;
+
+ /* Fix driver references to invalid ID's */
+ for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
+ /* only change the used targets, since the others will need fixing manually anyway */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ /* change the ID's used... */
+ if (dtar->id == src_id) {
+ dtar->id = dst_id;
+
+ /* also check on the subtarget...
+ * XXX: We duplicate the logic from drivers_path_rename_fix() here, with our own
+ * little twists so that we know that it isn't going to clobber the wrong data
+ */
+ if ((dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) || (dtar->pchan_name[0])) {
+ GHASH_ITER(gh_iter, afd->names_map) {
+ const char *old_name = BLI_ghashIterator_getKey(&gh_iter);
+ const char *new_name = BLI_ghashIterator_getValue(&gh_iter);
+
+ /* only remap if changed */
+ if (!STREQ(old_name, new_name)) {
+ if ((dtar->rna_path) && strstr(dtar->rna_path, old_name)) {
+ /* Fix up path */
+ dtar->rna_path = BKE_animsys_fix_rna_path_rename(id, dtar->rna_path, "pose.bones",
+ old_name, new_name, 0, 0, false);
+ break; /* no need to try any more names for bone path */
+ }
+ else if (STREQ(dtar->pchan_name, old_name)) {
+ /* Change target bone name */
+ BLI_strncpy(dtar->pchan_name, new_name, sizeof(dtar->pchan_name));
+ break; /* no need to try any more names for bone subtarget */
+ }
+ }
+ }
}
}
}
+ DRIVER_TARGETS_LOOPER_END
}
-
}
}
/* Helper function for armature joining - link fixing */
-static void joined_armature_fix_links(Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
+static void joined_armature_fix_links(Main *bmain, Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone)
{
Object *ob;
bPose *pose;
bPoseChannel *pchant;
/* let's go through all objects in database */
- for (ob = G.main->object.first; ob; ob = ob->id.next) {
+ for (ob = bmain->object.first; ob; ob = ob->id.next) {
/* do some object-type specific things */
if (ob->type == OB_ARMATURE) {
pose = ob->pose;
@@ -198,8 +293,17 @@ int join_armature_exec(bContext *C, wmOperator *op)
CTX_DATA_BEGIN(C, Base *, base, selected_editable_bases)
{
if ((base->object->type == OB_ARMATURE) && (base->object != ob)) {
+ tJoinArmature_AdtFixData afd = {NULL};
bArmature *curarm = base->object->data;
+ /* we assume that each armature datablock is only used in a single place */
+ BLI_assert(ob->data != base->object->data);
+
+ /* init callback data for fixing up AnimData links later */
+ afd.srcArm = base->object;
+ afd.tarArm = ob;
+ afd.names_map = BLI_ghash_str_new("join_armature_adt_fix");
+
/* Make a list of editbones in current armature */
ED_armature_to_edit(base->object->data);
@@ -219,6 +323,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
/* Get new name */
unique_editbone_name(arm->edbo, curbone->name, NULL);
+ BLI_ghash_insert(afd.names_map, BLI_strdup(pchan->name), curbone->name);
/* Transform the bone */
{
@@ -249,7 +354,7 @@ int join_armature_exec(bContext *C, wmOperator *op)
}
/* Fix Constraints and Other Links to this Bone and Armature */
- joined_armature_fix_links(ob, base->object, pchan, curbone);
+ joined_armature_fix_links(bmain, ob, base->object, pchan, curbone);
/* Rename pchan */
BLI_strncpy(pchan->name, curbone->name, sizeof(pchan->name));
@@ -264,6 +369,37 @@ int join_armature_exec(bContext *C, wmOperator *op)
BKE_pose_channels_hash_free(pose);
}
+ /* Fix all the drivers (and animation data) */
+ BKE_animdata_main_cb(bmain, joined_armature_fix_animdata_cb, &afd);
+ BLI_ghash_free(afd.names_map, MEM_freeN, NULL);
+
+ /* Only copy over animdata now, after all the remapping has been done,
+ * so that we don't have to worry about ambiguities re which armature
+ * a bone came from!
+ */
+ if (base->object->adt) {
+ if (ob->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ ob->adt = BKE_copy_animdata(base->object->adt, false);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(&ob->id, &base->object->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+
+ if (curarm->adt) {
+ if (arm->adt == NULL) {
+ /* no animdata, so just use a copy of the whole thing */
+ arm->adt = BKE_copy_animdata(curarm->adt, false);
+ }
+ else {
+ /* merge in data - we'll fix the drivers manually */
+ BKE_animdata_merge_copy(&arm->id, &curarm->id, ADT_MERGECOPY_KEEP_DST, false);
+ }
+ }
+
+ /* Free the old object data */
ED_base_object_free_and_unlink(bmain, scene, base);
}
}
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c
index c6ef76c570c..307e6c076f2 100644
--- a/source/blender/editors/armature/armature_select.c
+++ b/source/blender/editors/armature/armature_select.c
@@ -254,7 +254,7 @@ static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEv
static int armature_select_linked_poll(bContext *C)
{
- return (ED_operator_view3d_active(C) && ED_operator_editarmature(C) );
+ return (ED_operator_view3d_active(C) && ED_operator_editarmature(C));
}
void ARMATURE_OT_select_linked(wmOperatorType *ot)
diff --git a/source/blender/editors/armature/editarmature_retarget.c b/source/blender/editors/armature/editarmature_retarget.c
index aace8c5434c..5376fc8c79b 100644
--- a/source/blender/editors/armature/editarmature_retarget.c
+++ b/source/blender/editors/armature/editarmature_retarget.c
@@ -718,7 +718,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
cti->get_constraint_targets(con, &targets);
for (target_index = 0, ct = targets.first; ct; target_index++, ct = ct->next) {
- if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) {
+ if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
/* SET bone link to bone corresponding to pchan */
EditBone *link = BLI_ghash_lookup(rg->bones_map, pchan->name);
@@ -841,7 +841,7 @@ static void RIG_reconnectControlBones(RigGraph *rg)
cti->get_constraint_targets(con, &targets);
for (ct = targets.first; ct; ct = ct->next) {
- if ((ct->tar == rg->ob) && strcmp(ct->subtarget, ctrl->bone->name) == 0) {
+ if ((ct->tar == rg->ob) && STREQ(ct->subtarget, ctrl->bone->name)) {
/* SET bone link to ctrl corresponding to pchan */
RigControl *link = BLI_ghash_lookup(rg->controls_map, pchan->name);
@@ -1160,7 +1160,7 @@ static void RIG_arcFromBoneChain(RigGraph *rg, ListBase *list, EditBone *root_bo
last_bone = bone;
- if (strcmp(bone->name, "head") == 0) {
+ if (STREQ(bone->name, "head")) {
contain_head = 1;
}
}
diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c
index 3dbf7b4b65a..6c2d4256a0f 100644
--- a/source/blender/editors/armature/editarmature_sketch.c
+++ b/source/blender/editors/armature/editarmature_sketch.c
@@ -333,11 +333,11 @@ static void sk_autoname(bContext *C, ReebArc *arc)
if (side[0] == '\0') {
valid = 1;
}
- else if (strcmp(side, "R") == 0 || strcmp(side, "L") == 0) {
+ else if (STREQ(side, "R") || STREQ(side, "L")) {
valid = 1;
caps = 1;
}
- else if (strcmp(side, "r") == 0 || strcmp(side, "l") == 0) {
+ else if (STREQ(side, "r") || STREQ(side, "l")) {
valid = 1;
caps = 0;
}
diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c
index 2e6eace88aa..d571fb374d9 100644
--- a/source/blender/editors/armature/pose_lib.c
+++ b/source/blender/editors/armature/pose_lib.c
@@ -1050,7 +1050,7 @@ static void poselib_preview_get_next(tPoseLib_PreviewData *pld, int step)
LinkData *ld, *ldn, *ldc;
/* free and rebuild if needed (i.e. if search-str changed) */
- if (strcmp(pld->searchstr, pld->searchold)) {
+ if (!STREQ(pld->searchstr, pld->searchold)) {
/* free list of temporary search matches */
BLI_freelistN(&pld->searchp);
diff --git a/source/blender/editors/armature/pose_utils.c b/source/blender/editors/armature/pose_utils.c
index 1297755b7d0..2ba1eedd33b 100644
--- a/source/blender/editors/armature/pose_utils.c
+++ b/source/blender/editors/armature/pose_utils.c
@@ -259,7 +259,7 @@ LinkData *poseAnim_mapping_getNextFCurve(ListBase *fcuLinks, LinkData *prev, con
FCurve *fcu = (FCurve *)ld->data;
/* check if paths match */
- if (strcmp(path, fcu->rna_path) == 0)
+ if (STREQ(path, fcu->rna_path))
return ld;
}
diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c
index 99c64be5797..4aeeaa87269 100644
--- a/source/blender/editors/curve/editcurve.c
+++ b/source/blender/editors/curve/editcurve.c
@@ -643,25 +643,20 @@ static void keyData_switchDirectionNurb(Curve *cu, Nurb *nu)
static GHash *dupli_keyIndexHash(GHash *keyindex)
{
GHash *gh;
- GHashIterator *hashIter;
+ GHashIterator gh_iter;
gh = BLI_ghash_ptr_new_ex("dupli_keyIndex gh", BLI_ghash_size(keyindex));
- for (hashIter = BLI_ghashIterator_new(keyindex);
- BLI_ghashIterator_done(hashIter) == false;
- BLI_ghashIterator_step(hashIter))
- {
- void *cv = BLI_ghashIterator_getKey(hashIter);
- CVKeyIndex *index = BLI_ghashIterator_getValue(hashIter);
- CVKeyIndex *newIndex = MEM_callocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
+ GHASH_ITER (gh_iter, keyindex) {
+ void *cv = BLI_ghashIterator_getKey(&gh_iter);
+ CVKeyIndex *index = BLI_ghashIterator_getValue(&gh_iter);
+ CVKeyIndex *newIndex = MEM_mallocN(sizeof(CVKeyIndex), "dupli_keyIndexHash index");
memcpy(newIndex, index, sizeof(CVKeyIndex));
BLI_ghash_insert(gh, cv, newIndex);
}
- BLI_ghashIterator_free(hashIter);
-
return gh;
}
@@ -999,7 +994,7 @@ static void fcurve_path_rename(AnimData *adt, const char *orig_rna_path, char *r
for (fcu = orig_curves->first; fcu; fcu = nextfcu) {
nextfcu = fcu->next;
- if (!strncmp(fcu->rna_path, orig_rna_path, len)) {
+ if (STREQLEN(fcu->rna_path, orig_rna_path, len)) {
char *spath, *suffix = fcu->rna_path + len;
nfcu = copy_fcurve(fcu);
spath = nfcu->rna_path;
@@ -1102,10 +1097,10 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
for (fcu = orig_curves->first; fcu; fcu = next) {
next = fcu->next;
- if (!strncmp(fcu->rna_path, "splines", 7)) {
+ if (STREQLEN(fcu->rna_path, "splines", 7)) {
const char *ch = strchr(fcu->rna_path, '.');
- if (ch && (!strncmp(ch, ".bezier_points", 14) || !strncmp(ch, ".points", 7)))
+ if (ch && (STREQLEN(ch, ".bezier_points", 14) || STREQLEN(ch, ".points", 7)))
fcurve_remove(adt, orig_curves, fcu);
}
}
@@ -1129,7 +1124,7 @@ static void curve_rename_fcurves(Curve *cu, ListBase *orig_curves)
for (fcu = orig_curves->first; fcu; fcu = next) {
next = fcu->next;
- if (!strncmp(fcu->rna_path, "splines", 7)) fcurve_remove(adt, orig_curves, fcu);
+ if (STREQLEN(fcu->rna_path, "splines", 7)) fcurve_remove(adt, orig_curves, fcu);
else BLI_addtail(&curves, fcu);
}
@@ -2007,7 +2002,7 @@ static void ed_curve_delete_selected(Object *obedit)
}
/* only for OB_SURF */
-bool ed_editnurb_extrude_flag(EditNurb *editnurb, short flag)
+bool ed_editnurb_extrude_flag(EditNurb *editnurb, const short flag)
{
Nurb *nu;
BPoint *bp, *bpn, *newbp;
@@ -2368,7 +2363,6 @@ static void adduplicateflagNurb(Object *obedit, ListBase *newnurb,
}
else {
/* knots done after duplicate as pntsu may change */
- nu->knotsu = nu->knotsv = NULL;
BKE_nurb_order_clamp_u(nu);
BKE_nurb_knot_calc_u(nu);
@@ -4889,285 +4883,405 @@ void CURVE_OT_spin(wmOperatorType *ot)
RNA_def_float_vector(ot->srna, "axis", 3, NULL, -FLT_MAX, FLT_MAX, "Axis", "Axis in global view space", -1.0f, 1.0f);
}
-/***************** add vertex operator **********************/
+/***************** extrude vertex operator **********************/
-static int addvert_Nurb(bContext *C, short mode, float location[3])
+static bool ed_editcurve_extrude(Curve *cu, EditNurb *editnurb)
{
- Object *obedit = CTX_data_edit_object(C);
- Curve *cu = (Curve *)obedit->data;
- EditNurb *editnurb = cu->editnurb;
- Nurb *nu, *newnu = NULL;
- BezTriple *bezt, *newbezt = NULL;
- BPoint *bp, *newbp = NULL;
- float imat[4][4], temp[3];
- bool ok = false;
- BezTriple *bezt_recalc[3] = {NULL};
+ Nurb *nu = NULL;
+ Nurb *nu_last = NULL;
- invert_m4_m4(imat, obedit->obmat);
+ bool changed = false;
- findselectedNurbvert(&editnurb->nurbs, &nu, &bezt, &bp);
-
- if ((nu == NULL) || (nu->type == CU_BEZIER && bezt == NULL) || (nu->type != CU_BEZIER && bp == NULL)) {
- if (mode != 'e') {
- if (cu->actnu != CU_ACT_NONE)
- nu = BLI_findlink(&editnurb->nurbs, cu->actnu);
-
- if (!nu || nu->type == CU_BEZIER) {
- newbezt = (BezTriple *)MEM_callocN(sizeof(BezTriple), "addvert_Nurb");
- newbezt->radius = 1;
- newbezt->alfa = 0;
- BEZ_SEL(newbezt);
- newbezt->h2 = newbezt->h1 = HD_AUTO;
-
- newnu = (Nurb *)MEM_callocN(sizeof(Nurb), "addvert_Nurb newnu");
- if (!nu) {
- /* no selected segment -- create new one which is BEZIER type
- * type couldn't be determined from Curve bt could be changed
- * in the future, so shouldn't make much headache */
- newnu->type = CU_BEZIER;
- newnu->resolu = cu->resolu;
- newnu->flag |= CU_SMOOTH;
- }
- else {
- memcpy(newnu, nu, sizeof(Nurb));
- }
+ Nurb *cu_actnu;
+ union {
+ BezTriple *bezt;
+ BPoint *bp;
+ void *p;
+ } cu_actvert;
- BLI_addtail(&editnurb->nurbs, newnu);
- newnu->bezt = newbezt;
- newnu->pntsu = 1;
+ BKE_curve_nurb_vert_active_get(cu, &cu_actnu, &cu_actvert.p);
+ BKE_curve_nurb_vert_active_set(cu, NULL, NULL);
- temp[0] = 1;
- temp[1] = 0;
- temp[2] = 0;
+ /* first pass (endpoints) */
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
- copy_v3_v3(newbezt->vec[1], location);
- sub_v3_v3v3(newbezt->vec[0], newbezt->vec[1], temp);
- add_v3_v3v3(newbezt->vec[2], newbezt->vec[1], temp);
+ if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
+ continue;
+ }
- mul_m4_v3(imat, newbezt->vec[0]);
- mul_m4_v3(imat, newbezt->vec[1]);
- mul_m4_v3(imat, newbezt->vec[2]);
+ if (nu->type == CU_BEZIER) {
- ok = 1;
- nu = newnu;
- }
- else if (nu->pntsv == 1) {
- newbp = (BPoint *)MEM_callocN(sizeof(BPoint), "addvert_Nurb5");
- newbp->radius = 1;
- newbp->alfa = 0;
- newbp->f1 |= SELECT;
+ /* Check to see if the first bezier point is selected */
+ if (nu->pntsu > 0 && nu->bezt != NULL) {
+ BezTriple *nu_bezt_old = nu->bezt;
+ BezTriple *bezt = nu->bezt;
+
+ if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ BezTriple *bezt_new;
+ BEZ_DESEL(bezt);
- newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu");
- memcpy(newnu, nu, sizeof(Nurb));
- BLI_addtail(&editnurb->nurbs, newnu);
- newnu->bp = newbp;
- newnu->orderu = 2;
- newnu->pntsu = 1;
+ bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
+ ED_curve_beztcpy(editnurb, bezt_new + 1, bezt, nu->pntsu);
+ *bezt_new = *bezt;
- mul_v3_m4v3(newbp->vec, imat, location);
- newbp->vec[3] = 1.0;
- newnu->knotsu = newnu->knotsv = NULL;
- BKE_nurb_knot_calc_u(newnu);
+ MEM_freeN(nu->bezt);
+ nu->bezt = bezt_new;
- ok = 1;
- nu = newnu;
+ nu->pntsu += 1;
+
+ if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
+ cu_actvert.bezt = (cu_actvert.bezt == bezt) ?
+ bezt_new : &nu->bezt[(cu_actvert.bezt - nu_bezt_old) + 1];
+ BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
+ }
+
+ BEZ_SEL(bezt_new);
+ changed = true;
+ }
}
+ /* Check to see if the last bezier point is selected */
+ if (nu->pntsu > 1) {
+ BezTriple *nu_bezt_old = nu->bezt;
+ BezTriple *bezt = &nu->bezt[nu->pntsu - 1];
+
+ if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ BezTriple *bezt_new;
+ BEZ_DESEL(bezt);
+
+ bezt_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BezTriple), __func__);
+ ED_curve_beztcpy(editnurb, bezt_new, nu->bezt, nu->pntsu);
+ bezt_new[nu->pntsu] = *bezt;
+
+ MEM_freeN(nu->bezt);
+ nu->bezt = bezt_new;
+
+ bezt_new += nu->pntsu;
+ nu->pntsu += 1;
+
+ if (ARRAY_HAS_ITEM(cu_actvert.bezt, nu_bezt_old, nu->pntsu - 1)) {
+ cu_actvert.bezt = (cu_actvert.bezt == bezt) ?
+ bezt_new : &nu->bezt[cu_actvert.bezt - nu_bezt_old];
+ BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bezt);
+ }
+
+ BEZ_SEL(bezt_new);
+ changed = true;
+ }
+ }
}
+ else {
- if (!ok)
- return OPERATOR_CANCELLED;
- }
+ /* Check to see if the first bpoint is selected */
+ if (nu->pntsu > 0 && nu->bp != NULL) {
+ BPoint *nu_bp_old = nu->bp;
+ BPoint *bp = nu->bp;
- if (!ok && nu->type == CU_BEZIER) {
- /* which bezpoint? */
- if (bezt == &nu->bezt[nu->pntsu - 1]) { /* last */
- BEZ_DESEL(bezt);
- newbezt = (BezTriple *)MEM_callocN((nu->pntsu + 1) * sizeof(BezTriple), "addvert_Nurb");
- ED_curve_beztcpy(editnurb, newbezt, nu->bezt, nu->pntsu);
- newbezt[nu->pntsu] = *bezt;
- copy_v3_v3(temp, bezt->vec[1]);
- MEM_freeN(nu->bezt);
- nu->bezt = newbezt;
- newbezt += nu->pntsu;
- BEZ_SEL(newbezt);
- newbezt->h1 = newbezt->h2;
- bezt = &nu->bezt[nu->pntsu - 1];
- ok = 1;
+ if (bp->f1 & SELECT) {
+ BPoint *bp_new;
+ bp->f1 &= ~SELECT;
- if (nu->pntsu > 1) {
- bezt_recalc[1] = newbezt;
- bezt_recalc[0] = newbezt - 1;
- }
- }
- else if (bezt == nu->bezt) { /* first */
- BEZ_DESEL(bezt);
- newbezt = (BezTriple *)MEM_callocN((nu->pntsu + 1) * sizeof(BezTriple), "addvert_Nurb");
- ED_curve_beztcpy(editnurb, newbezt + 1, bezt, nu->pntsu);
- *newbezt = *bezt;
- BEZ_SEL(newbezt);
- newbezt->h2 = newbezt->h1;
- copy_v3_v3(temp, bezt->vec[1]);
- MEM_freeN(nu->bezt);
- nu->bezt = newbezt;
- bezt = newbezt + 1;
- ok = 1;
+ bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
+ ED_curve_bpcpy(editnurb, bp_new + 1, bp, nu->pntsu);
+ *bp_new = *bp;
+
+ MEM_freeN(nu->bp);
+ nu->bp = bp_new;
+ nu->pntsu += 1;
+ BKE_nurb_knot_calc_u(nu);
+
+ if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
+ cu_actvert.bp = (cu_actvert.bp == bp) ?
+ bp_new : &nu->bp[(cu_actvert.bp - nu_bp_old) + 1];
+ BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
+ }
+
+ bp_new->f1 |= SELECT;
+ changed = true;
+ }
+ }
+
+ /* Check to see if the last bpoint is selected */
if (nu->pntsu > 1) {
- bezt_recalc[1] = newbezt;
- bezt_recalc[2] = newbezt + 1;
+ BPoint *nu_bp_old = nu->bp;
+ BPoint *bp = &nu->bp[nu->pntsu - 1];
+
+ if (bp->f1 & SELECT) {
+ BPoint *bp_new;
+ bp->f1 &= ~SELECT;
+
+ bp_new = MEM_mallocN((nu->pntsu + 1) * sizeof(BPoint), __func__);
+ ED_curve_bpcpy(editnurb, bp_new, nu->bp, nu->pntsu);
+ bp_new[nu->pntsu] = *bp;
+
+ MEM_freeN(nu->bp);
+ nu->bp = bp_new;
+
+ bp_new += nu->pntsu;
+ nu->pntsu += 1;
+
+ if (ARRAY_HAS_ITEM(cu_actvert.bp, nu_bp_old, nu->pntsu - 1)) {
+ cu_actvert.bp = (cu_actvert.bp == bp) ?
+ bp_new : &nu->bp[cu_actvert.bp - nu_bp_old];
+ BKE_curve_nurb_vert_active_set(cu, nu, cu_actvert.bp);
+ }
+
+ BKE_nurb_knot_calc_u(nu);
+
+ bp_new->f1 |= SELECT;
+ changed = true;
+ }
}
}
- else if (mode != 'e') {
- BEZ_DESEL(bezt);
- newbezt = (BezTriple *)MEM_callocN(sizeof(BezTriple), "addvert_Nurb");
- *newbezt = *bezt;
- BEZ_SEL(newbezt);
- newbezt->h2 = newbezt->h1;
- copy_v3_v3(temp, bezt->vec[1]);
+ }
- newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu");
- memcpy(newnu, nu, sizeof(Nurb));
- BLI_addtail(&editnurb->nurbs, newnu);
- newnu->bezt = newbezt;
- newnu->pntsu = 1;
+ /* second pass (interior points) */
+ nu_last = editnurb->nurbs.last;
+ for (nu = editnurb->nurbs.first; (nu != nu_last->next); nu = nu->next) {
+ int i, i_end;
- nu = newnu;
- bezt = newbezt;
- ok = 1;
+ if ((nu->flagu & CU_NURB_CYCLIC) && (nu->pntsu > 1)) {
+ /* all points are interior */
+ i = 0;
+ i_end = nu->pntsu;
}
else {
- bezt = NULL;
+ /* skip endpoints */
+ i = 1;
+ i_end = nu->pntsu - 1;
}
- if (bezt) {
- if (!newnu) nu->pntsu++;
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
- if (mode == 'e') {
- copy_v3_v3(newbezt->vec[0], bezt->vec[0]);
- copy_v3_v3(newbezt->vec[1], bezt->vec[1]);
- copy_v3_v3(newbezt->vec[2], bezt->vec[2]);
- }
- else {
- mul_v3_m4v3(newbezt->vec[1], imat, location);
- sub_v3_v3v3(temp, newbezt->vec[1], temp);
+ for (bezt = &nu->bezt[i]; i < i_end; i++, bezt++) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ Nurb *nurb_new;
+ BezTriple *bezt_new;
+
+ BEZ_DESEL(bezt);
+ nurb_new = BKE_nurb_copy(nu, 1, 1);
+ nurb_new->flagu &= ~CU_NURB_CYCLIC;
+ BLI_addtail(&editnurb->nurbs, nurb_new);
+ bezt_new = nurb_new->bezt;
+ ED_curve_beztcpy(editnurb, bezt_new, bezt, 1);
+ BEZ_SEL(bezt_new);
+
+ if (cu_actvert.bezt == bezt || cu_actnu == NULL) {
+ BKE_curve_nurb_vert_active_set(cu, nurb_new, bezt_new);
+ }
- if (bezt_recalc[1]) {
- const char h1 = bezt_recalc[1]->h1, h2 = bezt_recalc[1]->h2;
- bezt_recalc[1]->h1 = bezt_recalc[1]->h2 = HD_AUTO;
- BKE_nurb_handle_calc(bezt_recalc[1], bezt_recalc[0], bezt_recalc[2], 0);
- bezt_recalc[1]->h1 = h1;
- bezt_recalc[1]->h2 = h2;
- }
- else {
- add_v3_v3v3(newbezt->vec[0], bezt->vec[0], temp);
- add_v3_v3v3(newbezt->vec[2], bezt->vec[2], temp);
+ changed = true;
}
-
+ }
+ }
+ else {
+ BPoint *bp;
+
+ for (bp = &nu->bp[i]; i < i_end; i++, bp++) {
+ if (bp->f1 & SELECT) {
+ Nurb *nurb_new;
+ BPoint *bp_new;
+
+ bp->f1 &= ~SELECT;
+ nurb_new = BKE_nurb_copy(nu, 1, 1);
+ nurb_new->flagu &= ~CU_NURB_CYCLIC;
+ BLI_addtail(&editnurb->nurbs, nurb_new);
+ bp_new = nurb_new->bp;
+ ED_curve_bpcpy(editnurb, bp_new, bp, 1);
+ bp_new->f1 |= SELECT;
+
+ if (cu_actvert.bp == bp || cu_actnu == NULL) {
+ BKE_curve_nurb_vert_active_set(cu, nurb_new, bp_new);
+ }
- if (newnu) BKE_nurb_handles_calc(newnu);
- else BKE_nurb_handles_calc(nu);
+ changed = true;
+ }
}
}
}
- else if (!ok && nu->pntsv == 1) {
- /* which b-point? */
- if (bp == &nu->bp[nu->pntsu - 1]) { /* last */
- bp->f1 = 0;
- newbp = (BPoint *)MEM_callocN((nu->pntsu + 1) * sizeof(BPoint), "addvert_Nurb4");
- ED_curve_bpcpy(editnurb, newbp, nu->bp, nu->pntsu);
- newbp[nu->pntsu] = *bp;
- MEM_freeN(nu->bp);
- nu->bp = newbp;
- newbp += nu->pntsu;
- newbp->f1 |= SELECT;
- bp = newbp - 1;
- ok = 1;
- }
- else if (bp == nu->bp) { /* first */
- bp->f1 = 0;
- newbp = (BPoint *)MEM_callocN((nu->pntsu + 1) * sizeof(BPoint), "addvert_Nurb3");
- ED_curve_bpcpy(editnurb, newbp + 1, bp, nu->pntsu);
- *newbp = *bp;
- newbp->f1 |= SELECT;
- MEM_freeN(nu->bp);
- nu->bp = newbp;
- bp = newbp + 1;
- ok = 1;
- }
- else if (mode != 'e') {
- bp->f1 = 0;
- newbp = (BPoint *)MEM_callocN(sizeof(BPoint), "addvert_Nurb5");
- *newbp = *bp;
- newbp->f1 |= SELECT;
- newnu = (Nurb *)MEM_mallocN(sizeof(Nurb), "addvert_Nurb newnu");
- memcpy(newnu, nu, sizeof(Nurb));
- BLI_addtail(&editnurb->nurbs, newnu);
- newnu->bp = newbp;
- newnu->orderu = 2;
- newnu->pntsu = 1;
- newnu->knotsu = newnu->knotsv = NULL;
+ if (changed == false) {
+ BKE_curve_nurb_vert_active_set(cu, cu_actnu, cu_actvert.p);
+ }
- nu = newnu;
- bp = newbp;
- ok = 1;
+ return changed;
+}
+
+/***************** add vertex operator **********************/
+
+static int ed_editcurve_addvert(Curve *cu, EditNurb *editnurb, const float location[3])
+{
+ Nurb *nu;
+
+ float minmax[2][3];
+ float temp[3];
+ bool nu_has_select = false;
+
+ bool changed = false;
+
+ INIT_MINMAX(minmax[0], minmax[1]);
+
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ int i;
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
+
+ for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ minmax_v3v3_v3(UNPACK2(minmax), bezt->vec[1]);
+ nu_has_select = true;
+ }
+ }
}
else {
- bp = NULL;
+ BPoint *bp;
+
+ for (i = 0, bp = nu->bp; i < nu->pntsu; i++, bp++) {
+ if (bp->f1 & SELECT) {
+ minmax_v3v3_v3(UNPACK2(minmax), bp->vec);
+ nu_has_select = true;
+ }
+ }
}
+ }
+
+ if (nu_has_select && ed_editcurve_extrude(cu, editnurb)) {
+ float ofs[3], center[3];
+ int i;
+
+ mid_v3_v3v3(center, minmax[0], minmax[1]);
+ sub_v3_v3v3(ofs, location, center);
- if (bp) {
- if (mode == 'e') {
- copy_v3_v3(newbp->vec, bp->vec);
+ if ((cu->flag & CU_3D) == 0) {
+ ofs[2] = 0.0f;
+ }
+
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ if (nu->type == CU_BEZIER) {
+ BezTriple *bezt;
+ for (i = 0, bezt = nu->bezt; i < nu->pntsu; i++, bezt++) {
+ if (BEZSELECTED_HIDDENHANDLES(cu, bezt)) {
+ add_v3_v3(bezt->vec[0], ofs);
+ add_v3_v3(bezt->vec[1], ofs);
+ add_v3_v3(bezt->vec[2], ofs);
+
+ if (((nu->flagu & CU_NURB_CYCLIC) == 0) &&
+ (i == 0 || i == nu->pntsu - 1))
+ {
+ BKE_nurb_handle_calc_simple_auto(nu, bezt);
+ }
+ }
+ }
}
else {
- mul_v3_m4v3(newbp->vec, imat, location);
- newbp->vec[3] = 1.0;
+ BPoint *bp;
- if (!newnu && nu->orderu < 4 && nu->orderu <= nu->pntsu)
- nu->orderu++;
+ for (i = 0, bp = nu->bp; i < nu->pntsu; i++, bp++) {
+ if (bp->f1 & SELECT) {
+ add_v3_v3(bp->vec, ofs);
+ }
+ }
}
+ }
+ changed = true;
+ }
+ else {
+ /* nothing selected: create a new curve */
+ nu = BKE_curve_nurb_active_get(cu);
- if (!newnu) {
- nu->pntsu++;
- BKE_nurb_knot_calc_u(nu);
+ if (!nu || nu->type == CU_BEZIER) {
+ Nurb *nurb_new;
+ BezTriple *bezt_new;
+
+ if (nu) {
+ nurb_new = BKE_nurb_copy(nu, 1, 1);
}
else {
- BKE_nurb_knot_calc_u(newnu);
+ nurb_new = MEM_callocN(sizeof(Nurb), "BLI_editcurve_addvert new_bezt_nurb 2");
+ nurb_new->type = CU_BEZIER;
+ nurb_new->resolu = cu->resolu;
+ nurb_new->orderu = 4;
+ nurb_new->flag |= CU_SMOOTH;
+ BKE_nurb_bezierPoints_add(nurb_new, 1);
}
- }
- }
+ BLI_addtail(&editnurb->nurbs, nurb_new);
- if (ok) {
- if (nu->bezt) {
- BKE_curve_nurb_vert_active_set(cu, nu, newbezt);
+ bezt_new = nurb_new->bezt;
+
+ BEZ_SEL(bezt_new);
+
+ bezt_new->h1 = HD_AUTO;
+ bezt_new->h2 = HD_AUTO;
+
+ temp[0] = 1.0f;
+ temp[1] = 0.0f;
+ temp[2] = 0.0f;
+
+ copy_v3_v3(bezt_new->vec[1], location);
+ sub_v3_v3v3(bezt_new->vec[0], bezt_new->vec[1], temp);
+ add_v3_v3v3(bezt_new->vec[2], bezt_new->vec[1], temp);
+
+ changed = true;
}
else {
- BKE_curve_nurb_vert_active_set(cu, nu, newbp);
- }
+ Nurb *nurb_new;
+ BPoint *bp_new;
- BKE_nurb_test2D(nu);
+ {
+ nurb_new = MEM_callocN(sizeof(Nurb), __func__);
+ nurb_new->type = CU_POLY;
+ nurb_new->resolu = cu->resolu;
+ nurb_new->flag |= CU_SMOOTH;
+ nurb_new->orderu = 4;
+ BKE_nurb_points_add(nurb_new, 1);
+ }
+ BLI_addtail(&editnurb->nurbs, nurb_new);
- if (ED_curve_updateAnimPaths(obedit->data))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ bp_new = nurb_new->bp;
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ bp_new->f1 |= SELECT;
- return OPERATOR_FINISHED;
+ copy_v3_v3(bp_new->vec, location);
+ bp_new->vec[3] = 1.0f;
+
+ BKE_nurb_knot_calc_u(nurb_new);
+
+ changed = true;
+ }
}
- return OPERATOR_CANCELLED;
+ return changed;
}
static int add_vertex_exec(bContext *C, wmOperator *op)
{
+ Object *obedit = CTX_data_edit_object(C);
+ Curve *cu = obedit->data;
+ EditNurb *editnurb = cu->editnurb;
float location[3];
+ float imat[4][4];
RNA_float_get_array(op->ptr, "location", location);
- return addvert_Nurb(C, 0, location);
+
+ invert_m4_m4(imat, obedit->obmat);
+ mul_m4_v3(imat, location);
+
+ if (ed_editcurve_addvert(cu, editnurb, location)) {
+ if (ED_curve_updateAnimPaths(obedit->data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ }
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DAG_id_tag_update(obedit->data, 0);
+
+ return OPERATOR_FINISHED;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
}
static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -5236,29 +5350,39 @@ void CURVE_OT_vertex_add(wmOperatorType *ot)
/***************** extrude operator **********************/
-static int extrude_exec(bContext *C, wmOperator *UNUSED(op))
+static int curve_extrude_exec(bContext *C, wmOperator *UNUSED(op))
{
Object *obedit = CTX_data_edit_object(C);
Curve *cu = obedit->data;
EditNurb *editnurb = cu->editnurb;
- Nurb *nu;
+ bool changed = false;
+ bool as_curve = false;
/* first test: curve? */
- for (nu = editnurb->nurbs.first; nu; nu = nu->next)
- if (nu->pntsv == 1 && isNurbsel_count(cu, nu) == 1)
- break;
+ if (obedit->type != OB_CURVE) {
+ Nurb *nu;
+ for (nu = editnurb->nurbs.first; nu; nu = nu->next) {
+ if (nu->pntsv == 1 && isNurbsel_count(cu, nu) == 1) {
+ as_curve = true;
+ break;
+ }
+ }
+ }
- if (obedit->type == OB_CURVE || nu) {
- addvert_Nurb(C, 'e', NULL);
+ if (obedit->type == OB_CURVE || as_curve) {
+ changed = ed_editcurve_extrude(cu, editnurb);
}
else {
- if (ed_editnurb_extrude_flag(editnurb, SELECT)) {
- if (ED_curve_updateAnimPaths(obedit->data))
- WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
+ changed = ed_editnurb_extrude_flag(editnurb, SELECT);
+ }
- WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
- DAG_id_tag_update(obedit->data, 0);
+ if (changed) {
+ if (ED_curve_updateAnimPaths(obedit->data)) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, obedit);
}
+
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ DAG_id_tag_update(obedit->data, 0);
}
return OPERATOR_FINISHED;
@@ -5272,7 +5396,7 @@ void CURVE_OT_extrude(wmOperatorType *ot)
ot->idname = "CURVE_OT_extrude";
/* api callbacks */
- ot->exec = extrude_exec;
+ ot->exec = curve_extrude_exec;
ot->poll = ED_operator_editsurfcurve;
/* flags */
@@ -6543,7 +6667,6 @@ static int curve_delete_segments(Object *obedit, const bool split)
}
}
- nu->knotsu = nu->knotsv = NULL;
BKE_nurb_order_clamp_u(nu);
BKE_nurb_knot_calc_u(nu);
@@ -6640,7 +6763,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
Object *obedit = CTX_data_edit_object(C);
ListBase *editnurb = object_editcurve_get(obedit);
Nurb *nu;
- int clear = (strcmp(op->idname, "CURVE_OT_shade_flat") == 0);
+ int clear = (STREQ(op->idname, "CURVE_OT_shade_flat"));
if (obedit->type != OB_CURVE)
return OPERATOR_CANCELLED;
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index c9a961d1a4d..7c53896b969 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -529,11 +529,9 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
if (newob && enter_editmode)
ED_undo_push(C, "Enter Editmode");
- ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
dia = RNA_float_get(op->ptr, "radius");
- mat[0][0] *= dia;
- mat[1][1] *= dia;
- mat[2][2] *= dia;
+ mul_mat3_m4_fl(mat, dia);
nu = add_nurbs_primitive(C, obedit, mat, type, newob);
editnurb = object_editcurve_get(obedit);
diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c
index 97adaea41a8..a2ba6216f9c 100644
--- a/source/blender/editors/gpencil/editaction_gpencil.c
+++ b/source/blender/editors/gpencil/editaction_gpencil.c
@@ -390,7 +390,7 @@ void paste_gpdata(Scene *scene)
/* find suitable layer from buffer to use to paste from */
for (gpls = gpcopybuf.first; gpls; gpls = gpls->next) {
/* check if layer name matches */
- if ((no_name) || (strcmp(gpls->info, gpld->info) == 0))
+ if ((no_name) || STREQ(gpls->info, gpld->info))
break;
}
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 3dae25263e8..a830253f634 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -100,7 +100,8 @@ bGPdata **ED_gpencil_data_get_pointers_direct(ID *screen_id, Scene *scene, ScrAr
switch (sa->spacetype) {
case SPACE_VIEW3D: /* 3D-View */
- case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */
+ case SPACE_TIME: /* Timeline - XXX: this is a hack to get it to show GP keyframes for 3D view */
+ case SPACE_ACTION: /* DepeSheet - XXX: this is a hack to get the keyframe jump operator to take GP Keyframes into account */
{
BLI_assert(scene && ELEM(scene->toolsettings->gpencil_src,
GP_TOOL_SOURCE_SCENE, GP_TOOL_SOURCE_OBJECT));
@@ -620,6 +621,10 @@ static int gp_duplicate_exec(bContext *C, wmOperator *op)
/* make copies of selected strokes, and deselect these once we're done */
for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
if (gps->flag & GP_STROKE_SELECT) {
if (gps->totpoints == 1) {
/* Special Case: If there's just a single point in this stroke... */
@@ -728,6 +733,10 @@ static int gp_strokes_copy_exec(bContext *C, wmOperator *op)
/* make copies of selected strokes, and deselect these once we're done */
for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
if (gps->flag & GP_STROKE_SELECT) {
if (gps->totpoints == 1) {
/* Special Case: If there's just a single point in this stroke... */
@@ -936,6 +945,11 @@ static int gp_delete_selected_strokes(bContext *C)
for (gps = gpf->strokes.first; gps; gps = gpsn) {
gpsn = gps->next;
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+ /* free stroke if selected */
if (gps->flag & GP_STROKE_SELECT) {
/* free stroke memory arrays, then stroke itself */
if (gps->points) MEM_freeN(gps->points);
@@ -975,6 +989,10 @@ static int gp_dissolve_selected_points(bContext *C)
for (gps = gpf->strokes.first; gps; gps = gpsn) {
gpsn = gps->next;
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
if (gps->flag & GP_STROKE_SELECT) {
bGPDspoint *pt;
int i;
@@ -1050,6 +1068,11 @@ static int gp_delete_selected_points(bContext *C)
for (gps = gpf->strokes.first; gps; gps = gpsn) {
gpsn = gps->next;
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false)
+ continue;
+
+
if (gps->flag & GP_STROKE_SELECT) {
bGPDspoint *pt;
int i;
@@ -2480,50 +2503,50 @@ static bool gp_convert_draw_check_prop(PointerRNA *ptr, PropertyRNA *prop)
const bool valid_timing = RNA_boolean_get(ptr, "use_timing_data");
/* Always show those props */
- if (strcmp(prop_id, "type") == 0 ||
- strcmp(prop_id, "use_normalize_weights") == 0 ||
- strcmp(prop_id, "radius_multiplier") == 0 ||
- strcmp(prop_id, "use_link_strokes") == 0)
+ if (STREQ(prop_id, "type") ||
+ STREQ(prop_id, "use_normalize_weights") ||
+ STREQ(prop_id, "radius_multiplier") ||
+ STREQ(prop_id, "use_link_strokes"))
{
return true;
}
/* Never show this prop */
- if (strcmp(prop_id, "use_timing_data") == 0)
+ if (STREQ(prop_id, "use_timing_data"))
return false;
if (link_strokes) {
/* Only show when link_stroke is true */
- if (strcmp(prop_id, "timing_mode") == 0)
+ if (STREQ(prop_id, "timing_mode"))
return true;
if (timing_mode != GP_STROKECONVERT_TIMING_NONE) {
/* Only show when link_stroke is true and stroke timing is enabled */
- if (strcmp(prop_id, "frame_range") == 0 ||
- strcmp(prop_id, "start_frame") == 0)
+ if (STREQ(prop_id, "frame_range") ||
+ STREQ(prop_id, "start_frame"))
{
return true;
}
/* Only show if we have valid timing data! */
- if (valid_timing && strcmp(prop_id, "use_realtime") == 0)
+ if (valid_timing && STREQ(prop_id, "use_realtime"))
return true;
/* Only show if realtime or valid_timing is false! */
- if ((!realtime || !valid_timing) && strcmp(prop_id, "end_frame") == 0)
+ if ((!realtime || !valid_timing) && STREQ(prop_id, "end_frame"))
return true;
if (valid_timing && timing_mode == GP_STROKECONVERT_TIMING_CUSTOMGAP) {
/* Only show for custom gaps! */
- if (strcmp(prop_id, "gap_duration") == 0)
+ if (STREQ(prop_id, "gap_duration"))
return true;
/* Only show randomness for non-null custom gaps! */
- if (strcmp(prop_id, "gap_randomness") == 0 && (gap_duration > 0.0f))
+ if (STREQ(prop_id, "gap_randomness") && (gap_duration > 0.0f))
return true;
/* Only show seed for randomize action! */
- if (strcmp(prop_id, "seed") == 0 && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
+ if (STREQ(prop_id, "seed") && (gap_duration > 0.0f) && (gap_randomness > 0.0f))
return true;
}
}
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index e6f6644fd24..c03766a95e1 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -999,7 +999,7 @@ static void gp_session_validatebuffer(tGPsdata *p)
}
/* (re)init new painting data */
-static int gp_session_initdata(bContext *C, tGPsdata *p)
+static bool gp_session_initdata(bContext *C, tGPsdata *p)
{
bGPdata **gpd_ptr = NULL;
ScrArea *curarea = CTX_wm_area(C);
@@ -1082,7 +1082,13 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
case SPACE_CLIP:
{
SpaceClip *sc = curarea->spacedata.first;
+ MovieClip *clip = ED_space_clip_get_clip(sc);
+ if (clip == NULL) {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
+
/* set the current area */
p->sa = curarea;
p->ar = ar;
@@ -1097,13 +1103,18 @@ static int gp_session_initdata(bContext *C, tGPsdata *p)
p->custom_color[3] = 0.9f;
if (sc->gpencil_src == SC_GPENCIL_SRC_TRACK) {
- MovieClip *clip = ED_space_clip_get_clip(sc);
int framenr = ED_space_clip_get_clip_frame_number(sc);
MovieTrackingTrack *track = BKE_tracking_track_get_active(&clip->tracking);
- MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
-
- p->imat[3][0] -= marker->pos[0];
- p->imat[3][1] -= marker->pos[1];
+ MovieTrackingMarker *marker = track ? BKE_tracking_marker_get(track, framenr) : NULL;
+
+ if (marker) {
+ p->imat[3][0] -= marker->pos[0];
+ p->imat[3][1] -= marker->pos[1];
+ }
+ else {
+ p->status = GP_STATUS_ERROR;
+ return false;
+ }
}
invert_m4_m4(p->mat, p->imat);
diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c
index 7967d6a4d95..9ba77a4244e 100644
--- a/source/blender/editors/gpencil/gpencil_select.c
+++ b/source/blender/editors/gpencil/gpencil_select.c
@@ -136,11 +136,14 @@ static int gpencil_select_all_exec(bContext *C, wmOperator *op)
bGPDspoint *pt;
int i;
- for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
- pt->flag &= ~GP_SPOINT_SELECT;
+ /* only edit strokes that are valid in this view... */
+ if (ED_gpencil_stroke_can_use(C, gps)) {
+ for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
+ pt->flag &= ~GP_SPOINT_SELECT;
+ }
+
+ gps->flag &= ~GP_STROKE_SELECT;
}
-
- gps->flag &= ~GP_STROKE_SELECT;
}
}
}
diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c
index 5f0647fb43d..34e640a4b7b 100644
--- a/source/blender/editors/gpencil/gpencil_undo.c
+++ b/source/blender/editors/gpencil/gpencil_undo.c
@@ -76,7 +76,7 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
if (step == 1) { /* undo */
//printf("\t\tGP - undo step\n");
if (cur_node->prev) {
- if (!name || strcmp(cur_node->name, name) == 0) {
+ if (!name || STREQ(cur_node->name, name)) {
cur_node = cur_node->prev;
new_gpd = cur_node->gpd;
}
@@ -85,7 +85,7 @@ int ED_undo_gpencil_step(bContext *C, int step, const char *name)
else if (step == -1) {
//printf("\t\tGP - redo step\n");
if (cur_node->next) {
- if (!name || strcmp(cur_node->name, name) == 0) {
+ if (!name || STREQ(cur_node->name, name)) {
cur_node = cur_node->next;
new_gpd = cur_node->gpd;
}
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 4a913c3d2e5..289cbc568d2 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -90,6 +90,42 @@ bool gp_stroke_inside_circle(const int mval[2], const int UNUSED(mvalo[2]),
/* ******************************************************** */
+/* Check whether given stroke can be edited given the supplied context */
+// XXX: do we need additional flags for screenspace vs dataspace?
+bool ED_gpencil_stroke_can_use_direct(const ScrArea *sa, const bGPDstroke *gps)
+{
+ /* sanity check */
+ if (ELEM(NULL, sa, gps))
+ return false;
+
+ /* filter stroke types by flags + spacetype */
+ if (gps->flag & GP_STROKE_3DSPACE) {
+ /* 3D strokes - only in 3D view */
+ return (sa->spacetype == SPACE_VIEW3D);
+ }
+ else if (gps->flag & GP_STROKE_2DIMAGE) {
+ /* Special "image" strokes - only in Image Editor */
+ return (sa->spacetype == SPACE_IMAGE);
+ }
+ else if (gps->flag & GP_STROKE_2DSPACE) {
+ /* 2D strokes (dataspace) - for any 2D view (i.e. everything other than 3D view) */
+ return (sa->spacetype != SPACE_VIEW3D);
+ }
+ else {
+ /* view aligned - anything goes */
+ return true;
+ }
+}
+
+/* Check whether given stroke can be edited in the current context */
+bool ED_gpencil_stroke_can_use(const bContext *C, const bGPDstroke *gps)
+{
+ ScrArea *sa = CTX_wm_area(C);
+ return ED_gpencil_stroke_can_use_direct(sa, gps);
+}
+
+/* ******************************************************** */
+
/* Init handling for space-conversion function (from passed-in parameters) */
void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
{
@@ -127,7 +163,9 @@ void gp_point_conversion_init(bContext *C, GP_SpaceConversion *r_gsc)
}
-/* Convert Grease Pencil points to screen-space values */
+/* Convert Grease Pencil points to screen-space values
+ * WARNING: This assumes that the caller has already checked whether the stroke in question can be drawn
+ */
void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
int *r_x, int *r_y)
{
@@ -135,7 +173,12 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
View2D *v2d = gsc->v2d;
rctf *subrect = gsc->subrect;
int xyval[2];
-
+
+ /* sanity checks */
+ BLI_assert(!(gps->flag & GP_STROKE_3DSPACE) || (gsc->sa->spacetype == SPACE_VIEW3D));
+ BLI_assert(!(gps->flag & GP_STROKE_2DSPACE) || (gsc->sa->spacetype != SPACE_VIEW3D));
+
+
if (gps->flag & GP_STROKE_3DSPACE) {
if (ED_view3d_project_int_global(ar, &pt->x, xyval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) {
*r_x = xyval[0];
@@ -152,11 +195,13 @@ void gp_point_to_xy(GP_SpaceConversion *gsc, bGPDstroke *gps, bGPDspoint *pt,
UI_view2d_view_to_region_clip(v2d, vec[0], vec[1], r_x, r_y);
}
else {
- if (subrect == NULL) { /* normal 3D view */
+ if (subrect == NULL) {
+ /* normal 3D view (or view space) */
*r_x = (int)(pt->x / 100 * ar->winx);
*r_y = (int)(pt->y / 100 * ar->winy);
}
- else { /* camera view, use subrect */
+ else {
+ /* camera view, use subrect */
*r_x = (int)((pt->x / 100) * BLI_rctf_size_x(subrect)) + subrect->xmin;
*r_y = (int)((pt->y / 100) * BLI_rctf_size_y(subrect)) + subrect->ymin;
}
diff --git a/source/blender/editors/include/BIF_gl.h b/source/blender/editors/include/BIF_gl.h
index b06af01bab6..3b7d7bac44f 100644
--- a/source/blender/editors/include/BIF_gl.h
+++ b/source/blender/editors/include/BIF_gl.h
@@ -35,10 +35,6 @@
#include "GPU_glew.h"
-/* hacking pointsize and linewidth */
-#define glPointSize(f) glPointSize(U.pixelsize * (f))
-#define glLineWidth(f) glLineWidth(U.pixelsize * (f))
-
/*
* these should be phased out. cpack should be replaced in
* code with calls to glColor3ub. - zr
@@ -51,7 +47,6 @@
* */
void cpack(unsigned int x);
-
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
# define glMultMatrixf(x) \
glMultMatrixf(_Generic((x), \
@@ -71,9 +66,14 @@ void cpack(unsigned int x);
float (*)[4]: (float *)(x), \
float [4][4]: (float *)(x)) \
)
+/* hacking pointsize and linewidth */
+#define glPointSize(f) glPointSize(U.pixelsize * _Generic((f), double: (float)(f), default: (f)))
+#define glLineWidth(f) glLineWidth(U.pixelsize * _Generic((f), double: (float)(f), default: (f)))
#else
# define glMultMatrixf(x) glMultMatrixf((float *)(x))
# define glLoadMatrixf(x) glLoadMatrixf((float *)(x))
+#define glPointSize(f) glPointSize(U.pixelsize * (f))
+#define glLineWidth(f) glLineWidth(U.pixelsize * (f))
#endif
#define GLA_PIXEL_OFS 0.375f
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index b0d1be1bf5d..c4f08ca4775 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -43,6 +43,7 @@ struct Object;
struct bGPdata;
struct bGPDlayer;
struct bGPDframe;
+struct bGPDstroke;
struct PointerRNA;
struct ImBuf;
struct wmKeyConfig;
@@ -80,6 +81,11 @@ struct bGPdata *ED_gpencil_data_get_active_direct(struct ID *screen_id, struct S
/* 3D View */
struct bGPdata *ED_gpencil_data_get_active_v3d(struct Scene *scene, struct View3D *v3d);
+/* ----------- Stroke Editing Utilities ---------------- */
+
+bool ED_gpencil_stroke_can_use_direct(const struct ScrArea *sa, const struct bGPDstroke *gps);
+bool ED_gpencil_stroke_can_use(const struct bContext *C, const struct bGPDstroke *gps);
+
/* ----------- Grease Pencil Operators ----------------- */
void ED_keymap_gpencil(struct wmKeyConfig *keyconf);
diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h
index 1188ecd0aa5..704876e1261 100644
--- a/source/blender/editors/include/ED_image.h
+++ b/source/blender/editors/include/ED_image.h
@@ -35,6 +35,7 @@ struct Main;
struct bContext;
struct Image;
struct ImageUser;
+struct ImBuf;
struct ToolSettings;
struct uiBlock;
struct wmWindowManager;
@@ -58,6 +59,8 @@ void ED_space_image_get_aspect(struct SpaceImage *sima, float *aspx, float *aspy
void ED_space_image_get_zoom(struct SpaceImage *sima, struct ARegion *ar, float *zoomx, float *zoomy);
void ED_space_image_get_uv_aspect(struct SpaceImage *sima, float *aspx, float *aspy);
+void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *sima, struct ImBuf *ibuf, bool use_view_settings);
+
void ED_space_image_paint_update(struct wmWindowManager *wm, struct ToolSettings *settings);
void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct ToolSettings *settings);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 900da3ee07c..ccdde39f263 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -141,9 +141,9 @@ bool ED_object_editmode_load(struct Object *obedit);
void ED_object_location_from_view(struct bContext *C, float loc[3]);
void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis);
void ED_object_base_init_transform(struct bContext *C, struct Base *base, const float loc[3], const float rot[3]);
-float ED_object_new_primitive_matrix(struct bContext *C, struct Object *editob,
- const float loc[3], const float rot[3], float primmat[4][4],
- bool apply_diameter);
+float ED_object_new_primitive_matrix(
+ struct bContext *C, struct Object *editob,
+ const float loc[3], const float rot[3], float primmat[4][4]);
void ED_object_add_unit_props(struct wmOperatorType *ot);
void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode);
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index b790c656b61..8c33395cc49 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -107,7 +107,7 @@ void ED_screen_set_subwinactive(struct bContext *C, struct wmEvent *event);
void ED_screen_exit(struct bContext *C, struct wmWindow *window, struct bScreen *screen);
void ED_screen_animation_timer(struct bContext *C, int redraws, int refresh, int sync, int enable);
void ED_screen_animation_timer_update(struct bScreen *screen, int redraws, int refresh);
-void ED_screen_retore_temp_type(struct bContext *C, ScrArea *sa, bool is_screen_change);
+void ED_screen_restore_temp_type(struct bContext *C, ScrArea *sa);
ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *sa, int type);
void ED_screen_full_prevspace(struct bContext *C, ScrArea *sa);
void ED_screen_full_restore(struct bContext *C, ScrArea *sa);
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 76ad4ba7bdb..b62d9960117 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -310,7 +310,6 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D
bool draw_background, int alpha_mode, char err_out[256]);
struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype,
bool use_solid_tex, bool use_gpencil, bool draw_background, int alpha_mode, char err_out[256]);
-void ED_view3d_offscreen_sky_color_get(struct Scene *scene, float sky_color[3]);
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, bool do_clip);
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index fa349c4f006..bfb7a3420c9 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -54,7 +54,7 @@ DEF_ICON(DOT)
DEF_ICON(COLLAPSEMENU)
DEF_ICON(X)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK005)
+ DEF_ICON(BLANK005) /* XXX 'DOWNARROW' icon! */
#endif
DEF_ICON(GO_LEFT)
DEF_ICON(PLUG)
@@ -461,9 +461,9 @@ DEF_ICON(FORCE_SMOKEFLOW)
DEF_ICON(BLANK685)
/* EMPTY */
- DEF_ICON(BLANK690)
- DEF_ICON(BLANK691)
- DEF_ICON(BLANK692)
+ DEF_ICON(BLANK690) /* XXX 'Temperature' icon! */
+ DEF_ICON(BLANK691) /* XXX 'Temperature' icon! */
+ DEF_ICON(BLANK692) /* XXX 'Gear' icon! */
DEF_ICON(BLANK693)
DEF_ICON(BLANK694)
DEF_ICON(BLANK695)
@@ -590,8 +590,8 @@ DEF_ICON(MOD_SKIN)
DEF_ICON(MOD_TRIANGULATE)
DEF_ICON(MOD_WIREFRAME)
DEF_ICON(MOD_DATA_TRANSFER)
+DEF_ICON(MOD_NORMALEDIT)
#ifndef DEF_ICON_BLANK_SKIP
- DEF_ICON(BLANK168)
DEF_ICON(BLANK169)
DEF_ICON(BLANK170)
DEF_ICON(BLANK171)
@@ -689,7 +689,7 @@ DEF_ICON(RNDCURVE)
DEF_ICON(PROP_OFF)
DEF_ICON(PROP_ON)
DEF_ICON(PROP_CON)
-DEF_ICON(SCULPT_DYNTOPO)
+DEF_ICON(SCULPT_DYNTOPO) /* XXX Empty icon! */
DEF_ICON(PARTICLE_POINT)
DEF_ICON(PARTICLE_TIP)
DEF_ICON(PARTICLE_PATH)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 8789e837f17..590ab1d694d 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -316,6 +316,10 @@ void UI_draw_roundbox_shade_x(int mode, float minx, float miny, float maxx, floa
void UI_draw_roundbox_shade_y(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadeLeft, float shadeRight);
void UI_draw_text_underline(int pos_x, int pos_y, int len, int height);
+void UI_draw_safe_areas(
+ float x1, float x2, float y1, float y2,
+ const float title_aspect[2], const float action_aspect[2]);
+
/* state for scrolldrawing */
#define UI_SCROLL_PRESSED (1 << 0)
#define UI_SCROLL_ARROWS (1 << 1)
@@ -888,6 +892,7 @@ void uiTemplateGameStates(uiLayout *layout, struct PointerRNA *ptr, const char *
void uiTemplateImage(uiLayout *layout, struct bContext *C, struct PointerRNA *ptr, const char *propname, struct PointerRNA *userptr, int compact);
void uiTemplateImageSettings(uiLayout *layout, struct PointerRNA *imfptr, int color_management);
void uiTemplateImageLayers(uiLayout *layout, struct bContext *C, struct Image *ima, struct ImageUser *iuser);
+void uiTemplateImageInfo(uiLayout *layout, struct bContext *C, Image *ima, ImageUser *iuser);
void uiTemplateRunningJobs(uiLayout *layout, struct bContext *C);
void UI_but_func_operator_search(uiBut *but);
void uiTemplateOperatorSearch(uiLayout *layout);
@@ -970,15 +975,20 @@ void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct
void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop);
/* Styled text draw */
-void UI_fontstyle_set(struct uiFontStyle *fs);
+void UI_fontstyle_set(const struct uiFontStyle *fs);
void UI_fontstyle_draw_ex(
- struct uiFontStyle *fs, const struct rcti *rect, const char *str,
+ const struct uiFontStyle *fs, const struct rcti *rect, const char *str,
size_t len, float *r_xofs, float *r_yofs);
-void UI_fontstyle_draw(struct uiFontStyle *fs, const struct rcti *rect, const char *str);
-void UI_fontstyle_draw_rotated(struct uiFontStyle *fs, const struct rcti *rect, const char *str);
+void UI_fontstyle_draw(const struct uiFontStyle *fs, const struct rcti *rect, const char *str);
+void UI_fontstyle_draw_rotated(const struct uiFontStyle *fs, const struct rcti *rect, const char *str);
+void UI_fontstyle_draw_simple(const struct uiFontStyle *fs, float x, float y, const char *str);
+void UI_fontstyle_draw_simple_backdrop(
+ const uiFontStyle *fs, float x, float y, const char *str,
+ const unsigned char fg[4], const unsigned char bg[4]);
+
+int UI_fontstyle_string_width(const struct uiFontStyle *fs, const char *str);
+int UI_fontstyle_height_max(const struct uiFontStyle *fs);
-int UI_fontstyle_string_width(const char *str); // XXX temp
-void UI_draw_string(float x, float y, const char *str); // XXX temp
void UI_draw_icon_tri(float x, float y, char dir);
uiStyle *UI_style_get(void); /* use for fonts etc */
@@ -1009,6 +1019,9 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
/* Float precision helpers */
#define UI_PRECISION_FLOAT_MAX 7
+/* Typical UI text */
+#define UI_FSTYLE_WIDGET (const uiFontStyle *)&(UI_style_get()->widget)
+
int UI_calc_float_precision(int prec, double value);
#endif /* __UI_INTERFACE_H__ */
diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h
index d289e90c257..4a6d9911d3b 100644
--- a/source/blender/editors/include/UI_resources.h
+++ b/source/blender/editors/include/UI_resources.h
@@ -293,6 +293,8 @@ enum {
TH_INFO_DEBUG,
TH_INFO_DEBUG_TEXT,
TH_VIEW_OVERLAY,
+
+ TH_V3D_CLIPPING_BORDER
};
/* XXX WARNING: previous is saved in file, so do not change order! */
diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c
index 0b1d1c8c30c..8fa604d57cb 100644
--- a/source/blender/editors/interface/interface.c
+++ b/source/blender/editors/interface/interface.c
@@ -297,7 +297,7 @@ void ui_block_bounds_calc(uiBlock *block)
/* hardcoded exception... but that one is annoying with larger safety */
bt = block->buttons.first;
- if (bt && strncmp(bt->str, "ERROR", 5) == 0) xof = 10;
+ if (bt && STREQLEN(bt->str, "ERROR", 5)) xof = 10;
else xof = 40;
block->safety.xmin = block->rect.xmin - xof;
diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c
index bcd9b9a5547..e03ea5efba4 100644
--- a/source/blender/editors/interface/interface_draw.c
+++ b/source/blender/editors/interface/interface_draw.c
@@ -450,6 +450,51 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(ar), uiBut *but, uiWidgetColors *UNUSED(w
#endif
}
+/**
+ * Draw title and text safe areas.
+ *
+ * The first 4 parameters are the offsets for the view, not the zones.
+ */
+void UI_draw_safe_areas(
+ float x1, float x2, float y1, float y2,
+ const float title_aspect[2], const float action_aspect[2])
+{
+ const float size_x_half = (x2 - x1) * 0.5f;
+ const float size_y_half = (y2 - y1) * 0.5f;
+
+ const float *safe_areas[] = {title_aspect, action_aspect};
+ int i, safe_len = ARRAY_SIZE(safe_areas);
+ bool is_first = true;
+
+ for (i = 0; i < safe_len; i++) {
+ if (safe_areas[i][0] || safe_areas[i][1]) {
+ float margin_x, margin_y;
+ float minx, miny, maxx, maxy;
+
+ if (is_first) {
+ UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25f, 0);
+ is_first = false;
+ }
+
+ margin_x = safe_areas[i][0] * size_x_half;
+ margin_y = safe_areas[i][1] * size_y_half;
+
+ minx = x1 + margin_x;
+ miny = y1 + margin_y;
+ maxx = x2 - margin_x;
+ maxy = y2 - margin_y;
+
+ glBegin(GL_LINE_LOOP);
+ glVertex2f(maxx, miny);
+ glVertex2f(maxx, maxy);
+ glVertex2f(minx, maxy);
+ glVertex2f(minx, miny);
+ glEnd();
+ }
+ }
+}
+
+
static void draw_scope_end(const rctf *rect, GLint *scissor)
{
/* restore scissortest */
@@ -494,7 +539,7 @@ static void histogram_draw_one(float r, float g, float b, float alpha,
glColor4f(r, g, b, alpha);
glShadeModel(GL_FLAT);
- glBegin(GL_QUAD_STRIP);
+ glBegin(GL_TRIANGLE_STRIP);
glVertex2f(x, y);
glVertex2f(x, y + (data[0] * h));
for (i = 1; i < res; i++) {
@@ -777,8 +822,8 @@ static void vectorscope_draw_target(float centerx, float centery, float diam, co
if (u > 0 && v >= 0) tangle = atanf(v / u);
else if (u > 0 && v < 0) tangle = atanf(v / u) + 2.0f * (float)M_PI;
else if (u < 0) tangle = atanf(v / u) + (float)M_PI;
- else if (u == 0 && v > 0.0f) tangle = (float)M_PI / 2.0f;
- else if (u == 0 && v < 0.0f) tangle = -(float)M_PI / 2.0f;
+ else if (u == 0 && v > 0.0f) tangle = M_PI_2;
+ else if (u == 0 && v < 0.0f) tangle = -M_PI_2;
tampli = sqrtf(u * u + v * v);
/* small target vary by 2.5 degree and 2.5 IRE unit */
@@ -1102,7 +1147,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
v1[1] = y1 + sizey_solid;
v2[1] = rect->ymax;
- glBegin(GL_QUAD_STRIP);
+ glBegin(GL_TRIANGLE_STRIP);
for (a = 0; a <= sizex; a++) {
pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
@@ -1121,7 +1166,7 @@ void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti
v1[1] = y1;
v2[1] = y1 + sizey_solid;
- glBegin(GL_QUAD_STRIP);
+ glBegin(GL_TRIANGLE_STRIP);
for (a = 0; a <= sizex; a++) {
pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c
index d7a4720d595..f5b24f49f98 100644
--- a/source/blender/editors/interface/interface_eyedropper.c
+++ b/source/blender/editors/interface/interface_eyedropper.c
@@ -73,10 +73,13 @@
static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, const char *name)
{
- int width;
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
wmWindow *win = CTX_wm_window(C);
int x = win->eventstate->x;
int y = win->eventstate->y;
+ const unsigned char fg[4] = {255, 255, 255, 255};
+ const unsigned char bg[4] = {0, 0, 0, 50};
+
if ((name[0] == '\0') ||
(BLI_rcti_isect_pt(&ar->winrct, x, y) == false))
@@ -84,19 +87,12 @@ static void eyedropper_draw_cursor_text(const struct bContext *C, ARegion *ar, c
return;
}
- width = UI_fontstyle_string_width(name);
x = x - ar->winrct.xmin;
y = y - ar->winrct.ymin;
- y += 20;
-
- glColor4ub(0, 0, 0, 50);
-
- UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA);
- UI_draw_roundbox(x, y, x + width + 8, y + 15, 4);
+ y += U.widget_unit;
- glColor4ub(255, 255, 255, 255);
- UI_draw_string(x + 4, y + 4, name);
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg);
}
/** \} */
@@ -176,43 +172,42 @@ static void eyedropper_color_sample_fl(bContext *C, Eyedropper *UNUSED(eye), int
/* we could use some clever */
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa;
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) {
- if (sa->spacetype == SPACE_IMAGE) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
- SpaceImage *sima = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_image_color_sample(CTX_data_scene(C), sima, ar, mval, r_col)) {
- return;
- }
+ ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
+
+ if (sa) {
+ if (sa->spacetype == SPACE_IMAGE) {
+ ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ SpaceImage *sima = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_image_color_sample(CTX_data_scene(C), sima, ar, mval, r_col)) {
+ return;
}
}
- else if (sa->spacetype == SPACE_NODE) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
- SpaceNode *snode = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_node_color_sample(CTX_data_scene(C), snode, ar, mval, r_col)) {
- return;
- }
+ }
+ else if (sa->spacetype == SPACE_NODE) {
+ ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ SpaceNode *snode = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_node_color_sample(CTX_data_scene(C), snode, ar, mval, r_col)) {
+ return;
}
}
- else if (sa->spacetype == SPACE_CLIP) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
- SpaceClip *sc = sa->spacedata.first;
- int mval[2] = {mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
-
- if (ED_space_clip_color_sample(CTX_data_scene(C), sc, ar, mval, r_col)) {
- return;
- }
+ }
+ else if (sa->spacetype == SPACE_CLIP) {
+ ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ SpaceClip *sc = sa->spacedata.first;
+ int mval[2] = {mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+
+ if (ED_space_clip_color_sample(CTX_data_scene(C), sc, ar, mval, r_col)) {
+ return;
}
}
}
@@ -477,53 +472,49 @@ static void datadropper_id_sample_pt(bContext *C, DataDropper *ddr, int mx, int
/* we could use some clever */
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa;
+ ScrArea *sa = BKE_screen_find_area_xy(win->screen, -1, mx, my);
ScrArea *area_prev = CTX_wm_area(C);
ARegion *ar_prev = CTX_wm_region(C);
ddr->name[0] = '\0';
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
- const int mval[2] = {
- mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
- Base *base;
-
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- /* grr, always draw else we leave stale text */
- ED_region_tag_redraw(ar);
-
- base = ED_view3d_give_base_under_cursor(C, mval);
- if (base) {
- Object *ob = base->object;
- ID *id = NULL;
- if (ddr->idcode == ID_OB) {
- id = (ID *)ob;
- }
- else if (ob->data) {
- if (GS(((ID *)ob->data)->name) == ddr->idcode) {
- id = (ID *)ob->data;
- }
- else {
- BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s",
- ddr->idcode_name);
- }
+ if (sa) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ const int mval[2] = {
+ mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+ Base *base;
+
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ /* grr, always draw else we leave stale text */
+ ED_region_tag_redraw(ar);
+
+ base = ED_view3d_give_base_under_cursor(C, mval);
+ if (base) {
+ Object *ob = base->object;
+ ID *id = NULL;
+ if (ddr->idcode == ID_OB) {
+ id = (ID *)ob;
+ }
+ else if (ob->data) {
+ if (GS(((ID *)ob->data)->name) == ddr->idcode) {
+ id = (ID *)ob->data;
}
-
- if (id) {
- BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
- ddr->idcode_name, id->name + 2);
- *r_id = id;
+ else {
+ BLI_snprintf(ddr->name, sizeof(ddr->name), "Incompatible, expected a %s",
+ ddr->idcode_name);
}
+ }
- break;
+ if (id) {
+ BLI_snprintf(ddr->name, sizeof(ddr->name), "%s: %s",
+ ddr->idcode_name, id->name + 2);
+ *r_id = id;
}
}
}
@@ -760,7 +751,7 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
/* we could use some clever */
wmWindow *win = CTX_wm_window(C);
- ScrArea *sa;
+ ScrArea *sa = BKE_screen_find_area_xy(win->screen, SPACE_TYPE_ANY, mx, my);
Scene *scene = win->screen->scene;
UnitSettings *unit = &scene->unit;
const bool do_split = (unit->flag & USER_UNIT_OPT_SPLIT) != 0;
@@ -770,47 +761,44 @@ static void depthdropper_depth_sample_pt(bContext *C, DepthDropper *ddr, int mx,
ddr->name[0] = '\0';
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (BLI_rcti_isect_pt(&sa->totrct, mx, my)) {
- if (sa->spacetype == SPACE_VIEW3D) {
- ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
- if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
- View3D *v3d = sa->spacedata.first;
- RegionView3D *rv3d = ar->regiondata;
- /* weak, we could pass in some reference point */
- const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
- const int mval[2] = {
- mx - ar->winrct.xmin,
- my - ar->winrct.ymin};
- float co[3];
-
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- /* grr, always draw else we leave stale text */
- ED_region_tag_redraw(ar);
-
- view3d_operator_needs_opengl(C);
-
- if (ED_view3d_autodist(scene, ar, v3d, mval, co, true, NULL)) {
- const float mval_center_fl[2] = {
- (float)ar->winx / 2,
- (float)ar->winy / 2};
- float co_align[3];
-
- /* quick way to get view-center aligned point */
- ED_view3d_win_to_3d(ar, co, mval_center_fl, co_align);
-
- *r_depth = len_v3v3(view_co, co_align);
-
- bUnit_AsString(ddr->name, sizeof(ddr->name),
- (double)*r_depth,
- 4, unit->system, B_UNIT_LENGTH, do_split, false);
- }
- else {
- BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
- }
- break;
+ if (sa) {
+ if (sa->spacetype == SPACE_VIEW3D) {
+ ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ if (ar && BLI_rcti_isect_pt(&ar->winrct, mx, my)) {
+ View3D *v3d = sa->spacedata.first;
+ RegionView3D *rv3d = ar->regiondata;
+ /* weak, we could pass in some reference point */
+ const float *view_co = v3d->camera ? v3d->camera->obmat[3] : rv3d->viewinv[3];
+ const int mval[2] = {
+ mx - ar->winrct.xmin,
+ my - ar->winrct.ymin};
+ float co[3];
+
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+ /* grr, always draw else we leave stale text */
+ ED_region_tag_redraw(ar);
+
+ view3d_operator_needs_opengl(C);
+
+ if (ED_view3d_autodist(scene, ar, v3d, mval, co, true, NULL)) {
+ const float mval_center_fl[2] = {
+ (float)ar->winx / 2,
+ (float)ar->winy / 2};
+ float co_align[3];
+
+ /* quick way to get view-center aligned point */
+ ED_view3d_win_to_3d(ar, co, mval_center_fl, co_align);
+
+ *r_depth = len_v3v3(view_co, co_align);
+
+ bUnit_AsString(ddr->name, sizeof(ddr->name),
+ (double)*r_depth,
+ 4, unit->system, B_UNIT_LENGTH, do_split, false);
+ }
+ else {
+ BLI_strncpy(ddr->name, "Nothing under cursor", sizeof(ddr->name));
}
}
}
@@ -830,8 +818,10 @@ static void depthdropper_depth_set(bContext *C, DepthDropper *ddr, const float d
/* set sample from accumulated values */
static void depthdropper_depth_set_accum(bContext *C, DepthDropper *ddr)
{
- float depth;
- depth = ddr->accum_depth * 1.0f / (float)ddr->accum_tot;
+ float depth = ddr->accum_depth;
+ if (ddr->accum_tot) {
+ depth /= (float)ddr->accum_tot;
+ }
depthdropper_depth_set(C, ddr, depth);
}
diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c
index 98b065dabcf..96973194576 100644
--- a/source/blender/editors/interface/interface_handlers.c
+++ b/source/blender/editors/interface/interface_handlers.c
@@ -114,6 +114,7 @@
static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to);
static void ui_but_link_add(bContext *C, uiBut *from, uiBut *to);
static int ui_do_but_EXIT(bContext *C, uiBut *but, struct uiHandleButtonData *data, const wmEvent *event);
+static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b);
#ifdef USE_KEYNAV_LIMIT
static void ui_mouse_motion_keynav_init(struct uiKeyNavLock *keynav, const wmEvent *event);
@@ -355,6 +356,12 @@ static enum eSnapType ui_event_to_snap(const wmEvent *event)
return (event->ctrl) ? (event->shift) ? SNAP_ON_SMALL : SNAP_ON : SNAP_OFF;
}
+static bool ui_event_is_snap(const wmEvent *event)
+{
+ return (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY) ||
+ ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY));
+}
+
static void ui_color_snap_hue(const enum eSnapType snap, float *r_hue)
{
const float snap_increment = (snap == SNAP_ON_SMALL) ? 24 : 12;
@@ -2749,7 +2756,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
case VKEY:
case XKEY:
case CKEY:
- if (event->ctrl || event->oskey) {
+ if (IS_EVENT_MOD(event, ctrl, oskey)) {
if (event->type == VKEY)
changed = ui_textedit_copypaste(but, data, UI_TEXTEDIT_PASTE);
else if (event->type == CKEY)
@@ -2822,10 +2829,10 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
/* Ctrl + A: Select all */
#if defined(__APPLE__)
/* OSX uses cmd-a systemwide, so add it */
- if ((event->oskey && !(event->alt || event->shift || event->ctrl)) ||
- (event->ctrl && !(event->alt || event->shift || event->oskey)))
+ if ((event->oskey && !IS_EVENT_MOD(event, shift, alt, ctrl)) ||
+ (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey)))
#else
- if (event->ctrl && !(event->alt || event->shift || event->oskey))
+ if (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey))
#endif
{
ui_textedit_move(but, data, STRCUR_DIR_PREV,
@@ -2848,7 +2855,7 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle
update = true; /* do live update for tab key */
}
/* the hotkey here is not well defined, was G.qual so we check all */
- else if (event->shift || event->ctrl || event->alt || event->oskey) {
+ else if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
ui_textedit_prev_but(block, but, data);
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
@@ -3342,6 +3349,38 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons
button_activate_state(C, but, BUTTON_STATE_EXIT);
return WM_UI_HANDLER_BREAK;
}
+ else if (ELEM(event->type, WHEELDOWNMOUSE, WHEELUPMOUSE) && event->alt) {
+ /* Support alt+wheel on expanded enum rows */
+ if (but->type == UI_BTYPE_ROW) {
+ const int direction = (event->type == WHEELDOWNMOUSE) ? -1 : 1;
+ uiBut *but_select = ui_but_find_select_in_enum(but, direction);
+ if (but_select) {
+ uiBut *but_other = (direction == -1) ? but_select->next : but_select->prev;
+ if (but_other && ui_but_find_select_in_enum__cmp(but, but_other)) {
+ ARegion *ar = data->region;
+
+ data->cancel = true;
+ button_activate_exit(C, but, data, false, false);
+
+ /* Activate the text button. */
+ button_activate_init(C, ar, but_other, BUTTON_ACTIVATE_OVER);
+ data = but_other->active;
+ if (data) {
+ ui_apply_but(C, but->block, but_other, but_other->active, true);
+ button_activate_exit(C, but_other, data, false, false);
+
+ /* restore active button */
+ button_activate_init(C, ar, but, BUTTON_ACTIVATE_OVER);
+ }
+ else {
+ /* shouldn't happen */
+ BLI_assert(0);
+ }
+ }
+ }
+ return WM_UI_HANDLER_BREAK;
+ }
+ }
}
return WM_UI_HANDLER_CONTINUE;
}
@@ -3706,7 +3745,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 1;
}
}
- else if (event->type == MOUSEMOVE) {
+ else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
const enum eSnapType snap = ui_event_to_snap(event);
float fac;
@@ -4003,7 +4042,7 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton
click = 1;
}
}
- else if (event->type == MOUSEMOVE) {
+ else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
#ifdef USE_DRAG_MULTINUM
data->multi_data.drag_dir[0] += abs(data->draglastx - mx);
data->multi_data.drag_dir[1] += abs(data->draglasty - my);
@@ -4542,8 +4581,8 @@ static int ui_do_but_UNITVEC(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
}
}
else if (data->state == BUTTON_STATE_NUM_EDITING) {
- if (event->type == MOUSEMOVE) {
- if (mx != data->draglastx || my != data->draglasty) {
+ if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ if (mx != data->draglastx || my != data->draglasty || event->type != MOUSEMOVE) {
const enum eSnapType snap = ui_event_to_snap(event);
if (ui_numedit_but_UNITVEC(but, data, mx, my, snap))
ui_numedit_apply(C, block, but, data);
@@ -4862,8 +4901,8 @@ static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleBu
button_activate_state(C, but, BUTTON_STATE_EXIT);
}
}
- else if (event->type == MOUSEMOVE) {
- if (mx != data->draglastx || my != data->draglasty) {
+ else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ if (mx != data->draglastx || my != data->draglasty || event->type != MOUSEMOVE) {
const enum eSnapType snap = ui_event_to_snap(event);
if (ui_numedit_but_HSVCUBE(but, data, mx, my, snap, event->shift != 0))
@@ -5134,8 +5173,8 @@ static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandle
ui_but_hsv_set(but); /* converts to rgb */
ui_numedit_apply(C, block, but, data);
}
- else if (event->type == MOUSEMOVE) {
- if (mx != data->draglastx || my != data->draglasty) {
+ else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) {
+ if (mx != data->draglastx || my != data->draglasty || event->type != MOUSEMOVE) {
const enum eSnapType snap = ui_event_to_snap(event);
if (ui_numedit_but_HSVCIRCLE(but, data, mx, my, snap, event->shift != 0)) {
@@ -6254,7 +6293,9 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
if ((data->state == BUTTON_STATE_HIGHLIGHT) || (event->type == EVT_DROP)) {
/* handle copy-paste */
- if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS && (event->ctrl || event->oskey)) {
+ if (ELEM(event->type, CKEY, VKEY) && event->val == KM_PRESS &&
+ IS_EVENT_MOD(event, ctrl, oskey))
+ {
/* Specific handling for listrows, we try to find their overlapping tex button. */
if (but->type == UI_BTYPE_LISTROW) {
uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_OVER);
@@ -6273,7 +6314,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle eyedropper */
else if ((event->type == EKEY) && (event->val == KM_PRESS)) {
- if (event->alt || event->shift || event->ctrl || event->oskey) {
+ if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
/* pass */
}
else {
@@ -6305,7 +6346,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle keyframing */
else if ((event->type == IKEY) &&
- !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey) &&
+ !IS_EVENT_MOD(event, ctrl, oskey) &&
(event->val == KM_PRESS))
{
if (event->alt) {
@@ -6326,7 +6367,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle drivers */
else if ((event->type == DKEY) &&
- !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !IS_EVENT_MOD(event, shift, ctrl, oskey) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6340,7 +6381,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
}
/* handle keyingsets */
else if ((event->type == KKEY) &&
- !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift) &&
+ !IS_EVENT_MOD(event, shift, ctrl, oskey) &&
(event->val == KM_PRESS))
{
if (event->alt)
@@ -6353,7 +6394,10 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent *
return WM_UI_HANDLER_BREAK;
}
/* handle menu */
- else if (event->type == RIGHTMOUSE && event->val == KM_PRESS) {
+ else if ((event->type == RIGHTMOUSE) &&
+ !IS_EVENT_MOD(event, shift, ctrl, alt, oskey) &&
+ (event->val == KM_PRESS))
+ {
/* RMB has two options now */
if (ui_but_menu(C, but)) {
return WM_UI_HANDLER_BREAK;
@@ -6591,6 +6635,45 @@ static bool ui_but_isect_pie_seg(uiBlock *block, uiBut *but)
return false;
}
+static bool ui_but_find_select_in_enum__cmp(const uiBut *but_a, const uiBut *but_b)
+{
+ return ((but_a->type == but_b->type) &&
+ (but_a->alignnr == but_b->alignnr) &&
+ (but_a->poin == but_b->poin) &&
+ (but_a->rnapoin.type == but_b->rnapoin.type) &&
+ (but_a->rnaprop == but_b->rnaprop));
+}
+
+/**
+ * Finds the pressed button in an aligned row (typically an expanded enum).
+ *
+ * \param direction Use when there may be multiple buttons pressed.
+ */
+uiBut *ui_but_find_select_in_enum(uiBut *but, int direction)
+{
+ uiBut *but_iter = but;
+ uiBut *but_found = NULL;
+ BLI_assert(ELEM(direction, -1, 1));
+
+ while ((but_iter->prev) &&
+ ui_but_find_select_in_enum__cmp(but_iter->prev, but))
+ {
+ but_iter = but_iter->prev;
+ }
+
+ while (but_iter && ui_but_find_select_in_enum__cmp(but_iter, but)) {
+ if (but_iter->flag & UI_SELECT) {
+ but_found = but_iter;
+ if (direction == 1) {
+ break;
+ }
+ }
+ but_iter = but_iter->next;
+ }
+
+ return but_found;
+}
+
uiBut *ui_but_find_active_in_region(ARegion *ar)
{
uiBlock *block;
@@ -8301,7 +8384,7 @@ static int ui_handle_menu_event(
case WHEELDOWNMOUSE:
case MOUSEPAN:
/* arrowkeys: only handle for block_loop blocks */
- if (event->alt || event->shift || event->ctrl || event->oskey) {
+ if (IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) {
/* pass */
}
else if (inside || (block->flag & UI_BLOCK_LOOP)) {
@@ -8446,9 +8529,7 @@ static int ui_handle_menu_event(
case ZKEY:
{
if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
- (event->shift == 0) &&
- (event->ctrl == 0) &&
- (event->oskey == 0))
+ !IS_EVENT_MOD(event, shift, ctrl, oskey))
{
if (ui_menu_pass_event_to_parent_if_nonactive(menu, but, level, retval))
break;
@@ -8825,7 +8906,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
block->pie_data.duration_gesture = duration;
}
- if (len_sq < 1.0) {
+ if (len_sq < 1.0f) {
uiBut *but = ui_but_find_active_in_region(menu->region);
if (but) {
@@ -8940,9 +9021,7 @@ static int ui_pie_handler(bContext *C, const wmEvent *event, uiPopupBlockHandle
case ZKEY:
{
if ((event->val == KM_PRESS || event->val == KM_DBL_CLICK) &&
- (event->shift == 0) &&
- (event->ctrl == 0) &&
- (event->oskey == 0))
+ !IS_EVENT_MOD(event, shift, ctrl, oskey))
{
for (but = block->buttons.first; but; but = but->next) {
if (but->menu_key == event->type) {
@@ -9123,13 +9202,13 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata))
ui_apply_but_funcs_after(C);
}
+/* handle buttons at the window level, modal, for example while
+ * number sliding, text editing, or when a menu block is open */
static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSED(userdata))
{
ARegion *ar;
uiBut *but;
- /* here we handle buttons at the window level, modal, for example
- * while number sliding, text editing, or when a menu block is open */
ar = CTX_wm_menu(C);
if (!ar)
ar = CTX_wm_region(C);
@@ -9137,13 +9216,32 @@ static int ui_handler_region_menu(bContext *C, const wmEvent *event, void *UNUSE
but = ui_but_find_active_in_region(ar);
if (but) {
+ bScreen *screen = CTX_wm_screen(C);
+ ARegion *ar_temp;
uiBut *but_other;
uiHandleButtonData *data;
+ bool is_inside_menu = false;
+
+ /* look for a popup menu containing the mouse */
+ for (ar_temp = screen->regionbase.first; ar_temp; ar_temp = ar_temp->next) {
+ rcti rect = ar_temp->winrct;
+
+ /* resize region rect to ignore shadow */
+ BLI_rcti_resize(&rect, (BLI_rcti_size_x(&ar_temp->winrct) - UI_ThemeMenuShadowWidth() * 2),
+ (BLI_rcti_size_y(&ar_temp->winrct) - UI_ThemeMenuShadowWidth() * 2));
+ if (BLI_rcti_isect_pt_v(&rect, &event->x)) {
+ BLI_assert(ar_temp->type->regionid == RGN_TYPE_TEMPORARY);
+
+ is_inside_menu = true;
+ break;
+ }
+ }
/* handle activated button events */
data = but->active;
if ((data->state == BUTTON_STATE_MENU_OPEN) &&
+ (is_inside_menu == false) && /* make sure mouse isn't inside another menu (see T43247) */
(but->type == UI_BTYPE_PULLDOWN) &&
(but_other = ui_but_find_mouse_over(ar, event)) &&
(but != but_other) &&
diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h
index 54ba3d784d1..458e268170f 100644
--- a/source/blender/editors/interface/interface_intern.h
+++ b/source/blender/editors/interface/interface_intern.h
@@ -616,6 +616,7 @@ extern void ui_but_active_free(const struct bContext *C, uiBut *but);
extern bool ui_but_is_active(struct ARegion *ar) ATTR_WARN_UNUSED_RESULT;
extern int ui_but_menu_direction(uiBut *but);
extern void ui_but_text_password_hide(char password_str[UI_MAX_DRAW_STR], uiBut *but, const bool restore);
+extern uiBut *ui_but_find_select_in_enum(uiBut *but, int direction);
extern uiBut *ui_but_find_active_in_region(struct ARegion *ar);
bool ui_but_is_editable(const uiBut *but);
bool ui_but_is_editable_as_text(const uiBut *but);
diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c
index f02c6a234a9..fb73b8ec34c 100644
--- a/source/blender/editors/interface/interface_layout.c
+++ b/source/blender/editors/interface/interface_layout.c
@@ -235,9 +235,10 @@ static int ui_text_icon_width(uiLayout *layout, const char *name, int icon, bool
variable = (ui_layout_vary_direction(layout) == UI_ITEM_VARY_X);
if (variable) {
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
/* it may seem odd that the icon only adds (UI_UNIT_X / 4)
* but taking margins into account its fine */
- return (UI_fontstyle_string_width(name) +
+ return (UI_fontstyle_string_width(fstyle, name) +
(UI_UNIT_X * ((compact ? 1.25f : 1.50f) +
(icon ? 0.25f : 0.0f))));
}
@@ -639,7 +640,7 @@ static uiBut *ui_item_with_label(uiLayout *layout, uiBlock *block, const char *n
if (name[0]) {
/* XXX UI_fontstyle_string_width is not accurate */
#if 0
- labelw = UI_fontstyle_string_width(name);
+ labelw = UI_fontstyle_string_width(fstyle, name);
CLAMP(labelw, w / 4, 3 * w / 4);
#endif
labelw = w / 3;
@@ -1003,7 +1004,7 @@ void uiItemEnumO_value(uiLayout *layout, const char *name, int icon, const char
PointerRNA ptr;
PropertyRNA *prop;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
@@ -1035,7 +1036,7 @@ void uiItemEnumO_string(uiLayout *layout, const char *name, int icon, const char
int value;
bool free;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
@@ -1074,7 +1075,7 @@ void uiItemBooleanO(uiLayout *layout, const char *name, int icon, const char *op
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
PointerRNA ptr;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
RNA_boolean_set(&ptr, propname, value);
@@ -1087,7 +1088,7 @@ void uiItemIntO(uiLayout *layout, const char *name, int icon, const char *opname
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
PointerRNA ptr;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
RNA_int_set(&ptr, propname, value);
@@ -1100,7 +1101,7 @@ void uiItemFloatO(uiLayout *layout, const char *name, int icon, const char *opna
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
PointerRNA ptr;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
RNA_float_set(&ptr, propname, value);
@@ -1113,7 +1114,7 @@ void uiItemStringO(uiLayout *layout, const char *name, int icon, const char *opn
wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */
PointerRNA ptr;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
WM_operator_properties_create_ptr(&ptr, ot);
RNA_string_set(&ptr, propname, value);
@@ -1877,7 +1878,7 @@ void uiItemMenuEnumO(uiLayout *layout, bContext *C, const char *opname, const ch
MenuItemLevel *lvl;
uiBut *but;
- UI_OPERATOR_ERROR_RET(ot, opname, return );
+ UI_OPERATOR_ERROR_RET(ot, opname, return);
if (!ot->srna) {
ui_item_disabled(layout, opname);
diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c
index 074faaa86bc..19e389154e4 100644
--- a/source/blender/editors/interface/interface_ops.c
+++ b/source/blender/editors/interface/interface_ops.c
@@ -515,7 +515,7 @@ static bool ui_editsource_uibut_match(uiBut *but_a, uiBut *but_b)
(but_a->rnaprop == but_b->rnaprop) &&
(but_a->optype == but_b->optype) &&
(but_a->unit_type == but_b->unit_type) &&
- (strncmp(but_a->drawstr, but_b->drawstr, UI_MAX_DRAW_STR) == 0))
+ STREQLEN(but_a->drawstr, but_b->drawstr, UI_MAX_DRAW_STR))
{
return true;
}
@@ -858,7 +858,7 @@ int UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED(e
void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop)
{
- uiDragColorHandle *drag_info = (uiDragColorHandle *)drag->poin;
+ uiDragColorHandle *drag_info = drag->poin;
RNA_float_set_array(drop->ptr, "color", drag_info->color);
RNA_boolean_set(drop->ptr, "gamma", drag_info->gamma_corrected);
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index e68c86353a3..d165e2719c5 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -1490,7 +1490,7 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active)
}
BLF_enable(fontid, BLF_ROTATION);
- BLF_rotation(fontid, M_PI / 2);
+ BLF_rotation(fontid, M_PI_2);
//UI_fontstyle_set(&style->widget);
ui_fontscale(&fstyle_points, aspect / (U.pixelsize * 1.1f));
BLF_size(fontid, fstyle_points, U.dpi);
@@ -1757,7 +1757,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 && !ELEM(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) {
+ if (event->type == AKEY && ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) {
if (pa->flag & PNL_CLOSEDY) {
if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my))
diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c
index 0ec59e4e4cd..b6a93c8306d 100644
--- a/source/blender/editors/interface/interface_regions.c
+++ b/source/blender/editors/interface/interface_regions.c
@@ -1919,7 +1919,7 @@ static void ui_update_color_picker_buts_rgb(uiBlock *block, ColorPicker *cpicker
ui_but_v3_set(bt, rgb);
}
- else if (strcmp(bt->str, "Hex: ") == 0) {
+ else if (STREQ(bt->str, "Hex: ")) {
float rgb_gamma[3];
unsigned char rgb_gamma_uchar[3];
double intpart;
@@ -2726,7 +2726,8 @@ static uiBlock *ui_block_func_PIE(bContext *UNUSED(C), uiPopupBlockHandle *handl
static float ui_pie_menu_title_width(const char *name, int icon)
{
- return (UI_fontstyle_string_width(name) +
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ return (UI_fontstyle_string_width(fstyle, name) +
(UI_UNIT_X * (1.50f + (icon ? 0.25f : 0.0f))));
}
diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c
index 8b2ce90dcf5..2f46c0906ae 100644
--- a/source/blender/editors/interface/interface_style.c
+++ b/source/blender/editors/interface/interface_style.c
@@ -45,6 +45,7 @@
#include "BKE_global.h"
+#include "BIF_gl.h"
#include "BLF_api.h"
#ifdef WITH_INTERNATIONAL
@@ -147,8 +148,9 @@ static uiFont *uifont_to_blfont(int id)
/* *************** draw ************************ */
-void UI_fontstyle_draw_ex(uiFontStyle *fs, const rcti *rect, const char *str,
- size_t len, float *r_xofs, float *r_yofs)
+void UI_fontstyle_draw_ex(
+ const uiFontStyle *fs, const rcti *rect, const char *str,
+ size_t len, float *r_xofs, float *r_yofs)
{
float height;
int xofs = 0, yofs;
@@ -194,15 +196,17 @@ void UI_fontstyle_draw_ex(uiFontStyle *fs, const rcti *rect, const char *str,
*r_yofs = yofs;
}
-void UI_fontstyle_draw(uiFontStyle *fs, const rcti *rect, const char *str)
+void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str)
{
float xofs, yofs;
- UI_fontstyle_draw_ex(fs, rect, str,
- BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs);
+
+ UI_fontstyle_draw_ex(
+ fs, rect, str,
+ BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs);
}
/* drawn same as above, but at 90 degree angle */
-void UI_fontstyle_draw_rotated(uiFontStyle *fs, const rcti *rect, const char *str)
+void UI_fontstyle_draw_rotated(const uiFontStyle *fs, const rcti *rect, const char *str)
{
float height;
int xofs, yofs;
@@ -220,7 +224,7 @@ void UI_fontstyle_draw_rotated(uiFontStyle *fs, const rcti *rect, const char *st
/* rotate counter-clockwise for now (assumes left-to-right language)*/
xofs += height;
yofs = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX) + 5;
- angle = (float)M_PI / 2.0f;
+ angle = M_PI_2;
/* translate rect to vertical */
txtrect.xmin = rect->xmin - BLI_rcti_size_y(rect);
@@ -255,6 +259,66 @@ void UI_fontstyle_draw_rotated(uiFontStyle *fs, const rcti *rect, const char *st
BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
}
+/**
+ * Similar to #UI_fontstyle_draw
+ * but ignore alignment, shadow & no clipping rect.
+ *
+ * For drawing on-screen labels.
+ */
+void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str)
+{
+ if (fs->kerning == 1)
+ BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
+
+ UI_fontstyle_set(fs);
+ BLF_position(fs->uifont_id, x, y, 0.0f);
+ BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+
+ if (fs->kerning == 1)
+ BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
+}
+
+/**
+ * Same as #UI_fontstyle_draw but draw a colored backdrop.
+ */
+void UI_fontstyle_draw_simple_backdrop(
+ const uiFontStyle *fs, float x, float y, const char *str,
+ const unsigned char fg[4], const unsigned char bg[4])
+{
+ if (fs->kerning == 1)
+ BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
+
+ UI_fontstyle_set(fs);
+
+ {
+ const float width = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ const float height = BLF_height_max(fs->uifont_id);
+ const float decent = BLF_descender(fs->uifont_id);
+ const float margin = height / 4.0f;
+
+ /* backdrop */
+ glColor4ubv(bg);
+
+ UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA);
+ UI_draw_roundbox(
+ x - margin,
+ (y + decent) - margin,
+ x + width + margin,
+ (y + decent) + height + margin,
+ margin);
+
+ glColor4ubv(fg);
+ }
+
+
+ BLF_position(fs->uifont_id, x, y, 0.0f);
+ BLF_draw(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+
+ if (fs->kerning == 1)
+ BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
+}
+
+
/* ************** helpers ************************ */
/* XXX: read a style configure */
uiStyle *UI_style_get(void)
@@ -291,41 +355,29 @@ uiStyle *UI_style_get_dpi(void)
return &_style;
}
-/* temporarily, does widget font */
-int UI_fontstyle_string_width(const char *str)
+int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str)
{
- uiStyle *style = UI_style_get();
- uiFontStyle *fstyle = &style->widget;
int width;
- if (fstyle->kerning == 1) /* for BLF_width */
- BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
+ if (fs->kerning == 1) /* for BLF_width */
+ BLF_enable(fs->uifont_id, BLF_KERNING_DEFAULT);
- UI_fontstyle_set(fstyle);
- width = BLF_width(fstyle->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
+ UI_fontstyle_set(fs);
+ width = BLF_width(fs->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
- if (fstyle->kerning == 1)
- BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
+ if (fs->kerning == 1)
+ BLF_disable(fs->uifont_id, BLF_KERNING_DEFAULT);
return width;
}
-/* temporarily, does widget font */
-void UI_draw_string(float x, float y, const char *str)
+int UI_fontstyle_height_max(const uiFontStyle *fs)
{
- uiStyle *style = UI_style_get();
-
- if (style->widget.kerning == 1)
- BLF_enable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
-
- UI_fontstyle_set(&style->widget);
- BLF_position(style->widget.uifont_id, x, y, 0.0f);
- BLF_draw(style->widget.uifont_id, str, BLF_DRAW_STR_DUMMY_MAX);
-
- if (style->widget.kerning == 1)
- BLF_disable(style->widget.uifont_id, BLF_KERNING_DEFAULT);
+ UI_fontstyle_set(fs);
+ return BLF_height_max(fs->uifont_id);
}
+
/* ************** init exit ************************ */
/* called on each startup.blend read */
@@ -398,11 +450,10 @@ void uiStyleInit(void)
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);
- }
}
+ BLF_default_set(font->blf_id);
+
if (font->blf_id == -1) {
if (G.debug & G_DEBUG)
printf("%s: error, no fonts available\n", __func__);
@@ -453,7 +504,7 @@ void uiStyleInit(void)
BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72);
}
-void UI_fontstyle_set(uiFontStyle *fs)
+void UI_fontstyle_set(const uiFontStyle *fs)
{
uiFont *font = uifont_to_blfont(fs->uifont_id);
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 407843d663c..5ac991cbd94 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -2862,7 +2862,7 @@ void uiTemplateList(uiLayout *layout, bContext *C, const char *listtype_name, co
/* validate arguments */
/* Forbid default UI_UL_DEFAULT_CLASS_NAME list class without a custom list_id! */
- if (!strcmp(UI_UL_DEFAULT_CLASS_NAME, listtype_name) && !(list_id && list_id[0])) {
+ if (STREQ(UI_UL_DEFAULT_CLASS_NAME, listtype_name) && !(list_id && list_id[0])) {
RNA_warning("template_list using default '%s' UIList class must provide a custom list_id",
UI_UL_DEFAULT_CLASS_NAME);
return;
@@ -3570,8 +3570,7 @@ void uiTemplateColorspaceSettings(uiLayout *layout, PointerRNA *ptr, const char
colorspace_settings_ptr = RNA_property_pointer_get(ptr, prop);
- uiItemL(layout, IFACE_("Input Color Space:"), ICON_NONE);
- uiItemR(layout, &colorspace_settings_ptr, "name", 0, "", ICON_NONE);
+ uiItemR(layout, &colorspace_settings_ptr, "name", 0, IFACE_("Color Space"), ICON_NONE);
}
void uiTemplateColormanagedViewSettings(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr, const char *propname)
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index 04a886ba2a8..9b22f8a1e7f 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -610,36 +610,36 @@ static void round_box_shade_col4_r(unsigned char r_col[4], const char col1[4], c
r_col[3] = (faci * col1[3] + facm * col2[3]) >> 8;
}
-static void widget_verts_to_quad_strip(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2])
+static void widget_verts_to_triangle_strip(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
{
int a;
for (a = 0; a < totvert; a++) {
- copy_v2_v2(quad_strip[a * 2], wtb->outer_v[a]);
- copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[a]);
+ copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[a]);
+ copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[a]);
}
- copy_v2_v2(quad_strip[a * 2], wtb->outer_v[0]);
- copy_v2_v2(quad_strip[a * 2 + 1], wtb->inner_v[0]);
+ copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[0]);
+ copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[0]);
}
-static void widget_verts_to_quad_strip_open(uiWidgetBase *wtb, const int totvert, float quad_strip[WIDGET_SIZE_MAX * 2][2])
+static void widget_verts_to_triangle_strip_open(uiWidgetBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2][2])
{
int a;
for (a = 0; a < totvert; a++) {
- quad_strip[a * 2][0] = wtb->outer_v[a][0];
- quad_strip[a * 2][1] = wtb->outer_v[a][1];
- quad_strip[a * 2 + 1][0] = wtb->outer_v[a][0];
- quad_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f;
+ triangle_strip[a * 2][0] = wtb->outer_v[a][0];
+ triangle_strip[a * 2][1] = wtb->outer_v[a][1];
+ triangle_strip[a * 2 + 1][0] = wtb->outer_v[a][0];
+ triangle_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f;
}
}
static void widgetbase_outline(uiWidgetBase *wtb)
{
- float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
- widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip);
+ float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
+ widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(2, GL_FLOAT, 0, quad_strip);
- glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2);
+ glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
glDisableClientState(GL_VERTEX_ARRAY);
}
@@ -733,18 +733,18 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
/* for each AA step */
if (wtb->outline) {
- float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
- float quad_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
+ float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
+ float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
const unsigned char tcol[4] = {wcol->outline[0],
wcol->outline[1],
wcol->outline[2],
wcol->outline[3] / WIDGET_AA_JITTER};
- widget_verts_to_quad_strip(wtb, wtb->totvert, quad_strip);
+ widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
if (wtb->emboss) {
- widget_verts_to_quad_strip_open(wtb, wtb->halfwayvert, quad_strip_emboss);
+ widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss);
}
glEnableClientState(GL_VERTEX_ARRAY);
@@ -757,8 +757,8 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
/* outline */
glColor4ubv(tcol);
- glVertexPointer(2, GL_FLOAT, 0, quad_strip);
- glDrawArrays(GL_QUAD_STRIP, 0, wtb->totvert * 2 + 2);
+ glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
/* emboss bottom shadow */
if (wtb->emboss) {
@@ -766,8 +766,8 @@ static void widgetbase_draw(uiWidgetBase *wtb, uiWidgetColors *wcol)
if (emboss[3]) {
glColor4ubv(emboss);
- glVertexPointer(2, GL_FLOAT, 0, quad_strip_emboss);
- glDrawArrays(GL_QUAD_STRIP, 0, wtb->halfwayvert * 2);
+ glVertexPointer(2, GL_FLOAT, 0, triangle_strip_emboss);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->halfwayvert * 2);
}
}
@@ -2098,7 +2098,7 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
rcti rect1 = *rect;
float alphastep;
int step, totvert;
- float quad_strip[WIDGET_SIZE_MAX * 2 + 2][2];
+ float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2];
const float radout = UI_ThemeMenuShadowWidth();
/* disabled shadow */
@@ -2126,10 +2126,10 @@ static void widget_softshadow(const rcti *rect, int roundboxalign, const float r
glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
- widget_verts_to_quad_strip(&wtb, totvert, quad_strip);
+ widget_verts_to_triangle_strip(&wtb, totvert, triangle_strip);
- glVertexPointer(2, GL_FLOAT, 0, quad_strip);
- glDrawArrays(GL_QUAD_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
+ glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
}
glDisableClientState(GL_VERTEX_ARRAY);
@@ -2210,7 +2210,7 @@ void ui_hsvcircle_pos_from_vals(uiBut *but, const rcti *rect, float *hsv, float
float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
float ang, radius_t;
- ang = 2.0f * (float)M_PI * hsv[0] + 0.5f * (float)M_PI;
+ ang = 2.0f * (float)M_PI * hsv[0] + (float)M_PI_2;
if ((but->flag & UI_BUT_COLOR_CUBIC) && (U.color_picker_type == USER_CP_CIRCLE_HSV))
radius_t = (1.0f - pow3f(1.0f - hsv[1]));
@@ -3007,11 +3007,8 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat
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;
+
+ bw += (bw < 0.5f) ? 0.5f : -0.5f;
glColor4f(bw, bw, bw, 1.0);
glBegin(GL_TRIANGLES);
@@ -3947,7 +3944,7 @@ void ui_draw_pie_center(uiBlock *block)
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);
+ float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_2 : M_PI_4;
glPushMatrix();
glTranslatef(cx, cy, 0.0f);
diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c
index aa5b2570952..dab4b6a941c 100644
--- a/source/blender/editors/interface/resources.c
+++ b/source/blender/editors/interface/resources.c
@@ -682,6 +682,9 @@ const unsigned char *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colo
case TH_INFO_DEBUG_TEXT:
cp = ts->info_debug_text;
break;
+ case TH_V3D_CLIPPING_BORDER:
+ cp = ts->clipping_border_3d;
+ break;
}
}
}
@@ -951,6 +954,7 @@ void ui_theme_init_default(void)
rgba_char_args_set(btheme->tv3d.gradients.high_gradient, 58, 58, 58, 255);
btheme->tv3d.gradients.show_grad = false;
+ rgba_char_args_set(btheme->tv3d.clipping_border_3d, 50, 50, 50, 255);
/* space buttons */
/* to have something initialized */
btheme->tbuts = btheme->tv3d;
@@ -1574,7 +1578,7 @@ void init_userdef_do_versions(void)
U.tb_rightmouse = 5;
}
if (U.mixbufsize == 0) U.mixbufsize = 2048;
- if (strcmp(U.tempdir, "/") == 0) {
+ if (STREQ(U.tempdir, "/")) {
BKE_tempdir_system_init(U.tempdir);
}
if (U.autokey_mode == 0) {
@@ -1907,39 +1911,39 @@ void init_userdef_do_versions(void)
wmKeyMap *km;
for (km = U.user_keymaps.first; km; km = km->next) {
- if (strcmp(km->idname, "Armature_Sketch") == 0)
+ if (STREQ(km->idname, "Armature_Sketch"))
strcpy(km->idname, "Armature Sketch");
- else if (strcmp(km->idname, "View3D") == 0)
+ else if (STREQ(km->idname, "View3D"))
strcpy(km->idname, "3D View");
- else if (strcmp(km->idname, "View3D Generic") == 0)
+ else if (STREQ(km->idname, "View3D Generic"))
strcpy(km->idname, "3D View Generic");
- else if (strcmp(km->idname, "EditMesh") == 0)
+ else if (STREQ(km->idname, "EditMesh"))
strcpy(km->idname, "Mesh");
- else if (strcmp(km->idname, "TimeLine") == 0)
+ else if (STREQ(km->idname, "TimeLine"))
strcpy(km->idname, "Timeline");
- else if (strcmp(km->idname, "UVEdit") == 0)
+ else if (STREQ(km->idname, "UVEdit"))
strcpy(km->idname, "UV Editor");
- else if (strcmp(km->idname, "Animation_Channels") == 0)
+ else if (STREQ(km->idname, "Animation_Channels"))
strcpy(km->idname, "Animation Channels");
- else if (strcmp(km->idname, "GraphEdit Keys") == 0)
+ else if (STREQ(km->idname, "GraphEdit Keys"))
strcpy(km->idname, "Graph Editor");
- else if (strcmp(km->idname, "GraphEdit Generic") == 0)
+ else if (STREQ(km->idname, "GraphEdit Generic"))
strcpy(km->idname, "Graph Editor Generic");
- else if (strcmp(km->idname, "Action_Keys") == 0)
+ else if (STREQ(km->idname, "Action_Keys"))
strcpy(km->idname, "Dopesheet");
- else if (strcmp(km->idname, "NLA Data") == 0)
+ else if (STREQ(km->idname, "NLA Data"))
strcpy(km->idname, "NLA Editor");
- else if (strcmp(km->idname, "Node Generic") == 0)
+ else if (STREQ(km->idname, "Node Generic"))
strcpy(km->idname, "Node Editor");
- else if (strcmp(km->idname, "Logic Generic") == 0)
+ else if (STREQ(km->idname, "Logic Generic"))
strcpy(km->idname, "Logic Editor");
- else if (strcmp(km->idname, "File") == 0)
+ else if (STREQ(km->idname, "File"))
strcpy(km->idname, "File Browser");
- else if (strcmp(km->idname, "FileMain") == 0)
+ else if (STREQ(km->idname, "FileMain"))
strcpy(km->idname, "File Browser Main");
- else if (strcmp(km->idname, "FileButtons") == 0)
+ else if (STREQ(km->idname, "FileButtons"))
strcpy(km->idname, "File Browser Buttons");
- else if (strcmp(km->idname, "Buttons Generic") == 0)
+ else if (STREQ(km->idname, "Buttons Generic"))
strcpy(km->idname, "Property Editor");
}
}
@@ -2572,6 +2576,25 @@ void init_userdef_do_versions(void)
}
}
+ if (U.versionfile < 273 || (U.versionfile == 273 && U.subversionfile < 5)) {
+ bTheme *btheme;
+ for (btheme = U.themes.first; btheme; btheme = btheme->next) {
+ unsigned char *cp = (unsigned char *)btheme->tv3d.clipping_border_3d;
+ int c;
+ copy_v4_v4_char((char *)cp, btheme->tv3d.back);
+ c = cp[0] - 8;
+ CLAMP(c, 0, 255);
+ cp[0] = c;
+ c = cp[1] - 8;
+ CLAMP(c, 0, 255);
+ cp[1] = c;
+ c = cp[2] - 8;
+ CLAMP(c, 0, 255);
+ cp[2] = c;
+ cp[3] = 255;
+ }
+ }
+
if (U.pixelsize == 0.0f)
U.pixelsize = 1.0f;
diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c
index de46d47e5a3..b4a120b2dea 100644
--- a/source/blender/editors/interface/view2d.c
+++ b/source/blender/editors/interface/view2d.c
@@ -371,7 +371,8 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
float winx, winy;
rctf *cur, *tot;
- /* use mask as size of region that View2D resides in, as it takes into account scrollbars already */
+ /* use mask as size of region that View2D resides in, as it takes into account
+ * scrollbars already - keep in sync with zoomx/zoomy in view_zoomstep_apply_ex! */
winx = (float)(BLI_rcti_size_x(&v2d->mask) + 1);
winy = (float)(BLI_rcti_size_y(&v2d->mask) + 1);
@@ -393,6 +394,7 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, int resize, int mask_
*/
totwidth = BLI_rctf_size_x(tot);
totheight = BLI_rctf_size_y(tot);
+ /* keep in sync with zoomx/zoomy in view_zoomstep_apply_ex! */
curwidth = width = BLI_rctf_size_x(cur);
curheight = height = BLI_rctf_size_y(cur);
@@ -1851,7 +1853,7 @@ void UI_view2d_scrollers_draw(const bContext *C, View2D *v2d, View2DScrollers *v
/* draw vertical steps */
if (dfac > 0.0f) {
- BLF_rotation_default(M_PI / 2);
+ BLF_rotation_default(M_PI_2);
BLF_enable_default(BLF_ROTATION);
for (; fac < vert.ymax - 10; fac += dfac, val += grid->dy) {
diff --git a/source/blender/editors/interface/view2d_ops.c b/source/blender/editors/interface/view2d_ops.c
index 297d8d0f258..88140d897ae 100644
--- a/source/blender/editors/interface/view2d_ops.c
+++ b/source/blender/editors/interface/view2d_ops.c
@@ -625,6 +625,7 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool
{
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
+ const rctf cur_old = v2d->cur;
float dx, dy;
/* calculate amount to move view by, ensuring symmetry so the
@@ -651,17 +652,23 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool
v2d->cur.xmax -= 2 * dx;
}
else {
+
+ v2d->cur.xmin += dx;
+ v2d->cur.xmax -= dx;
+
if (use_mousepos && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) {
- float mval_fac = (vzd->mx_2d - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur);
- float mval_faci = 1.0f - mval_fac;
- float ofs = (mval_fac * dx) - (mval_faci * dx);
-
- v2d->cur.xmin += ofs + dx;
- v2d->cur.xmax += ofs - dx;
- }
- else {
- v2d->cur.xmin += dx;
- v2d->cur.xmax -= dx;
+ /* get zoom fac the same way as in ui_view2d_curRect_validate_resize - better keep in sync! */
+ const float zoomx = (float)(BLI_rcti_size_x(&v2d->mask) + 1) / BLI_rctf_size_x(&v2d->cur);
+
+ /* only move view to mouse if zoom fac is inside minzoom/maxzoom */
+ if (IN_RANGE_INCL(zoomx, v2d->minzoom, v2d->maxzoom)) {
+ float mval_fac = (vzd->mx_2d - cur_old.xmin) / BLI_rctf_size_x(&cur_old);
+ float mval_faci = 1.0f - mval_fac;
+ float ofs = (mval_fac * dx) - (mval_faci * dx);
+
+ v2d->cur.xmin += ofs;
+ v2d->cur.xmax += ofs;
+ }
}
}
}
@@ -676,17 +683,23 @@ static void view_zoomstep_apply_ex(bContext *C, v2dViewZoomData *vzd, const bool
v2d->cur.ymax -= 2 * dy;
}
else {
+
+ v2d->cur.ymin += dy;
+ v2d->cur.ymax -= dy;
+
if (use_mousepos && (U.uiflag & USER_ZOOM_TO_MOUSEPOS)) {
- float mval_fac = (vzd->my_2d - v2d->cur.ymin) / BLI_rctf_size_y(&v2d->cur);
- float mval_faci = 1.0f - mval_fac;
- float ofs = (mval_fac * dy) - (mval_faci * dy);
-
- v2d->cur.ymin += ofs + dy;
- v2d->cur.ymax += ofs - dy;
- }
- else {
- v2d->cur.ymin += dy;
- v2d->cur.ymax -= dy;
+ /* get zoom fac the same way as in ui_view2d_curRect_validate_resize - better keep in sync! */
+ const float zoomy = (float)(BLI_rcti_size_y(&v2d->mask) + 1) / BLI_rctf_size_y(&v2d->cur);
+
+ /* only move view to mouse if zoom fac is inside minzoom/maxzoom */
+ if (IN_RANGE_INCL(zoomy, v2d->minzoom, v2d->maxzoom)) {
+ float mval_fac = (vzd->my_2d - cur_old.ymin) / BLI_rctf_size_y(&cur_old);
+ float mval_faci = 1.0f - mval_fac;
+ float ofs = (mval_fac * dy) - (mval_faci * dy);
+
+ v2d->cur.ymin += ofs;
+ v2d->cur.ymax += ofs;
+ }
}
}
}
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index b288a02a3d1..6ce5e8a304b 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -32,6 +32,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
+#include "BLI_math.h"
#include "BLF_translation.h"
@@ -71,7 +72,7 @@ static Object *make_prim_init(bContext *C, const char *idname,
*was_editmode = true;
}
- *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false);
+ *dia = ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
return obedit;
}
@@ -421,7 +422,9 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
{
Object *obedit;
BMEditMesh *em;
- float loc[3], rot[3], mat[4][4], dia;
+ float mat[4][4];
+ float loc[3], rot[3];
+ float dia;
bool enter_editmode;
unsigned int layer;
bool was_editmode;
@@ -431,9 +434,7 @@ static int add_primitive_monkey_exec(bContext *C, wmOperator *op)
obedit = make_prim_init(C, CTX_DATA_(BLF_I18NCONTEXT_ID_MESH, "Suzanne"), &dia, mat, &was_editmode, loc, rot, layer);
dia = RNA_float_get(op->ptr, "radius");
- mat[0][0] *= dia;
- mat[1][1] *= dia;
- mat[2][2] *= dia;
+ mul_mat3_m4_fl(mat, dia);
em = BKE_editmesh_from_object(obedit);
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c
index 0a78f299159..e8a5202029b 100644
--- a/source/blender/editors/mesh/editmesh_knife.c
+++ b/source/blender/editors/mesh/editmesh_knife.c
@@ -1241,7 +1241,9 @@ static BMElem *bm_elem_from_knife_vert(KnifeVert *kfv, KnifeEdge **r_kfe)
for (ref = kfv->edges.first; ref; ref = ref->next) {
kfe = ref->ref;
if (kfe->e) {
- *r_kfe = kfe;
+ if (r_kfe) {
+ *r_kfe = kfe;
+ }
break;
}
}
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index a480b2051cc..16b74c3bddd 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -964,6 +964,40 @@ void MESH_OT_vert_connect(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+static int edbm_vert_connect_concave_exec(bContext *C, wmOperator *op)
+{
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ if (!EDBM_op_call_and_selectf(
+ em, op,
+ "faces.out", true,
+ "connect_verts_concave faces=%hf",
+ BM_ELEM_SELECT))
+ {
+ return OPERATOR_CANCELLED;
+ }
+
+
+ EDBM_update_generic(em, true, true);
+ return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vert_connect_concave(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Split Concave Faces";
+ ot->idname = "MESH_OT_vert_connect_concave";
+ ot->description = "Make all faces convex";
+
+ /* api callbacks */
+ ot->exec = edbm_vert_connect_concave_exec;
+ ot->poll = ED_operator_editmesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
static int edbm_vert_connect_nonplaner_exec(bContext *C, wmOperator *op)
{
@@ -4541,7 +4575,7 @@ static int edbm_noise_exec(bContext *C, wmOperator *op)
BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
float tin, dum;
- externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL);
+ externtex(ma->mtex[0], eve->co, &tin, &dum, &dum, &dum, &dum, 0, NULL, false);
eve->co[2] += fac * tin;
}
}
diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c
index 152d055d239..30e9a85d083 100644
--- a/source/blender/editors/mesh/mesh_data.c
+++ b/source/blender/editors/mesh/mesh_data.c
@@ -57,6 +57,7 @@
#include "ED_mesh.h"
#include "ED_object.h"
+#include "ED_screen.h"
#include "ED_uvedit.h"
#include "ED_view3d.h"
@@ -838,6 +839,71 @@ void MESH_OT_customdata_clear_skin(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
+/* Clear custom loop normals */
+static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ Mesh *me = ob->data;
+
+ if (!BKE_mesh_has_custom_loop_normals(me)) {
+ CustomData *data = GET_CD_DATA(me, ldata);
+
+ if (me->edit_btmesh) {
+ BM_data_layer_add(me->edit_btmesh->bm, data, CD_CUSTOMLOOPNORMAL);
+ }
+ else {
+ CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop);
+ }
+
+ DAG_id_tag_update(&me->id, 0);
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, me);
+
+ return OPERATOR_FINISHED;
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void MESH_OT_customdata_custom_splitnormals_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Custom Split Normals Data";
+ ot->idname = "MESH_OT_customdata_custom_splitnormals_add";
+ ot->description = "Add a custom split normals layer, if none exists yet";
+
+ /* api callbacks */
+ ot->exec = mesh_customdata_custom_splitnormals_add_exec;
+ ot->poll = ED_operator_object_active_editable_mesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
+static int mesh_customdata_custom_splitnormals_clear_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Object *ob = ED_object_context(C);
+ Mesh *me = ob->data;
+
+ if (BKE_mesh_has_custom_loop_normals(me)) {
+ return mesh_customdata_clear_exec__internal(C, BM_LOOP, CD_CUSTOMLOOPNORMAL);
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void MESH_OT_customdata_custom_splitnormals_clear(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Clear Custom Split Normals Data";
+ ot->idname = "MESH_OT_customdata_custom_splitnormals_clear";
+ ot->description = "Remove the custom split normals layer, if it exists";
+
+ /* api callbacks */
+ ot->exec = mesh_customdata_custom_splitnormals_clear_exec;
+ ot->poll = ED_operator_object_active_editable_mesh;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
/************************** Add Geometry Layers *************************/
void ED_mesh_update(Mesh *mesh, bContext *C, int calc_edges, int calc_tessface)
diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h
index 6ba91097ec4..8f5ecaed524 100644
--- a/source/blender/editors/mesh/mesh_intern.h
+++ b/source/blender/editors/mesh/mesh_intern.h
@@ -175,6 +175,7 @@ void MESH_OT_normals_make_consistent(struct wmOperatorType *ot);
void MESH_OT_vertices_smooth(struct wmOperatorType *ot);
void MESH_OT_vertices_smooth_laplacian(struct wmOperatorType *ot);
void MESH_OT_vert_connect(struct wmOperatorType *ot);
+void MESH_OT_vert_connect_concave(struct wmOperatorType *ot);
void MESH_OT_vert_connect_nonplanar(struct wmOperatorType *ot);
void MESH_OT_edge_split(struct wmOperatorType *ot);
void MESH_OT_bridge_edge_loops(struct wmOperatorType *ot);
@@ -237,6 +238,8 @@ void MESH_OT_vertex_color_remove(struct wmOperatorType *ot);
/* no create_mask yet */
void MESH_OT_customdata_clear_mask(struct wmOperatorType *ot);
void MESH_OT_customdata_clear_skin(struct wmOperatorType *ot);
+void MESH_OT_customdata_custom_splitnormals_add(struct wmOperatorType *ot);
+void MESH_OT_customdata_custom_splitnormals_clear(struct wmOperatorType *ot);
void MESH_OT_drop_named_image(struct wmOperatorType *ot);
diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c
index e7dc5a69d53..59d0de87de6 100644
--- a/source/blender/editors/mesh/mesh_ops.c
+++ b/source/blender/editors/mesh/mesh_ops.c
@@ -153,6 +153,8 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_vertex_color_remove);
WM_operatortype_append(MESH_OT_customdata_clear_mask);
WM_operatortype_append(MESH_OT_customdata_clear_skin);
+ WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_add);
+ WM_operatortype_append(MESH_OT_customdata_custom_splitnormals_clear);
WM_operatortype_append(MESH_OT_drop_named_image);
WM_operatortype_append(MESH_OT_edgering_select);
@@ -161,6 +163,7 @@ void ED_operatortypes_mesh(void)
WM_operatortype_append(MESH_OT_solidify);
WM_operatortype_append(MESH_OT_select_nth);
WM_operatortype_append(MESH_OT_vert_connect);
+ WM_operatortype_append(MESH_OT_vert_connect_concave);
WM_operatortype_append(MESH_OT_vert_connect_nonplanar);
WM_operatortype_append(MESH_OT_knife_tool);
WM_operatortype_append(MESH_OT_knife_project);
diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c
index 19040062fda..dee216d9c73 100644
--- a/source/blender/editors/mesh/meshtools.c
+++ b/source/blender/editors/mesh/meshtools.c
@@ -329,7 +329,7 @@ int join_mesh_exec(bContext *C, wmOperator *op)
if (odg) {
/* Search for a match in the new object, and set new index */
for (dg = ob->defbase.first, index = 0; dg; dg = dg->next, index++) {
- if (!strcmp(dg->name, odg->name)) {
+ if (STREQ(dg->name, odg->name)) {
dvert[i].dw[j].def_nr = index;
break;
}
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index c3edd63b2d4..1180c082783 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -162,14 +162,13 @@ void ED_object_rotation_from_view(bContext *C, float rot[3], const char align_ax
BLI_assert(align_axis >= 'X' && align_axis <= 'Z');
if (rv3d) {
- const float pi_2 = (float)M_PI / 2.0f;
float quat[4];
switch (align_axis) {
case 'X':
{
float quat_y[4];
- axis_angle_to_quat(quat_y, rv3d->viewinv[1], -pi_2);
+ axis_angle_to_quat(quat_y, rv3d->viewinv[1], -M_PI_2);
mul_qt_qtqt(quat, rv3d->viewquat, quat_y);
quat[0] = -quat[0];
@@ -182,7 +181,7 @@ void ED_object_rotation_from_view(bContext *C, float rot[3], const char align_ax
quat[0] = -quat[0];
quat_to_eul(rot, quat);
- rot[0] -= pi_2;
+ rot[0] -= (float)M_PI_2;
break;
}
case 'Z':
@@ -219,9 +218,9 @@ void ED_object_base_init_transform(bContext *C, Base *base, const float loc[3],
/* Uses context to figure out transform for primitive.
* Returns standard diameter. */
-float ED_object_new_primitive_matrix(bContext *C, Object *obedit,
- const float loc[3], const float rot[3], float primmat[4][4],
- bool apply_diameter)
+float ED_object_new_primitive_matrix(
+ bContext *C, Object *obedit,
+ const float loc[3], const float rot[3], float primmat[4][4])
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -246,13 +245,6 @@ float ED_object_new_primitive_matrix(bContext *C, Object *obedit,
{
const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) : ED_scene_grid_scale(scene, NULL);
-
- if (apply_diameter) {
- primmat[0][0] *= dia;
- primmat[1][1] *= dia;
- primmat[2][2] *= dia;
- }
-
return dia;
}
@@ -516,7 +508,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
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);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
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);
@@ -639,7 +631,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
DAG_id_tag_update(&obedit->id, OB_RECALC_DATA);
}
- ED_object_new_primitive_matrix(C, obedit, loc, rot, mat, false);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
dia = RNA_float_get(op->ptr, "radius");
add_metaball_primitive(C, obedit, mat, dia, RNA_enum_get(op->ptr, "type"));
diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c
index 83eeedfef52..fca527f8931 100644
--- a/source/blender/editors/object/object_bake_api.c
+++ b/source/blender/editors/object/object_bake_api.c
@@ -916,7 +916,7 @@ cage_cleanup:
BakeData *bake = &scene->r.bake;
char name[FILE_MAX];
- BKE_makepicstring_from_type(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false);
+ BKE_image_path_from_imtype(name, filepath, bmain->name, 0, bake->im_format.imtype, true, false);
if (is_automatic_name) {
BLI_path_suffix(name, FILE_MAX, ob_low->id.name + 2, "_");
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index 2596ea0a064..8f793f7f7f9 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -471,7 +471,7 @@ static void test_constraints(Object *owner, bPoseChannel *pchan)
/* TODO: clear subtarget? */
curcon->flag |= CONSTRAINT_DISABLE;
}
- else if (strcmp(pchan->name, ct->subtarget) == 0) {
+ else if (STREQ(pchan->name, ct->subtarget)) {
/* cannot target self */
ct->subtarget[0] = '\0';
curcon->flag |= CONSTRAINT_DISABLE;
diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c
index f6cf0312e2d..c57cae41bf4 100644
--- a/source/blender/editors/object/object_data_transfer.c
+++ b/source/blender/editors/object/object_data_transfer.c
@@ -42,6 +42,7 @@
#include "BKE_context.h"
#include "BKE_data_transfer.h"
+#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
@@ -82,6 +83,7 @@ static EnumPropertyItem DT_layer_items[] = {
{DT_TYPE_BWEIGHT_EDGE, "BEVEL_WEIGHT_EDGE", 0, "Bevel Weight", "Transfer bevel weights"},
{DT_TYPE_FREESTYLE_EDGE, "FREESTYLE_EDGE", 0, "Freestyle Mark", "Transfer Freestyle edge mark"},
{0, "", 0, "Face Corner Data", ""},
+ {DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
{DT_TYPE_VCOL, "VCOL", 0, "VCol", "Vertex (face corners) colors"},
{DT_TYPE_UV, "UV", 0, "UVs", "Transfer UV layers"},
{0, "", 0, "Face Data", ""},
@@ -393,6 +395,8 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
}
}
+ DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
+
if (reverse_transfer) {
SWAP(Object *, ob_src, ob_dst);
}
@@ -400,6 +404,8 @@ static int data_transfer_exec(bContext *C, wmOperator *op)
BLI_freelistN(&ctx_objects);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
#if 0 /* TODO */
/* Note: issue with that is that if canceled, operator cannot be redone... Nasty in our case. */
return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
@@ -592,6 +598,8 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op)
BKE_object_data_transfer_layout(scene, ob_src, ob_dst, dtmd->data_types, use_delete,
dtmd->layers_select_src, dtmd->layers_select_dst);
+
+ DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
}
else {
Object *ob_src = ob_act;
@@ -621,11 +629,15 @@ static int datalayout_transfer_exec(bContext *C, wmOperator *op)
BKE_object_data_transfer_layout(scene, ob_src, ob_dst, data_type, use_delete,
layers_select_src, layers_select_dst);
}
+
+ DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA);
}
BLI_freelistN(&ctx_objects);
}
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c
index 0a053d771df..64004de1087 100644
--- a/source/blender/editors/object/object_edit.c
+++ b/source/blender/editors/object/object_edit.c
@@ -42,6 +42,8 @@
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
+#include "BLF_translation.h"
+
#include "DNA_armature_types.h"
#include "DNA_curve_types.h"
#include "DNA_group_types.h"
@@ -1347,7 +1349,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op)
ID *data;
Curve *cu;
Nurb *nu;
- int clear = (strcmp(op->idname, "OBJECT_OT_shade_flat") == 0);
+ int clear = (STREQ(op->idname, "OBJECT_OT_shade_flat"));
bool done = false, linked_data = false;
CTX_DATA_BEGIN(C, Object *, ob, selected_editable_objects)
@@ -1701,7 +1703,7 @@ static int game_property_new_exec(bContext *C, wmOperator *op)
BLI_strncpy(prop->name, name, sizeof(prop->name));
}
- BKE_bproperty_unique(NULL, prop, 0); // make_unique_prop_names(prop->name);
+ BLI_uniquename(&ob->prop, prop, DATA_("Property"), '.', offsetof(bProperty, name), sizeof(prop->name));
WM_event_add_notifier(C, NC_LOGIC, NULL);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c
index 20e2e22cdf8..3c43f2729bd 100644
--- a/source/blender/editors/object/object_group.c
+++ b/source/blender/editors/object/object_group.c
@@ -61,47 +61,6 @@
/********************* 3d view operators ***********************/
-static bool group_link_early_exit_check(Group *group, Object *object)
-{
- GroupObject *group_object;
-
- for (group_object = group->gobject.first; group_object; group_object = group_object->next) {
- if (group_object->ob == object) {
- return true;
- }
- }
-
- return false;
-}
-
-static bool check_object_instances_group_recursive(Object *object, Group *group)
-{
- 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;
- }
- /* 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;
- }
-
- return false;
-}
-
/* can be called with C == NULL */
static EnumPropertyItem *group_object_active_itemf(bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
{
@@ -185,15 +144,12 @@ static int objects_add_active_exec(bContext *C, wmOperator *op)
if (!BKE_group_object_exists(group, ob))
continue;
- /* for recursive check */
- BKE_main_id_tag_listbase(&bmain->group, true);
-
CTX_DATA_BEGIN (C, Base *, base, selected_editable_bases)
{
- if (group_link_early_exit_check(group, base->object))
+ if (BKE_group_object_exists(group, base->object))
continue;
- if (!check_object_instances_group_recursive(base->object, group)) {
+ if (!BKE_group_object_cyclic_check(bmain, base->object, group)) {
BKE_group_object_add(group, base->object, scene, base);
updated = true;
}
@@ -486,7 +442,7 @@ static int group_link_exec(bContext *C, wmOperator *op)
* we could sckip all the dependency check and just consider
* operator is finished.
*/
- if (group_link_early_exit_check(group, ob)) {
+ if (BKE_group_object_exists(group, ob)) {
return OPERATOR_FINISHED;
}
@@ -495,8 +451,7 @@ static int group_link_exec(bContext *C, wmOperator *op)
* It is also bad idea to add object to group which is in group which
* contains our current object.
*/
- BKE_main_id_tag_listbase(&bmain->group, true);
- if (check_object_instances_group_recursive(ob, group)) {
+ if (BKE_group_object_cyclic_check(bmain, ob, group)) {
BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
return OPERATOR_CANCELLED;
}
diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c
index 9f9a647c9f1..1d764ced524 100644
--- a/source/blender/editors/object/object_hook.c
+++ b/source/blender/editors/object/object_hook.c
@@ -503,6 +503,15 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
unit_m4(pose_mat);
+ invert_m4_m4(obedit->imat, obedit->obmat);
+ if (mode == OBJECT_ADDHOOK_NEWOB) {
+ /* pass */
+ }
+ else {
+ /* may overwrite with pose-bone location, below */
+ mul_v3_m4v3(cent, obedit->imat, ob->obmat[3]);
+ }
+
if (mode == OBJECT_ADDHOOK_SELOB_BONE) {
bArmature *arm = ob->data;
BLI_assert(ob->type == OB_ARMATURE);
@@ -514,6 +523,8 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
pchan_act = BKE_pose_channel_active(ob);
if (LIKELY(pchan_act)) {
invert_m4_m4(pose_mat, pchan_act->pose_mat);
+ mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]);
+ mul_v3_m4v3(cent, obedit->imat, cent);
}
}
else {
@@ -521,6 +532,9 @@ static int add_hook_object(Main *bmain, Scene *scene, Object *obedit, Object *ob
}
}
+ copy_v3_v3(hmd->cent, cent);
+
+
/* matrix calculus */
/* vert x (obmat x hook->imat) x hook->obmat x ob->imat */
/* (parentinv ) */
diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c
index 5a479af83b5..bed85444101 100644
--- a/source/blender/editors/object/object_modifier.c
+++ b/source/blender/editors/object/object_modifier.c
@@ -440,9 +440,9 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
for (a = 0; a < totpart; a++) {
key = cache[a];
- if (key->steps > 0) {
- totvert += key->steps + 1;
- totedge += key->steps;
+ if (key->segments > 0) {
+ totvert += key->segments + 1;
+ totedge += key->segments;
}
}
@@ -450,9 +450,9 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
for (a = 0; a < totchild; a++) {
key = cache[a];
- if (key->steps > 0) {
- totvert += key->steps + 1;
- totedge += key->steps;
+ if (key->segments > 0) {
+ totvert += key->segments + 1;
+ totedge += key->segments;
}
}
@@ -476,7 +476,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
cache = psys->pathcache;
for (a = 0; a < totpart; a++) {
key = cache[a];
- kmax = key->steps;
+ kmax = key->segments;
for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) {
copy_v3_v3(mvert->co, key->co);
if (k) {
@@ -495,7 +495,7 @@ int ED_object_modifier_convert(ReportList *UNUSED(reports), Main *bmain, Scene *
cache = psys->childcache;
for (a = 0; a < totchild; a++) {
key = cache[a];
- kmax = key->steps;
+ kmax = key->segments;
for (k = 0; k <= kmax; k++, key++, cvert++, mvert++) {
copy_v3_v3(mvert->co, key->co);
if (k) {
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index 67b5c8061cd..430994aed60 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -973,7 +973,7 @@ void OBJECT_OT_parent_set(wmOperatorType *ot)
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- RNA_def_enum(ot->srna, "type", prop_make_parent_types, 0, "Type", "");
+ ot->prop = 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",
@@ -2344,10 +2344,8 @@ void OBJECT_OT_make_local(wmOperatorType *ot)
}
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,
+ MAKE_SINGLE_USER_ALL = 1,
+ MAKE_SINGLE_USER_SELECTED = 2,
};
static int make_single_user_exec(bContext *C, wmOperator *op)
@@ -2355,7 +2353,7 @@ 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 */
- const int flag = RNA_enum_get(op->ptr, "type");
+ const int flag = (RNA_enum_get(op->ptr, "type") == MAKE_SINGLE_USER_SELECTED) ? SELECT : 0;
const bool copy_groups = false;
bool update_deps = false;
@@ -2421,7 +2419,7 @@ void OBJECT_OT_make_single_user(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
- ot->prop = RNA_def_enum(ot->srna, "type", type_items, SELECT, "Type", "");
+ ot->prop = RNA_def_enum(ot->srna, "type", type_items, MAKE_SINGLE_USER_SELECTED, "Type", "");
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");
diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c
index e70281c502b..f885cbbb24f 100644
--- a/source/blender/editors/object/object_vgroup.c
+++ b/source/blender/editors/object/object_vgroup.c
@@ -1646,7 +1646,7 @@ static void vgroup_blend_subset(Object *ob, const bool *vgroup_validmap, const i
BMesh *bm = em ? em->bm : NULL;
Mesh *me = em ? NULL : ob->data;
- MeshElemMap *emap ;
+ MeshElemMap *emap;
int *emap_mem;
BLI_SMALLSTACK_DECLARE(dv_stack, MDeformVert *);
diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c
index 5e30ca4ed2f..fd32aad852d 100644
--- a/source/blender/editors/physics/particle_edit.c
+++ b/source/blender/editors/physics/particle_edit.c
@@ -61,7 +61,7 @@
#include "BKE_modifier.h"
#include "BKE_particle.h"
#include "BKE_report.h"
-
+#include "BKE_bvhutils.h"
#include "BKE_pointcache.h"
#include "BIF_gl.h"
@@ -85,8 +85,10 @@
static void PE_create_particle_edit_from_psys(Scene *scene, Object *ob, ParticleSystem *psys);
static void PE_create_particle_edit_from_cache(Scene *scene, Object *ob, PointCache *cache, ListBase *mem_cache);
-static void PTCacheUndo_clear(PTCacheEdit *edit);
-static void recalc_emitter_field(Object *ob, ParticleSystem *psys);
+void PTCacheUndo_clear(PTCacheEdit *edit);
+void recalc_lengths(PTCacheEdit *edit);
+void recalc_emitter_field(Object *ob, ParticleSystem *psys);
+void update_world_cos(Object *ob, PTCacheEdit *edit);
#define KEY_K PTCacheEditKey *key; int k
#define POINT_P PTCacheEditPoint *point; int p
@@ -362,6 +364,7 @@ typedef struct PEData {
Object *ob;
DerivedMesh *dm;
PTCacheEdit *edit;
+ BVHTreeFromMesh shape_bvh;
const int *mval;
rcti *rect;
@@ -418,6 +421,25 @@ static void PE_set_view3d_data(bContext *C, PEData *data)
}
}
+static void PE_create_shape_tree(PEData *data, Object *shapeob)
+{
+ DerivedMesh *dm = shapeob->derivedFinal;
+
+ memset(&data->shape_bvh, 0, sizeof(data->shape_bvh));
+
+ if (!dm) {
+ return;
+ }
+
+ DM_ensure_tessface(dm);
+ bvhtree_from_mesh_faces(&data->shape_bvh, dm, 0.0f, 4, 8);
+}
+
+static void PE_free_shape_tree(PEData *data)
+{
+ free_bvhtree_from_mesh(&data->shape_bvh);
+}
+
/*************************** selection utilities *******************************/
static bool key_test_depth(PEData *data, const float co[3], const int screen_co[2])
@@ -1062,7 +1084,7 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit)
}
}
/* set current distances to be kept between neighbouting keys */
-static void recalc_lengths(PTCacheEdit *edit)
+void recalc_lengths(PTCacheEdit *edit)
{
POINT_P; KEY_K;
@@ -1078,7 +1100,7 @@ static void recalc_lengths(PTCacheEdit *edit)
}
/* calculate a tree for finding nearest emitter's vertice */
-static void recalc_emitter_field(Object *ob, ParticleSystem *psys)
+void recalc_emitter_field(Object *ob, ParticleSystem *psys)
{
DerivedMesh *dm=psys_get_modifier(ob, psys)->dm;
PTCacheEdit *edit= psys->edit;
@@ -1166,7 +1188,7 @@ static void PE_update_selection(Scene *scene, Object *ob, int useflag)
point->flag &= ~PEP_EDIT_RECALC;
}
-static void update_world_cos(Object *ob, PTCacheEdit *edit)
+void update_world_cos(Object *ob, PTCacheEdit *edit)
{
ParticleSystem *psys = edit->psys;
ParticleSystemModifierData *psmd= psys_get_modifier(ob, psys);
@@ -3236,7 +3258,7 @@ static void brush_puff(PEData *data, int point_index)
static void BKE_brush_weight_get(PEData *data, float UNUSED(mat[4][4]), float UNUSED(imat[4][4]), int point_index, int key_index, PTCacheEditKey *UNUSED(key))
{
- /* roots have full weight allways */
+ /* roots have full weight always */
if (key_index) {
PTCacheEdit *edit = data->edit;
ParticleSystem *psys = edit->psys;
@@ -4039,6 +4061,180 @@ void PARTICLE_OT_brush_edit(wmOperatorType *ot)
RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
}
+/*********************** cut shape ***************************/
+
+static int shape_cut_poll(bContext *C)
+{
+ if (PE_hair_poll(C)) {
+ Scene *scene= CTX_data_scene(C);
+ ParticleEditSettings *pset= PE_settings(scene);
+
+ if (pset->shape_object)
+ return true;
+ }
+
+ return false;
+}
+
+typedef struct PointInsideBVH {
+ BVHTreeFromMesh bvhdata;
+ int num_hits;
+} PointInsideBVH;
+
+static void point_inside_bvh_cb(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit)
+{
+ PointInsideBVH *data = userdata;
+
+ data->bvhdata.raycast_callback(&data->bvhdata, index, ray, hit);
+
+ if (hit->index != -1)
+ ++data->num_hits;
+}
+
+/* true if the point is inside the shape mesh */
+static bool shape_cut_test_point(PEData *data, ParticleCacheKey *key)
+{
+ BVHTreeFromMesh *shape_bvh = &data->shape_bvh;
+ const float dir[3] = {1.0f, 0.0f, 0.0f};
+ PointInsideBVH userdata;
+
+ userdata.bvhdata = data->shape_bvh;
+ userdata.num_hits = 0;
+
+ BLI_bvhtree_ray_cast_all(shape_bvh->tree, key->co, dir, 0.0f, point_inside_bvh_cb, &userdata);
+
+ /* for any point inside a watertight mesh the number of hits is uneven */
+ return (userdata.num_hits % 2) == 1;
+}
+
+static void shape_cut(PEData *data, int pa_index)
+{
+ PTCacheEdit *edit = data->edit;
+ Object *ob = data->ob;
+ ParticleEditSettings *pset = PE_settings(data->scene);
+ ParticleCacheKey *key;
+
+ bool cut;
+ float cut_time = 1.0;
+ int k, totkeys = 1 << pset->draw_step;
+
+ /* don't cut hidden */
+ if (edit->points[pa_index].flag & PEP_HIDE)
+ return;
+
+ cut = false;
+
+ /* check if root is inside the cut shape */
+ key = edit->pathcache[pa_index];
+ if (!shape_cut_test_point(data, key)) {
+ cut_time = -1.0f;
+ cut = true;
+ }
+ else {
+ for (k = 0; k < totkeys; k++, key++) {
+ BVHTreeRayHit hit;
+ float dir[3];
+ float len;
+
+ sub_v3_v3v3(dir, (key+1)->co, key->co);
+ len = normalize_v3(dir);
+
+ memset(&hit, 0, sizeof(hit));
+ hit.index = -1;
+ hit.dist = len;
+ BLI_bvhtree_ray_cast(data->shape_bvh.tree, key->co, dir, 0.0f, &hit, data->shape_bvh.raycast_callback, &data->shape_bvh);
+ if (hit.index >= 0) {
+ if (hit.dist < len) {
+ cut_time = (hit.dist / len + (float)k) / (float)totkeys;
+ cut = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (cut) {
+ if (cut_time < 0.0f) {
+ edit->points[pa_index].flag |= PEP_TAG;
+ }
+ else {
+ rekey_particle_to_time(data->scene, ob, pa_index, cut_time);
+ edit->points[pa_index].flag |= PEP_EDIT_RECALC;
+ }
+ }
+}
+
+static int shape_cut_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+ ParticleEditSettings *pset = PE_settings(scene);
+ PTCacheEdit *edit = PE_get_current(scene, ob);
+ Object *shapeob = pset->shape_object;
+ int selected = count_selected_keys(scene, edit);
+ int lock_root = pset->flag & PE_LOCK_FIRST;
+
+ if (!PE_start_edit(edit))
+ return OPERATOR_CANCELLED;
+
+ /* disable locking temporatily for disconnected hair */
+ if (edit->psys && edit->psys->flag & PSYS_GLOBAL_HAIR)
+ pset->flag &= ~PE_LOCK_FIRST;
+
+ if (edit->psys && edit->pathcache) {
+ PEData data;
+ int removed;
+
+ PE_set_data(C, &data);
+ PE_create_shape_tree(&data, shapeob);
+
+ if (selected)
+ foreach_selected_point(&data, shape_cut);
+ else
+ foreach_point(&data, shape_cut);
+
+ removed = remove_tagged_particles(ob, edit->psys, pe_x_mirror(ob));
+ recalc_lengths(edit);
+
+ if (removed) {
+ update_world_cos(ob, edit);
+ psys_free_path_cache(NULL, edit);
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ }
+ else
+ PE_update_object(scene, ob, 1);
+
+ if (edit->psys) {
+ WM_event_add_notifier(C, NC_OBJECT|ND_PARTICLE|NA_EDITED, ob);
+ }
+ else {
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_event_add_notifier(C, NC_OBJECT|ND_MODIFIER, ob);
+ }
+
+ PE_free_shape_tree(&data);
+ }
+
+ pset->flag |= lock_root;
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_shape_cut(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Shape Cut";
+ ot->idname = "PARTICLE_OT_shape_cut";
+ ot->description = "Cut hair to conform to the set shape object";
+
+ /* api callbacks */
+ ot->exec = shape_cut_exec;
+ ot->poll = shape_cut_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
/*********************** undo ***************************/
static void free_PTCacheUndo(PTCacheUndo *undo)
@@ -4266,7 +4462,7 @@ int PE_undo_valid(Scene *scene)
return 0;
}
-static void PTCacheUndo_clear(PTCacheEdit *edit)
+void PTCacheUndo_clear(PTCacheEdit *edit)
{
PTCacheUndo *undo;
diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c
index 5a61f77e5a8..dba6d6f5085 100644
--- a/source/blender/editors/physics/particle_object.c
+++ b/source/blender/editors/physics/particle_object.c
@@ -40,18 +40,21 @@
#include "BLI_math.h"
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
+#include "BLI_string.h"
#include "BKE_context.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
#include "BKE_cdderivedmesh.h"
#include "BKE_global.h"
+#include "BKE_library.h"
#include "BKE_main.h"
+#include "BKE_modifier.h"
+#include "BKE_object.h"
#include "BKE_particle.h"
#include "BKE_pointcache.h"
#include "BKE_report.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
@@ -62,8 +65,37 @@
#include "ED_screen.h"
#include "ED_object.h"
+#include "UI_resources.h"
+
#include "physics_intern.h"
+extern void PE_create_particle_edit(Scene *scene, Object *ob, PointCache *cache, ParticleSystem *psys);
+extern void PTCacheUndo_clear(PTCacheEdit *edit);
+extern void recalc_lengths(PTCacheEdit *edit);
+extern void recalc_emitter_field(Object *ob, ParticleSystem *psys);
+extern void update_world_cos(Object *ob, PTCacheEdit *edit);
+
+#define KEY_K PTCacheEditKey *key; int k
+#define POINT_P PTCacheEditPoint *point; int p
+#define LOOP_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++)
+#if 0
+#define LOOP_VISIBLE_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!(point->flag & PEP_HIDE))
+#define LOOP_SELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point_is_selected(point))
+#define LOOP_UNSELECTED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (!point_is_selected(point))
+#define LOOP_EDITED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_EDIT_RECALC)
+#define LOOP_TAGGED_POINTS for (p=0, point=edit->points; p<edit->totpoint; p++, point++) if (point->flag & PEP_TAG)
+#endif
+#define LOOP_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++)
+#if 0
+#define LOOP_VISIBLE_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (!(key->flag & PEK_HIDE))
+#define LOOP_SELECTED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if ((key->flag & PEK_SELECT) && !(key->flag & PEK_HIDE))
+#define LOOP_TAGGED_KEYS for (k=0, key=point->keys; k<point->totkey; k++, key++) if (key->flag & PEK_TAG)
+
+#define KEY_WCO (key->flag & PEK_USE_WCO ? key->world_co : key->co)
+#endif
+
+static float I[4][4] = {{1.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 1.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 1.0f}};
+
/********************** particle system slot operators *********************/
static int particle_system_add_exec(bContext *C, wmOperator *UNUSED(op))
@@ -623,38 +655,50 @@ void PARTICLE_OT_disconnect_hair(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Disconnect all hair systems from the emitter mesh");
}
-static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
+/* from/to_world_space : whether from/to particles are in world or hair space
+ * from/to_mat : additional transform for from/to particles (e.g. for using object space copying)
+ */
+static bool remap_hair_emitter(Scene *scene, Object *ob, ParticleSystem *psys,
+ Object *target_ob, ParticleSystem *target_psys, PTCacheEdit *target_edit,
+ float from_mat[4][4], float to_mat[4][4], bool from_global, bool to_global)
{
- ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys);
- ParticleData *pa;
- PTCacheEdit *edit;
- PTCacheEditPoint *point;
- PTCacheEditKey *ekey = NULL;
- HairKey *key;
+ ParticleSystemModifierData *target_psmd = psys_get_modifier(target_ob, target_psys);
+ ParticleData *pa, *tpa;
+ PTCacheEditPoint *edit_point;
+ PTCacheEditKey *ekey;
BVHTreeFromMesh bvhtree= {NULL};
- BVHTreeNearest nearest;
MFace *mface = NULL, *mf;
MEdge *medge = NULL, *me;
MVert *mvert;
- DerivedMesh *dm = NULL;
+ DerivedMesh *dm, *target_dm;
int numverts;
int i, k;
- float hairmat[4][4], imat[4][4];
- float v[4][3], vec[3];
+ float from_ob_imat[4][4], to_ob_imat[4][4];
+ float from_imat[4][4], to_imat[4][4];
- if (!psys || !psys->part || psys->part->type != PART_HAIR || !psmd->dm)
+ if (!target_psmd->dm)
+ return false;
+ if (!psys->part || psys->part->type != PART_HAIR)
return false;
+ if (!target_psys->part || target_psys->part->type != PART_HAIR)
+ return false;
+
+ edit_point = target_edit ? target_edit->points : NULL;
- edit= psys->edit;
- point= edit ? edit->points : NULL;
+ invert_m4_m4(from_ob_imat, ob->obmat);
+ invert_m4_m4(to_ob_imat, target_ob->obmat);
+ invert_m4_m4(from_imat, from_mat);
+ invert_m4_m4(to_imat, to_mat);
- if (psmd->dm->deformedOnly) {
- /* we don't want to mess up psmd->dm when converting to global coordinates below */
- dm = psmd->dm;
+ if (target_psmd->dm->deformedOnly) {
+ /* we don't want to mess up target_psmd->dm when converting to global coordinates below */
+ dm = target_psmd->dm;
}
else {
- dm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+ /* warning: this rebuilds target_psmd->dm! */
+ dm = mesh_get_derived_deform(scene, target_ob, CD_MASK_BAREMESH);
}
+ target_dm = target_psmd->dm;
/* don't modify the original vertices */
dm = CDDM_copy(dm);
@@ -662,12 +706,11 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
DM_ensure_tessface(dm);
numverts = dm->getNumVerts(dm);
-
mvert = dm->getVertArray(dm);
/* convert to global coordinates */
for (i=0; i<numverts; i++)
- mul_m4_v3(ob->obmat, mvert[i].co);
+ mul_m4_v3(to_mat, mvert[i].co);
if (dm->getNumTessFaces(dm) != 0) {
mface = dm->getTessFaceArray(dm);
@@ -682,13 +725,23 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
return false;
}
- for (i=0, pa= psys->particles; i<psys->totpart; i++, pa++) {
- key = pa->hair;
+ for (i = 0, tpa = target_psys->particles, pa = psys->particles;
+ i < target_psys->totpart;
+ i++, tpa++, pa++) {
+
+ float from_co[3];
+ BVHTreeNearest nearest;
+
+ if (from_global)
+ mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].co);
+ else
+ mul_v3_m4v3(from_co, from_ob_imat, pa->hair[0].world_co);
+ mul_m4_v3(from_mat, from_co);
nearest.index = -1;
nearest.dist_sq = FLT_MAX;
- BLI_bvhtree_find_nearest(bvhtree.tree, key->co, &nearest, bvhtree.nearest_callback, &bvhtree);
+ BLI_bvhtree_find_nearest(bvhtree.tree, from_co, &nearest, bvhtree.nearest_callback, &bvhtree);
if (nearest.index == -1) {
if (G.debug & G_DEBUG)
@@ -697,6 +750,8 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
}
if (mface) {
+ float v[4][3];
+
mf = &mface[nearest.index];
copy_v3_v3(v[0], mvert[mf->v1].co);
@@ -704,44 +759,80 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
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);
+ interp_weights_poly_v3(tpa->fuv, v, 4, nearest.co);
}
else
- interp_weights_poly_v3(pa->fuv, v, 3, nearest.co);
+ interp_weights_poly_v3(tpa->fuv, v, 3, nearest.co);
+ tpa->foffset = 0.0f;
- pa->num = nearest.index;
- pa->num_dmcache = psys_particle_dm_face_lookup(ob, psmd->dm, pa->num, pa->fuv, NULL);
+ tpa->num = nearest.index;
+ tpa->num_dmcache = psys_particle_dm_face_lookup(target_ob, target_dm, tpa->num, tpa->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;
+ tpa->fuv[1] = line_point_factor_v3(nearest.co,
+ mvert[me->v1].co,
+ mvert[me->v2].co);
+ tpa->fuv[0] = 1.0f - tpa->fuv[1];
+ tpa->fuv[2] = tpa->fuv[3] = 0.0f;
+ tpa->foffset = 0.0f;
- pa->num = nearest.index;
- pa->num_dmcache = -1;
+ tpa->num = nearest.index;
+ tpa->num_dmcache = -1;
}
- psys_mat_hair_to_global(ob, psmd->dm, psys->part->from, pa, hairmat);
- invert_m4_m4(imat, hairmat);
-
- sub_v3_v3v3(vec, nearest.co, key->co);
-
- if (point) {
- ekey = point->keys;
- point++;
- }
-
- for (k=0, key=pa->hair; k<pa->totkey; k++, key++) {
- add_v3_v3(key->co, vec);
- mul_m4_v3(imat, key->co);
-
- if (ekey) {
- ekey->flag |= PEK_USE_WCO;
- ekey++;
+ /* translate hair keys */
+ {
+ HairKey *key, *tkey;
+ float hairmat[4][4], imat[4][4];
+ float offset[3];
+
+ if (to_global)
+ copy_m4_m4(imat, target_ob->obmat);
+ else {
+ /* note: using target_dm here, which is in target_ob object space and has full modifiers */
+ psys_mat_hair_to_object(target_ob, target_dm, target_psys->part->from, tpa, hairmat);
+ invert_m4_m4(imat, hairmat);
+ }
+ mul_m4_m4m4(imat, imat, to_imat);
+
+ /* offset in world space */
+ sub_v3_v3v3(offset, nearest.co, from_co);
+
+ if (edit_point) {
+ for (k=0, key=pa->hair, tkey=tpa->hair, ekey = edit_point->keys; k<tpa->totkey; k++, key++, tkey++, ekey++) {
+ float co_orig[3];
+
+ if (from_global)
+ mul_v3_m4v3(co_orig, from_ob_imat, key->co);
+ else
+ mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
+ mul_m4_v3(from_mat, co_orig);
+
+ add_v3_v3v3(tkey->co, co_orig, offset);
+
+ mul_m4_v3(imat, tkey->co);
+
+ ekey->flag |= PEK_USE_WCO;
+ }
+
+ edit_point++;
+ }
+ else {
+ for (k=0, key=pa->hair, tkey=tpa->hair; k<tpa->totkey; k++, key++, tkey++) {
+ float co_orig[3];
+
+ if (from_global)
+ mul_v3_m4v3(co_orig, from_ob_imat, key->co);
+ else
+ mul_v3_m4v3(co_orig, from_ob_imat, key->world_co);
+ mul_m4_v3(from_mat, co_orig);
+
+ add_v3_v3v3(tkey->co, co_orig, offset);
+
+ mul_m4_v3(imat, tkey->co);
+ }
}
}
}
@@ -749,15 +840,26 @@ static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
free_bvhtree_from_mesh(&bvhtree);
dm->release(dm);
- psys_free_path_cache(psys, psys->edit);
+ psys_free_path_cache(target_psys, target_edit);
- psys->flag &= ~PSYS_GLOBAL_HAIR;
-
- PE_update_object(scene, ob, 0);
+ PE_update_object(scene, target_ob, 0);
return true;
}
+static bool connect_hair(Scene *scene, Object *ob, ParticleSystem *psys)
+{
+ bool ok;
+
+ if (!psys)
+ return false;
+
+ ok = remap_hair_emitter(scene, ob, psys, ob, psys, psys->edit, ob->obmat, ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false);
+ psys->flag &= ~PSYS_GLOBAL_HAIR;
+
+ return ok;
+}
+
static int connect_hair_exec(bContext *C, wmOperator *op)
{
Scene *scene= CTX_data_scene(C);
@@ -805,3 +907,284 @@ void PARTICLE_OT_connect_hair(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "all", 0, "All hair", "Connect all hair systems to the emitter mesh");
}
+/************************ particle system copy operator *********************/
+
+typedef enum eCopyParticlesSpace {
+ PAR_COPY_SPACE_OBJECT = 0,
+ PAR_COPY_SPACE_WORLD = 1,
+} eCopyParticlesSpace;
+
+static void copy_particle_edit(Scene *scene, Object *ob, ParticleSystem *psys, ParticleSystem *psys_from)
+{
+ PTCacheEdit *edit_from = psys_from->edit, *edit;
+ ParticleData *pa;
+ KEY_K;
+ POINT_P;
+
+ if (!edit_from)
+ return;
+
+ edit = MEM_dupallocN(edit_from);
+ edit->psys = psys;
+ psys->edit = edit;
+
+ edit->pathcache = NULL;
+ BLI_listbase_clear(&edit->pathcachebufs);
+
+ edit->emitter_field = NULL;
+ edit->emitter_cosnos = NULL;
+
+ BLI_listbase_clear(&edit->undo);
+ edit->curundo = NULL;
+
+ edit->points = MEM_dupallocN(edit_from->points);
+ pa = psys->particles;
+ LOOP_POINTS {
+ HairKey *hkey = pa->hair;
+
+ point->keys= MEM_dupallocN(point->keys);
+ LOOP_KEYS {
+ key->co = hkey->co;
+ key->time = &hkey->time;
+ key->flag = hkey->editflag;
+ if (!(psys->flag & PSYS_GLOBAL_HAIR)) {
+ key->flag |= PEK_USE_WCO;
+ hkey->editflag |= PEK_USE_WCO;
+ }
+
+ hkey++;
+ }
+
+ pa++;
+ }
+ update_world_cos(ob, edit);
+
+ UI_GetThemeColor3ubv(TH_EDGE_SELECT, edit->sel_col);
+ UI_GetThemeColor3ubv(TH_WIRE, edit->nosel_col);
+
+ recalc_lengths(edit);
+ recalc_emitter_field(ob, psys);
+ PE_update_object(scene, ob, true);
+
+ PTCacheUndo_clear(edit);
+ PE_undo_push(scene, "Original");
+}
+
+static void remove_particle_systems_from_object(Object *ob_to)
+{
+ ModifierData *md, *md_next;
+
+ if (ob_to->type != OB_MESH)
+ return;
+ if (!ob_to->data || ((ID *)ob_to->data)->lib)
+ return;
+
+ for (md = ob_to->modifiers.first; md; md = md_next) {
+ md_next = md->next;
+
+ /* remove all particle system modifiers as well,
+ * these need to sync to the particle system list
+ */
+ if (ELEM(md->type, eModifierType_ParticleSystem, eModifierType_DynamicPaint, eModifierType_Smoke)) {
+ BLI_remlink(&ob_to->modifiers, md);
+ modifier_free(md);
+ }
+ }
+
+ BKE_object_free_particlesystems(ob_to);
+}
+
+/* single_psys_from is optional, if NULL all psys of ob_from are copied */
+static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, ParticleSystem *single_psys_from, Object *ob_to, int space)
+{
+ ModifierData *md;
+ ParticleSystem *psys_start, *psys, *psys_from;
+ ParticleSystem **tmp_psys;
+ DerivedMesh *final_dm;
+ CustomDataMask cdmask;
+ int i, totpsys;
+
+ if (ob_to->type != OB_MESH)
+ return false;
+ if (!ob_to->data || ((ID *)ob_to->data)->lib)
+ return false;
+
+ /* For remapping we need a valid DM.
+ * Because the modifiers are appended at the end it's safe to use
+ * the final DM of the object without particles.
+ * However, when evaluating the DM all the particle modifiers must be valid,
+ * i.e. have the psys assigned already.
+ * To break this hen/egg problem we create all psys separately first (to collect required customdata masks),
+ * then create the DM, then add them to the object and make the psys modifiers ...
+ */
+ #define PSYS_FROM_FIRST (single_psys_from ? single_psys_from : ob_from->particlesystem.first)
+ #define PSYS_FROM_NEXT(cur) (single_psys_from ? NULL : (cur)->next)
+ totpsys = single_psys_from ? 1 : BLI_listbase_count(&ob_from->particlesystem);
+
+ tmp_psys = MEM_mallocN(sizeof(ParticleSystem*) * totpsys, "temporary particle system array");
+
+ cdmask = 0;
+ for (psys_from = PSYS_FROM_FIRST, i = 0;
+ psys_from;
+ psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
+
+ psys = BKE_object_copy_particlesystem(psys_from);
+ tmp_psys[i] = psys;
+
+ if (psys_start == NULL)
+ psys_start = psys;
+
+ cdmask |= psys_emitter_customdata_mask(psys);
+ }
+ /* to iterate source and target psys in sync,
+ * we need to know where the newly added psys start
+ */
+ psys_start = totpsys > 0 ? tmp_psys[0] : NULL;
+
+ /* get the DM (psys and their modifiers have not been appended yet) */
+ final_dm = mesh_get_derived_final(scene, ob_to, cdmask);
+
+ /* now append psys to the object and make modifiers */
+ for (i = 0, psys_from = PSYS_FROM_FIRST;
+ i < totpsys;
+ ++i, psys_from = PSYS_FROM_NEXT(psys_from)) {
+
+ ParticleSystemModifierData *psmd;
+
+ psys = tmp_psys[i];
+
+ /* append to the object */
+ BLI_addtail(&ob_to->particlesystem, psys);
+
+ /* add a particle system modifier for each system */
+ md = modifier_new(eModifierType_ParticleSystem);
+ psmd = (ParticleSystemModifierData *)md;
+ /* push on top of the stack, no use trying to reproduce old stack order */
+ BLI_addtail(&ob_to->modifiers, md);
+
+ BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i);
+ modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd);
+
+ psmd->psys = psys;
+ psmd->dm = CDDM_copy(final_dm);
+ CDDM_calc_normals(psmd->dm);
+ DM_ensure_tessface(psmd->dm);
+
+ if (psys_from->edit)
+ copy_particle_edit(scene, ob_to, psys, psys_from);
+ }
+ MEM_freeN(tmp_psys);
+
+ /* note: do this after creating DM copies for all the particle system modifiers,
+ * the remapping otherwise makes final_dm invalid!
+ */
+ for (psys = psys_start, psys_from = PSYS_FROM_FIRST, i = 0;
+ psys;
+ psys = psys->next, psys_from = PSYS_FROM_NEXT(psys_from), ++i) {
+
+ float (*from_mat)[4], (*to_mat)[4];
+
+ switch (space) {
+ case PAR_COPY_SPACE_OBJECT:
+ from_mat = I;
+ to_mat = I;
+ break;
+ case PAR_COPY_SPACE_WORLD:
+ from_mat = ob_from->obmat;
+ to_mat = ob_to->obmat;
+ break;
+ default:
+ /* should not happen */
+ BLI_assert(false);
+ break;
+ }
+
+ remap_hair_emitter(scene, ob_from, psys_from, ob_to, psys, psys->edit, from_mat, to_mat, psys_from->flag & PSYS_GLOBAL_HAIR, psys->flag & PSYS_GLOBAL_HAIR);
+
+ /* tag for recalc */
+// psys->recalc |= PSYS_RECALC_RESET;
+ }
+
+ #undef PSYS_FROM_FIRST
+ #undef PSYS_FROM_NEXT
+
+ DAG_id_tag_update(&ob_to->id, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, ob_to);
+ return true;
+}
+
+static int copy_particle_systems_poll(bContext *C)
+{
+ Object *ob;
+ if (!ED_operator_object_active_editable(C))
+ return false;
+
+ ob = ED_object_active_context(C);
+ if (BLI_listbase_is_empty(&ob->particlesystem))
+ return false;
+
+ return true;
+}
+
+static int copy_particle_systems_exec(bContext *C, wmOperator *op)
+{
+ const int space = RNA_enum_get(op->ptr, "space");
+ const bool remove_target_particles = RNA_boolean_get(op->ptr, "remove_target_particles");
+ const bool use_active = RNA_boolean_get(op->ptr, "use_active");
+ Scene *scene = CTX_data_scene(C);
+ Object *ob_from = ED_object_active_context(C);
+ ParticleSystem *psys_from = use_active ? CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data : NULL;
+
+ int changed_tot = 0;
+ int fail = 0;
+
+ CTX_DATA_BEGIN (C, Object *, ob_to, selected_editable_objects)
+ {
+ if (ob_from != ob_to) {
+ bool changed = false;
+ if (remove_target_particles) {
+ remove_particle_systems_from_object(ob_to);
+ changed = true;
+ }
+ if (copy_particle_systems_to_object(scene, ob_from, psys_from, ob_to, space))
+ changed = true;
+ else
+ fail++;
+
+ if (changed)
+ changed_tot++;
+ }
+ }
+ CTX_DATA_END;
+
+ if ((changed_tot == 0 && fail == 0) || fail) {
+ BKE_reportf(op->reports, RPT_ERROR,
+ "Copy particle systems to selected: %d done, %d failed",
+ changed_tot, fail);
+ }
+
+ return OPERATOR_FINISHED;
+}
+
+void PARTICLE_OT_copy_particle_systems(wmOperatorType *ot)
+{
+ static EnumPropertyItem space_items[] = {
+ {PAR_COPY_SPACE_OBJECT, "OBJECT", 0, "Object", "Copy inside each object's local space"},
+ {PAR_COPY_SPACE_WORLD, "WORLD", 0, "World", "Copy in world space"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ ot->name = "Copy Particle Systems";
+ ot->description = "Copy particle systems from the active object to selected objects";
+ ot->idname = "PARTICLE_OT_copy_particle_systems";
+
+ ot->poll = copy_particle_systems_poll;
+ ot->exec = copy_particle_systems_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ RNA_def_enum(ot->srna, "space", space_items, PAR_COPY_SPACE_OBJECT, "Space", "Space transform for copying from one object to another");
+ RNA_def_boolean(ot->srna, "remove_target_particles", true, "Remove Target Particles", "Remove particle systems on the target objects");
+ RNA_def_boolean(ot->srna, "use_active", false, "Use Active", "Use the active particle system from the context");
+}
diff --git a/source/blender/editors/physics/physics_intern.h b/source/blender/editors/physics/physics_intern.h
index 8c49bf21191..88542515553 100644
--- a/source/blender/editors/physics/physics_intern.h
+++ b/source/blender/editors/physics/physics_intern.h
@@ -56,6 +56,8 @@ void PARTICLE_OT_mirror(struct wmOperatorType *ot);
void PARTICLE_OT_brush_edit(struct wmOperatorType *ot);
+void PARTICLE_OT_shape_cut(struct wmOperatorType *ot);
+
void PARTICLE_OT_particle_edit_toggle(struct wmOperatorType *ot);
void PARTICLE_OT_edited_clear(struct wmOperatorType *ot);
@@ -70,6 +72,7 @@ void PARTICLE_OT_target_move_up(struct wmOperatorType *ot);
void PARTICLE_OT_target_move_down(struct wmOperatorType *ot);
void PARTICLE_OT_connect_hair(struct wmOperatorType *ot);
void PARTICLE_OT_disconnect_hair(struct wmOperatorType *ot);
+void PARTICLE_OT_copy_particle_systems(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_copy(struct wmOperatorType *ot);
void PARTICLE_OT_dupliob_remove(struct wmOperatorType *ot);
diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c
index 37cf95e5c2d..8f32b0dffe9 100644
--- a/source/blender/editors/physics/physics_ops.c
+++ b/source/blender/editors/physics/physics_ops.c
@@ -64,6 +64,8 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_brush_edit);
+ WM_operatortype_append(PARTICLE_OT_shape_cut);
+
WM_operatortype_append(PARTICLE_OT_particle_edit_toggle);
WM_operatortype_append(PARTICLE_OT_edited_clear);
@@ -78,6 +80,7 @@ static void operatortypes_particle(void)
WM_operatortype_append(PARTICLE_OT_target_move_down);
WM_operatortype_append(PARTICLE_OT_connect_hair);
WM_operatortype_append(PARTICLE_OT_disconnect_hair);
+ WM_operatortype_append(PARTICLE_OT_copy_particle_systems);
WM_operatortype_append(PARTICLE_OT_dupliob_copy);
WM_operatortype_append(PARTICLE_OT_dupliob_remove);
diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c
index 8024add41cf..fc6ff4eb0c0 100644
--- a/source/blender/editors/render/render_opengl.c
+++ b/source/blender/editors/render/render_opengl.c
@@ -315,8 +315,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
/* rr->rectf is now filled with image data */
- if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW))
- BKE_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4);
+ if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) {
+ BKE_image_stamp_buf(scene, camera, rect, rr->rectf, rr->rectx, rr->recty, 4);
+ }
RE_ReleaseResult(oglrender->re);
@@ -335,8 +336,9 @@ static void screen_opengl_render_apply(OGLRender *oglrender)
IMB_color_to_bw(ibuf);
}
- BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
ok = BKE_imbuf_write_as(ibuf, name, &scene->r.im_format, true); /* no need to stamp here */
if (ok) printf("OpenGL Render written to '%s'\n", name);
else printf("OpenGL Render failed to write '%s'\n", name);
@@ -564,8 +566,9 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op)
is_movie = BKE_imtype_is_movie(scene->r.im_format.imtype);
if (!is_movie) {
- BKE_makepicstring(name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, oglrender->bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) {
BKE_reportf(op->reports, RPT_INFO, "Skipping existing frame \"%s\"", name);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index ea80a07fdd4..99edaff759e 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -359,7 +359,7 @@ static Scene *preview_prepare_scene(Scene *scene, ID *id, int id_type, ShaderPre
for (base = sce->base.first; base; base = base->next) {
if (base->object->type == OB_LAMP) {
/* if doesn't match 'Lamp.002' --> main key light */
- if (strcmp(base->object->id.name + 2, "Lamp.002") != 0) {
+ if (!STREQ(base->object->id.name + 2, "Lamp.002")) {
if (mat->material_type == MA_TYPE_VOLUME)
base->object->restrictflag |= OB_RESTRICT_RENDER;
else
@@ -1100,7 +1100,7 @@ static void icon_preview_free(void *customdata)
void ED_preview_icon_render(Scene *scene, ID *id, unsigned int *rect, int sizex, int sizey)
{
- IconPreview ip = {0};
+ IconPreview ip = {NULL};
short stop = false, update = false;
float progress = 0.0f;
diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c
index 91c689373be..94a3defa95a 100644
--- a/source/blender/editors/render/render_shading.c
+++ b/source/blender/editors/render/render_shading.c
@@ -1412,7 +1412,7 @@ static int envmap_save_exec(bContext *C, wmOperator *op)
RNA_string_get(op->ptr, "filepath", path);
if (scene->r.scemode & R_EXTENSION) {
- BKE_add_image_extension(path, &scene->r.im_format);
+ BKE_image_path_ensure_ext_from_imformat(path, &scene->r.im_format);
}
WM_cursor_wait(1);
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index ab28f5fa675..fe357a7a0e2 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -161,11 +161,19 @@ ScrArea *render_view_open(bContext *C, int mx, int my)
}
else if (scene->r.displaymode == R_OUTPUT_SCREEN) {
sa = CTX_wm_area(C);
- if (sa && sa->spacetype == SPACE_IMAGE)
- area_was_image = true;
- /* this function returns with changed context */
- sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE);
+ /* if the active screen is already in fullscreen mode, skip this and
+ * unset the area, so that the fullscreen area is just changed later */
+ if (sa && sa->full) {
+ sa = NULL;
+ }
+ else {
+ if (sa && sa->spacetype == SPACE_IMAGE)
+ area_was_image = true;
+
+ /* this function returns with changed context */
+ sa = ED_screen_full_newspace(C, sa, SPACE_IMAGE);
+ }
}
if (!sa) {
@@ -186,10 +194,15 @@ ScrArea *render_view_open(bContext *C, int mx, int my)
/* makes ESC go back to prev space */
sima->flag |= SI_PREVSPACE;
+
+ /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
+ if (sa->full) {
+ sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
+ }
}
else {
/* use any area of decent size */
- sa = BKE_screen_find_big_area(CTX_wm_screen(C), -1, 0);
+ sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
if (sa->spacetype != SPACE_IMAGE) {
// XXX newspace(sa, SPACE_IMAGE);
sima = sa->spacedata.first;
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 71714bdcda9..83b22bb1a8a 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1645,6 +1645,8 @@ void ED_area_prevspace(bContext *C, ScrArea *sa)
/* no change */
return;
}
+ sa->flag &= ~AREA_FLAG_STACKED_FULLSCREEN;
+
ED_area_tag_redraw(sa);
/* send space change notifier */
@@ -2161,4 +2163,3 @@ void ED_region_cache_draw_cached_segments(const ARegion *ar, const int num_segme
}
}
}
-
diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c
index 134feb59d55..4c1698bd1d4 100644
--- a/source/blender/editors/screen/glutil.c
+++ b/source/blender/editors/screen/glutil.c
@@ -1136,9 +1136,9 @@ void glaDrawImBuf_glsl_ctx(const bContext *C, ImBuf *ibuf, float x, float y, int
void cpack(unsigned int x)
{
- glColor3ub( ( (x) & 0xFF),
- (((x) >> 8) & 0xFF),
- (((x) >> 16) & 0xFF) );
+ glColor3ub(( (x) & 0xFF),
+ (((x) >> 8) & 0xFF),
+ (((x) >> 16) & 0xFF));
}
void glaDrawBorderCorners(const rcti *border, float zoomx, float zoomy)
diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c
index ce9c608247b..3431ce9f50a 100644
--- a/source/blender/editors/screen/screen_context.c
+++ b/source/blender/editors/screen/screen_context.c
@@ -497,7 +497,9 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult
bGPDstroke *gps;
for (gps = gpf->strokes.first; gps; gps = gps->next) {
- CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
+ if (ED_gpencil_stroke_can_use_direct(sa, gps)) {
+ CTX_data_list_add(result, &gpd->id, &RNA_GPencilStroke, gps);
+ }
}
}
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index 3972d00293c..f338fa160f5 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1762,15 +1762,16 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
{
- wmWindow *win = CTX_wm_window(C);
-
- ED_area_prevspace(C, sa);
-
- if (sa->full)
- ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
+ if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) {
+ /* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */
+ ED_area_prevspace(C, sa);
+ }
+ else {
+ ED_screen_restore_temp_type(C, sa);
+ }
}
-void ED_screen_retore_temp_type(bContext *C, ScrArea *sa, bool is_screen_change)
+void ED_screen_restore_temp_type(bContext *C, ScrArea *sa)
{
/* incase nether functions below run */
ED_area_tag_redraw(sa);
@@ -1780,7 +1781,7 @@ void ED_screen_retore_temp_type(bContext *C, ScrArea *sa, bool is_screen_change)
sa->flag &= ~AREA_FLAG_TEMP_TYPE;
}
- if (is_screen_change && sa->full) {
+ if (sa->full) {
ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED);
}
}
@@ -1793,25 +1794,11 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
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 */
+ /* if fullscreen area has a temporary space (such as a file browser or fullscreen render
+ * overlaid on top of an existing setup) then return to the previous space */
if (sl->next) {
- /* specific checks for space types */
-
- /* Special check added for non-render image window (back from fullscreen through "Back to Previous" button) */
- if (sl->spacetype == SPACE_IMAGE) {
- SpaceImage *sima = sa->spacedata.first;
-
- if (sima->flag & (SI_PREVSPACE | SI_FULLWINDOW)) {
- sima->flag &= ~SI_PREVSPACE;
- sima->flag &= ~SI_FULLWINDOW;
- ED_screen_full_prevspace(C, sa);
- }
- else
- ED_screen_state_toggle(C, win, sa, state);
- }
- else if (sa->flag & AREA_FLAG_TEMP_TYPE) {
+ if (sa->flag & AREA_FLAG_TEMP_TYPE) {
ED_screen_full_prevspace(C, sa);
}
else {
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index 39321ec0770..ad3d2d1a21a 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -598,19 +598,6 @@ typedef struct sActionzoneData {
int x, y, gesture_dir, modifier;
} sActionzoneData;
-/* used by other operators too */
-static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
-{
- ScrArea *sa = NULL;
- sa = scr->areabase.first;
- while (sa) {
- if (BLI_rcti_isect_pt(&sa->totrct, x, y)) break;
- sa = sa->next;
- }
-
- return sa;
-}
-
/* quick poll to save operators to be created and handled */
static int actionzone_area_poll(bContext *C)
{
@@ -808,7 +795,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* gesture is large enough? */
if (is_gesture) {
/* second area, for join when (sa1 != sa2) */
- sad->sa2 = screen_areahascursor(sc, event->x, event->y);
+ sad->sa2 = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y);
/* apply sends event */
actionzone_apply(C, op, sad->az->type);
actionzone_exit(op);
@@ -929,7 +916,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event)
switch (event->type) {
case MOUSEMOVE:
/* second area, for join */
- sad->sa2 = screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
+ sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y);
break;
case LEFTMOUSE: /* release LMB */
if (event->val == KM_RELEASE) {
@@ -1679,7 +1666,8 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event)
sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H | AREA_FLAG_DRAWSPLIT_V);
ED_area_tag_redraw(sd->sarea);
}
- sd->sarea = screen_areahascursor(CTX_wm_screen(C), event->x, event->y); /* area context not set */
+ /* area context not set */
+ sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->x, event->y);
if (sd->sarea) {
ED_area_tag_redraw(sd->sarea);
@@ -2482,8 +2470,8 @@ static int area_join_init(bContext *C, wmOperator *op)
x2 = RNA_int_get(op->ptr, "max_x");
y2 = RNA_int_get(op->ptr, "max_y");
- sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
- sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
+ sa1 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, x1, y1);
+ sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, x2, y2);
if (sa1 == NULL || sa2 == NULL || sa1 == sa2)
return 0;
@@ -2616,7 +2604,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event)
case MOUSEMOVE:
{
- ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
+ ScrArea *sa = BKE_screen_find_area_xy(sc, SPACE_TYPE_ANY, event->x, event->y);
int dir;
if (sa) {
@@ -3399,7 +3387,12 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
(sad->flag & ANIMPLAY_FLAG_REVERSE) == false &&
finite(time = sound_sync_scene(scene)))
{
- scene->r.cfra = (double)time * FPS + 0.5;
+ double newfra = (double)time * FPS;
+ /* give some space here to avoid jumps */
+ if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra)
+ scene->r.cfra++;
+ else
+ scene->r.cfra = newfra + 0.5;
}
else {
if (sync) {
@@ -3476,11 +3469,29 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv
for (sa = window->screen->areabase.first; sa; sa = sa->next) {
ARegion *ar;
for (ar = sa->regionbase.first; ar; ar = ar->next) {
+ bool redraw = false;
if (ar == sad->ar) {
- ED_region_tag_redraw(ar);
+ redraw = true;
}
else if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws)) {
+ redraw = true;
+ }
+
+ if (redraw) {
ED_region_tag_redraw(ar);
+ /* do follow here if editor type supports it */
+ if ((sad->redraws & TIME_FOLLOW)) {
+ if ((ar->regiontype == RGN_TYPE_WINDOW &&
+ ELEM (sa->spacetype, SPACE_SEQ, SPACE_TIME, SPACE_IPO, SPACE_ACTION, SPACE_NLA)) ||
+ (sa->spacetype == SPACE_CLIP && ar->regiontype == RGN_TYPE_PREVIEW))
+ {
+ float w = BLI_rctf_size_x(&ar->v2d.cur);
+ if (scene->r.cfra < ar->v2d.cur.xmin || scene->r.cfra > (ar->v2d.cur.xmax)) {
+ ar->v2d.cur.xmin = scene->r.cfra;
+ ar->v2d.cur.xmax = ar->v2d.cur.xmin + w;
+ }
+ }
+ }
}
}
@@ -3546,6 +3557,8 @@ int ED_screen_animation_play(bContext *C, int sync, int mode)
/* stop playback now */
ED_screen_animation_timer(C, 0, 0, 0, 0);
sound_stop_scene(scene);
+
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
}
else {
int refresh = SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */
@@ -3707,9 +3720,9 @@ static int fullscreen_back_exec(bContext *C, wmOperator *op)
BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found");
return OPERATOR_CANCELLED;
}
-
- ED_screen_full_restore(C, sa);
-
+
+ ED_screen_full_prevspace(C, sa);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index e7f256e414a..9c05f1d4780 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -377,8 +377,9 @@ static void screenshot_startjob(void *sjv, short *stop, short *do_update, float
char name[FILE_MAX];
int ok;
- BKE_makepicstring(name, rd.pic, sj->bmain->name, rd.cfra,
- &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true);
+ BKE_image_path_from_imformat(
+ name, rd.pic, sj->bmain->name, rd.cfra,
+ &rd.im_format, (rd.scemode & R_EXTENSION) != 0, true);
ibuf->rect = sj->dumprect;
ok = BKE_imbuf_write(ibuf, name, &rd.im_format);
diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c
index 430ea1cc11d..2d425b7e5a0 100644
--- a/source/blender/editors/sculpt_paint/paint_cursor.c
+++ b/source/blender/editors/sculpt_paint/paint_cursor.c
@@ -652,16 +652,12 @@ static void paint_draw_tex_overlay(UnifiedPaintSettings *ups, Brush *brush,
}
/* set quad color. Colored overlay does not get blending */
- if (col)
- glColor4f(1.0,
- 1.0,
- 1.0,
- overlay_alpha / 100.0f);
- else
- glColor4f(U.sculpt_paint_overlay_col[0],
- U.sculpt_paint_overlay_col[1],
- U.sculpt_paint_overlay_col[2],
- overlay_alpha / 100.0f);
+ if (col) {
+ glColor4f(1.0, 1.0, 1.0, overlay_alpha / 100.0f);
+ }
+ else {
+ glColor4f(UNPACK3(U.sculpt_paint_overlay_col), overlay_alpha / 100.0f);
+ }
/* draw textured quad */
glBegin(GL_QUADS);
diff --git a/source/blender/editors/sculpt_paint/paint_curve.c b/source/blender/editors/sculpt_paint/paint_curve.c
index 1f5ee708ad0..439c2a639bd 100644
--- a/source/blender/editors/sculpt_paint/paint_curve.c
+++ b/source/blender/editors/sculpt_paint/paint_curve.c
@@ -108,7 +108,7 @@ static void paintcurve_undo_restore(bContext *C, ListBase *lb)
uc = (UndoCurve *)lb->first;
- if (strncmp(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname))) == 0) {
+ if (STREQLEN(uc->idname, pc->id.name, BLI_strnlen(uc->idname, sizeof(uc->idname)))) {
SWAP(PaintCurvePoint *, pc->points, uc->points);
SWAP(int, pc->tot_points, uc->tot_points);
SWAP(int, pc->add_index, uc->active_point);
diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c
index d52b17372f7..5cfbd164153 100644
--- a/source/blender/editors/sculpt_paint/paint_image.c
+++ b/source/blender/editors/sculpt_paint/paint_image.c
@@ -158,9 +158,10 @@ static void undo_copy_tile(UndoImageTile *tile, ImBuf *tmpibuf, ImBuf *ibuf, Cop
}
}
else {
- if (mode == RESTORE_COPY)
+ 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);
+ 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);
@@ -192,7 +193,7 @@ void *image_undo_find_tile(Image *ima, ImBuf *ibuf, int x_tile, int y_tile, unsi
for (tile = lb->first; tile; tile = tile->next) {
if (tile->x == x_tile && tile->y == y_tile && ima->gen_type == tile->gen_type && ima->source == tile->source) {
if (tile->use_float == use_float) {
- if (strcmp(tile->idname, ima->id.name) == 0 && strcmp(tile->ibufname, ibuf->name) == 0) {
+ if (STREQ(tile->idname, ima->id.name) && STREQ(tile->ibufname, ibuf->name)) {
if (mask) {
/* allocate mask if requested */
if (!tile->mask) {
@@ -327,7 +328,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
short use_float;
/* find image based on name, pointer becomes invalid with global undo */
- if (ima && strcmp(tile->idname, ima->id.name) == 0) {
+ if (ima && STREQ(tile->idname, ima->id.name)) {
/* ima is valid */
}
else {
@@ -336,7 +337,7 @@ void ED_image_undo_restore(bContext *C, ListBase *lb)
ibuf = BKE_image_acquire_ibuf(ima, NULL, NULL);
- if (ima && ibuf && strcmp(tile->ibufname, ibuf->name) != 0) {
+ if (ima && ibuf && !STREQ(tile->ibufname, ibuf->name)) {
/* current ImBuf filename was changed, probably current frame
* was changed when painting on image sequence, rather than storing
* full image user (which isn't so obvious, btw) try to find ImBuf with
diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c
index 3e675012d05..098477ed2a1 100644
--- a/source/blender/editors/sculpt_paint/paint_image_proj.c
+++ b/source/blender/editors/sculpt_paint/paint_image_proj.c
@@ -203,6 +203,7 @@ typedef struct ProjPaintState {
/* the paint color. It can change depending of inverted mode or not */
float paint_color[3];
float paint_color_linear[3];
+ float dither;
Brush *brush;
short tool, blend, mode;
@@ -422,17 +423,19 @@ static int project_bucket_offset_safe(const ProjPaintState *ps, const float proj
}
}
-static float VecZDepthOrtho(const float pt[2],
- const float v1[3], const float v2[3], const float v3[3],
- float w[3])
+static float VecZDepthOrtho(
+ const float pt[2],
+ const float v1[3], const float v2[3], const float v3[3],
+ float w[3])
{
barycentric_weights_v2(v1, v2, v3, pt, w);
return (v1[2] * w[0]) + (v2[2] * w[1]) + (v3[2] * w[2]);
}
-static float VecZDepthPersp(const float pt[2],
- const float v1[4], const float v2[4], const float v3[4],
- float w[3])
+static float VecZDepthPersp(
+ const float pt[2],
+ const float v1[4], const float v2[4], const float v3[4],
+ float w[3])
{
float wtot_inv, wtot;
float w_tmp[3];
@@ -542,8 +545,9 @@ static void uvco_to_wrapped_pxco(const float uv[2], int ibuf_x, int ibuf_y, floa
}
/* Set the top-most face color that the screen space coord 'pt' touches (or return 0 if none touch) */
-static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
- float *rgba_fp, unsigned char *rgba, const bool interp)
+static bool project_paint_PickColor(
+ const ProjPaintState *ps, const float pt[2],
+ float *rgba_fp, unsigned char *rgba, const bool interp)
{
float w[3], uv[2];
int side;
@@ -637,9 +641,10 @@ static bool project_paint_PickColor(const ProjPaintState *ps, const float pt[2],
* 1 : occluded
* 2 : occluded with w[3] weights set (need to know in some cases) */
-static int project_paint_occlude_ptv(const float pt[3],
- const float v1[4], const float v2[4], const float v3[4],
- float w[3], const bool is_ortho)
+static int project_paint_occlude_ptv(
+ const float pt[3],
+ const float v1[4], const float v2[4], const float v3[4],
+ float w[3], const bool is_ortho)
{
/* if all are behind us, return false */
if (v1[2] > pt[2] && v2[2] > pt[2] && v3[2] > pt[2])
@@ -669,9 +674,10 @@ static int project_paint_occlude_ptv(const float pt[3],
}
-static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace *mf,
- const float pt[3], const float v1[4], const float v2[4], const float v3[4],
- const int side)
+static int project_paint_occlude_ptv_clip(
+ const ProjPaintState *ps, const MFace *mf,
+ const float pt[3], const float v1[4], const float v2[4], const float v3[4],
+ const int side)
{
float w[3], wco[3];
int ret = project_paint_occlude_ptv(pt, v1, v2, v3, w, ps->is_ortho);
@@ -699,8 +705,9 @@ static int project_paint_occlude_ptv_clip(const ProjPaintState *ps, const MFace
/* Check if a screenspace location is occluded by any other faces
* check, pixelScreenCo must be in screenspace, its Z-Depth only needs to be used for comparison
* and doesn't need to be correct in relation to X and Y coords (this is the case in perspective view) */
-static bool project_bucket_point_occluded(const ProjPaintState *ps, LinkNode *bucketFace,
- const int orig_face, const float pixelScreenCo[4])
+static bool project_bucket_point_occluded(
+ const ProjPaintState *ps, LinkNode *bucketFace,
+ const int orig_face, const float pixelScreenCo[4])
{
MFace *mf;
int face_index;
@@ -912,9 +919,10 @@ static void project_face_winding_init(const ProjPaintState *ps, const int face_i
/* 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,
- const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx,
- int *other_face, int *orig_fidx)
+static bool check_seam(
+ const ProjPaintState *ps,
+ const int orig_face, const int orig_i1_fidx, const int orig_i2_fidx,
+ int *other_face, int *orig_fidx)
{
LinkNode *node;
int face_index;
@@ -1003,8 +1011,9 @@ BLI_INLINE float shell_v2v2_normal_dir_to_dist(float n[2], float d[2])
/* Calculate outset UV's, this is not the same as simply scaling the UVs,
* since the outset coords are a margin that keep an even distance from the original UV's,
* note that the image aspect is taken into account */
-static void uv_image_outset(float (*orig_uv)[2], float (*outset_uv)[2], const float scaler,
- const int ibuf_x, const int ibuf_y, const bool is_quad, const bool cw)
+static void uv_image_outset(
+ float (*orig_uv)[2], float (*outset_uv)[2], const float scaler,
+ const int ibuf_x, const int ibuf_y, const bool is_quad, const bool cw)
{
float a1, a2, a3, a4 = 0.0f;
float puv[4][2]; /* pixelspace uv's */
@@ -1212,8 +1221,9 @@ static void screen_px_from_persp(
}
-static void project_face_pixel(const MTFace *tf_other, ImBuf *ibuf_other, const float w[3],
- int side, unsigned char rgba_ub[4], float rgba_f[4])
+static void project_face_pixel(
+ const MTFace *tf_other, ImBuf *ibuf_other, const float w[3],
+ int side, unsigned char rgba_ub[4], float rgba_f[4])
{
const float *uvCo1, *uvCo2, *uvCo3;
float uv_other[2], x, y;
@@ -1454,7 +1464,7 @@ static ProjPixel *project_paint_uvpixel_init(
y_px = mod_i(y_px, ibuf->y);
BLI_assert(ps->pixel_sizeof == project_paint_pixel_sizeof(ps->tool));
- projPixel = (ProjPixel *)BLI_memarena_alloc(arena, ps->pixel_sizeof);
+ 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 */
@@ -1585,7 +1595,7 @@ static ProjPixel *project_paint_uvpixel_init(
}
static bool line_clip_rect2f(
- rctf *rect,
+ const rctf *rect,
const float l1[2], const float l2[2],
float l1_clip[2], float l2_clip[2])
{
@@ -1800,7 +1810,7 @@ static float len_squared_v2v2_alt(const float v1[2], const float v2_1, const flo
/* note, use a squared value so we can use len_squared_v2v2
* be sure that you have done a bounds check first or this may fail */
/* only give bucket_bounds as an arg because we need it elsewhere */
-static bool project_bucket_isect_circle(const float cent[2], const float radius_squared, rctf *bucket_bounds)
+static bool project_bucket_isect_circle(const float cent[2], const float radius_squared, const rctf *bucket_bounds)
{
/* Would normally to a simple intersection test, however we know the bounds of these 2 already intersect
@@ -1855,7 +1865,7 @@ static bool project_bucket_isect_circle(const float cent[2], const float radius_
* however switching back to this for ortho is always an option */
static void rect_to_uvspace_ortho(
- rctf *bucket_bounds,
+ const rctf *bucket_bounds,
const float *v1coSS, const float *v2coSS, const float *v3coSS,
const float *uv1co, const float *uv2co, const float *uv3co,
float bucket_bounds_uv[4][2],
@@ -1888,7 +1898,7 @@ static void rect_to_uvspace_ortho(
/* same as above but use barycentric_weights_v2_persp */
static void rect_to_uvspace_persp(
- rctf *bucket_bounds,
+ const rctf *bucket_bounds,
const float *v1coSS, const float *v2coSS, const float *v3coSS,
const float *uv1co, const float *uv2co, const float *uv3co,
float bucket_bounds_uv[4][2],
@@ -1964,7 +1974,7 @@ static int float_z_sort(const void *p1, const void *p2)
/* assumes one point is within the rectangle */
static void line_rect_clip(
- rctf *rect,
+ const rctf *rect,
const float l1[4], const float l2[4],
const float uv1[2], const float uv2[2],
float uv[2], bool is_ortho)
@@ -1989,14 +1999,14 @@ static void line_rect_clip(
tmp = (is_ortho) ? 1.0f : (l1[3] + min * (l2[3] - l1[3]));
- uv[0] = (uv1[0] + min * (uv2[0] - uv1[0])) / tmp;
- uv[1] = (uv1[1] + min * (uv2[1] - uv1[1])) / tmp;
+ uv[0] = (uv1[0] + min / tmp * (uv2[0] - uv1[0]));
+ uv[1] = (uv1[1] + min / tmp * (uv2[1] - uv1[1]));
}
static void project_bucket_clip_face(
const bool is_ortho,
- rctf *bucket_bounds,
+ const rctf *bucket_bounds,
float *v1coSS, float *v2coSS, float *v3coSS,
const float *uv1co, const float *uv2co, const float *uv3co,
float bucket_bounds_uv[8][2],
@@ -2004,7 +2014,8 @@ static void project_bucket_clip_face(
{
int inside_bucket_flag = 0;
int inside_face_flag = 0;
- const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) != (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
+ const int flip = ((line_point_side_v2(v1coSS, v2coSS, v3coSS) > 0.0f) !=
+ (line_point_side_v2(uv1co, uv2co, uv3co) > 0.0f));
bool colinear = false;
float bucket_bounds_ss[4][2];
@@ -2020,7 +2031,8 @@ static void project_bucket_clip_face(
inside_bucket_flag |= BLI_rctf_isect_pt_v(bucket_bounds, v3coSS) << 2;
if (inside_bucket_flag == ISECT_ALL3) {
- /* all screenspace points are inside the bucket bounding box, this means we don't need to clip and can simply return the UVs */
+ /* all screenspace points are inside the bucket bounding box,
+ * this means we don't need to clip and can simply return the UVs */
if (flip) { /* facing the back? */
copy_v2_v2(bucket_bounds_uv[0], uv3co);
copy_v2_v2(bucket_bounds_uv[1], uv2co);
@@ -2076,8 +2088,8 @@ static void project_bucket_clip_face(
/* at this point we have all uv points needed in a row. all that's needed is to invert them if necessary */
if (flip) {
/* flip only to the middle of the array */
- int i, max = *tot / 2;
- for (i = 0; i < max; i++) {
+ int i, max = *tot - 1, mid = *tot / 2;
+ for (i = 0; i < mid; i++) {
SWAP(float, bucket_bounds_uv[i][0], bucket_bounds_uv[max - i][0]);
SWAP(float, bucket_bounds_uv[i][1], bucket_bounds_uv[max - i][1]);
}
@@ -2205,7 +2217,8 @@ static void project_bucket_clip_face(
for (i = 0; i < (*tot); i++) {
v2_clipSS[0] = isectVCosSS[i][0] - cent[0];
v2_clipSS[1] = isectVCosSS[i][1] - cent[1];
- isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0], v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
+ isectVCosSS[i][2] = atan2f(v1_clipSS[0] * v2_clipSS[1] - v1_clipSS[1] * v2_clipSS[0],
+ v1_clipSS[0] * v2_clipSS[0] + v1_clipSS[1] * v2_clipSS[1]);
}
if (flip) qsort(isectVCosSS, *tot, sizeof(float) * 3, float_z_sort_flip);
@@ -2260,7 +2273,9 @@ static void project_bucket_clip_face(
int i;
if (is_ortho) rect_to_uvspace_ortho(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
else rect_to_uvspace_persp(bucket_bounds, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, test_uv, flip);
- printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ", test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1], test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]);
+ printf("( [(%f,%f), (%f,%f), (%f,%f), (%f,%f)], ",
+ test_uv[0][0], test_uv[0][1], test_uv[1][0], test_uv[1][1],
+ test_uv[2][0], test_uv[2][1], test_uv[3][0], test_uv[3][1]);
printf(" [(%f,%f), (%f,%f), (%f,%f)], ", uv1co[0], uv1co[1], uv2co[0], uv2co[1], uv3co[0], uv3co[1]);
@@ -2358,9 +2373,15 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot
return 1;
}
-/* 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, ImBuf *ibuf, ImBuf **tmpibuf, const short clamp_u, const short clamp_v)
+/* 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,
+ const 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];
@@ -2824,7 +2845,7 @@ static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x,
/* Fill this bucket with pixels from the faces that intersect it.
*
* have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
-static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, rctf *bucket_bounds)
+static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const rctf *bucket_bounds)
{
LinkNode *node;
int face_index, image_index = 0;
@@ -3000,145 +3021,9 @@ static void project_paint_delayed_face_init(ProjPaintState *ps, const MFace *mf,
#endif
}
-/* run once per stroke before projection painting */
-static void project_paint_begin(ProjPaintState *ps)
+/* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
+static void proj_paint_state_non_cddm_init(ProjPaintState *ps)
{
- /* Viewport vars */
- float mat[3][3];
-
- float no[3];
-
- float *projScreenCo; /* Note, we could have 4D vectors are only needed for */
- float projMargin;
-
- /* Image Vars - keep track of images we have used */
- LinkNode *image_LinkList = NULL;
- LinkNode *node;
-
- 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_base;
-
- MTFace **tf_clone;
- MTFace *tf_clone_base = NULL;
-
- int a, i; /* generic looping vars */
- int image_index = -1, face_index;
-
- /* double lookup */
- const int *index_mf_to_mpoly = NULL;
- const int *index_mp_to_orig = NULL;
-
- MVert *mv;
-
- MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
-
- const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
-
- bool reset_threads = false;
-
- /* ---- end defines ---- */
-
- if (ps->source == PROJ_SRC_VIEW)
- ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */
-
- ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
-
- /* paint onto the derived mesh */
-
- /* Workaround for subsurf selection, try the display mesh first */
- if (ps->source == PROJ_SRC_IMAGE_CAM) {
- /* using render mesh, assume only camera was rendered from */
- ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
- ps->dm_release = true;
- }
- else if (ps->ob->derivedFinal &&
- CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE) &&
- (ps->do_face_sel == false || CustomData_has_layer(&ps->ob->derivedFinal->polyData, CD_ORIGINDEX)))
- {
- ps->dm = ps->ob->derivedFinal;
- ps->dm_release = false;
- }
- else {
- ps->dm = mesh_get_derived_final(
- ps->scene, ps->ob,
- ps->scene->customdata_mask | CD_MASK_MTFACE | (ps->do_face_sel ? CD_ORIGINDEX : 0));
- ps->dm_release = true;
- }
-
- if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE)) {
-
- if (ps->dm_release)
- ps->dm->release(ps->dm);
-
- ps->dm = NULL;
- return;
- }
-
- 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);
- if (index_mf_to_mpoly == NULL) {
- index_mp_to_orig = NULL;
- }
- else {
- mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
- }
- }
- else {
- mpoly_orig = NULL;
- }
-
- /* use clone mtface? */
- if (ps->do_layer_clone) {
- ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces");
- }
-
- 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) {
- /* 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 */
if (ps->dm->type != DM_TYPE_CDDM) {
ps->dm_mvert = MEM_dupallocN(ps->dm_mvert);
ps->dm_mface = MEM_dupallocN(ps->dm_mface);
@@ -3149,97 +3034,108 @@ static void project_paint_begin(ProjPaintState *ps)
ps->dm_mtface_stencil = MEM_dupallocN(ps->dm_mtface_stencil);
#endif
}
+}
+
+static void proj_paint_state_viewport_init(ProjPaintState *ps)
+{
+ float mat[3][3];
+ float viewmat[4][4];
+ float viewinv[4][4];
ps->viewDir[0] = 0.0f;
ps->viewDir[1] = 0.0f;
ps->viewDir[2] = 1.0f;
- {
- float viewmat[4][4];
- float viewinv[4][4];
+ invert_m4_m4(ps->ob->imat, ps->ob->obmat);
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
+ if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) {
+ /* normal drawing */
+ ps->winx = ps->ar->winx;
+ ps->winy = ps->ar->winy;
- if (ELEM(ps->source, PROJ_SRC_VIEW, PROJ_SRC_VIEW_FILL)) {
- /* normal drawing */
- ps->winx = ps->ar->winx;
- ps->winy = ps->ar->winy;
+ copy_m4_m4(viewmat, ps->rv3d->viewmat);
+ copy_m4_m4(viewinv, ps->rv3d->viewinv);
- copy_m4_m4(viewmat, ps->rv3d->viewmat);
- copy_m4_m4(viewinv, ps->rv3d->viewinv);
+ ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat);
- ED_view3d_ob_project_mat_get(ps->rv3d, ps->ob, ps->projectMat);
+ ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
+ }
+ else {
+ /* re-projection */
+ float winmat[4][4];
+ float vmat[4][4];
- ps->is_ortho = ED_view3d_clip_range_get(ps->v3d, ps->rv3d, &ps->clipsta, &ps->clipend, true);
- }
- else {
- /* re-projection */
- float winmat[4][4];
- float vmat[4][4];
+ ps->winx = ps->reproject_ibuf->x;
+ ps->winy = ps->reproject_ibuf->y;
- ps->winx = ps->reproject_ibuf->x;
- ps->winy = ps->reproject_ibuf->y;
+ if (ps->source == PROJ_SRC_IMAGE_VIEW) {
+ /* image stores camera data, tricky */
+ IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
+ IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
- if (ps->source == PROJ_SRC_IMAGE_VIEW) {
- /* image stores camera data, tricky */
- IDProperty *idgroup = IDP_GetProperties(&ps->reproject_image->id, 0);
- IDProperty *view_data = IDP_GetPropertyFromGroup(idgroup, PROJ_VIEW_DATA_ID);
+ const float *array = (float *)IDP_Array(view_data);
- const float *array = (float *)IDP_Array(view_data);
+ /* use image array, written when creating image */
+ memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float);
+ memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float);
+ ps->clipsta = array[0];
+ ps->clipend = array[1];
+ ps->is_ortho = array[2] ? 1 : 0;
- /* use image array, written when creating image */
- memcpy(winmat, array, sizeof(winmat)); array += sizeof(winmat) / sizeof(float);
- memcpy(viewmat, array, sizeof(viewmat)); array += sizeof(viewmat) / sizeof(float);
- ps->clipsta = array[0];
- ps->clipend = array[1];
- ps->is_ortho = array[2] ? 1 : 0;
+ invert_m4_m4(viewinv, viewmat);
+ }
+ else if (ps->source == PROJ_SRC_IMAGE_CAM) {
+ Object *cam_ob = ps->scene->camera;
+ CameraParams params;
- invert_m4_m4(viewinv, viewmat);
- }
- else if (ps->source == PROJ_SRC_IMAGE_CAM) {
- Object *cam_ob = ps->scene->camera;
- CameraParams params;
-
- /* viewmat & viewinv */
- copy_m4_m4(viewinv, cam_ob->obmat);
- normalize_m4(viewinv);
- invert_m4_m4(viewmat, viewinv);
-
- /* window matrix, clipping and ortho */
- BKE_camera_params_init(&params);
- BKE_camera_params_from_object(&params, cam_ob);
- BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
- BKE_camera_params_compute_matrix(&params);
-
- copy_m4_m4(winmat, params.winmat);
- ps->clipsta = params.clipsta;
- ps->clipend = params.clipend;
- ps->is_ortho = params.is_ortho;
- }
+ /* viewmat & viewinv */
+ copy_m4_m4(viewinv, cam_ob->obmat);
+ normalize_m4(viewinv);
+ invert_m4_m4(viewmat, viewinv);
+
+ /* window matrix, clipping and ortho */
+ BKE_camera_params_init(&params);
+ BKE_camera_params_from_object(&params, cam_ob);
+ BKE_camera_params_compute_viewplane(&params, ps->winx, ps->winy, 1.0f, 1.0f);
+ BKE_camera_params_compute_matrix(&params);
- /* same as #ED_view3d_ob_project_mat_get */
- mul_m4_m4m4(vmat, viewmat, ps->ob->obmat);
- mul_m4_m4m4(ps->projectMat, winmat, vmat);
+ copy_m4_m4(winmat, params.winmat);
+ ps->clipsta = params.clipsta;
+ ps->clipend = params.clipend;
+ ps->is_ortho = params.is_ortho;
+ }
+ else {
+ BLI_assert(0);
}
+ /* same as #ED_view3d_ob_project_mat_get */
+ mul_m4_m4m4(vmat, viewmat, ps->ob->obmat);
+ mul_m4_m4m4(ps->projectMat, winmat, vmat);
+ }
- /* viewDir - object relative */
- invert_m4_m4(ps->ob->imat, ps->ob->obmat);
- copy_m3_m4(mat, viewinv);
- mul_m3_v3(mat, ps->viewDir);
- copy_m3_m4(mat, ps->ob->imat);
- mul_m3_v3(mat, ps->viewDir);
- normalize_v3(ps->viewDir);
- /* viewPos - object relative */
- copy_v3_v3(ps->viewPos, viewinv[3]);
- copy_m3_m4(mat, ps->ob->imat);
- mul_m3_v3(mat, ps->viewPos);
- add_v3_v3(ps->viewPos, ps->ob->imat[3]);
- }
+ /* viewDir - object relative */
+ invert_m4_m4(ps->ob->imat, ps->ob->obmat);
+ copy_m3_m4(mat, viewinv);
+ mul_m3_v3(mat, ps->viewDir);
+ copy_m3_m4(mat, ps->ob->imat);
+ mul_m3_v3(mat, ps->viewDir);
+ normalize_v3(ps->viewDir);
+
+ /* viewPos - object relative */
+ copy_v3_v3(ps->viewPos, viewinv[3]);
+ copy_m3_m4(mat, ps->ob->imat);
+ mul_m3_v3(mat, ps->viewPos);
+ add_v3_v3(ps->viewPos, ps->ob->imat[3]);
+}
+
+static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int diameter)
+{
+ MVert *mv;
+ float *projScreenCo;
+ float projMargin;
+ int a;
- /* calculate vert screen coords
- * run this early so we can calculate the x/y resolution of our bucket rect */
INIT_MINMAX2(ps->screenMin, ps->screenMax);
ps->screenCoords = MEM_mallocN(sizeof(float) * ps->dm_totvert * 4, "ProjectPaint ScreenVerts");
@@ -3305,38 +3201,24 @@ static void project_paint_begin(ProjPaintState *ps)
ps->screenMin[1] = 0;
ps->screenMax[1] = (float)(ps->winy);
}
+}
- /* only for convenience */
- ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
- ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
-
- ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
- ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
-
- /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
-
- if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) {
- reset_threads = true;
- }
-
- /* really high values could cause problems since it has to allocate a few
- * (ps->buckets_x*ps->buckets_y) sized arrays */
- CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
- CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
-
- ps->bucketRect = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect");
- ps->bucketFaces = (LinkNode **)MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
-
- ps->bucketFlags = (unsigned char *)MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
#ifndef PROJ_DEBUG_NOSEAMBLEED
+static void proj_paint_state_seam_bleed_init(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->vertFaces = MEM_callocN(sizeof(LinkNode *) * ps->dm_totvert, "paint-vertFaces");
+ ps->faceSeamFlags = MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceSeamFlags");
+ ps->faceWindingFlags = MEM_callocN(sizeof(char) * ps->dm_totface, "paint-faceWindindFlags");
ps->faceSeamUVs = MEM_mallocN(sizeof(float) * ps->dm_totface * 8, "paint-faceSeamUVs");
}
+}
#endif
+static void proj_paint_state_thread_init(ProjPaintState *ps, const bool reset_threads)
+{
+ int a;
+
/* Thread stuff
*
* very small brushes run a lot slower multithreaded since the advantage with
@@ -3360,11 +3242,15 @@ static void project_paint_begin(ProjPaintState *ps)
for (a = 0; a < ps->thread_tot; a++) {
ps->arena_mt[a] = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "project paint arena");
}
+}
- arena = ps->arena_mt[0];
-
+static void proj_paint_state_vert_flags_init(ProjPaintState *ps)
+{
if (ps->do_backfacecull && ps->do_mask_normal) {
float viewDirPersp[3];
+ MVert *mv;
+ float no[3];
+ int a;
ps->vertFlags = MEM_callocN(sizeof(char) * ps->dm_totvert, "paint-vertFlags");
@@ -3385,38 +3271,339 @@ static void project_paint_begin(ProjPaintState *ps)
}
}
}
-
- for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) {
- bool is_face_sel;
+ else {
+ ps->vertFlags = NULL;
+ }
+}
#ifndef PROJ_DEBUG_NOSEAMBLEED
- /* add face user if we have bleed enabled, set the UV seam flags later */
- /* annoying but we need to add all faces even ones we never use elsewhere */
- if (ps->seam_bleed_px > 0.0f) {
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena);
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena);
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena);
- if (mf->v4) {
- BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena);
- }
+static void project_paint_bleed_add_face_user(
+ const ProjPaintState *ps, MemArena *arena,
+ const MFace *mf, const int face_index)
+{
+ /* add face user if we have bleed enabled, set the UV seam flags later */
+ /* annoying but we need to add all faces even ones we never use elsewhere */
+ if (ps->seam_bleed_px > 0.0f) {
+ BLI_linklist_prepend_arena(&ps->vertFaces[mf->v1], SET_INT_IN_POINTER(face_index), arena);
+ BLI_linklist_prepend_arena(&ps->vertFaces[mf->v2], SET_INT_IN_POINTER(face_index), arena);
+ BLI_linklist_prepend_arena(&ps->vertFaces[mf->v3], SET_INT_IN_POINTER(face_index), arena);
+ if (mf->v4) {
+ BLI_linklist_prepend_arena(&ps->vertFaces[mf->v4], SET_INT_IN_POINTER(face_index), arena);
}
+ }
+}
#endif
- if (ps->do_face_sel) {
- int orig_index;
- if (index_mp_to_orig && ((orig_index = DM_origindex_mface_mpoly(index_mf_to_mpoly, index_mp_to_orig,
- face_index))) != ORIGINDEX_NONE)
- {
- MPoly *mp = &mpoly_orig[orig_index];
- is_face_sel = ((mp->flag & ME_FACE_SEL) != 0);
+/* Return true if DM can be painted on, false otherwise */
+static bool proj_paint_state_dm_init(ProjPaintState *ps)
+{
+ /* Workaround for subsurf selection, try the display mesh first */
+ if (ps->source == PROJ_SRC_IMAGE_CAM) {
+ /* using render mesh, assume only camera was rendered from */
+ ps->dm = mesh_create_derived_render(ps->scene, ps->ob, ps->scene->customdata_mask | CD_MASK_MTFACE);
+ ps->dm_release = true;
+ }
+ else if (ps->ob->derivedFinal &&
+ CustomData_has_layer(&ps->ob->derivedFinal->faceData, CD_MTFACE) &&
+ (ps->do_face_sel == false || CustomData_has_layer(&ps->ob->derivedFinal->polyData, CD_ORIGINDEX)))
+ {
+ ps->dm = ps->ob->derivedFinal;
+ ps->dm_release = false;
+ }
+ else {
+ ps->dm = mesh_get_derived_final(
+ ps->scene, ps->ob,
+ ps->scene->customdata_mask | CD_MASK_MTFACE | (ps->do_face_sel ? CD_ORIGINDEX : 0));
+ ps->dm_release = true;
+ }
+
+ if (!CustomData_has_layer(&ps->dm->faceData, CD_MTFACE)) {
+
+ if (ps->dm_release)
+ ps->dm->release(ps->dm);
+
+ ps->dm = NULL;
+ return false;
+ }
+
+ 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");
+
+ return true;
+}
+
+typedef struct {
+ MTFace *tf_clone_base;
+ MTFace **tf_clone;
+ TexPaintSlot *slot_last_clone;
+ TexPaintSlot *slot_clone;
+} ProjPaintLayerClone;
+
+static void proj_paint_layer_clone_init(
+ ProjPaintState *ps,
+ ProjPaintLayerClone *layer_clone)
+{
+ MTFace *tf_clone_base = NULL;
+
+ /* use clone mtface? */
+ if (ps->do_layer_clone) {
+ const int layer_num = CustomData_get_clone_layer(&((Mesh *)ps->ob->data)->pdata, CD_MTEXPOLY);
+
+ ps->dm_mtface_clone = MEM_mallocN(ps->dm_totface * sizeof(MTFace *), "proj_paint_mtfaces");
+
+ 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);
+ }
+
+ }
+
+ memset(layer_clone, 0, sizeof(*layer_clone));
+ layer_clone->tf_clone_base = tf_clone_base;
+}
+
+/* Return true if face should be skipped, false otherwise */
+static bool project_paint_clone_face_skip(
+ ProjPaintState *ps,
+ ProjPaintLayerClone *lc,
+ const TexPaintSlot *slot,
+ const int face_index)
+{
+ if (ps->do_layer_clone) {
+ if (ps->do_material_slots) {
+ lc->slot_clone = project_paint_face_clone_slot(ps, face_index);
+ /* all faces should have a valid slot, reassert here */
+ if (ELEM(lc->slot_clone, NULL, slot))
+ return true;
+ }
+ else if (ps->clone_ima == ps->canvas_ima)
+ return true;
+
+ lc->tf_clone = ps->dm_mtface_clone + face_index;
+
+ if (ps->do_material_slots) {
+ if (lc->slot_clone != lc->slot_last_clone) {
+ if (!slot->uvname ||
+ !(lc->tf_clone_base = CustomData_get_layer_named(
+ &ps->dm->faceData, CD_MTFACE,
+ lc->slot_clone->uvname)))
+ {
+ lc->tf_clone_base = CustomData_get_layer(&ps->dm->faceData, CD_MTFACE);
+ }
+ lc->slot_last_clone = lc->slot_clone;
}
- else {
- is_face_sel = ((mf->flag & ME_FACE_SEL) != 0);
+ }
+
+ *lc->tf_clone = lc->tf_clone_base + face_index;
+ }
+ return false;
+}
+
+typedef struct {
+ MPoly *mpoly_orig;
+
+ /* double lookup */
+ const int *index_mf_to_mpoly;
+ const int *index_mp_to_orig;
+} ProjPaintFaceLookup;
+
+static void proj_paint_face_lookup_init(
+ const ProjPaintState *ps,
+ ProjPaintFaceLookup *face_lookup)
+{
+ memset(face_lookup, 0, sizeof(*face_lookup));
+ if (ps->do_face_sel) {
+ face_lookup->index_mf_to_mpoly = ps->dm->getTessFaceDataArray(ps->dm, CD_ORIGINDEX);
+ face_lookup->index_mp_to_orig = ps->dm->getPolyDataArray(ps->dm, CD_ORIGINDEX);
+ if (face_lookup->index_mf_to_mpoly == NULL) {
+ face_lookup->index_mp_to_orig = NULL;
+ }
+ else {
+ face_lookup->mpoly_orig = ((Mesh *)ps->ob->data)->mpoly;
+ }
+ }
+}
+
+/* Return true if face should be considered selected, false otherwise */
+static bool project_paint_check_face_sel(
+ const ProjPaintState *ps,
+ const ProjPaintFaceLookup *face_lookup,
+ const MFace *mf, const int face_index)
+{
+ if (ps->do_face_sel) {
+ int orig_index;
+ if (face_lookup->index_mp_to_orig &&
+ ((orig_index = DM_origindex_mface_mpoly(
+ face_lookup->index_mf_to_mpoly,
+ face_lookup->index_mp_to_orig,
+ face_index))) != ORIGINDEX_NONE)
+ {
+ MPoly *mp = &face_lookup->mpoly_orig[orig_index];
+ return ((mp->flag & ME_FACE_SEL) != 0);
+ }
+ else {
+ return ((mf->flag & ME_FACE_SEL) != 0);
+ }
+ }
+ else {
+ return true;
+ }
+}
+
+typedef struct {
+ const float *v1;
+ const float *v2;
+ const float *v3;
+ const float *v4;
+} ProjPaintFaceCoSS;
+
+static void proj_paint_face_coSS_init(
+ const ProjPaintState *ps, const MFace *mf,
+ ProjPaintFaceCoSS *coSS)
+{
+ coSS->v1 = ps->screenCoords[mf->v1];
+ coSS->v2 = ps->screenCoords[mf->v2];
+ coSS->v3 = ps->screenCoords[mf->v3];
+ coSS->v4 = mf->v4 ? ps->screenCoords[mf->v4] : NULL;
+}
+
+/* Return true if face should be culled, false otherwise */
+static bool project_paint_flt_max_cull(
+ const ProjPaintState *ps,
+ const ProjPaintFaceCoSS *coSS)
+{
+ if (!ps->is_ortho) {
+ if (coSS->v1[0] == FLT_MAX ||
+ coSS->v2[0] == FLT_MAX ||
+ coSS->v3[0] == FLT_MAX ||
+ (coSS->v4 && coSS->v4[0] == FLT_MAX))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifdef PROJ_DEBUG_WINCLIP
+/* Return true if face should be culled, false otherwise */
+static bool project_paint_winclip(
+ const ProjPaintState *ps, const MFace *mf,
+ const ProjPaintFaceCoSS *coSS)
+{
+ /* ignore faces outside the view */
+ return ((ps->source != PROJ_SRC_VIEW_FILL) &&
+ ((coSS->v1[0] < ps->screenMin[0] &&
+ coSS->v2[0] < ps->screenMin[0] &&
+ coSS->v3[0] < ps->screenMin[0] &&
+ (mf->v4 && coSS->v4[0] < ps->screenMin[0])) ||
+
+ (coSS->v1[0] > ps->screenMax[0] &&
+ coSS->v2[0] > ps->screenMax[0] &&
+ coSS->v3[0] > ps->screenMax[0] &&
+ (mf->v4 && coSS->v4[0] > ps->screenMax[0])) ||
+
+ (coSS->v1[1] < ps->screenMin[1] &&
+ coSS->v2[1] < ps->screenMin[1] &&
+ coSS->v3[1] < ps->screenMin[1] &&
+ (mf->v4 && coSS->v4[1] < ps->screenMin[1])) ||
+
+ (coSS->v1[1] > ps->screenMax[1] &&
+ coSS->v2[1] > ps->screenMax[1] &&
+ coSS->v3[1] > ps->screenMax[1] &&
+ (mf->v4 && coSS->v4[1] > ps->screenMax[1]))));
+}
+#endif //PROJ_DEBUG_WINCLIP
+
+/* Return true if face should be culled, false otherwise */
+static bool project_paint_backface_cull(
+ const ProjPaintState *ps, const MFace *mf,
+ const ProjPaintFaceCoSS *coSS)
+{
+ if (ps->do_backfacecull) {
+ if (ps->do_mask_normal) {
+ /* Since we are interpolating the normals of faces, we want to make
+ * sure all the verts are pointing away from the view,
+ * not just the face */
+ if ((ps->vertFlags[mf->v1] & PROJ_VERT_CULL) &&
+ (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) &&
+ (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) &&
+ (mf->v4 == 0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL))
+ {
+ return true;
}
}
else {
- is_face_sel = true;
+ if (line_point_side_v2(coSS->v1, coSS->v2, coSS->v3) < 0.0f) {
+ return true;
+ }
+
}
+ }
+
+ return false;
+}
+
+static void project_paint_build_proj_ima(
+ ProjPaintState *ps, MemArena *arena,
+ LinkNode *image_LinkList)
+{
+ ProjPaintImage *projIma;
+ LinkNode *node;
+ int i;
+
+ /* build an array of images we use */
+ projIma = ps->projImages = 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);
+ 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 = BLI_memarena_alloc(arena, size);
+ memset(projIma->maskRect, 0, size);
+ projIma->valid = BLI_memarena_alloc(arena, size);
+ memset(projIma->valid, 0, size);
+ }
+}
+
+static void project_paint_prepare_all_faces(
+ ProjPaintState *ps, MemArena *arena,
+ const ProjPaintFaceLookup *face_lookup,
+ ProjPaintLayerClone *layer_clone,
+ MTFace *tf_base)
+{
+ /* Image Vars - keep track of images we have used */
+ LinkNode *image_LinkList = NULL;
+
+ Image *tpage_last = NULL, *tpage;
+ TexPaintSlot *slot_last = NULL;
+ TexPaintSlot *slot = NULL;
+ MTFace **tf;
+ MFace *mf;
+ int image_index = -1, face_index;
+
+ for (face_index = 0, tf = ps->dm_mtface, mf = ps->dm_mface; face_index < ps->dm_totface; mf++, tf++, face_index++) {
+ bool is_face_sel;
+
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ project_paint_bleed_add_face_user(ps, arena, mf, face_index);
+#endif
+
+ is_face_sel = project_paint_check_face_sel(ps, face_lookup, mf, face_index);
if (!ps->do_stencil_brush) {
slot = project_paint_face_paint_slot(ps, face_index);
@@ -3445,103 +3632,31 @@ static void project_paint_begin(ProjPaintState *ps)
*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;
+ if (project_paint_clone_face_skip(ps, layer_clone, slot, face_index)) {
+ continue;
}
/* tfbase here should be non-null! */
BLI_assert (tf_base != NULL);
if (is_face_sel && tpage) {
- const float *v1coSS, *v2coSS, *v3coSS, *v4coSS = NULL;
+ ProjPaintFaceCoSS coSS;
+ proj_paint_face_coSS_init(ps, mf, &coSS);
- v1coSS = ps->screenCoords[mf->v1];
- v2coSS = ps->screenCoords[mf->v2];
- v3coSS = ps->screenCoords[mf->v3];
- if (mf->v4) {
- v4coSS = ps->screenCoords[mf->v4];
- }
-
-
- if (!ps->is_ortho) {
- if (v1coSS[0] == FLT_MAX ||
- v2coSS[0] == FLT_MAX ||
- v3coSS[0] == FLT_MAX ||
- (mf->v4 && v4coSS[0] == FLT_MAX))
- {
- continue;
- }
+ if (project_paint_flt_max_cull(ps, &coSS)) {
+ continue;
}
#ifdef PROJ_DEBUG_WINCLIP
- /* ignore faces outside the view */
- if ((ps->source != PROJ_SRC_VIEW_FILL) &&
- ((v1coSS[0] < ps->screenMin[0] &&
- v2coSS[0] < ps->screenMin[0] &&
- v3coSS[0] < ps->screenMin[0] &&
- (mf->v4 && v4coSS[0] < ps->screenMin[0])) ||
-
- (v1coSS[0] > ps->screenMax[0] &&
- v2coSS[0] > ps->screenMax[0] &&
- v3coSS[0] > ps->screenMax[0] &&
- (mf->v4 && v4coSS[0] > ps->screenMax[0])) ||
-
- (v1coSS[1] < ps->screenMin[1] &&
- v2coSS[1] < ps->screenMin[1] &&
- v3coSS[1] < ps->screenMin[1] &&
- (mf->v4 && v4coSS[1] < ps->screenMin[1])) ||
-
- (v1coSS[1] > ps->screenMax[1] &&
- v2coSS[1] > ps->screenMax[1] &&
- v3coSS[1] > ps->screenMax[1] &&
- (mf->v4 && v4coSS[1] > ps->screenMax[1])))
- )
- {
+ if (project_paint_winclip(ps, mf, &coSS)) {
continue;
}
#endif //PROJ_DEBUG_WINCLIP
- if (ps->do_backfacecull) {
- if (ps->do_mask_normal) {
- /* Since we are interpolating the normals of faces, we want to make
- * sure all the verts are pointing away from the view,
- * not just the face */
- if ((ps->vertFlags[mf->v1] & PROJ_VERT_CULL) &&
- (ps->vertFlags[mf->v2] & PROJ_VERT_CULL) &&
- (ps->vertFlags[mf->v3] & PROJ_VERT_CULL) &&
- (mf->v4 == 0 || ps->vertFlags[mf->v4] & PROJ_VERT_CULL)
- )
- {
- continue;
- }
- }
- else {
- if (line_point_side_v2(v1coSS, v2coSS, v3coSS) < 0.0f) {
- continue;
- }
-
- }
+ if (project_paint_backface_cull(ps, mf, &coSS)) {
+ continue;
}
if (tpage_last != tpage) {
@@ -3566,28 +3681,98 @@ static void project_paint_begin(ProjPaintState *ps)
}
/* build an array of images we use*/
- 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);
- 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);
- }
+ project_paint_build_proj_ima(ps, arena, image_LinkList);
/* we have built the array, discard the linked list */
BLI_linklist_free(image_LinkList, NULL);
}
+/* run once per stroke before projection painting */
+static void project_paint_begin(ProjPaintState *ps)
+{
+ ProjPaintLayerClone layer_clone;
+ ProjPaintFaceLookup face_lookup;
+ MTFace *tf_base;
+
+ MemArena *arena; /* at the moment this is just ps->arena_mt[0], but use this to show were not multithreading */
+
+ const int diameter = 2 * BKE_brush_size_get(ps->scene, ps->brush);
+
+ bool reset_threads = false;
+
+ /* ---- end defines ---- */
+
+ if (ps->source == PROJ_SRC_VIEW)
+ ED_view3d_clipping_local(ps->rv3d, ps->ob->obmat); /* faster clipping lookups */
+
+ ps->do_face_sel = ((((Mesh *)ps->ob->data)->editflag & ME_EDIT_PAINT_FACE_SEL) != 0);
+
+ /* paint onto the derived mesh */
+ if (!proj_paint_state_dm_init(ps)) {
+ return;
+ }
+
+ proj_paint_face_lookup_init(ps, &face_lookup);
+ proj_paint_layer_clone_init(ps, &layer_clone);
+
+ 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) {
+ /* 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;
+ }
+
+ /* when using subsurf or multires, mface arrays are thrown away, we need to keep a copy */
+ proj_paint_state_non_cddm_init(ps);
+
+ proj_paint_state_viewport_init(ps);
+
+ /* calculate vert screen coords
+ * run this early so we can calculate the x/y resolution of our bucket rect */
+ proj_paint_state_screen_coords_init(ps, diameter);
+
+ /* only for convenience */
+ ps->screen_width = ps->screenMax[0] - ps->screenMin[0];
+ ps->screen_height = ps->screenMax[1] - ps->screenMin[1];
+
+ ps->buckets_x = (int)(ps->screen_width / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+ ps->buckets_y = (int)(ps->screen_height / (((float)diameter) / PROJ_BUCKET_BRUSH_DIV));
+
+ /* printf("\tscreenspace bucket division x:%d y:%d\n", ps->buckets_x, ps->buckets_y); */
+
+ if (ps->buckets_x > PROJ_BUCKET_RECT_MAX || ps->buckets_y > PROJ_BUCKET_RECT_MAX) {
+ reset_threads = true;
+ }
+
+ /* really high values could cause problems since it has to allocate a few
+ * (ps->buckets_x*ps->buckets_y) sized arrays */
+ CLAMP(ps->buckets_x, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+ CLAMP(ps->buckets_y, PROJ_BUCKET_RECT_MIN, PROJ_BUCKET_RECT_MAX);
+
+ ps->bucketRect = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketRect");
+ ps->bucketFaces = MEM_callocN(sizeof(LinkNode *) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
+
+ ps->bucketFlags = MEM_callocN(sizeof(char) * ps->buckets_x * ps->buckets_y, "paint-bucketFaces");
+#ifndef PROJ_DEBUG_NOSEAMBLEED
+ proj_paint_state_seam_bleed_init(ps);
+#endif
+
+ proj_paint_state_thread_init(ps, reset_threads);
+ arena = ps->arena_mt[0];
+
+ proj_paint_state_vert_flags_init(ps);
+
+ project_paint_prepare_all_faces(ps, arena, &face_lookup, &layer_clone, tf_base);
+}
+
static void paint_proj_begin_clone(ProjPaintState *ps, const float mouse[2])
{
/* setup clone offset */
@@ -3773,7 +3958,9 @@ 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])
+static bool project_bucket_iter_next(
+ ProjPaintState *ps, int *bucket_index,
+ rctf *bucket_bounds, const float mval[2])
{
const int diameter = 2 * ps->brush_size;
@@ -4011,20 +4198,21 @@ static void do_projectpaint_soften(ProjPaintState *ps, ProjPixel *projPixel, flo
}
}
-static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask)
+static void do_projectpaint_draw(ProjPaintState *ps, ProjPixel *projPixel, const float texrgb[3], float mask, float dither, float u, float v)
{
float rgb[3];
unsigned char rgba_ub[4];
- copy_v3_v3(rgb, ps->paint_color);
-
if (ps->is_texbrush) {
- mul_v3_v3(rgb, texrgb);
+ mul_v3_v3v3(rgb, texrgb, ps->paint_color_linear);
/* TODO(sergey): Support texture paint color space. */
linearrgb_to_srgb_v3_v3(rgb, rgb);
}
+ else {
+ copy_v3_v3(rgb, ps->paint_color);
+ }
- rgb_float_to_uchar(rgba_ub, rgb);
+ float_to_byte_dither_v3(rgba_ub, rgb, dither, u, v);
rgba_ub[3] = f_to_char(mask);
if (ps->do_masking) {
@@ -4205,7 +4393,8 @@ static void *do_projectpaint_thread(void *ph_v)
}
else {
linearrgb_to_srgb_v3_v3(color_f, color_f);
- rgba_float_to_uchar(projPixel->newColor.ch, color_f);
+ float_to_byte_dither_v3(projPixel->newColor.ch, color_f, ps->dither, projPixel->x_px, projPixel->y_px);
+ projPixel->newColor.ch[3] = FTOCHAR(color_f[3]);
IMB_blend_color_byte(projPixel->pixel.ch_pt, projPixel->origColor.ch_pt,
projPixel->newColor.ch, ps->blend);
}
@@ -4401,7 +4590,7 @@ static void *do_projectpaint_thread(void *ph_v)
break;
default:
if (is_floatbuf) do_projectpaint_draw_f(ps, projPixel, texrgb, mask);
- else do_projectpaint_draw(ps, projPixel, texrgb, mask);
+ else do_projectpaint_draw(ps, projPixel, texrgb, mask, ps->dither, projPixel->x_px, projPixel->y_px);
break;
}
}
@@ -4485,13 +4674,13 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po
/* thread specific */
handles[a].thread_index = a;
- handles[a].projImages = (ProjPaintImage *)BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage));
+ handles[a].projImages = BLI_memarena_alloc(ps->arena_mt[a], ps->image_tot * sizeof(ProjPaintImage));
memcpy(handles[a].projImages, ps->projImages, ps->image_tot * sizeof(ProjPaintImage));
/* image bounds */
for (i = 0; i < ps->image_tot; i++) {
- handles[a].projImages[i].partRedrawRect = (ImagePaintPartialRedraw *)BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
+ handles[a].projImages[i].partRedrawRect = BLI_memarena_alloc(ps->arena_mt[a], sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
memcpy(handles[a].projImages[i].partRedrawRect, ps->projImages[i].partRedrawRect, sizeof(ImagePaintPartialRedraw) * PROJ_BOUNDBOX_SQUARED);
}
@@ -4705,6 +4894,8 @@ static void project_state_init(bContext *C, Object *ob, ProjPaintState *ps, int
if (ps->normal_angle_range <= 0.0f)
ps->do_mask_normal = false; /* no need to do blending */
+ ps->dither = settings->imapaint.dither;
+
return;
}
@@ -4732,7 +4923,7 @@ void *paint_proj_new_stroke(bContext *C, Object *ob, const float mouse[2], int m
/* Don't allow brush size below 2 */
if (BKE_brush_size_get(ps->scene, ps->brush) < 2)
- BKE_brush_size_set(ps->scene, ps->brush, 2);
+ BKE_brush_size_set(ps->scene, ps->brush, 2 * U.pixelsize);
/* allocate and initialize spatial data structures */
project_paint_begin(ps);
@@ -4851,7 +5042,7 @@ static int texture_paint_camera_project_exec(bContext *C, wmOperator *op)
ps.is_maskbrush = 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 */
+ BKE_brush_size_set(scene, ps.brush, 32 * U.pixelsize); /* cover the whole image */
ps.tool = PAINT_TOOL_DRAW; /* so pixels are initialized with minimal info */
@@ -4945,6 +5136,9 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
image = BKE_image_add_from_imbuf(ibuf);
+ /* Drop reference to ibuf so that the image owns it */
+ IMB_freeImBuf(ibuf);
+
if (image) {
/* now for the trickyness. store the view projection here!
* re-projection will reuse this */
@@ -4965,7 +5159,9 @@ static int texture_paint_image_from_view_exec(bContext *C, wmOperator *op)
memcpy(array, rv3d->winmat, sizeof(rv3d->winmat)); array += sizeof(rv3d->winmat) / sizeof(float);
memcpy(array, rv3d->viewmat, sizeof(rv3d->viewmat)); array += sizeof(rv3d->viewmat) / sizeof(float);
is_ortho = ED_view3d_clip_range_get(v3d, rv3d, &array[0], &array[1], true);
- array[2] = is_ortho ? 1.0f : 0.0f; /* using float for a bool is dodgy but since its an extra member in the array... easier then adding a single bool prop */
+ /* using float for a bool is dodgy but since its an extra member in the array...
+ * easier then adding a single bool prop */
+ array[2] = is_ortho ? 1.0f : 0.0f;
IDP_AddToGroup(idgroup, view_data);
@@ -5041,17 +5237,17 @@ bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *m
hasmat = true;
if (!ma->texpaintslot) {
/* refresh here just in case */
- BKE_texpaint_slot_refresh_cache(scene, ma);
+ BKE_texpaint_slot_refresh_cache(scene, ma);
/* if still no slots, we have to add */
- if (ma->texpaintslot) {
+ if (ma->texpaintslot) {
hastex = true;
- break;
+ break;
}
}
else {
hastex = true;
- break;
+ break;
}
}
}
@@ -5060,7 +5256,7 @@ bool BKE_paint_proj_mesh_data_check(Scene *scene, Object *ob, bool *uvs, bool *m
else if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) {
if (imapaint->canvas == NULL) {
hastex = false;
- }
+ }
}
me = BKE_mesh_from_object(ob);
@@ -5141,7 +5337,7 @@ static Image *proj_paint_image_create(wmOperator *op, Main *bmain)
RNA_string_get(op->ptr, "name", imagename);
}
ima = BKE_image_add_generated(bmain, width, height, imagename, alpha ? 32 : 24, use_float,
- gen_type, color);
+ gen_type, color);
return ima;
}
@@ -5221,7 +5417,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op)
DAG_id_tag_update(&ma->id, 0);
ED_area_tag_redraw(CTX_wm_area(C));
- BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
+ BKE_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL);
return true;
}
@@ -5251,7 +5447,7 @@ static int texture_paint_add_texture_paint_slot_invoke(bContext *C, wmOperator *
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);
+ assign_material(ob, ma, ob->actcol, BKE_MAT_ASSIGN_USERPREF);
}
type = RNA_enum_from_value(layer_type_items, type);
@@ -5323,8 +5519,13 @@ static int texture_paint_delete_texture_paint_slot_exec(bContext *C, wmOperator
slot = ma->texpaintslot + ma->paint_active_slot;
- if (ma->mtex[slot->index]->tex)
+ if (ma->mtex[slot->index]->tex) {
id_us_min(&ma->mtex[slot->index]->tex->id);
+
+ if (ma->mtex[slot->index]->tex->ima) {
+ id_us_min(&ma->mtex[slot->index]->tex->ima->id);
+ }
+ }
MEM_freeN(ma->mtex[slot->index]);
ma->mtex[slot->index] = NULL;
diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c
index ea5f77acc5b..fac1a05862f 100644
--- a/source/blender/editors/sculpt_paint/paint_ops.c
+++ b/source/blender/editors/sculpt_paint/paint_ops.c
@@ -106,15 +106,14 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op)
const int old_size = BKE_brush_size_get(scene, brush);
int size = (int)(scalar * old_size);
- if (old_size == size) {
+ if (abs(old_size - size) < U.pixelsize) {
if (scalar > 1) {
- size++;
+ size += U.pixelsize;
}
else if (scalar < 1) {
- size--;
+ size -= U.pixelsize;
}
}
- CLAMP(size, 1, 2000); // XXX magic number
BKE_brush_size_set(scene, brush, size);
}
@@ -128,6 +127,8 @@ static int brush_scale_size_exec(bContext *C, wmOperator *op)
BKE_brush_unprojected_radius_set(scene, brush, unprojected_radius);
}
+
+ WM_main_add_notifier(NC_BRUSH | NA_EDITED, brush);
}
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c
index bb875d2ef00..d9d0d8f5ef6 100644
--- a/source/blender/editors/sculpt_paint/paint_stroke.c
+++ b/source/blender/editors/sculpt_paint/paint_stroke.c
@@ -122,6 +122,10 @@ typedef struct PaintStroke {
float zoom_2d;
int pen_flip;
+
+ /* line constraint */
+ bool constrain_line;
+ float constrained_pos[2];
StrokeGetLocation get_location;
StrokeTestStart test_start;
@@ -161,13 +165,25 @@ static void paint_draw_line_cursor(bContext *C, int x, int y, void *customdata)
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 (stroke->constrain_line) {
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ stroke->constrained_pos[0], stroke->constrained_pos[1]);
+ }
+ else {
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ x, y);
+ }
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);
+ if (stroke->constrain_line) {
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ stroke->constrained_pos[0], stroke->constrained_pos[1]);
+ }
+ else {
+ sdrawline((int)stroke->last_mouse_position[0], (int)stroke->last_mouse_position[1],
+ x, y);
+ }
glDisable(GL_LINE_STIPPLE);
@@ -288,7 +304,7 @@ static bool paint_brush_update(bContext *C,
ups->anchored_size = ups->pixel_radius = sqrtf(dx * dx + dy * dy);
- ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + M_PI;
+ ups->brush_rotation = ups->brush_rotation_sec = atan2f(dx, dy) + (float)M_PI;
if (brush->flag & BRUSH_EDGE_TO_EDGE) {
halfway[0] = dx * 0.5f + stroke->initial_mouse[0];
@@ -654,10 +670,11 @@ PaintStroke *paint_stroke_new(bContext *C,
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"))
+ if (stroke->stroke_mode == BRUSH_STROKE_INVERT)
{
- RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
+ if (br->flag & (BRUSH_CURVE | BRUSH_LINE)) {
+ RNA_enum_set(op->ptr, "mode", BRUSH_STROKE_NORMAL);
+ }
}
/* initialize here */
ups->overlap_factor = 1.0;
@@ -996,6 +1013,34 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str
return false;
}
+static void paint_stroke_line_constrain (PaintStroke *stroke, float mouse[2])
+{
+ if (stroke->constrain_line) {
+ float line[2];
+ float angle, len, res;
+
+ sub_v2_v2v2(line, mouse, stroke->last_mouse_position);
+ angle = atan2(line[1], line[0]);
+ len = len_v2(line);
+
+ /* divide angle by PI/4 */
+ angle = 4.0f * angle / (float)M_PI;
+
+ /* now take residue */
+ res = angle - floorf(angle);
+
+ /* residue decides how close we are at a certain angle */
+ if (res <= 0.5f) {
+ angle = floorf(angle) * (float)M_PI_4;
+ }
+ else {
+ angle = (floorf(angle) + 1.0f) * (float)M_PI_4;
+ }
+
+ mouse[0] = stroke->constrained_pos[0] = len * cosf(angle) + stroke->last_mouse_position[0];
+ mouse[1] = stroke->constrained_pos[1] = len * sinf(angle) + stroke->last_mouse_position[1];
+ }
+}
int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
@@ -1069,7 +1114,9 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
if (event->type == stroke->event_type && !first_modal) {
if (event->val == KM_RELEASE) {
- paint_stroke_line_end (C, op, stroke, sample_average.mouse);
+ copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
+ paint_stroke_line_constrain(stroke, mouse);
+ paint_stroke_line_end (C, op, stroke, mouse);
stroke_done(C, op);
return OPERATOR_FINISHED;
}
@@ -1079,13 +1126,22 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
stroke_done(C, op);
return OPERATOR_FINISHED;
}
- else if ((br->flag & BRUSH_LINE) && stroke->stroke_started &&
- (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))))
- {
- if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
- copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
+ else if (br->flag & BRUSH_LINE) {
+ if (event->ctrl)
+ stroke->constrain_line = true;
+ else
+ stroke->constrain_line = false;
+
+ copy_v2_fl2(mouse, event->mval[0], event->mval[1]);
+ paint_stroke_line_constrain(stroke, mouse);
+
+ if (stroke->stroke_started && (first_modal || (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE))))
+ {
+ if ((br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE) || (br->mtex.brush_angle_mode & MTEX_ANGLE_RAKE)) {
+ copy_v2_v2(stroke->ups->last_rake, stroke->last_mouse_position);
+ }
+ paint_calculate_rake_rotation(stroke->ups, br, mouse);
}
- paint_calculate_rake_rotation(stroke->ups, br, sample_average.mouse);
}
else if (first_modal ||
/* regular dabs */
diff --git a/source/blender/editors/sculpt_paint/paint_undo.c b/source/blender/editors/sculpt_paint/paint_undo.c
index 20e3155c01d..0293a0bfc00 100644
--- a/source/blender/editors/sculpt_paint/paint_undo.c
+++ b/source/blender/editors/sculpt_paint/paint_undo.c
@@ -210,7 +210,7 @@ static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *
/* pass */
}
else {
- if (!name || strcmp(stack->current->name, name) == 0) {
+ if (!name || STREQ(stack->current->name, name)) {
if (G.debug & G_DEBUG_WM) {
printf("%s: undo '%s'\n", __func__, stack->current->name);
}
@@ -225,7 +225,7 @@ static int undo_stack_step(bContext *C, UndoStack *stack, int step, const char *
/* pass */
}
else {
- if (!name || strcmp(stack->current->name, name) == 0) {
+ if (!name || STREQ(stack->current->name, name)) {
undo = (stack->current && stack->current->next) ? stack->current->next : stack->elems.first;
undo_restore(C, stack, undo);
stack->current = undo;
@@ -394,7 +394,7 @@ int ED_undo_paint_valid(int type, const char *name)
/* pass */
}
else {
- if (name && strcmp(stack->current->name, name) == 0)
+ if (name && STREQ(stack->current->name, name))
return 1;
else
return stack->elems.first != stack->elems.last;
diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c
index 9c2c13f9a2d..c0ed5005397 100644
--- a/source/blender/editors/sculpt_paint/paint_utils.c
+++ b/source/blender/editors/sculpt_paint/paint_utils.c
@@ -177,7 +177,7 @@ float paint_get_tex_pixel(MTex *mtex, float u, float v, struct ImagePool *pool,
float co[3] = {u, v, 0.0f};
externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
return intensity;
}
@@ -189,7 +189,7 @@ void paint_get_tex_pixel_col(MTex *mtex, float u, float v, float rgba[4], struct
float intensity;
hasrgb = externtex(mtex, co, &intensity,
- rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool);
+ rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false);
if (!hasrgb) {
rgba[0] = intensity;
rgba[1] = intensity;
@@ -373,15 +373,15 @@ static void imapaint_pick_uv(Scene *scene, Object *ob, unsigned int faceindex, c
}
/* 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)
+static int imapaint_pick_face(ViewContext *vc, const int mval[2], unsigned int *r_index, unsigned int totpoly)
{
- if (totface == 0)
+ if (totpoly == 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) {
+ if ((*r_index) == 0 || (*r_index) > (unsigned int)totpoly) {
return 0;
}
@@ -456,7 +456,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
ViewContext vc;
const int mval[2] = {x, y};
unsigned int faceindex;
- unsigned int totface = me->totface;
+ unsigned int totpoly = me->totpoly;
MTFace *dm_mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
if (dm_mtface) {
@@ -464,7 +464,7 @@ void paint_sample_color(bContext *C, ARegion *ar, int x, int y, bool texpaint_pr
view3d_operator_needs_opengl(C);
- if (imapaint_pick_face(&vc, mval, &faceindex, totface)) {
+ if (imapaint_pick_face(&vc, mval, &faceindex, totpoly)) {
Image *image;
if (use_material)
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index dbb29997102..69428c0f0d7 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -4248,14 +4248,14 @@ static void sculpt_stroke_update_step(bContext *C, struct PaintStroke *UNUSED(st
sculpt_restore_mesh(sd, ob);
if (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT) {
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
- sd->constant_detail / 100.0f);
+ BKE_pbvh_bmesh_detail_size_set(ss->pbvh, sd->constant_detail / 100.0f);
}
else {
- BKE_pbvh_bmesh_detail_size_set(ss->pbvh,
- (ss->cache->radius /
- (float)ups->pixel_radius) *
- (float)sd->detail_size / 0.4f);
+ BKE_pbvh_bmesh_detail_size_set(
+ ss->pbvh,
+ (ss->cache->radius /
+ (float)ups->pixel_radius) *
+ (float)(sd->detail_size * U.pixelsize) / 0.4f);
}
if (sculpt_stroke_dynamic_topology(ss, brush)) {
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 4e9d23d3d97..a4adbc6bca8 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -104,7 +104,7 @@ static int sculpt_undo_restore_coords(bContext *C, DerivedMesh *dm, SculptUndoNo
if (unode->maxvert) {
/* regular mesh restore */
- if (ss->kb && strcmp(ss->kb->name, unode->shapeName)) {
+ if (ss->kb && !STREQ(ss->kb->name, unode->shapeName)) {
/* shape key has been changed before calling undo operator */
Key *key = BKE_key_from_object(ob);
@@ -404,7 +404,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
bool need_mask = false;
for (unode = lb->first; unode; unode = unode->next) {
- if (strcmp(unode->idname, ob->id.name) == 0) {
+ if (STREQ(unode->idname, ob->id.name)) {
if (unode->type == SCULPT_UNDO_MASK) {
/* is possible that we can't do the mask undo (below)
* because of the vertex count */
@@ -423,7 +423,7 @@ static void sculpt_undo_restore(bContext *C, ListBase *lb)
return;
for (unode = lb->first; unode; unode = unode->next) {
- if (!(strcmp(unode->idname, ob->id.name) == 0))
+ if (!STREQ(unode->idname, ob->id.name))
continue;
/* check if undo data matches current data well enough to
@@ -550,7 +550,7 @@ static bool sculpt_undo_cleanup(bContext *C, ListBase *lb)
unode = lb->first;
- if (unode && strcmp(unode->idname, ob->id.name) != 0) {
+ if (unode && !STREQ(unode->idname, ob->id.name)) {
if (unode->bm_entry)
BM_log_cleanup_entry(unode->bm_entry);
diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c
index 23bc4a483d3..a9feb9f48de 100644
--- a/source/blender/editors/sculpt_paint/sculpt_uv.c
+++ b/source/blender/editors/sculpt_paint/sculpt_uv.c
@@ -598,7 +598,7 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
UvEdge *edges;
GHash *edgeHash;
- GHashIterator *ghi;
+ GHashIterator gh_iter;
bool do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
int island_index = 0;
@@ -754,21 +754,15 @@ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, const wm
uv_sculpt_stroke_exit(C, op);
return NULL;
}
- ghi = BLI_ghashIterator_new(edgeHash);
- if (!ghi) {
- BLI_ghash_free(edgeHash, NULL, NULL);
- MEM_freeN(edges);
- uv_sculpt_stroke_exit(C, op);
- return NULL;
- }
+
/* fill the edges with data */
- for (i = 0; !BLI_ghashIterator_done(ghi); BLI_ghashIterator_step(ghi)) {
- data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
+ i = 0;
+ GHASH_ITER (gh_iter, edgeHash) {
+ data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
}
data->totalUvEdges = BLI_ghash_size(edgeHash);
/* cleanup temporary stuff */
- BLI_ghashIterator_free(ghi);
BLI_ghash_free(edgeHash, NULL, NULL);
MEM_freeN(edges);
diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c
index d9f4b97fe09..5ce3517696e 100644
--- a/source/blender/editors/sound/sound_ops.c
+++ b/source/blender/editors/sound/sound_ops.c
@@ -399,7 +399,7 @@ static bool sound_mixdown_check(bContext *UNUSED(C), wmOperator *op)
if (item->value == container) {
const char **ext = snd_ext_sound;
while (*ext != NULL) {
- if (!strcmp(*ext + 1, item->name)) {
+ if (STREQ(*ext + 1, item->name)) {
extension = *ext;
break;
}
@@ -449,9 +449,9 @@ static int sound_mixdown_invoke(bContext *C, wmOperator *op, const wmEvent *even
static bool sound_mixdown_draw_check_prop(PointerRNA *UNUSED(ptr), PropertyRNA *prop)
{
const char *prop_id = RNA_property_identifier(prop);
- return !(strcmp(prop_id, "filepath") == 0 ||
- strcmp(prop_id, "directory") == 0 ||
- strcmp(prop_id, "filename") == 0);
+ return !(STREQ(prop_id, "filepath") ||
+ STREQ(prop_id, "directory") ||
+ STREQ(prop_id, "filename"));
}
static void sound_mixdown_draw(bContext *C, wmOperator *op)
diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c
index a67af289f59..a263f22e072 100644
--- a/source/blender/editors/space_buttons/buttons_texture.c
+++ b/source/blender/editors/space_buttons/buttons_texture.c
@@ -559,7 +559,7 @@ static void template_texture_user_menu(bContext *C, uiLayout *layout, void *UNUS
char name[UI_MAX_NAME_STR];
/* add label per category */
- if (!last_category || strcmp(last_category, user->category) != 0) {
+ if (!last_category || !STREQ(last_category, user->category)) {
uiItemL(layout, user->category, ICON_NONE);
but = block->buttons.last;
but->drawflag = UI_BUT_TEXT_LEFT;
diff --git a/source/blender/editors/space_clip/clip_buttons.c b/source/blender/editors/space_clip/clip_buttons.c
index f8299a8d335..c32d06cf9b1 100644
--- a/source/blender/editors/space_clip/clip_buttons.c
+++ b/source/blender/editors/space_clip/clip_buttons.c
@@ -540,7 +540,7 @@ void uiTemplateMovieclipInformation(uiLayout *layout, PointerRNA *ptr, const cha
uiItemL(col, str, ICON_NONE);
/* Display current frame number. */
- framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr) ;
+ framenr = BKE_movieclip_remap_scene_to_clip_frame(clip, user->framenr);
if (framenr <= clip->len)
BLI_snprintf(str, sizeof(str), IFACE_("Frame: %d / %d"), framenr, clip->len);
else
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index e3d45a297a7..b99b23c60d3 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -1342,7 +1342,8 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
if (clip->anim) {
pj->index_context = IMB_anim_index_rebuild_context(clip->anim, clip->proxy.build_tc_flag,
- clip->proxy.build_size_flag, clip->proxy.quality);
+ clip->proxy.build_size_flag, clip->proxy.quality,
+ true, NULL);
}
WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
diff --git a/source/blender/editors/space_console/console_ops.c b/source/blender/editors/space_console/console_ops.c
index 2d5e5c6e0f2..8263268898f 100644
--- a/source/blender/editors/space_console/console_ops.c
+++ b/source/blender/editors/space_console/console_ops.c
@@ -107,7 +107,7 @@ static ConsoleLine *console_history_find(SpaceConsole *sc, const char *str, Cons
if (cl == cl_ignore)
continue;
- if (strcmp(str, cl->line) == 0)
+ if (STREQ(str, cl->line))
return cl;
}
@@ -722,7 +722,7 @@ static int console_history_cycle_exec(bContext *C, wmOperator *op)
if (ci->prev) {
ConsoleLine *ci_prev = (ConsoleLine *)ci->prev;
- if (strcmp(ci->line, ci_prev->line) == 0)
+ if (STREQ(ci->line, ci_prev->line))
console_history_free(sc, ci_prev);
}
@@ -791,7 +791,7 @@ static int console_history_append_exec(bContext *C, wmOperator *op)
while ((cl = console_history_find(sc, ci->line, ci)))
console_history_free(sc, cl);
- if (strcmp(str, ci->line) == 0) {
+ if (STREQ(str, ci->line)) {
MEM_freeN(str);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c
index 3f3c14d3a7d..57611930e99 100644
--- a/source/blender/editors/space_file/file_draw.c
+++ b/source/blender/editors/space_file/file_draw.c
@@ -133,7 +133,8 @@ void file_draw_buttons(const bContext *C, ARegion *ar)
loadbutton = 0;
}
else {
- loadbutton = UI_fontstyle_string_width(params->title) + btn_margin;
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin;
CLAMP_MIN(loadbutton, btn_minw);
if (available_w <= loadbutton + separator + input_minw) {
loadbutton = 0;
@@ -238,7 +239,7 @@ static void draw_tile(int sx, int sy, int width, int height, int colorid, int sh
static int get_file_icon(struct direntry *file)
{
if (file->type & S_IFDIR) {
- if (strcmp(file->relname, "..") == 0) {
+ if (FILENAME_IS_PARENT(file->relname)) {
return ICON_FILE_PARENT;
}
if (file->flags & FILE_TYPE_APPLICATIONBUNDLE) {
@@ -402,7 +403,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname)
BLI_strncpy(filename, sfile->params->renameedit, sizeof(filename));
BLI_make_file_string(G.main->name, newname, sfile->params->dir, filename);
- if (strcmp(orgname, newname) != 0) {
+ if (!STREQ(orgname, newname)) {
if (!BLI_exists(newname)) {
BLI_rename(orgname, newname);
/* to make sure we show what is on disk */
@@ -528,7 +529,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
int shade = (params->active_file == i) || (file->selflag & FILE_SEL_HIGHLIGHTED) ? 20 : 0;
/* readonly files (".." and ".") must not be drawn as selected - set color back to normal */
- if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) {
+ if (FILENAME_IS_CURRPAR(file->relname)) {
colorid = TH_BACK;
}
draw_tile(sx, sy - 1, layout->tile_w + 4, sfile->layout->tile_h + layout->tile_border_y, colorid, shade);
@@ -537,7 +538,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
UI_draw_roundbox_corner_set(UI_CNR_NONE);
/* don't drag parent or refresh items */
- do_drag = !(STREQ(file->relname, "..") || STREQ(file->relname, "."));
+ do_drag = !(FILENAME_IS_CURRPAR(file->relname));
if (FILE_IMGDISPLAY == params->display) {
is_icon = 0;
@@ -590,7 +591,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
if (params->display == FILE_SHORTDISPLAY) {
sx += (int)layout->column_widths[COLUMN_NAME] + column_space;
- if (!(file->type & S_IFDIR)) {
+ if ((BLI_is_dir(file->path) == false) && file->size[0]) {
file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
}
@@ -619,7 +620,7 @@ void file_draw_list(const bContext *C, ARegion *ar)
file_draw_string(sx, sy, file->time, layout->column_widths[COLUMN_TIME], layout->tile_h, align);
sx += (int)layout->column_widths[COLUMN_TIME] + column_space;
- if (!(file->type & S_IFDIR)) {
+ if ((BLI_is_dir(file->path) == false) && file->size[0]) {
file_draw_string(sx, sy, file->size, layout->column_widths[COLUMN_SIZE], layout->tile_h, align);
sx += (int)layout->column_widths[COLUMN_SIZE] + column_space;
}
diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c
index 3a579820106..ba6f91e8301 100644
--- a/source/blender/editors/space_file/file_ops.c
+++ b/source/blender/editors/space_file/file_ops.c
@@ -183,11 +183,11 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
retval = FILE_SELECT_DIR;
}
/* the path is too long and we are not going up! */
- else if (strcmp(file->relname, "..") && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) {
+ else if (!FILENAME_IS_PARENT(file->relname) && strlen(params->dir) + strlen(file->relname) >= FILE_MAX) {
// XXX error("Path too long, cannot enter this directory");
}
else {
- if (strcmp(file->relname, "..") == 0) {
+ if (FILENAME_IS_PARENT(file->relname)) {
/* avoids /../../ */
BLI_parent_dir(params->dir);
}
@@ -269,7 +269,7 @@ static int file_border_select_modal(bContext *C, wmOperator *op, const wmEvent *
for (idx = sel.last; idx >= 0; idx--) {
struct direntry *file = filelist_file(sfile->files, idx);
- if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) {
+ if (FILENAME_IS_CURRPAR(file->relname)) {
file->selflag &= ~FILE_SEL_HIGHLIGHTED;
}
@@ -362,7 +362,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
if (idx >= 0) {
struct direntry *file = filelist_file(sfile->files, idx);
- if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) {
+ if (FILENAME_IS_CURRPAR(file->relname)) {
/* skip - If a readonly file (".." or ".") is selected, skip deselect all! */
}
else {
@@ -1531,7 +1531,7 @@ static int file_rename_poll(bContext *C)
if (idx >= 0) {
struct direntry *file = filelist_file(sfile->files, idx);
- if (STREQ(file->relname, "..") || STREQ(file->relname, ".")) {
+ if (FILENAME_IS_CURRPAR(file->relname)) {
poll = 0;
}
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index bcef0817ffe..f0180c3c841 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -237,9 +237,6 @@ typedef struct FileList {
bool (*filterf)(struct direntry *, const char *, FileListFilter *);
} FileList;
-#define FILENAME_IS_BREADCRUMBS(_n) \
- ((_n)[0] == '.' && ((_n)[1] == '\0' || ((_n)[1] == '.' && (_n)[2] == '\0')))
-
#define SPECIAL_IMG_SIZE 48
#define SPECIAL_IMG_ROWS 4
#define SPECIAL_IMG_COLS 4
@@ -304,10 +301,10 @@ static int compare_direntry_generic(const struct direntry *entry1, const struct
if ((entry1->type & S_IFMT) > (entry2->type & S_IFMT)) return (1);
/* make sure "." and ".." are always first */
- if (strcmp(entry1->relname, ".") == 0) return (-1);
- if (strcmp(entry2->relname, ".") == 0) return (1);
- if (strcmp(entry1->relname, "..") == 0) return (-1);
- if (strcmp(entry2->relname, "..") == 0) return (1);
+ if (FILENAME_IS_CURRENT(entry1->relname)) return (-1);
+ if (FILENAME_IS_CURRENT(entry2->relname)) return (1);
+ if (FILENAME_IS_PARENT(entry1->relname)) return (-1);
+ if (FILENAME_IS_PARENT(entry2->relname)) return (1);
return 0;
}
@@ -447,7 +444,7 @@ static bool is_filtered_file(struct direntry *file, const char *UNUSED(root), Fi
{
bool is_filtered = !is_hidden_file(file->relname, filter);
- if (is_filtered && filter->filter && !FILENAME_IS_BREADCRUMBS(file->relname)) {
+ if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relname)) {
if ((file->type & S_IFDIR) && !(filter->filter & FILE_TYPE_FOLDER)) {
is_filtered = false;
}
@@ -471,7 +468,7 @@ static bool is_filtered_lib(struct direntry *file, const char *root, FileListFil
if (BLO_is_a_library(root, dir, group)) {
is_filtered = !is_hidden_file(file->relname, filter);
- if (is_filtered && filter->filter && !FILENAME_IS_BREADCRUMBS(file->relname)) {
+ if (is_filtered && filter->filter && !FILENAME_IS_CURRPAR(file->relname)) {
if (is_filtered && (filter->filter_search[0] != '\0')) {
if (fnmatch(filter->filter_search, file->relname, FNM_CASEFOLD) != 0) {
is_filtered = false;
@@ -634,10 +631,10 @@ ImBuf *filelist_geticon(struct FileList *filelist, const int index)
fidx = filelist->fidx[index];
file = &filelist->filelist[fidx];
if (file->type & S_IFDIR) {
- if (strcmp(filelist->filelist[fidx].relname, "..") == 0) {
+ if (FILENAME_IS_PARENT(filelist->filelist[fidx].relname)) {
ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT];
}
- else if (strcmp(filelist->filelist[fidx].relname, ".") == 0) {
+ else if (FILENAME_IS_CURRENT(filelist->filelist[fidx].relname)) {
ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH];
}
else {
@@ -764,28 +761,20 @@ struct direntry *filelist_file(struct FileList *filelist, int index)
int filelist_find(struct FileList *filelist, const char *filename)
{
- int index = -1;
- int i;
int fidx = -1;
if (!filelist->fidx)
return fidx;
-
- for (i = 0; i < filelist->numfiles; ++i) {
- if (strcmp(filelist->filelist[i].relname, filename) == 0) { /* not dealing with user input so don't need BLI_path_cmp */
- index = i;
- break;
- }
- }
+ for (fidx = 0; fidx < filelist->numfiltered; fidx++) {
+ int index = filelist->fidx[fidx];
- for (i = 0; i < filelist->numfiltered; ++i) {
- if (filelist->fidx[i] == index) {
- fidx = i;
- break;
+ if (STREQ(filelist->filelist[index].relname, filename)) {
+ return fidx;
}
}
- return fidx;
+
+ return -1;
}
/* would recognize .blend as well */
@@ -1116,7 +1105,7 @@ static void filelist_from_library(struct FileList *filelist)
filelist->filelist = malloc(filelist->numfiles * sizeof(*filelist->filelist));
memset(filelist->filelist, 0, filelist->numfiles * sizeof(*filelist->filelist));
- filelist->filelist[0].relname = BLI_strdup("..");
+ filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT);
filelist->filelist[0].type |= S_IFDIR;
for (i = 0, l = names; i < nnames; i++, l = l->next) {
@@ -1191,7 +1180,7 @@ static void filelist_from_main(struct FileList *filelist)
filelist->filelist[a].type |= S_IFDIR;
}
- filelist->filelist[0].relname = BLI_strdup("..");
+ filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT);
filelist->filelist[1].relname = BLI_strdup("Scene");
filelist->filelist[2].relname = BLI_strdup("Object");
filelist->filelist[3].relname = BLI_strdup("Mesh");
@@ -1244,7 +1233,7 @@ static void filelist_from_main(struct FileList *filelist)
if (!filelist->filter_data.hide_parent) {
memset(&(filelist->filelist[0]), 0, sizeof(struct direntry));
- filelist->filelist[0].relname = BLI_strdup("..");
+ filelist->filelist[0].relname = BLI_strdup(FILENAME_PARENT);
filelist->filelist[0].type |= S_IFDIR;
files++;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 3e663275dcd..c452f2e1ff4 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -669,7 +669,7 @@ int autocomplete_directory(struct bContext *C, char *str, void *UNUSED(arg_v))
AutoComplete *autocpl = UI_autocomplete_begin(str, FILE_MAX);
while ((de = readdir(dir)) != NULL) {
- if (strcmp(".", de->d_name) == 0 || strcmp("..", de->d_name) == 0) {
+ if (FILENAME_IS_CURRPAR(de->d_name)) {
/* pass */
}
else {
diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c
index 4ab9bc6a849..05dfdf66ab6 100644
--- a/source/blender/editors/space_file/fsmenu.c
+++ b/source/blender/editors/space_file/fsmenu.c
@@ -283,10 +283,10 @@ void fsmenu_read_bookmarks(struct FSMenu *fsmenu, const char *filename)
if (!fp) return;
while (fgets(line, sizeof(line), fp) != NULL) { /* read a line */
- if (strncmp(line, "[Bookmarks]", 11) == 0) {
+ if (STREQLEN(line, "[Bookmarks]", 11)) {
category = FS_CATEGORY_BOOKMARKS;
}
- else if (strncmp(line, "[Recent]", 8) == 0) {
+ else if (STREQLEN(line, "[Recent]", 8)) {
category = FS_CATEGORY_RECENT;
}
else {
@@ -359,7 +359,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
continue;
FSRefMakePath(&dir, path, FILE_MAX);
- if (strcmp((char *)path, "/home") && strcmp((char *)path, "/net")) {
+ if (!STREQ((char *)path, "/home") && !STREQ((char *)path, "/net")) {
/* /net and /home are meaningless on OSX, home folders are stored in /Users */
fsmenu_insert_entry(fsmenu, FS_CATEGORY_SYSTEM, (char *)path, FS_INSERT_SORTED);
}
@@ -488,7 +488,7 @@ void fsmenu_read_system(struct FSMenu *fsmenu, int read_bookmarks)
else {
while ((mnt = getmntent(fp))) {
/* not sure if this is right, but seems to give the relevant mnts */
- if (strncmp(mnt->mnt_fsname, "/dev", 4))
+ if (!STREQLEN(mnt->mnt_fsname, "/dev", 4))
continue;
len = strlen(mnt->mnt_dir);
diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c
index 9093734f25f..2d8a0a3da29 100644
--- a/source/blender/editors/space_graph/graph_draw.c
+++ b/source/blender/editors/space_graph/graph_draw.c
@@ -848,11 +848,13 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
* NOTE: we need to scale the y-values to be valid for the units
*/
glBegin(GL_LINES);
+ {
t = v2d->cur.xmin;
glVertex2f(t, t * unitfac);
t = v2d->cur.xmax;
glVertex2f(t, t * unitfac);
+ }
glEnd();
/* cleanup line drawing */
@@ -875,6 +877,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
setlinestyle(5);
glBegin(GL_LINES);
+ {
/* x-axis lookup */
co[0] = x;
@@ -894,6 +897,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu)
co[0] = x;
glVertex2fv(co);
+ }
glEnd();
setlinestyle(0);
diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c
index b87f80c4e62..2944901663b 100644
--- a/source/blender/editors/space_graph/graph_edit.c
+++ b/source/blender/editors/space_graph/graph_edit.c
@@ -1721,7 +1721,7 @@ static int graphkeys_euler_filter_exec(bContext *C, wmOperator *op)
* so if the paths or the ID's don't match up, then a curve needs to be added
* to a new group
*/
- if ((euf) && (euf->id == ale->id) && (strcmp(euf->rna_path, fcu->rna_path) == 0)) {
+ if ((euf) && (euf->id == ale->id) && (STREQ(euf->rna_path, fcu->rna_path))) {
/* this should be fine to add to the existing group then */
euf->fcurves[fcu->array_index] = fcu;
}
diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c
index 78dbae7618b..46a39806ad7 100644
--- a/source/blender/editors/space_graph/graph_select.c
+++ b/source/blender/editors/space_graph/graph_select.c
@@ -66,6 +66,15 @@
/* ************************************************************************** */
/* KEYFRAMES STUFF */
+static void graphkeys_auto_view(bContext *C)
+{
+ const SpaceIpo *sipo = CTX_wm_space_graph(C);
+
+ if (sipo && sipo->flag & SIPO_AUTO_VIEW_SELECTED) {
+ WM_operator_name_call(C, "GRAPH_OT_view_selected", WM_OP_INVOKE_DEFAULT, NULL);
+ }
+}
+
/* ******************** Deselect All Operator ***************************** */
/* This operator works in one of three ways:
* 1) (de)select all (AKEY) - test if select all or deselect all
@@ -83,7 +92,7 @@
* 2 = invert
* - do_channels: whether to affect selection status of channels
*/
-static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short do_channels)
+static short deselect_graph_keys(bAnimContext *ac, short test, short sel, short do_channels)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
@@ -142,6 +151,8 @@ static void deselect_graph_keys(bAnimContext *ac, short test, short sel, short d
/* Cleanup */
ANIM_animdata_freelist(&anim_data);
+
+ return sel;
}
/* ------------------- */
@@ -150,6 +161,7 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
bAnimListElem *ale_active = NULL;
+ short sel;
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0)
@@ -163,9 +175,9 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op)
/* 'standard' behavior - check if selected, then apply relevant selection */
if (RNA_boolean_get(op->ptr, "invert"))
- deselect_graph_keys(&ac, 0, SELECT_INVERT, true);
+ sel = deselect_graph_keys(&ac, 0, SELECT_INVERT, true);
else
- deselect_graph_keys(&ac, 1, SELECT_ADD, true);
+ sel = deselect_graph_keys(&ac, 1, SELECT_ADD, true);
/* restore active F-Curve... */
if (ale_active) {
@@ -180,6 +192,9 @@ static int graphkeys_deselectall_exec(bContext *C, wmOperator *op)
ale_active = NULL;
}
+ if (sel != SELECT_SUBTRACT)
+ graphkeys_auto_view(C);
+
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -374,6 +389,8 @@ static int graphkeys_borderselect_exec(bContext *C, wmOperator *op)
/* apply borderselect action */
borderselect_graphkeys(&ac, &rect_fl, mode, selectmode, incl_handles, NULL);
+ graphkeys_auto_view(C);
+
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -461,6 +478,8 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op)
MEM_freeN((void *)data_lasso.mcords);
+ graphkeys_auto_view(C);
+
/* send notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -491,6 +510,14 @@ void GRAPH_OT_select_lasso(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first");
}
+static int graph_circle_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (event->type == EVT_MODAL_MAP && event->val == GESTURE_MODAL_NOP)
+ graphkeys_auto_view(C);
+
+ return WM_gesture_circle_modal(C, op, event);
+}
+
static int graph_circle_select_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
@@ -552,7 +579,7 @@ void GRAPH_OT_select_circle(wmOperatorType *ot)
ot->idname = "GRAPH_OT_select_circle";
ot->invoke = WM_gesture_circle_invoke;
- ot->modal = WM_gesture_circle_modal;
+ ot->modal = graph_circle_select_modal;
ot->exec = graph_circle_select_exec;
ot->poll = graphop_visible_keyframes_poll;
ot->cancel = WM_gesture_circle_cancel;
@@ -725,6 +752,8 @@ static int graphkeys_columnselect_exec(bContext *C, wmOperator *op)
else
columnselect_graph_keys(&ac, mode);
+ graphkeys_auto_view(C);
+
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -783,6 +812,8 @@ static int graphkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
/* Cleanup */
ANIM_animdata_freelist(&anim_data);
+ graphkeys_auto_view(C);
+
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -807,12 +838,13 @@ void GRAPH_OT_select_linked(wmOperatorType *ot)
/* ******************** Select More/Less Operators *********************** */
/* Common code to perform selection */
-static void select_moreless_graph_keys(bAnimContext *ac, short mode)
+static void select_moreless_graph_keys(bContext *C, bAnimContext *ac, short mode)
{
ListBase anim_data = {NULL, NULL};
bAnimListElem *ale;
int filter;
+ const SpaceIpo *sipo = (SpaceIpo *)ac->sl;
KeyframeEditData ked;
KeyframeEditFunc build_cb;
@@ -842,6 +874,24 @@ static void select_moreless_graph_keys(bAnimContext *ac, short mode)
/* free the selmap used here */
MEM_freeN(ked.data);
ked.data = NULL;
+
+ /* only do auto view if a bezier point is selected */
+ if (sipo->flag & SIPO_AUTO_VIEW_SELECTED) {
+ const FCurve *fcu = (FCurve *)ale->key_data;
+ const BezTriple *bezt;
+ unsigned int i;
+
+ /* only continue if F-Curve has keyframes */
+ if (fcu->bezt == NULL)
+ continue;
+
+ for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) {
+ if (BEZSELECTED(bezt)) {
+ graphkeys_auto_view(C);
+ break;
+ }
+ }
+ }
}
/* Cleanup */
@@ -859,7 +909,7 @@ static int graphkeys_select_more_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* perform select changes */
- select_moreless_graph_keys(&ac, SELMAP_MORE);
+ select_moreless_graph_keys(C, &ac, SELMAP_MORE);
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -893,7 +943,7 @@ static int graphkeys_select_less_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* perform select changes */
- select_moreless_graph_keys(&ac, SELMAP_LESS);
+ select_moreless_graph_keys(C, &ac, SELMAP_LESS);
/* set notifier that keyframe selection has changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL);
@@ -1008,6 +1058,8 @@ static int graphkeys_select_leftright_exec(bContext *C, wmOperator *op)
/* do the selecting now */
graphkeys_select_leftright(&ac, leftright, selectmode);
+ graphkeys_auto_view(C);
+
/* set notifier that keyframe selection (and channels too) have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | ND_ANIMCHAN | NA_SELECTED, NULL);
diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c
index 05868283b2e..fb3c140fddf 100644
--- a/source/blender/editors/space_image/image_buttons.c
+++ b/source/blender/editors/space_image/image_buttons.c
@@ -64,6 +64,7 @@
#include "image_intern.h"
#define B_NOP -1
+#define MAX_IMAGE_INFO_LEN 128
/* proto */
@@ -640,8 +641,6 @@ static void rna_update_cb(bContext *C, void *arg_cb, void *UNUSED(arg))
void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char *propname, PointerRNA *userptr, int compact)
{
-#define MAX_INFO_LEN 128
-
PropertyRNA *prop;
PointerRNA imaptr;
RNAUpdateCb *cb;
@@ -650,7 +649,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
Scene *scene = CTX_data_scene(C);
uiLayout *row, *split, *col;
uiBlock *block;
- char str[MAX_INFO_LEN];
+ char str[MAX_IMAGE_INFO_LEN];
void *lock;
@@ -687,14 +686,14 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
uiLayoutSetContextPointer(layout, "edit_image_user", userptr);
if (!compact)
- uiTemplateID(layout, C, ptr, propname, "IMAGE_OT_new", "IMAGE_OT_open", NULL);
+ uiTemplateID(layout, C, ptr, propname, ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL);
if (ima) {
UI_block_funcN_set(block, rna_update_cb, MEM_dupallocN(cb), NULL);
if (ima->source == IMA_SRC_VIEWER) {
ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
- image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN);
+ image_info(scene, iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN);
BKE_image_release_ibuf(ima, ibuf, lock);
uiItemL(layout, ima->id.name + 2, ICON_NONE);
@@ -763,10 +762,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
}
else if (ima->source != IMA_SRC_GENERATED) {
if (compact == 0) {
- ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
- image_info(scene, iuser, ima, ibuf, str, MAX_INFO_LEN);
- BKE_image_release_ibuf(ima, ibuf, lock);
- uiItemL(layout, str, ICON_NONE);
+ uiTemplateImageInfo(layout, C, ima, iuser);
}
}
@@ -780,7 +776,7 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
bool has_alpha = true;
if (ibuf) {
- int imtype = BKE_ftype_to_imtype(ibuf->ftype);
+ int imtype = BKE_image_ftype_to_imtype(ibuf->ftype);
char valid_channels = BKE_imtype_valid_channels(imtype, false);
has_alpha = (valid_channels & IMA_CHAN_FLAG_ALPHA) != 0;
@@ -791,7 +787,14 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
if (has_alpha) {
col = uiLayoutColumn(layout, false);
uiItemR(col, &imaptr, "use_alpha", 0, NULL, ICON_NONE);
- uiItemR(col, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE);
+ row = uiLayoutRow(col, false);
+ uiLayoutSetActive(row, RNA_boolean_get(&imaptr, "use_alpha"));
+ uiItemR(row, &imaptr, "alpha_mode", 0, IFACE_("Alpha"), ICON_NONE);
+ }
+
+ if (ima->source == IMA_SRC_MOVIE) {
+ col = uiLayoutColumn(layout, false);
+ uiItemR(col, &imaptr, "use_deinterlace", 0, IFACE_("Deinterlace"), ICON_NONE);
}
uiItemS(layout);
@@ -856,8 +859,6 @@ void uiTemplateImage(uiLayout *layout, bContext *C, PointerRNA *ptr, const char
}
MEM_freeN(cb);
-
-#undef MAX_INFO_LEN
}
void uiTemplateImageSettings(uiLayout *layout, PointerRNA *imfptr, int color_management)
@@ -977,6 +978,24 @@ void uiTemplateImageLayers(uiLayout *layout, bContext *C, Image *ima, ImageUser
}
}
+void uiTemplateImageInfo(uiLayout *layout, bContext *C, Image *ima, ImageUser *iuser)
+{
+ ImBuf *ibuf;
+ char str[MAX_IMAGE_INFO_LEN];
+ void *lock;
+
+ if (!ima || !iuser)
+ return;
+
+ ibuf = BKE_image_acquire_ibuf(ima, iuser, &lock);
+
+ image_info(CTX_data_scene(C), iuser, ima, ibuf, str, MAX_IMAGE_INFO_LEN);
+ BKE_image_release_ibuf(ima, ibuf, lock);
+ uiItemL(layout, str, ICON_NONE);
+}
+
+#undef MAX_IMAGE_INFO_LEN
+
void image_buttons_register(ARegionType *UNUSED(art))
{
diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c
index 757059ebc29..8e2c6b97a5b 100644
--- a/source/blender/editors/space_image/image_edit.c
+++ b/source/blender/editors/space_image/image_edit.c
@@ -35,6 +35,7 @@
#include "BLI_rect.h"
+#include "BKE_colortools.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
@@ -290,6 +291,20 @@ void ED_image_point_pos__reverse(SpaceImage *sima, ARegion *ar, const float co[2
r_co[1] = (co[1] * height * zoomy) + (float)sy;
}
+void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *sima, struct ImBuf *ibuf, bool use_view_settings)
+{
+ Scene *scene = CTX_data_scene(C);
+ Object *ob = CTX_data_active_object(C);
+
+ /* scope update can be expensive, don't update during paint modes */
+ if (sima->mode == SI_MODE_PAINT)
+ return;
+ if (ob && ((ob->mode & OB_MODE_TEXTURE_PAINT) != 0))
+ return;
+
+ scopes_update(&sima->scopes, ibuf, use_view_settings ? &scene->view_settings : NULL, &scene->display_settings);
+}
+
bool ED_space_image_show_render(SpaceImage *sima)
{
return (sima->image && ELEM(sima->image->type, IMA_TYPE_R_RESULT, IMA_TYPE_COMPOSITE));
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 6cf53533618..af1502509f5 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -899,9 +899,9 @@ static void image_tools_area_draw(const bContext *C, ARegion *ar)
BKE_histogram_update_sample_line(&sima->sample_line_hist, ibuf, &scene->view_settings, &scene->display_settings);
}
if (sima->image->flag & IMA_VIEW_AS_RENDER)
- scopes_update(&sima->scopes, ibuf, &scene->view_settings, &scene->display_settings);
+ ED_space_image_scopes_update(C, sima, ibuf, true);
else
- scopes_update(&sima->scopes, ibuf, NULL, &scene->display_settings);
+ ED_space_image_scopes_update(C, sima, ibuf, false);
}
}
ED_space_image_release_buffer(sima, ibuf, lock);
diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c
index 62703ba517e..2c6280f5670 100644
--- a/source/blender/editors/space_logic/logic_ops.c
+++ b/source/blender/editors/space_logic/logic_ops.c
@@ -39,6 +39,8 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLF_translation.h"
+
#include "BKE_context.h"
#include "BKE_main.h"
#include "BKE_sca.h"
@@ -298,7 +300,7 @@ static int sensor_add_exec(bContext *C, wmOperator *op)
BLI_strncpy(sens->name, sens_name, sizeof(sens->name));
}
- make_unique_prop_names(C, sens->name);
+ BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
ob->scaflag |= OB_SHOWSENS;
WM_event_add_notifier(C, NC_LOGIC, NULL);
@@ -405,7 +407,8 @@ static int controller_add_exec(bContext *C, wmOperator *op)
BLI_strncpy(cont->name, cont_name, sizeof(cont->name));
}
- make_unique_prop_names(C, cont->name);
+ BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name));
+
/* set the controller state mask from the current object state.
* A controller is always in a single state, so select the lowest bit set
* from the object state */
@@ -523,7 +526,7 @@ static int actuator_add_exec(bContext *C, wmOperator *op)
BLI_strncpy(act->name, act_name, sizeof(act->name));
}
- make_unique_prop_names(C, act->name);
+ BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
ob->scaflag |= OB_SHOWACT;
WM_event_add_notifier(C, NC_LOGIC, NULL);
diff --git a/source/blender/editors/space_logic/logic_window.c b/source/blender/editors/space_logic/logic_window.c
index 21a9246d7e6..37c634672df 100644
--- a/source/blender/editors/space_logic/logic_window.c
+++ b/source/blender/editors/space_logic/logic_window.c
@@ -48,6 +48,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
#include "BKE_action.h"
#include "BKE_context.h"
@@ -94,87 +95,6 @@
/* proto */
static ID **get_selected_and_linked_obs(bContext *C, short *count, short scavisflag);
-static int vergname(const void *v1, const void *v2)
-{
- const char * const *x1 = v1, * const *x2 = v2;
- return BLI_natstrcmp(*x1, *x2);
-}
-
-void make_unique_prop_names(bContext *C, char *str)
-{
- Object *ob;
- bProperty *prop;
- bSensor *sens;
- bController *cont;
- bActuator *act;
- ID **idar;
- short a, obcount, propcount=0, nr;
- const char **names;
-
- /* this function is called by a Button, and gives the current
- * stringpointer as an argument, this is the one that can change
- */
-
- idar= get_selected_and_linked_obs(C, &obcount, BUTS_SENS_SEL|BUTS_SENS_ACT|BUTS_ACT_SEL|BUTS_ACT_ACT|BUTS_CONT_SEL|BUTS_CONT_ACT);
-
- /* for each object, make properties and sca names unique */
-
- /* count total names */
- for (a=0; a<obcount; a++) {
- ob= (Object *)idar[a];
- propcount+= BLI_listbase_count(&ob->prop);
- propcount+= BLI_listbase_count(&ob->sensors);
- propcount+= BLI_listbase_count(&ob->controllers);
- propcount+= BLI_listbase_count(&ob->actuators);
- }
- if (propcount==0) {
- if (idar) MEM_freeN(idar);
- return;
- }
-
- /* make names array for sorting */
- names= MEM_callocN(propcount*sizeof(void *), "names");
-
- /* count total names */
- nr= 0;
- for (a=0; a<obcount; a++) {
- ob= (Object *)idar[a];
- prop= ob->prop.first;
- while (prop) {
- names[nr++] = prop->name;
- prop= prop->next;
- }
- sens= ob->sensors.first;
- while (sens) {
- names[nr++] = sens->name;
- sens= sens->next;
- }
- cont= ob->controllers.first;
- while (cont) {
- names[nr++] = cont->name;
- cont= cont->next;
- }
- act= ob->actuators.first;
- while (act) {
- names[nr++] = act->name;
- act= act->next;
- }
- }
-
- qsort(names, propcount, sizeof(void *), vergname);
-
- /* now we check for double names, and change them */
-
- for (nr=0; nr<propcount; nr++) {
- if (names[nr]!=str && strcmp( names[nr], str )==0 ) {
- BLI_newname(str, +1);
- }
- }
-
- MEM_freeN(idar);
- MEM_freeN(names);
-}
-
static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
{
Main *bmain= CTX_data_main(C);
@@ -206,7 +126,7 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
ob->scaflag &= ~OB_ADDSENS;
sens= new_sensor(SENS_ALWAYS);
BLI_addtail(&(ob->sensors), sens);
- make_unique_prop_names(C, sens->name);
+ BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
ob->scaflag |= OB_SHOWSENS;
}
}
@@ -248,7 +168,7 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
if (ob->scaflag & OB_ADDCONT) {
ob->scaflag &= ~OB_ADDCONT;
cont= new_controller(CONT_LOGIC_AND);
- make_unique_prop_names(C, cont->name);
+ BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name));
ob->scaflag |= OB_SHOWCONT;
BLI_addtail(&(ob->controllers), cont);
/* set the controller state mask from the current object state.
@@ -324,7 +244,7 @@ static void do_logic_buts(bContext *C, void *UNUSED(arg), int event)
if (ob->scaflag & OB_ADDACT) {
ob->scaflag &= ~OB_ADDACT;
act= new_actuator(ACT_OBJECT);
- make_unique_prop_names(C, act->name);
+ BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
BLI_addtail(&(ob->actuators), act);
ob->scaflag |= OB_SHOWACT;
}
diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c
index 0abe5e42c3e..5476d1c2683 100644
--- a/source/blender/editors/space_nla/nla_channels.c
+++ b/source/blender/editors/space_nla/nla_channels.c
@@ -650,7 +650,7 @@ static int nlaedit_delete_tracks_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
/* get a list of the AnimData blocks being shown in the NLA */
- filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL);
+ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
/* delete tracks */
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index c45626e4284..2089dced7e3 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -38,6 +38,7 @@
#include "DNA_space_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
+#include "DNA_text_types.h"
#include "BKE_context.h"
#include "BKE_curve.h"
@@ -389,6 +390,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
float width, ascender;
float x, y;
const int font_size = data->label_size / aspect;
+ const float margin = (float)(NODE_DY / 4);
nodeLabel(ntree, node, label, sizeof(label));
@@ -404,11 +406,42 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
/* 'x' doesn't need aspect correction */
x = BLI_rctf_cent_x(rct) - (0.5f * width);
- y = rct->ymax - (((NODE_DY / 4) / aspect) + (ascender * aspect));
+ y = rct->ymax - ((margin / aspect) + (ascender * aspect));
BLF_position(fontid, x, y, 0);
BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
+ /* draw text body */
+ if (node->id) {
+ Text *text = (Text *)node->id;
+ TextLine *line;
+ const float line_spacing = (BLF_height_max(fontid) * aspect) * 0.7f;
+
+ /* 'x' doesn't need aspect correction */
+ x = rct->xmin + margin;
+ y = rct->ymax - ((margin / aspect) + (ascender * aspect));
+ y -= line_spacing;
+
+ BLF_enable(fontid, BLF_CLIPPING);
+ BLF_clipping(
+ fontid,
+ rct->xmin,
+ rct->ymin,
+ rct->xmin + ((rct->xmax - rct->xmin) / aspect) - margin,
+ rct->ymax);
+
+ for (line = text->lines.first; line; line = line->next) {
+ BLF_position(fontid, x, y, 0);
+ BLF_draw(fontid, line->line, line->len);
+ y -= line_spacing;
+ if (y < rct->ymin) {
+ break;
+ }
+ }
+
+ BLF_disable(fontid, BLF_CLIPPING);
+ }
+
BLF_disable(fontid, BLF_ASPECT);
}
@@ -498,6 +531,7 @@ static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA
{
uiItemR(layout, ptr, "label_size", 0, IFACE_("Label Size"), ICON_NONE);
uiItemR(layout, ptr, "shrink", 0, IFACE_("Shrink"), ICON_NONE);
+ uiItemR(layout, ptr, "text", 0, NULL, ICON_NONE);
}
@@ -669,10 +703,10 @@ static void node_buts_image_user(uiLayout *layout, bContext *C, PointerRNA *ptr,
uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE);
}
- col = uiLayoutColumn(layout, false);
-
- if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER)
+ if (RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER) {
+ col = uiLayoutColumn(layout, false);
uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE);
+ }
}
static void node_shader_buts_material(uiLayout *layout, bContext *C, PointerRNA *ptr)
@@ -805,10 +839,51 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin
uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
uiTemplateID(layout, C, ptr, "image", NULL, "IMAGE_OT_open", NULL);
+
+ node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr);
+
uiItemR(layout, ptr, "color_space", 0, "", ICON_NONE);
uiItemR(layout, ptr, "projection", 0, "", ICON_NONE);
+}
- node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr);
+static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, PointerRNA *ptr)
+{
+ PointerRNA imaptr = RNA_pointer_get(ptr, "image");
+ PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user");
+ Image *ima = imaptr.data;
+
+ uiLayoutSetContextPointer(layout, "image_user", &iuserptr);
+ uiTemplateID(layout, C, ptr, "image", ima ? NULL : "IMAGE_OT_new", "IMAGE_OT_open", NULL);
+
+ if (!ima)
+ return;
+
+ uiItemR(layout, &imaptr, "source", 0, IFACE_("Source"), ICON_NONE);
+
+ if (!(ELEM(ima->source, IMA_SRC_GENERATED, IMA_SRC_VIEWER))) {
+ uiLayout *row = uiLayoutRow(layout, true);
+
+ if (ima->packedfile)
+ uiItemO(row, "", ICON_PACKAGE, "image.unpack");
+ else
+ uiItemO(row, "", ICON_UGLYPACKAGE, "image.pack");
+
+ row = uiLayoutRow(row, true);
+ uiLayoutSetEnabled(row, ima->packedfile == NULL);
+ uiItemR(row, &imaptr, "filepath", 0, "", ICON_NONE);
+ uiItemO(row, "", ICON_FILE_REFRESH, "image.reload");
+ }
+
+ /* multilayer? */
+ if (ima->type == IMA_TYPE_MULTILAYER && ima->rr) {
+ uiTemplateImageLayers(layout, C, ima, iuserptr.data);
+ }
+ else if (ima->source != IMA_SRC_GENERATED) {
+ uiTemplateImageInfo(layout, C, ima, iuserptr.data);
+ }
+
+ uiItemR(layout, ptr, "color_space", 0, IFACE_("Color Space"), ICON_NONE);
+ uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE);
}
static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
@@ -861,6 +936,7 @@ static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C),
static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
{
+ uiItemR(layout, ptr, "object", 0, NULL, 0);
uiItemR(layout, ptr, "from_dupli", 0, NULL, 0);
}
@@ -1071,6 +1147,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
break;
case SH_NODE_TEX_ENVIRONMENT:
ntype->draw_buttons = node_shader_buts_tex_environment;
+ ntype->draw_buttons_ex = node_shader_buts_tex_environment_ex;
break;
case SH_NODE_TEX_GRADIENT:
ntype->draw_buttons = node_shader_buts_tex_gradient;
@@ -2279,6 +2356,7 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN
static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr)
{
bNode *node = ptr->data;
+ NodePlaneTrackDeformData *data = node->storage;
uiTemplateID(layout, C, ptr, "clip", NULL, "CLIP_OT_open", NULL);
@@ -2307,6 +2385,12 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P
uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA);
}
}
+
+ uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE);
+ if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) {
+ uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE);
+ uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE);
+ }
}
static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), bContext *UNUSED(C), PointerRNA *UNUSED(ptr))
@@ -3053,9 +3137,7 @@ void draw_nodespace_back_pix(const bContext *C, ARegion *ar, SpaceNode *snode, b
/* somehow the offset has to be calculated inverse */
glaDefine2DArea(&ar->winrct);
- /* ortho at pixel level curarea */
- /* almost #wmOrtho2_region_pixelspace, but no +1 px */
- wmOrtho2_pixelspace(ar->winx, ar->winy);
+ wmOrtho2_region_pixelspace(ar);
x = (ar->winx - snode->zoom * ibuf->x) / 2 + snode->xof;
y = (ar->winy - snode->zoom * ibuf->y) / 2 + snode->yof;
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index 16ad63bcafa..87a64e95e63 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -1304,6 +1304,11 @@ void drawnodespace(const bContext *C, ARegion *ar)
path = snode->treepath.last;
+ /* update tree path name (drawn in the bottom left) */
+ if (snode->id && UNLIKELY(!STREQ(path->node_name, snode->id->name + 2))) {
+ BLI_strncpy(path->node_name, snode->id->name + 2, sizeof(path->node_name));
+ }
+
/* current View2D center, will be set temporarily for parent node trees */
UI_view2d_center_get(v2d, &center[0], &center[1]);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index 1e258368b8b..f79d6e26f22 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -566,7 +566,7 @@ void snode_set_context(const bContext *C)
return;
}
- if (snode->nodetree && strcmp(snode->nodetree->idname, snode->tree_idname) != 0) {
+ if (snode->nodetree && !STREQ(snode->nodetree->idname, snode->tree_idname)) {
/* current tree does not match selected type, clear tree path */
ntree = NULL;
id = NULL;
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index e3baddef158..62cb0bc73cd 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -668,7 +668,7 @@ static void node_main_area_draw(const bContext *C, ARegion *ar)
static int node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_IM)
return 1;
}
@@ -682,7 +682,7 @@ static int node_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *
static int node_mask_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_MSK)
return 1;
}
@@ -691,14 +691,14 @@ static int node_mask_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent
static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (id) {
RNA_string_set(drop->ptr, "name", id->name + 2);
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index 9bc043b384e..47bf87b360b 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -31,6 +31,7 @@
#include "DNA_anim_types.h"
#include "DNA_armature_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_lamp_types.h"
#include "DNA_object_types.h"
@@ -346,6 +347,11 @@ static void restrictbutton_ebone_visibility_cb(bContext *C, void *UNUSED(poin),
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL);
}
+static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), void *UNUSED(poin2))
+{
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL);
+}
+
static int group_restrict_flag(Group *gr, int flag)
{
GroupObject *gob;
@@ -447,7 +453,7 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
TreeStoreElem *tselem = tsep;
if (ts && tselem) {
- TreeElement *te = outliner_find_tse(soops, tselem);
+ TreeElement *te = outliner_find_tree_element(&soops->tree, tselem);
if (tselem->type == 0) {
test_idbutton(tselem->id->name); // library.c, unique name and alpha sort
@@ -549,6 +555,17 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
break;
}
+ case TSE_GP_LAYER:
+ {
+ bGPdata *gpd = (bGPdata *)tselem->id; // id = GP Datablock
+ bGPDlayer *gpl = te->directdata;
+
+ // XXX: name needs translation stuff
+ BLI_uniquename(&gpd->layers, gpl, "GP Layer", '.',
+ offsetof(bGPDlayer, info), sizeof(gpl->info));
+ WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, gpd);
+ break;
+ }
case TSE_R_LAYER:
break;
}
@@ -742,6 +759,29 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar
UI_block_emboss_set(block, UI_EMBOSS);
}
+ else if (tselem->type == TSE_GP_LAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)te->directdata;
+
+ UI_block_emboss_set(block, UI_EMBOSS_NONE);
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_HIDE, 0, ICON_RESTRICT_VIEW_OFF,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow visibility in the 3D View"));
+ UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE, GP_LAYER_LOCKED, 0, ICON_UNLOCKED,
+ (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X,
+ UI_UNIT_Y, &gpl->flag, 0, 0, 0, 0,
+ TIP_("Restrict/Allow editing of strokes and keyframes in this layer"));
+ UI_but_func_set(bt, restrictbutton_gp_layer_flag_cb, NULL, gpl);
+ UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK);
+
+ /* TODO: visibility in renders */
+
+ UI_block_emboss_set(block, UI_EMBOSS);
+ }
}
if (TSELEM_OPEN(tselem, soops)) outliner_draw_restrictbuts(block, scene, ar, soops, &te->subtree);
@@ -877,6 +917,36 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon)
}
+static void tselem_draw_gp_icon_uibut(struct DrawIconArg *arg, ID *id, bGPDlayer *gpl)
+{
+ /* restrict column clip - skip it for now... */
+ if (arg->x >= arg->xmax) {
+ /* pass */
+ }
+ else {
+ PointerRNA ptr;
+ float w = 0.85f * U.widget_unit;
+ float h = 0.85f * UI_UNIT_Y;
+
+ RNA_pointer_create(id, &RNA_GPencilLayer, gpl, &ptr);
+
+ UI_block_align_begin(arg->block);
+
+ UI_block_emboss_set(arg->block, RNA_boolean_get(&ptr, "is_stroke_visible") ? UI_EMBOSS : UI_EMBOSS_NONE);
+ uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h,
+ &ptr, "color", -1,
+ 0, 0, 0, 0, NULL);
+
+ UI_block_emboss_set(arg->block, RNA_boolean_get(&ptr, "is_fill_visible") ? UI_EMBOSS : UI_EMBOSS_NONE);
+ uiDefButR(arg->block, UI_BTYPE_COLOR, 1, "", arg->xb, arg->yb, w, h,
+ &ptr, "fill_color", -1,
+ 0, 0, 0, 0, NULL);
+
+ UI_block_emboss_set(arg->block, UI_EMBOSS_NONE);
+ UI_block_align_end(arg->block);
+ }
+}
+
static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeStoreElem *tselem, TreeElement *te,
float alpha)
{
@@ -1020,6 +1090,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
case eModifierType_DataTransfer:
UI_icon_draw(x, y, ICON_MOD_DATA_TRANSFER); break;
+ case eModifierType_NormalEdit:
+ UI_icon_draw(x, y, ICON_MOD_NORMALEDIT); break;
case eModifierType_PointCache:
UI_icon_draw(x, y, ICON_MOD_MESHDEFORM); break; /* XXX, needs own icon */
/* Default */
@@ -1074,6 +1146,9 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
else
UI_icon_draw(x, y, RNA_struct_ui_icon(te->rnaptr.type));
break;
+ case TSE_GP_LAYER:
+ tselem_draw_gp_icon_uibut(&arg, tselem->id, te->directdata);
+ break;
default:
UI_icon_draw(x, y, ICON_DOT); break;
}
@@ -1167,6 +1242,8 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto
tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); break;
case ID_LS:
tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break;
+ case ID_GD:
+ tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break;
}
}
}
@@ -1250,8 +1327,9 @@ static void outliner_set_coord_tree_element(SpaceOops *soops, TreeElement *te, i
}
-static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene, ARegion *ar, SpaceOops *soops,
- TreeElement *te, int startx, int *starty, TreeElement **te_edit)
+static void outliner_draw_tree_element(
+ bContext *C, uiBlock *block, const uiFontStyle *fstyle, Scene *scene, ARegion *ar, SpaceOops *soops,
+ TreeElement *te, int startx, int *starty, TreeElement **te_edit)
{
TreeElement *ten;
TreeStoreElem *tselem;
@@ -1410,9 +1488,9 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
else if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) UI_ThemeColorBlend(TH_BACK, TH_TEXT, 0.75f);
else UI_ThemeColor(TH_TEXT);
- UI_draw_string(startx + offsx, *starty + 5 * ufac, te->name);
+ UI_fontstyle_draw_simple(fstyle, startx + offsx, *starty + 5 * ufac, te->name);
- offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(te->name));
+ offsx += (int)(UI_UNIT_X + UI_fontstyle_string_width(fstyle, te->name));
/* closed item, we draw the icons, not when it's a scene, or master-server list though */
if (!TSELEM_OPEN(tselem, soops)) {
@@ -1450,13 +1528,15 @@ static void outliner_draw_tree_element(bContext *C, uiBlock *block, Scene *scene
if (TSELEM_OPEN(tselem, soops)) {
*starty -= UI_UNIT_Y;
-
- for (ten = te->subtree.first; ten; ten = ten->next)
- outliner_draw_tree_element(C, block, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit);
+
+ for (ten = te->subtree.first; ten; ten = ten->next) {
+ outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, ten, startx + UI_UNIT_X, starty, te_edit);
+ }
}
else {
- for (ten = te->subtree.first; ten; ten = ten->next)
+ for (ten = te->subtree.first; ten; ten = ten->next) {
outliner_set_coord_tree_element(soops, ten, startx, *starty);
+ }
*starty -= UI_UNIT_Y;
}
@@ -1539,6 +1619,7 @@ static void outliner_draw_selection(ARegion *ar, SpaceOops *soops, ListBase *lb,
static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegion *ar,
SpaceOops *soops, TreeElement **te_edit)
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
TreeElement *te;
int starty, startx;
float col[3];
@@ -1569,7 +1650,7 @@ static void outliner_draw_tree(bContext *C, uiBlock *block, Scene *scene, ARegio
starty = (int)ar->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET;
startx = 0;
for (te = soops->tree.first; te; te = te->next) {
- outliner_draw_tree_element(C, block, scene, ar, soops, te, startx, &starty, te_edit);
+ outliner_draw_tree_element(C, block, fstyle, scene, ar, soops, te, startx, &starty, te_edit);
}
}
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index ab7b1583275..d17ab33d0fa 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -50,6 +50,7 @@
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_material.h"
+#include "BKE_group.h"
#include "ED_object.h"
#include "ED_screen.h"
@@ -73,22 +74,6 @@
/* This is not used anywhere at the moment */
#if 0
-/* return 1 when levels were opened */
-static int outliner_open_back(SpaceOops *soops, TreeElement *te)
-{
- TreeStoreElem *tselem;
- int retval = 0;
-
- for (te = te->parent; te; te = te->parent) {
- tselem = TREESTORE(te);
- if (tselem->flag & TSE_CLOSED) {
- tselem->flag &= ~TSE_CLOSED;
- retval = 1;
- }
- }
- return retval;
-}
-
static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *teFind, int *found)
{
TreeElement *te;
@@ -113,7 +98,9 @@ static void outliner_open_reveal(SpaceOops *soops, ListBase *lb, TreeElement *te
}
#endif
-static TreeElement *outliner_dropzone_element(const SpaceOops *soops, TreeElement *te, const float fmval[2], const int children)
+static TreeElement *outliner_dropzone_element(
+ const SpaceOops *soops, TreeElement *te,
+ const float fmval[2], const bool children)
{
if ((fmval[1] > te->ys) && (fmval[1] < (te->ys + UI_UNIT_Y))) {
/* name and first icon */
@@ -132,7 +119,7 @@ static TreeElement *outliner_dropzone_element(const SpaceOops *soops, TreeElemen
}
/* Used for drag and drop parenting */
-TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const int children)
+TreeElement *outliner_dropzone_find(const SpaceOops *soops, const float fmval[2], const bool children)
{
TreeElement *te;
@@ -601,6 +588,50 @@ void OUTLINER_OT_selected_toggle(wmOperatorType *ot)
/* Show Active --------------------------------------------------- */
+static void outliner_set_coordinates_element_recursive(SpaceOops *soops, TreeElement *te, int startx, int *starty)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ /* store coord and continue, we need coordinates for elements outside view too */
+ te->xs = (float)startx;
+ te->ys = (float)(*starty);
+ *starty -= UI_UNIT_Y;
+
+ if (TSELEM_OPEN(tselem, soops)) {
+ TreeElement *ten;
+ for (ten = te->subtree.first; ten; ten = ten->next) {
+ outliner_set_coordinates_element_recursive(soops, ten, startx + UI_UNIT_X, starty);
+ }
+ }
+}
+
+/* to retrieve coordinates with redrawing the entire tree */
+static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
+{
+ TreeElement *te;
+ int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
+
+ for (te = soops->tree.first; te; te = te->next) {
+ outliner_set_coordinates_element_recursive(soops, te, 0, &starty);
+ }
+}
+
+/* return 1 when levels were opened */
+static int outliner_open_back(TreeElement *te)
+{
+ TreeStoreElem *tselem;
+ int retval = 0;
+
+ for (te = te->parent; te; te = te->parent) {
+ tselem = TREESTORE(te);
+ if (tselem->flag & TSE_CLOSED) {
+ tselem->flag &= ~TSE_CLOSED;
+ retval = 1;
+ }
+ }
+ return retval;
+}
+
static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
{
SpaceOops *so = CTX_wm_space_outliner(C);
@@ -617,6 +648,11 @@ static int outliner_show_active_exec(bContext *C, wmOperator *UNUSED(op))
te = outliner_find_id(so, &so->tree, (ID *)OBACT);
if (te) {
+ /* open up tree to active object */
+ if (outliner_open_back(te)) {
+ outliner_set_coordinates(ar, so);
+ }
+
/* make te->ys center of view */
ytop = te->ys + BLI_rcti_size_y(&v2d->mask) / 2;
if (ytop > 0) ytop = 0;
@@ -642,7 +678,7 @@ void OUTLINER_OT_show_active(wmOperatorType *ot)
/* identifiers */
ot->name = "Show Active";
ot->idname = "OUTLINER_OT_show_active";
- ot->description = "Adjust the view so that the active Object is shown centered";
+ ot->description = "Open up the tree and adjust the view so that the active Object is shown centered";
/* callbacks */
ot->exec = outliner_show_active_exec;
@@ -690,37 +726,6 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot)
#if 0
-/* recursive helper for function below */
-static void outliner_set_coordinates_element(SpaceOops *soops, TreeElement *te, int startx, int *starty)
-{
- TreeStoreElem *tselem = TREESTORE(te);
-
- /* store coord and continue, we need coordinates for elements outside view too */
- te->xs = (float)startx;
- te->ys = (float)(*starty);
- *starty -= UI_UNIT_Y;
-
- if (TSELEM_OPEN(tselem, soops)) {
- TreeElement *ten;
- for (ten = te->subtree.first; ten; ten = ten->next) {
- outliner_set_coordinates_element(soops, ten, startx + UI_UNIT_X, starty);
- }
- }
-
-}
-
-/* to retrieve coordinates with redrawing the entire tree */
-static void outliner_set_coordinates(ARegion *ar, SpaceOops *soops)
-{
- TreeElement *te;
- int starty = (int)(ar->v2d.tot.ymax) - UI_UNIT_Y;
- int startx = 0;
-
- for (te = soops->tree.first; te; te = te->next) {
- outliner_set_coordinates_element(soops, te, startx, &starty);
- }
-}
-
/* find next element that has this name */
static TreeElement *outliner_find_name(SpaceOops *soops, ListBase *lb, char *name, int flags,
TreeElement *prev, int *prevFound)
@@ -1500,7 +1505,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, 1);
+ te = outliner_dropzone_find(soops, fmval, true);
if (te) {
RNA_string_set(op->ptr, "parent", te->name);
@@ -1715,7 +1720,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event)
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, 0);
+ te = outliner_dropzone_find(soops, fmval, false);
if (te) {
Base *base;
@@ -1785,7 +1790,7 @@ static int material_drop_invoke(bContext *C, wmOperator *op, const wmEvent *even
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
/* Find object hovered over */
- te = outliner_dropzone_find(soops, fmval, 1);
+ te = outliner_dropzone_find(soops, fmval, true);
if (te) {
RNA_string_set(op->ptr, "object", te->name);
@@ -1829,3 +1834,65 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot)
RNA_def_string(ot->srna, "material", "Material", MAX_ID_NAME, "Material", "Target Material");
}
+static int group_link_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Main *bmain = CTX_data_main(C);
+ Group *group = NULL;
+ Object *ob = NULL;
+ Scene *scene = CTX_data_scene(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ ARegion *ar = CTX_wm_region(C);
+ TreeElement *te = NULL;
+ char ob_name[MAX_ID_NAME - 2];
+ float fmval[2];
+
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ /* Find object hovered over */
+ te = outliner_dropzone_find(soops, fmval, true);
+
+ if (te) {
+ group = (Group *)BKE_libblock_find_name(ID_GR, te->name);
+
+ RNA_string_get(op->ptr, "object", ob_name);
+ ob = (Object *)BKE_libblock_find_name(ID_OB, ob_name);
+
+ if (ELEM(NULL, group, ob)) {
+ return OPERATOR_CANCELLED;
+ }
+ if (BKE_group_object_exists(group, ob)) {
+ return OPERATOR_FINISHED;
+ }
+
+ if (BKE_group_object_cyclic_check(bmain, ob, group)) {
+ BKE_report(op->reports, RPT_ERROR, "Could not add the group because of dependency cycle detected");
+ return OPERATOR_CANCELLED;
+ }
+
+ BKE_group_object_add(group, ob, scene, NULL);
+ WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
+
+ return OPERATOR_FINISHED;
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void OUTLINER_OT_group_link(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Link Object to Group";
+ ot->description = "Link Object to Group in Outliner";
+ ot->idname = "OUTLINER_OT_group_link";
+
+ /* api callbacks */
+ ot->invoke = group_link_invoke;
+
+ ot->poll = ED_operator_outliner_active;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+
+ /* properties */
+ RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object");
+}
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 317d33dd3e2..f0920466b85 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -104,6 +104,7 @@ typedef struct TreeElement {
#define TSE_KEYMAP 34
#define TSE_KEYMAP_ITEM 35
#define TSE_ID_BASE 36
+#define TSE_GP_LAYER 37
/* button events */
#define OL_NAMEBUTTON 1
@@ -166,6 +167,7 @@ void outliner_free_tree(ListBase *lb);
void outliner_cleanup_tree(struct SpaceOops *soops);
TreeElement *outliner_find_tse(struct SpaceOops *soops, TreeStoreElem *tse);
+TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem);
TreeElement *outliner_find_id(struct SpaceOops *soops, ListBase *lb, struct ID *id);
struct ID *outliner_search_back(SpaceOops *soops, TreeElement *te, short idcode);
@@ -205,7 +207,7 @@ void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, Tree
void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem);
-TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const int children);
+TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children);
/* ...................................................... */
void OUTLINER_OT_item_activate(struct wmOperatorType *ot);
@@ -237,6 +239,7 @@ void OUTLINER_OT_parent_drop(struct wmOperatorType *ot);
void OUTLINER_OT_parent_clear(struct wmOperatorType *ot);
void OUTLINER_OT_scene_drop(struct wmOperatorType *ot);
void OUTLINER_OT_material_drop(struct wmOperatorType *ot);
+void OUTLINER_OT_group_link(struct wmOperatorType *ot);
/* outliner_tools.c ---------------------------------------------- */
diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c
index 4f13454ef34..d54ae3f22a7 100644
--- a/source/blender/editors/space_outliner/outliner_ops.c
+++ b/source/blender/editors/space_outliner/outliner_ops.c
@@ -77,6 +77,7 @@ void outliner_operatortypes(void)
WM_operatortype_append(OUTLINER_OT_parent_clear);
WM_operatortype_append(OUTLINER_OT_scene_drop);
WM_operatortype_append(OUTLINER_OT_material_drop);
+ WM_operatortype_append(OUTLINER_OT_group_link);
}
void outliner_keymap(wmKeyConfig *keyconf)
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 23586a6a509..730ee02f448 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -775,7 +775,7 @@ static eOLDrawState tree_element_active_sequence_dup(
continue;
}
-// if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+// if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
// XXX select_single_seq(p, 0);
p = p->next;
}
@@ -873,6 +873,9 @@ eOLDrawState tree_element_type_active(
return tree_element_active_sequence_dup(scene, te, tselem, set);
case TSE_KEYMAP_ITEM:
return tree_element_active_keymap_item(C, te, tselem, set);
+ case TSE_GP_LAYER:
+ //return tree_element_active_gplayer(C, scene, te, tselem, set);
+ break;
}
return OL_DRAWSEL_NONE;
@@ -915,7 +918,7 @@ static bool do_outliner_item_activate(bContext *C, Scene *scene, ARegion *ar, Sp
if (tselem->type != TSE_SEQUENCE && tselem->type != TSE_SEQ_STRIP && tselem->type != TSE_SEQUENCE_DUP)
tree_element_set_active_object(C, scene, soops, te,
(extend && tselem->type == 0) ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
- recursive && tselem->type == 0 );
+ recursive && tselem->type == 0);
if (tselem->type == 0) { // the lib blocks
/* editmode? */
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index d09ed1a100e..bd884039b30 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -499,19 +499,28 @@ static void refreshdrivers_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te
/* --------------------------------- */
+typedef enum eOutliner_PropDataOps {
+ OL_DOP_INVALID = 0,
+ OL_DOP_SELECT,
+ OL_DOP_DESELECT,
+ OL_DOP_HIDE,
+ OL_DOP_UNHIDE,
+ OL_DOP_SELECT_LINKED,
+} eOutliner_PropDataOps;
+
static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg))
{
bPoseChannel *pchan = (bPoseChannel *)te->directdata;
- if (event == 1)
+ if (event == OL_DOP_SELECT)
pchan->bone->flag |= BONE_SELECTED;
- else if (event == 2)
+ else if (event == OL_DOP_DESELECT)
pchan->bone->flag &= ~BONE_SELECTED;
- else if (event == 3) {
+ else if (event == OL_DOP_HIDE) {
pchan->bone->flag |= BONE_HIDDEN_P;
pchan->bone->flag &= ~BONE_SELECTED;
}
- else if (event == 4)
+ else if (event == OL_DOP_UNHIDE)
pchan->bone->flag &= ~BONE_HIDDEN_P;
}
@@ -519,15 +528,15 @@ static void bone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), v
{
Bone *bone = (Bone *)te->directdata;
- if (event == 1)
+ if (event == OL_DOP_SELECT)
bone->flag |= BONE_SELECTED;
- else if (event == 2)
+ else if (event == OL_DOP_DESELECT)
bone->flag &= ~BONE_SELECTED;
- else if (event == 3) {
+ else if (event == OL_DOP_HIDE) {
bone->flag |= BONE_HIDDEN_P;
bone->flag &= ~BONE_SELECTED;
}
- else if (event == 4)
+ else if (event == OL_DOP_UNHIDE)
bone->flag &= ~BONE_HIDDEN_P;
}
@@ -535,22 +544,22 @@ static void ebone_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem),
{
EditBone *ebone = (EditBone *)te->directdata;
- if (event == 1)
+ if (event == OL_DOP_SELECT)
ebone->flag |= BONE_SELECTED;
- else if (event == 2)
+ else if (event == OL_DOP_DESELECT)
ebone->flag &= ~BONE_SELECTED;
- else if (event == 3) {
+ else if (event == OL_DOP_HIDE) {
ebone->flag |= BONE_HIDDEN_A;
ebone->flag &= ~BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
}
- else if (event == 4)
+ else if (event == OL_DOP_UNHIDE)
ebone->flag &= ~BONE_HIDDEN_A;
}
static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void *scene_ptr)
{
Sequence *seq = (Sequence *)te->directdata;
- if (event == 1) {
+ if (event == OL_DOP_SELECT) {
Scene *scene = (Scene *)scene_ptr;
Editing *ed = BKE_sequencer_editing_get(scene, false);
if (BLI_findindex(ed->seqbasep, seq) != -1) {
@@ -563,7 +572,7 @@ static void sequence_cb(int event, TreeElement *te, TreeStoreElem *tselem, void
static void data_select_linked_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v)
{
- if (event == 5) {
+ if (event == OL_DOP_SELECT_LINKED) {
if (RNA_struct_is_ID(te->rnaptr.type)) {
bContext *C = (bContext *) C_v;
ID *id = te->rnaptr.data;
@@ -593,6 +602,49 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li
}
}
+static void outline_delete_hierarchy(bContext *C, Scene *scene, Base *base)
+{
+ Base *child_base;
+ Object *parent;
+
+ if (!base) {
+ return;
+ }
+
+ for (child_base = scene->base.first; child_base; child_base = child_base->next) {
+ for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent);
+ if (parent) {
+ outline_delete_hierarchy(C, scene, child_base);
+ }
+ }
+
+ ED_base_object_free_and_unlink(CTX_data_main(C), scene, base);
+}
+
+static void object_delete_hierarchy_cb(
+ bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem)
+{
+ Base *base = (Base *)te->directdata;
+ Object *obedit = scene->obedit;
+
+ if (!base) {
+ base = BKE_scene_base_find(scene, (Object *)tselem->id);
+ }
+ if (base) {
+ /* Check also library later. */
+ for (; obedit && (obedit != base->object); obedit = obedit->parent);
+ if (obedit == base->object) {
+ ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO);
+ }
+
+ outline_delete_hierarchy(C, scene, base);
+ te->directdata = NULL;
+ tselem->id = NULL;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+}
+
/* **************************************** */
enum {
@@ -601,6 +653,7 @@ enum {
OL_OP_DESELECT,
OL_OP_SELECT_HIERARCHY,
OL_OP_DELETE,
+ OL_OP_DELETE_HIERARCHY,
OL_OP_LOCALIZED, /* disabled, see below */
OL_OP_TOGVIS,
OL_OP_TOGSEL,
@@ -613,6 +666,7 @@ static EnumPropertyItem prop_object_op_types[] = {
{OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""},
{OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""},
{OL_OP_DELETE, "DELETE", 0, "Delete", ""},
+ {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""},
{OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""},
{OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""},
{OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""},
@@ -672,6 +726,16 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op)
str = "Delete Objects";
WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
}
+ else if (event == OL_OP_DELETE_HIERARCHY) {
+ outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_hierarchy_cb);
+
+ /* XXX: See OL_OP_DELETE comment above. */
+ outliner_cleanup_tree(soops);
+
+ DAG_relations_tag_update(bmain);
+ str = "Delete Object Hierarchy";
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene);
+ }
else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */
outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb);
str = "Localized Objects";
@@ -1196,11 +1260,11 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot)
/* **************************************** */
static EnumPropertyItem prop_data_op_types[] = {
- {1, "SELECT", 0, "Select", ""},
- {2, "DESELECT", 0, "Deselect", ""},
- {3, "HIDE", 0, "Hide", ""},
- {4, "UNHIDE", 0, "Unhide", ""},
- {5, "SELECT_LINKED", 0, "Select Linked", ""},
+ {OL_DOP_SELECT, "SELECT", 0, "Select", ""},
+ {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""},
+ {OL_DOP_HIDE, "HIDE", 0, "Hide", ""},
+ {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""},
+ {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -1208,7 +1272,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
{
SpaceOops *soops = CTX_wm_space_outliner(C);
int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0;
- int event;
+ eOutliner_PropDataOps event;
/* check for invalid states */
if (soops == NULL)
@@ -1217,7 +1281,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
event = RNA_enum_get(op->ptr, "type");
set_operation_types(soops, &soops->tree, &scenelevel, &objectlevel, &idlevel, &datalevel);
- if (event <= 0)
+ if (event <= OL_DOP_INVALID)
return OPERATOR_CANCELLED;
switch (datalevel) {
@@ -1253,7 +1317,7 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op)
break;
case TSE_RNA_STRUCT:
- if (event == 5) {
+ if (event == OL_DOP_SELECT_LINKED) {
outliner_do_data_operation(soops, datalevel, event, &soops->tree, data_select_linked_cb, C);
}
break;
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 4aa36da594b..abc82775c8d 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -38,6 +38,7 @@
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_camera_types.h"
+#include "DNA_gpencil_types.h"
#include "DNA_group_types.h"
#include "DNA_key_types.h"
#include "DNA_lamp_types.h"
@@ -196,7 +197,7 @@ void outliner_cleanup_tree(SpaceOops *soops)
}
/* Find specific item from the treestore */
-static TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem)
+TreeElement *outliner_find_tree_element(ListBase *lb, TreeStoreElem *store_elem)
{
TreeElement *te, *tes;
for (te = lb->first; te; te = te->next) {
@@ -430,6 +431,8 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s
// TODO: move this to the front?
if (outliner_animdata_test(sce->adt))
outliner_add_element(soops, lb, sce, te, TSE_ANIM_DATA, 0);
+
+ outliner_add_element(soops, lb, sce->gpd, te, 0, 0);
outliner_add_element(soops, lb, sce->world, te, 0, 0);
@@ -451,6 +454,8 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree
if (ob->proxy && ob->id.lib == NULL)
outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0);
+
+ outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0);
outliner_add_element(soops, &te->subtree, ob->data, te, 0, 0);
@@ -809,6 +814,21 @@ static void outliner_add_id_contents(SpaceOops *soops, TreeElement *te, TreeStor
}
break;
}
+ case ID_GD:
+ {
+ bGPdata *gpd = (bGPdata *)id;
+ bGPDlayer *gpl;
+ int a = 0;
+
+ if (outliner_animdata_test(gpd->adt))
+ outliner_add_element(soops, &te->subtree, gpd, te, TSE_ANIM_DATA, 0);
+
+ // TODO: base element for layers?
+ for (gpl = gpd->layers.first; gpl; gpl = gpl->next) {
+ outliner_add_element(soops, &te->subtree, gpl, te, TSE_GP_LAYER, a);
+ a++;
+ }
+ }
}
}
@@ -856,6 +876,9 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
else if (type == TSE_ANIM_DATA) {
/* pass */
}
+ else if (type == TSE_GP_LAYER) {
+ /* pass */
+ }
else if (type == TSE_ID_BASE) {
/* pass */
}
@@ -938,6 +961,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i
}
}
}
+ else if (type == TSE_GP_LAYER) {
+ bGPDlayer *gpl = (bGPDlayer *)idv;
+
+ te->name = gpl->info;
+ te->directdata = gpl;
+ }
else if (type == TSE_SEQUENCE) {
Sequence *seq = (Sequence *) idv;
Sequence *p;
@@ -1160,7 +1189,7 @@ static int need_add_seq_dup(Sequence *seq)
continue;
}
- if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
return(2);
p = p->prev;
}
@@ -1172,7 +1201,7 @@ static int need_add_seq_dup(Sequence *seq)
continue;
}
- if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
return(0);
p = p->next;
}
@@ -1191,7 +1220,7 @@ static void outliner_add_seq_dup(SpaceOops *soops, Sequence *seq, TreeElement *t
continue;
}
- if (!strcmp(p->strip->stripdata->name, seq->strip->stripdata->name))
+ if (STREQ(p->strip->stripdata->name, seq->strip->stripdata->name))
/* ch = */ /* UNUSED */ outliner_add_element(soops, &te->subtree, (void *)p, te, TSE_SEQUENCE, index);
p = p->next;
}
@@ -1311,7 +1340,10 @@ static void outliner_sort(SpaceOops *soops, ListBase *lb)
TreeElement *te;
TreeStoreElem *tselem;
int totelem = 0;
-
+
+ if (soops->flag & SO_SKIP_SORT_ALPHA)
+ return;
+
te = lb->last;
if (te == NULL) return;
tselem = TREESTORE(te);
diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c
index 504d9628d98..30de9c16500 100644
--- a/source/blender/editors/space_outliner/space_outliner.c
+++ b/source/blender/editors/space_outliner/space_outliner.c
@@ -98,10 +98,10 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB) {
/* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, 1);
+ TreeElement *te = outliner_dropzone_find(soops, fmval, true);
if (te && te->idcode == ID_OB && TREESTORE(te)->type == 0) {
Scene *scene;
@@ -129,7 +129,7 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
static void outliner_parent_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "child", id->name + 2);
}
@@ -148,10 +148,10 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
}
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB) {
if (((Object *)id)->parent) {
- if ((te = outliner_dropzone_find(soops, fmval, 1))) {
+ if ((te = outliner_dropzone_find(soops, fmval, true))) {
TreeStoreElem *tselem = TREESTORE(te);
switch (te->idcode) {
@@ -171,7 +171,7 @@ static int outliner_parent_clear_poll(bContext *C, wmDrag *drag, const wmEvent *
static void outliner_parent_clear_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "dragged_obj", id->name + 2);
/* Set to simple parent clear type. Avoid menus for drag and drop if possible.
@@ -188,10 +188,10 @@ static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *ev
UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB) {
/* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, 0);
+ TreeElement *te = outliner_dropzone_find(soops, fmval, false);
return (te && te->idcode == ID_SCE && TREESTORE(te)->type == 0);
}
}
@@ -200,7 +200,7 @@ static int outliner_scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *ev
static void outliner_scene_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "object", id->name + 2);
}
@@ -213,10 +213,10 @@ static int outliner_material_drop_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 (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_MA) {
/* Ensure item under cursor is valid drop target */
- TreeElement *te = outliner_dropzone_find(soops, fmval, 1);
+ TreeElement *te = outliner_dropzone_find(soops, fmval, true);
return (te && te->idcode == ID_OB && TREESTORE(te)->type == 0);
}
}
@@ -225,11 +225,35 @@ static int outliner_material_drop_poll(bContext *C, wmDrag *drag, const wmEvent
static void outliner_material_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "material", id->name + 2);
}
+static int outliner_group_link_poll(bContext *C, wmDrag *drag, const wmEvent *event)
+{
+ ARegion *ar = CTX_wm_region(C);
+ SpaceOops *soops = CTX_wm_space_outliner(C);
+ float fmval[2];
+ UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]);
+
+ if (drag->type == WM_DRAG_ID) {
+ ID *id = drag->poin;
+ if (GS(id->name) == ID_OB) {
+ /* Ensure item under cursor is valid drop target */
+ TreeElement *te = outliner_dropzone_find(soops, fmval, true);
+ return (te && te->idcode == ID_GR && TREESTORE(te)->type == 0);
+ }
+ }
+ return 0;
+}
+
+static void outliner_group_link_copy(wmDrag *drag, wmDropBox *drop)
+{
+ ID *id = drag->poin;
+ RNA_string_set(drop->ptr, "object", id->name + 2);
+}
+
/* region dropbox definition */
static void outliner_dropboxes(void)
{
@@ -239,6 +263,7 @@ static void outliner_dropboxes(void)
WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", outliner_parent_clear_poll, outliner_parent_clear_copy);
WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", outliner_scene_drop_poll, outliner_scene_drop_copy);
WM_dropbox_add(lb, "OUTLINER_OT_material_drop", outliner_material_drop_poll, outliner_material_drop_copy);
+ WM_dropbox_add(lb, "OUTLINER_OT_group_link", outliner_group_link_poll, outliner_group_link_copy);
}
static void outliner_main_area_draw(const bContext *C, ARegion *ar)
@@ -362,6 +387,13 @@ static void outliner_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa)
break;
}
break;
+ case NC_GPENCIL:
+ switch (wmn->data) {
+ case ND_DATA:
+ ED_region_tag_redraw(ar);
+ break;
+ }
+ break;
}
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index afb650f8cfd..3be6cd79504 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -70,6 +70,7 @@
#include "WM_api.h"
+#include "MEM_guardedalloc.h"
/* own include */
#include "sequencer_intern.h"
@@ -200,23 +201,25 @@ static void drawseqwave(const bContext *C, SpaceSeq *sseq, Scene *scene, Sequenc
SoundWaveform *waveform;
- if (!sound->mutex)
- sound->mutex = BLI_mutex_alloc();
+ if (!sound->spinlock) {
+ sound->spinlock = MEM_mallocN(sizeof(SpinLock), "sound_spinlock");
+ BLI_spin_init(sound->spinlock);
+ }
- BLI_mutex_lock(sound->mutex);
+ BLI_spin_lock(sound->spinlock);
if (!seq->sound->waveform) {
if (!(sound->flags & SOUND_FLAGS_WAVEFORM_LOADING)) {
/* prevent sounds from reloading */
seq->sound->flags |= SOUND_FLAGS_WAVEFORM_LOADING;
- BLI_mutex_unlock(sound->mutex);
+ BLI_spin_unlock(sound->spinlock);
sequencer_preview_add_sound(C, seq);
}
else {
- BLI_mutex_unlock(sound->mutex);
+ BLI_spin_unlock(sound->spinlock);
}
return; /* nothing to draw */
}
- BLI_mutex_unlock(sound->mutex);
+ BLI_spin_unlock(sound->spinlock);
waveform = seq->sound->waveform;
@@ -467,7 +470,7 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float
}
}
else if (seq->type == SEQ_TYPE_MOVIECLIP) {
- if (seq->clip && strcmp(name, seq->clip->id.name + 2) != 0) {
+ if (seq->clip && !STREQ(name, seq->clip->id.name + 2)) {
str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d",
name, seq->clip->id.name + 2, seq->len);
}
@@ -477,7 +480,7 @@ static void draw_seq_text(View2D *v2d, Sequence *seq, float x1, float x2, float
}
}
else if (seq->type == SEQ_TYPE_MASK) {
- if (seq->mask && strcmp(name, seq->mask->id.name + 2) != 0) {
+ if (seq->mask && !STREQ(name, seq->mask->id.name + 2)) {
str_len = BLI_snprintf(str, sizeof(str), "%s: %s | %d",
name, seq->mask->id.name + 2, seq->len);
}
@@ -1292,24 +1295,18 @@ void draw_image_seq(const bContext *C, Scene *scene, ARegion *ar, SpaceSeq *sseq
glEnd();
/* safety border */
- if ((sseq->flag & SEQ_DRAW_SAFE_MARGINS) != 0) {
- float fac = 0.1;
-
- float a = fac * (x2 - x1);
- x1 += a;
- x2 -= a;
-
- a = fac * (y2 - y1);
- y1 += a;
- y2 -= a;
-
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
-
- UI_draw_roundbox_corner_set(UI_CNR_ALL);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, x1, y1, x2, y2, 12.0);
-
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
-
+ if (sseq->flag & SEQ_SHOW_SAFE_MARGINS) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title,
+ scene->safe_areas.action);
+
+ if (sseq->flag & SEQ_SHOW_SAFE_CENTER) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title_center,
+ scene->safe_areas.action_center);
+ }
}
setlinestyle(0);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 81af6dccc70..8d4a82fc02c 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -37,6 +37,7 @@
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
#include "BLF_translation.h"
@@ -58,12 +59,14 @@
/* for menu/popup icons etc etc*/
+#include "ED_numinput.h"
#include "ED_screen.h"
#include "ED_transform.h"
#include "ED_sequencer.h"
#include "ED_space_api.h"
#include "UI_view2d.h"
+#include "UI_interface.h"
/* own include */
@@ -146,11 +149,12 @@ static void proxy_startjob(void *pjv, short *stop, short *do_update, float *prog
struct SeqIndexBuildContext *context = link->data;
BKE_sequencer_proxy_rebuild(context, stop, do_update, progress);
- }
-
- if (*stop) {
- pj->stop = 1;
- fprintf(stderr, "Canceling proxy rebuild on users request...\n");
+
+ if (*stop) {
+ pj->stop = 1;
+ fprintf(stderr, "Canceling proxy rebuild on users request...\n");
+ break;
+ }
}
}
@@ -179,7 +183,8 @@ static void seq_proxy_build_job(const bContext *C)
struct SeqIndexBuildContext *context;
LinkData *link;
Sequence *seq;
-
+ GSet *file_list;
+
if (ed == NULL) {
return;
}
@@ -200,16 +205,19 @@ static void seq_proxy_build_job(const bContext *C)
WM_jobs_callbacks(wm_job, proxy_startjob, NULL, NULL, proxy_endjob);
}
+ file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
SEQP_BEGIN (ed, seq)
{
if ((seq->flag & SELECT)) {
- context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq);
+ context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list);
link = BLI_genericNodeN(context);
BLI_addtail(&pj->queue, link);
}
}
SEQ_END
+ BLI_gset_free(file_list, MEM_freeN);
+
if (!WM_jobs_is_running(wm_job)) {
G.is_break = false;
WM_jobs_start(CTX_wm_manager(C), wm_job);
@@ -987,13 +995,13 @@ static void UNUSED_FUNCTION(seq_remap_paths) (Scene *scene)
// XXX if (0 == sbutton(to, 0, sizeof(to)-1, "To: "))
// return;
- if (strcmp(to, from) == 0)
+ if (STREQ(to, from))
return;
SEQP_BEGIN (ed, seq)
{
if (seq->flag & SELECT) {
- if (strncmp(seq->strip->dir, from, strlen(from)) == 0) {
+ if (STREQLEN(seq->strip->dir, from, strlen(from))) {
printf("found %s\n", seq->strip->dir);
/* strip off the beginning */
@@ -1262,6 +1270,7 @@ typedef struct SlipData {
bool slow;
int slow_offset; /* offset at the point where offset was turned on */
void *draw_handle;
+ NumInput num_input;
} SlipData;
static void transseq_backup(TransSeq *ts, Sequence *seq)
@@ -1375,6 +1384,13 @@ static int sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *eve
data->trim = MEM_mallocN(num_seq * sizeof(bool), "trimdata_trim");
data->num_seq = num_seq;
+ initNumInput(&data->num_input);
+ data->num_input.idx_max = 0;
+ data->num_input.val_flag[0] |= NUM_NO_FRACTION;
+ data->num_input.unit_sys = USER_UNIT_NONE;
+ data->num_input.unit_type[0] = 0;
+
+
slip_add_sequences_rec(ed->seqbasep, data->seq_array, data->trim, 0, true);
for (i = 0; i < num_seq; i++) {
@@ -1500,47 +1516,83 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
}
}
+
+static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *data, int offset)
+{
+#define HEADER_LENGTH 40
+ char msg[HEADER_LENGTH];
+
+ if (sa) {
+ if (hasNumInput(&data->num_input)) {
+ char num_str[NUM_STR_REP_LEN];
+ outputNumInput(&data->num_input, num_str, &scene->unit);
+ BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %s", num_str);
+ }
+ else {
+ BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %d", offset);
+ }
+ }
+
+ ED_area_headerprint(sa, msg);
+
+#undef HEADER_LENGTH
+}
+
static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
Scene *scene = CTX_data_scene(C);
SlipData *data = (SlipData *)op->customdata;
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
+ const bool has_numInput = hasNumInput(&data->num_input);
+ bool handled = true;
+
+ /* Modal numinput active, try to handle numeric inputs first... */
+ if (event->val == KM_PRESS && has_numInput && handleNumInput(C, &data->num_input, event)) {
+ float offset;
+ applyNumInput(&data->num_input, &offset);
+
+ sequencer_slip_update_header(scene, sa, data, (int)offset);
+
+ RNA_int_set(op->ptr, "offset", offset);
+
+ if (sequencer_slip_recursively(scene, data, offset)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ }
+
+ return OPERATOR_RUNNING_MODAL;
+ }
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];
- }
+ if (!has_numInput) {
+ 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];
+ /* 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);
+ sequencer_slip_update_header(scene, sa, data, 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);
- }
+ RNA_int_set(op->ptr, "offset", offset);
- if (sequencer_slip_recursively(scene, data, offset)) {
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ if (sequencer_slip_recursively(scene, data, offset)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ }
}
break;
}
@@ -1597,19 +1649,36 @@ static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *even
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;
+ if (!has_numInput) {
+ 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:
+ handled = false;
break;
}
+ /* Modal numinput inactive, try to handle numeric inputs last... */
+ if (!handled && event->val == KM_PRESS && handleNumInput(C, &data->num_input, event)) {
+ float offset;
+ applyNumInput(&data->num_input, &offset);
+
+ sequencer_slip_update_header(scene, sa, data, (int)offset);
+
+ RNA_int_set(op->ptr, "offset", offset);
+
+ if (sequencer_slip_recursively(scene, data, offset)) {
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+ }
+ }
+
return OPERATOR_RUNNING_MODAL;
}
@@ -3360,18 +3429,21 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
Sequence *seq;
-
+ GSet *file_list;
+
if (ed == NULL) {
return OPERATOR_CANCELLED;
}
+ file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
+
SEQP_BEGIN(ed, seq)
{
if ((seq->flag & SELECT)) {
struct SeqIndexBuildContext *context;
short stop = 0, do_update;
float progress;
- context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq);
+ context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list);
BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
BKE_sequencer_proxy_rebuild_finish(context, 0);
BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
@@ -3379,6 +3451,8 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
}
SEQ_END
+ BLI_gset_free(file_list, MEM_freeN);
+
return OPERATOR_FINISHED;
}
@@ -3397,6 +3471,88 @@ void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER;
}
+static int sequencer_enable_proxies_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ return WM_operator_props_dialog_popup(C, op, 10 * UI_UNIT_X, 5 * UI_UNIT_Y);
+}
+
+static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+ bool proxy_25 = RNA_boolean_get(op->ptr, "proxy_25");
+ bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50");
+ bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75");
+ bool proxy_100 = RNA_boolean_get(op->ptr, "proxy_100");
+ bool override = RNA_boolean_get(op->ptr, "override");
+ bool turnon = true;
+
+ if (ed == NULL || !(proxy_25 || proxy_50 || proxy_75 || proxy_100)) {
+ turnon = false;
+ }
+
+ SEQP_BEGIN(ed, seq)
+ {
+ if ((seq->flag & SELECT)) {
+ if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_IMAGE, SEQ_TYPE_META, SEQ_TYPE_SCENE, SEQ_TYPE_MULTICAM)) {
+ BKE_sequencer_proxy_set(seq, turnon);
+
+ if (proxy_25)
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_25;
+ else
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_25;
+
+ if (proxy_50)
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_50;
+ else
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_50;
+
+ if (proxy_75)
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_75;
+ else
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_75;
+
+ if (proxy_100)
+ seq->strip->proxy->build_size_flags |= SEQ_PROXY_IMAGE_SIZE_100;
+ else
+ seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_100;
+
+ if (!override)
+ seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
+ else
+ seq->strip->proxy->build_flags &= ~SEQ_PROXY_SKIP_EXISTING;
+ }
+ }
+ }
+ SEQ_END
+
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Set Selected Strip Proxies";
+ ot->idname = "SEQUENCER_OT_enable_proxies";
+ ot->description = "Enable selected proxies on all selected Movie strips";
+
+ /* api callbacks */
+ ot->invoke = sequencer_enable_proxies_invoke;
+ ot->exec = sequencer_enable_proxies_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER;
+
+ RNA_def_boolean(ot->srna, "proxy_25", false, "25%", "");
+ RNA_def_boolean(ot->srna, "proxy_50", false, "50%", "");
+ RNA_def_boolean(ot->srna, "proxy_75", false, "75%", "");
+ RNA_def_boolean(ot->srna, "proxy_100", false, "100%", "");
+ RNA_def_boolean(ot->srna, "override", false, "Override", "");
+}
+
/* change ops */
static EnumPropertyItem prop_change_effect_input_types[] = {
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 5f1c9317fd9..461c72961c2 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -131,6 +131,7 @@ void SEQUENCER_OT_copy(struct wmOperatorType *ot);
void SEQUENCER_OT_paste(struct wmOperatorType *ot);
void SEQUENCER_OT_rebuild_proxy(struct wmOperatorType *ot);
+void SEQUENCER_OT_enable_proxies(struct wmOperatorType *ot);
/* preview specific operators */
void SEQUENCER_OT_view_all_preview(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index 9b5ef18f7cd..33a8a1c5b41 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -88,6 +88,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_view_ghost_border);
WM_operatortype_append(SEQUENCER_OT_rebuild_proxy);
+ WM_operatortype_append(SEQUENCER_OT_enable_proxies);
WM_operatortype_append(SEQUENCER_OT_change_effect_input);
WM_operatortype_append(SEQUENCER_OT_change_effect_type);
WM_operatortype_append(SEQUENCER_OT_change_path);
diff --git a/source/blender/editors/space_sequencer/sequencer_preview.c b/source/blender/editors/space_sequencer/sequencer_preview.c
index da00b0ff6e1..c8834d394f5 100644
--- a/source/blender/editors/space_sequencer/sequencer_preview.c
+++ b/source/blender/editors/space_sequencer/sequencer_preview.c
@@ -95,9 +95,9 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p
sound = previewjb->sound;
/* make sure we cleanup the loading flag! */
- BLI_mutex_lock(sound->mutex);
+ BLI_spin_lock(sound->spinlock);
sound->flags &= ~SOUND_FLAGS_WAVEFORM_LOADING;
- BLI_mutex_unlock(sound->mutex);
+ BLI_spin_unlock(sound->spinlock);
BLI_mutex_lock(pj->mutex);
previewjb = previewjb->next;
@@ -117,7 +117,7 @@ static void preview_startjob(void *data, short *stop, short *do_update, float *p
BLI_freelinkN(&pj->previews, previewjb);
previewjb = preview_next;
pj->processed++;
- *progress = (pj->total > 0) ? (float)pj->processed / (float)pj->total : 1.0;
+ *progress = (pj->total > 0) ? (float)pj->processed / (float)pj->total : 1.0f;
*do_update = true;
BLI_mutex_unlock(pj->mutex);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 6792bbe0577..4fbe0c6a241 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -996,7 +996,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq)
if (SEQ_HAS_PATH(actseq) && dir) {
SEQP_BEGIN (ed, seq)
{
- if (SEQ_HAS_PATH(seq) && seq->strip && strcmp(seq->strip->dir, dir) == 0) {
+ if (SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
changed = true;
}
diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c
index 6231f02907a..7be356dd2ec 100644
--- a/source/blender/editors/space_sequencer/space_sequencer.c
+++ b/source/blender/editors/space_sequencer/space_sequencer.c
@@ -504,6 +504,13 @@ static void sequencer_main_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa
break;
}
break;
+ case NC_ANIMATION:
+ switch (wmn->data) {
+ case ND_KEYFRAME:
+ ED_region_tag_redraw(ar);
+ break;
+ }
+ break;
case NC_SPACE:
if (wmn->data == ND_SPACE_SEQUENCER)
ED_region_tag_redraw(ar);
@@ -599,6 +606,16 @@ static void sequencer_preview_area_listener(bScreen *UNUSED(sc), ScrArea *UNUSED
case ND_MARKERS:
case ND_SEQUENCER:
case ND_RENDER_OPTIONS:
+ case ND_DRAW_RENDER_VIEWPORT:
+ ED_region_tag_redraw(ar);
+ break;
+ }
+ break;
+ case NC_ANIMATION:
+ switch (wmn->data) {
+ case ND_KEYFRAME:
+ /* Otherwise, often prevents seing immediately effects of keyframe editing... */
+ BKE_sequencer_cache_cleanup();
ED_region_tag_redraw(ar);
break;
}
diff --git a/source/blender/editors/space_text/text_autocomplete.c b/source/blender/editors/space_text/text_autocomplete.c
index 99e1606c9bd..1637ae14892 100644
--- a/source/blender/editors/space_text/text_autocomplete.c
+++ b/source/blender/editors/space_text/text_autocomplete.c
@@ -183,7 +183,7 @@ static GHash *text_autocomplete_build(Text *text)
const int choice_len = i_end - i_start;
if ((choice_len > seek_len) &&
- (seek_len == 0 || strncmp(seek, str_sub, seek_len) == 0) &&
+ (seek_len == 0 || STREQLEN(seek, str_sub, seek_len)) &&
(seek != str_sub))
{
// printf("Adding: %s\n", s);
@@ -207,18 +207,16 @@ static GHash *text_autocomplete_build(Text *text)
}
{
- GHashIterator *iter = BLI_ghashIterator_new(gh);
+ GHashIterator gh_iter;
/* get the formatter for highlighting */
TextFormatType *tft;
tft = ED_text_format_get(text);
- for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) {
- const char *s = BLI_ghashIterator_getValue(iter);
+ GHASH_ITER (gh_iter, gh) {
+ const char *s = BLI_ghashIterator_getValue(&gh_iter);
texttool_suggest_add(s, tft->format_identifier(s));
}
- BLI_ghashIterator_free(iter);
-
}
}
diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c
index 31662c02966..462b619f497 100644
--- a/source/blender/editors/space_text/text_draw.c
+++ b/source/blender/editors/space_text/text_draw.c
@@ -549,7 +549,7 @@ static void text_update_drawcache(SpaceText *st, ARegion *ar)
full_update |= drawcache->tabnumber != st->tabnumber; /* word-wrapping option was toggled */
full_update |= drawcache->lheight != st->lheight_dpi; /* word-wrapping option was toggled */
full_update |= drawcache->cwidth != st->cwidth; /* word-wrapping option was toggled */
- full_update |= strncmp(drawcache->text_id, txt->id.name, MAX_ID_NAME); /* text datablock was changed */
+ full_update |= !STREQLEN(drawcache->text_id, txt->id.name, MAX_ID_NAME); /* text datablock was changed */
if (st->wordwrap) {
/* update line heights */
@@ -1447,7 +1447,6 @@ void draw_text_main(SpaceText *st, ARegion *ar)
/* draw other stuff */
draw_brackets(st, ar);
- glTranslatef(GLA_PIXEL_OFS, GLA_PIXEL_OFS, 0.0f); /* XXX scroll requires exact pixel space */
draw_textscroll(st, &scroll, &back);
draw_documentation(st, ar);
draw_suggestion_list(st, ar);
diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c
index 1cf0316aa06..ad8050a50e8 100644
--- a/source/blender/editors/space_text/text_ops.c
+++ b/source/blender/editors/space_text/text_ops.c
@@ -2537,10 +2537,14 @@ static void text_cursor_set_to_pos(SpaceText *st, ARegion *ar, int x, int y, con
y -= txt_get_span(text->lines.first, *linep) - st->top;
if (y > 0) {
- while (y-- != 0) if ((*linep)->next) *linep = (*linep)->next;
+ while (y-- != 0) {
+ if ((*linep)->next) *linep = (*linep)->next;
+ }
}
else if (y < 0) {
- while (y++ != 0) if ((*linep)->prev) *linep = (*linep)->prev;
+ while (y++ != 0) {
+ if ((*linep)->prev) *linep = (*linep)->prev;
+ }
}
@@ -2919,7 +2923,7 @@ static int text_find_and_replace(bContext *C, wmOperator *op, short mode)
if (mode != TEXT_FIND && txt_has_sel(text)) {
tmp = txt_sel_to_buf(text);
- if (flags & ST_MATCH_CASE) found = strcmp(st->findstr, tmp) == 0;
+ if (flags & ST_MATCH_CASE) found = STREQ(st->findstr, tmp);
else found = BLI_strcasecmp(st->findstr, tmp) == 0;
if (found) {
diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c
index 820d1d68f8d..e2c195fd544 100644
--- a/source/blender/editors/space_time/space_time.c
+++ b/source/blender/editors/space_time/space_time.c
@@ -58,6 +58,7 @@
#include "UI_resources.h"
#include "UI_view2d.h"
+#include "UI_interface.h"
#include "ED_space_api.h"
#include "ED_markers.h"
@@ -90,13 +91,12 @@ static void time_draw_sfra_efra(Scene *scene, View2D *v2d)
fdrawline((float)PEFRA, v2d->cur.ymin, (float)PEFRA, v2d->cur.ymax);
}
-#define CACHE_DRAW_HEIGHT 3.0f
-
static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
{
PTCacheID *pid;
ListBase pidlist;
SpaceTimeCache *stc = stime->caches.first;
+ const float cache_draw_height = (4.0f * UI_DPI_FAC * U.pixelsize);
float yoffs = 0.f;
if (!(stime->cache_display & TIME_CACHE_DISPLAY) || (!ob))
@@ -172,7 +172,7 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
glPushMatrix();
glTranslatef(0.0, (float)V2D_SCROLL_HEIGHT + yoffs, 0.0);
- glScalef(1.0, CACHE_DRAW_HEIGHT, 0.0);
+ glScalef(1.0, cache_draw_height, 0.0);
switch (pid->type) {
case PTCACHE_TYPE_SOFTBODY:
@@ -227,7 +227,7 @@ static void time_draw_cache(SpaceTime *stime, Object *ob, Scene *scene)
glPopMatrix();
- yoffs += CACHE_DRAW_HEIGHT;
+ yoffs += cache_draw_height;
stc = stc->next;
}
@@ -292,6 +292,8 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
bDopeSheet ads = {NULL};
DLRBT_Tree keys;
ActKeyColumn *ak;
+ float ymin = v2d->tot.ymin;
+ float ymax = v2d->tot.ymax * 0.6f + ymin * 0.4f;
/* init binarytree-list for getting keyframes */
BLI_dlrbTree_init(&keys);
@@ -299,7 +301,7 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
/* init dopesheet settings */
if (onlysel)
ads.filterflag |= ADS_FILTER_ONLYSEL;
-
+
/* populate tree with keyframe nodes */
switch (GS(id->name)) {
case ID_SCE:
@@ -326,8 +328,8 @@ static void time_draw_idblock_keyframes(View2D *v2d, ID *id, short onlysel)
(ak) && (ak->cfra <= v2d->cur.xmax);
ak = ak->next)
{
- glVertex2f(ak->cfra, v2d->tot.ymin);
- glVertex2f(ak->cfra, v2d->tot.ymax);
+ glVertex2f(ak->cfra, ymin);
+ glVertex2f(ak->cfra, ymax);
}
glEnd(); // GL_LINES
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index 320267a4a7c..ab69e67361d 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -44,6 +44,7 @@ set(SRC
drawarmature.c
drawmesh.c
drawobject.c
+ drawsimdebug.c
drawvolume.c
space_view3d.c
view3d_buttons.c
diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c
index 691da78f26b..f33f074e6c5 100644
--- a/source/blender/editors/space_view3d/drawarmature.c
+++ b/source/blender/editors/space_view3d/drawarmature.c
@@ -1619,7 +1619,7 @@ static void draw_pose_dofs(Object *ob)
for (a = -16; a <= 16; a++) {
/* *0.5f here comes from M_PI/360.0f when rotations were still in degrees */
float fac = ((float)a) / 16.0f * 0.5f;
- phi = (float)(0.5 * M_PI) + fac * (pchan->limitmax[0] - pchan->limitmin[0]);
+ phi = (float)M_PI_2 + fac * (pchan->limitmax[0] - pchan->limitmin[0]);
i = (a == -16) ? 2 : 3;
corner[i][0] = 0.0f;
diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c
index 1cbc8e5567c..add9b41a91f 100644
--- a/source/blender/editors/space_view3d/drawobject.c
+++ b/source/blender/editors/space_view3d/drawobject.c
@@ -733,7 +733,7 @@ void drawcircball(int mode, const float cent[3], float rad, float tmat[4][4])
}
/* circle for object centers, special_color is for library or ob users */
-static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, int special_color)
+static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3], int selstate, bool special_color)
{
const float size = ED_view3d_pixel_size(rv3d, co) * (float)U.obcenter_dia * 0.5f;
float verts[CIRCLE_RESOL][3];
@@ -741,6 +741,8 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3],
/* using gldepthfunc guarantees that it does write z values,
* but not checks for it, so centers remain visible independent order of drawing */
if (v3d->zbuf) glDepthFunc(GL_ALWAYS);
+ /* write to near buffer always */
+ glDepthRange(0.0, 0.0);
glEnable(GL_BLEND);
if (special_color) {
@@ -770,6 +772,7 @@ static void drawcentercircle(View3D *v3d, RegionView3D *rv3d, const float co[3],
/* finish up */
glDisableClientState(GL_VERTEX_ARRAY);
+ glDepthRange(0.0, 1.0);
glDisable(GL_BLEND);
if (v3d->zbuf) glDepthFunc(GL_LEQUAL);
@@ -4329,8 +4332,8 @@ static bool drawDispList_nobackface(Scene *scene, View3D *v3d, RegionView3D *rv3
ListBase *lb = NULL;
DispList *dl;
Curve *cu;
- const short render_only = (v3d->flag2 & V3D_RENDER_OVERRIDE);
- const short solid = (dt > OB_WIRE);
+ const bool render_only = (v3d->flag2 & V3D_RENDER_OVERRIDE) != 0;
+ const bool solid = (dt > OB_WIRE);
if (drawCurveDerivedMesh(scene, v3d, rv3d, base, dt) == false) {
return false;
@@ -5145,7 +5148,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
cache = psys->pathcache;
for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
path = cache[a];
- if (path->steps > 0) {
+ if (path->segments > 0) {
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
if (1) { //ob_dt > OB_WIRE) {
@@ -5157,7 +5160,136 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
}
- glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
+ glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
+ }
+ }
+
+ if (part->type == PART_HAIR) {
+ if (part->draw & PART_DRAW_GUIDE_HAIRS) {
+ DerivedMesh *hair_dm = psys->hair_out_dm;
+
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
+ if (pa->totkey > 1) {
+ HairKey *hkey = pa->hair;
+
+ glVertexPointer(3, GL_FLOAT, sizeof(HairKey), hkey->world_co);
+
+ // XXX use proper theme color here
+// UI_ThemeColor(TH_NORMAL);
+ glColor3f(0.58f, 0.67f, 1.0f);
+
+ glDrawArrays(GL_LINE_STRIP, 0, pa->totkey);
+ }
+ }
+
+ if (hair_dm) {
+ MVert *mvert = hair_dm->getVertArray(hair_dm);
+ int i;
+
+ glColor3f(0.9f, 0.4f, 0.4f);
+
+ glBegin(GL_LINES);
+ for (a = 0, pa = psys->particles; a < totpart; a++, pa++) {
+ for (i = 1; i < pa->totkey; ++i) {
+ float v1[3], v2[3];
+
+ copy_v3_v3(v1, mvert[pa->hair_index + i - 1].co);
+ copy_v3_v3(v2, mvert[pa->hair_index + i].co);
+
+ mul_m4_v3(ob->obmat, v1);
+ mul_m4_v3(ob->obmat, v2);
+
+ glVertex3fv(v1);
+ glVertex3fv(v2);
+ }
+ }
+ glEnd();
+ }
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ if ((dflag & DRAW_CONSTCOLOR) == 0)
+ if (part->draw_col == PART_DRAW_COL_MAT)
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
+
+ if (part->draw & PART_DRAW_HAIR_GRID) {
+ ClothModifierData *clmd = psys->clmd;
+ if (clmd) {
+ float *a = clmd->hair_grid_min;
+ float *b = clmd->hair_grid_max;
+ int *res = clmd->hair_grid_res;
+ int i;
+
+ glDisable(GL_LIGHTING);
+ glDisable(GL_COLOR_MATERIAL);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+
+ if (select)
+ UI_ThemeColor(TH_ACTIVE);
+ else
+ UI_ThemeColor(TH_WIRE);
+ glBegin(GL_LINES);
+ glVertex3f(a[0], a[1], a[2]); glVertex3f(b[0], a[1], a[2]);
+ glVertex3f(b[0], a[1], a[2]); glVertex3f(b[0], b[1], a[2]);
+ glVertex3f(b[0], b[1], a[2]); glVertex3f(a[0], b[1], a[2]);
+ glVertex3f(a[0], b[1], a[2]); glVertex3f(a[0], a[1], a[2]);
+
+ glVertex3f(a[0], a[1], b[2]); glVertex3f(b[0], a[1], b[2]);
+ glVertex3f(b[0], a[1], b[2]); glVertex3f(b[0], b[1], b[2]);
+ glVertex3f(b[0], b[1], b[2]); glVertex3f(a[0], b[1], b[2]);
+ glVertex3f(a[0], b[1], b[2]); glVertex3f(a[0], a[1], b[2]);
+
+ glVertex3f(a[0], a[1], a[2]); glVertex3f(a[0], a[1], b[2]);
+ glVertex3f(b[0], a[1], a[2]); glVertex3f(b[0], a[1], b[2]);
+ glVertex3f(a[0], b[1], a[2]); glVertex3f(a[0], b[1], b[2]);
+ glVertex3f(b[0], b[1], a[2]); glVertex3f(b[0], b[1], b[2]);
+ glEnd();
+
+ if (select)
+ UI_ThemeColorShadeAlpha(TH_ACTIVE, 0, -100);
+ else
+ UI_ThemeColorShadeAlpha(TH_WIRE, 0, -100);
+ glEnable(GL_BLEND);
+ glBegin(GL_LINES);
+ for (i = 1; i < res[0]-1; ++i) {
+ float f = interpf(b[0], a[0], (float)i / (float)(res[0]-1));
+ glVertex3f(f, a[1], a[2]); glVertex3f(f, b[1], a[2]);
+ glVertex3f(f, b[1], a[2]); glVertex3f(f, b[1], b[2]);
+ glVertex3f(f, b[1], b[2]); glVertex3f(f, a[1], b[2]);
+ glVertex3f(f, a[1], b[2]); glVertex3f(f, a[1], a[2]);
+ }
+ for (i = 1; i < res[1]-1; ++i) {
+ float f = interpf(b[1], a[1], (float)i / (float)(res[1]-1));
+ glVertex3f(a[0], f, a[2]); glVertex3f(b[0], f, a[2]);
+ glVertex3f(b[0], f, a[2]); glVertex3f(b[0], f, b[2]);
+ glVertex3f(b[0], f, b[2]); glVertex3f(a[0], f, b[2]);
+ glVertex3f(a[0], f, b[2]); glVertex3f(a[0], f, a[2]);
+ }
+ for (i = 1; i < res[2]-1; ++i) {
+ float f = interpf(b[2], a[2], (float)i / (float)(res[2]-1));
+ glVertex3f(a[0], a[1], f); glVertex3f(b[0], a[1], f);
+ glVertex3f(b[0], a[1], f); glVertex3f(b[0], b[1], f);
+ glVertex3f(b[0], b[1], f); glVertex3f(a[0], b[1], f);
+ glVertex3f(a[0], b[1], f); glVertex3f(a[0], a[1], f);
+ }
+ glEnd();
+ glDisable(GL_BLEND);
+
+ glEnable(GL_LIGHTING);
+ glEnable(GL_COLOR_MATERIAL);
+ glEnableClientState(GL_NORMAL_ARRAY);
+ if ((dflag & DRAW_CONSTCOLOR) == 0)
+ if (part->draw_col == PART_DRAW_COL_MAT)
+ glEnableClientState(GL_COLOR_ARRAY);
+ }
}
}
@@ -5176,7 +5308,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv
}
}
- glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
+ glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
}
@@ -5328,7 +5460,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
PTCacheEditKey *key;
ParticleEditSettings *pset = PE_settings(scene);
int i, k, totpoint = edit->totpoint, timed = pset->flag & PE_FADE_TIME ? pset->fade_frames : 0;
- int steps = 1;
+ int totkeys = 1;
float sel_col[3];
float nosel_col[3];
float *pathcol = NULL, *pcol;
@@ -5347,10 +5479,10 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
UI_GetThemeColor3fv(TH_VERTEX, nosel_col);
/* draw paths */
- steps = (*edit->pathcache)->steps + 1;
+ totkeys = (*edit->pathcache)->segments + 1;
glEnable(GL_BLEND);
- pathcol = MEM_callocN(steps * 4 * sizeof(float), "particle path color data");
+ pathcol = MEM_callocN(totkeys * 4 * sizeof(float), "particle path color data");
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
@@ -5370,7 +5502,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glVertexPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->co);
if (point->flag & PEP_HIDE) {
- for (k = 0, pcol = pathcol; k < steps; k++, pcol += 4) {
+ for (k = 0, pcol = pathcol; k < totkeys; k++, pcol += 4) {
copy_v3_v3(pcol, path->col);
pcol[3] = 0.25f;
}
@@ -5378,7 +5510,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
glColorPointer(4, GL_FLOAT, 4 * sizeof(float), pathcol);
}
else if (timed) {
- for (k = 0, pcol = pathcol, pkey = path; k < steps; k++, pkey++, pcol += 4) {
+ for (k = 0, pcol = pathcol, pkey = path; k < totkeys; k++, pkey++, pcol += 4) {
copy_v3_v3(pcol, pkey->col);
pcol[3] = 1.0f - fabsf((float)(CFRA) -pkey->time) / (float)pset->fade_frames;
}
@@ -5388,7 +5520,7 @@ static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit)
else
glColorPointer(3, GL_FLOAT, sizeof(ParticleCacheKey), path->col);
- glDrawArrays(GL_LINE_STRIP, 0, path->steps + 1);
+ glDrawArrays(GL_LINE_STRIP, 0, path->segments + 1);
}
if (pathcol) { MEM_freeN(pathcol); pathcol = pcol = NULL; }
@@ -7727,7 +7859,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
if (render_override) {
/* don't draw */
}
- else if ((scene->basact) == base)
+ else if (is_obact)
do_draw_center = ACTIVE;
else if (base->flag & SELECT)
do_draw_center = SELECT;
diff --git a/source/blender/editors/space_view3d/drawsimdebug.c b/source/blender/editors/space_view3d/drawsimdebug.c
new file mode 100644
index 00000000000..6113bfd4143
--- /dev/null
+++ b/source/blender/editors/space_view3d/drawsimdebug.c
@@ -0,0 +1,173 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/editors/space_view3d/drawsimdebug.c
+ * \ingroup spview3d
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "BKE_effect.h"
+#include "BKE_global.h"
+#include "BKE_modifier.h"
+
+#include "view3d_intern.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "UI_resources.h"
+
+static void draw_sim_debug_elements(SimDebugData *debug_data, float imat[4][4])
+{
+ GHashIterator iter;
+
+ /**** dots ****/
+
+ glPointSize(3.0f);
+ glBegin(GL_POINTS);
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ if (elem->type != SIM_DEBUG_ELEM_DOT)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
+ }
+ glEnd();
+ glPointSize(1.0f);
+
+ /**** circles ****/
+
+ {
+ float circle[16][2] = {
+ {0.000000, 1.000000}, {0.382683, 0.923880}, {0.707107, 0.707107}, {0.923880, 0.382683},
+ {1.000000, -0.000000}, {0.923880, -0.382683}, {0.707107, -0.707107}, {0.382683, -0.923880},
+ {-0.000000, -1.000000}, {-0.382683, -0.923880}, {-0.707107, -0.707107}, {-0.923879, -0.382684},
+ {-1.000000, 0.000000}, {-0.923879, 0.382684}, {-0.707107, 0.707107}, {-0.382683, 0.923880} };
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ float radius = elem->v2[0];
+ float co[3];
+ int i;
+
+ if (elem->type != SIM_DEBUG_ELEM_CIRCLE)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glBegin(GL_LINE_LOOP);
+ for (i = 0; i < 16; ++i) {
+ co[0] = radius * circle[i][0];
+ co[1] = radius * circle[i][1];
+ co[2] = 0.0f;
+ mul_mat3_m4_v3(imat, co);
+ add_v3_v3(co, elem->v1);
+
+ glVertex3f(co[0], co[1], co[2]);
+ }
+ glEnd();
+ }
+ }
+
+ /**** lines ****/
+
+ glBegin(GL_LINES);
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ if (elem->type != SIM_DEBUG_ELEM_LINE)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
+ glVertex3f(elem->v2[0], elem->v2[1], elem->v2[2]);
+ }
+ glEnd();
+
+ /**** vectors ****/
+
+ glPointSize(2.0f);
+ glBegin(GL_POINTS);
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ if (elem->type != SIM_DEBUG_ELEM_VECTOR)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
+ }
+ glEnd();
+ glPointSize(1.0f);
+
+ glBegin(GL_LINES);
+ for (BLI_ghashIterator_init(&iter, debug_data->gh); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) {
+ SimDebugElement *elem = BLI_ghashIterator_getValue(&iter);
+ float t[3];
+ if (elem->type != SIM_DEBUG_ELEM_VECTOR)
+ continue;
+
+ glColor3f(elem->color[0], elem->color[1], elem->color[2]);
+ glVertex3f(elem->v1[0], elem->v1[1], elem->v1[2]);
+ add_v3_v3v3(t, elem->v1, elem->v2);
+ glVertex3f(t[0], t[1], t[2]);
+ }
+ glEnd();
+}
+
+void draw_sim_debug_data(Scene *UNUSED(scene), View3D *UNUSED(v3d), ARegion *ar)
+{
+ RegionView3D *rv3d = ar->regiondata;
+ /*Object *ob = base->object;*/
+ float imat[4][4];
+
+ if (!_sim_debug_data)
+ return;
+
+ invert_m4_m4(imat, rv3d->viewmatob);
+
+// glDepthMask(GL_FALSE);
+// glEnable(GL_BLEND);
+
+ glPushMatrix();
+
+ glLoadMatrixf(rv3d->viewmat);
+ draw_sim_debug_elements(_sim_debug_data, imat);
+
+ glPopMatrix();
+
+// glDepthMask(GL_TRUE);
+// glDisable(GL_BLEND);
+}
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index 55d5273b198..25085368dac 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -564,7 +564,7 @@ static void view3d_main_area_exit(wmWindowManager *wm, ARegion *ar)
static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_OB)
return 1;
}
@@ -574,7 +574,7 @@ static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent
static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_GR)
return 1;
}
@@ -584,7 +584,7 @@ static int view3d_group_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEve
static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_MA)
return 1;
}
@@ -594,7 +594,7 @@ static int view3d_mat_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent
static int view3d_ima_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
{
if (drag->type == WM_DRAG_ID) {
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (GS(id->name) == ID_IM)
return 1;
}
@@ -641,14 +641,14 @@ static int view3d_ima_mesh_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e
static void view3d_ob_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
drop->opcontext = WM_OP_EXEC_DEFAULT;
RNA_string_set(drop->ptr, "name", id->name + 2);
@@ -656,14 +656,14 @@ static void view3d_group_drop_copy(wmDrag *drag, wmDropBox *drop)
static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
RNA_string_set(drop->ptr, "name", id->name + 2);
}
static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop)
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
if (id) {
RNA_string_set(drop->ptr, "name", id->name + 2);
@@ -817,6 +817,16 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
case ND_WORLD:
/* handled by space_view3d_listener() for v3d access */
break;
+ case ND_DRAW_RENDER_VIEWPORT:
+ {
+ if (v3d->camera && (scene == wmn->reference)) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB) {
+ ED_region_tag_redraw(ar);
+ }
+ }
+ break;
+ }
}
if (wmn->action == NA_EDITED)
ED_region_tag_redraw(ar);
@@ -856,6 +866,20 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
break;
}
break;
+ case NC_CAMERA:
+ switch (wmn->data) {
+ case ND_DRAW_RENDER_VIEWPORT:
+ {
+ if (v3d->camera && (v3d->camera->data == wmn->reference)) {
+ RegionView3D *rv3d = ar->regiondata;
+ if (rv3d->persp == RV3D_CAMOB) {
+ ED_region_tag_redraw(ar);
+ }
+ }
+ break;
+ }
+ }
+ break;
case NC_GROUP:
/* all group ops for now */
ED_region_tag_redraw(ar);
diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c
index 65721d52dff..929929c7dd0 100644
--- a/source/blender/editors/space_view3d/view3d_draw.c
+++ b/source/blender/editors/space_view3d/view3d_draw.c
@@ -162,15 +162,15 @@ static void view3d_draw_clipping(RegionView3D *rv3d)
/* fill in zero alpha for rendering & re-projection [#31530] */
unsigned char col[4];
- UI_GetThemeColorShade3ubv(TH_BACK, -8, col);
- col[3] = 0;
+ UI_GetThemeColor4ubv(TH_V3D_CLIPPING_BORDER, col);
glColor4ubv(col);
+ glEnable(GL_BLEND);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 0, bb->vec);
glDrawElements(GL_QUADS, sizeof(clipping_index) / sizeof(unsigned int), GL_UNSIGNED_INT, clipping_index);
glDisableClientState(GL_VERTEX_ARRAY);
-
+ glDisable(GL_BLEND);
}
}
@@ -586,20 +586,26 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
float ydisp = 0.0; /* vertical displacement to allow obj info text */
int bright = - 20 * (10 - U.rvibright); /* axis alpha offset (rvibright has range 0-10) */
float vec[3];
- char axis_text[2] = "x";
float dx, dy;
- int i;
-
+
+ int axis_order[3] = {0, 1, 2};
+ int axis_i;
+
startx += rect->xmin;
starty += rect->ymin;
-
+
+ axis_sort_v3(rv3d->viewinv[2], axis_order);
+
/* thickness of lines is proportional to k */
glLineWidth(2);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- for (i = 0; i < 3; i++) {
+ for (axis_i = 0; axis_i < 3; axis_i++) {
+ int i = axis_order[axis_i];
+ const char axis_text[2] = {'x' + i, '\0'};
+
zero_v3(vec);
vec[i] = 1.0f;
mul_qt_v3(rv3d->viewquat, vec);
@@ -616,8 +622,6 @@ static void draw_view_axis(RegionView3D *rv3d, rcti *rect)
BLF_draw_default_ascii(startx + dx + 2, starty + dy + ydisp + 2, 0.0f, axis_text, 1);
}
- axis_text[0]++;
-
/* BLF_draw_default disables blending */
glEnable(GL_BLEND);
}
@@ -1066,14 +1070,13 @@ static void drawviewborder_triangle(float x1, float x2, float y1, float y2, cons
static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
{
- float hmargin, vmargin;
float x1, x2, y1, y2;
float x1i, x2i, y1i, y2i;
rctf viewborder;
Camera *ca = NULL;
RegionView3D *rv3d = ar->regiondata;
-
+
if (v3d->camera == NULL)
return;
if (v3d->camera->type == OB_CAMERA)
@@ -1225,17 +1228,20 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
drawviewborder_triangle(x1, x2, y1, y2, 1, 'B');
}
- if (ca->flag & CAM_SHOWTITLESAFE) {
- UI_ThemeColorBlendShade(TH_VIEW_OVERLAY, TH_BACK, 0.25, 0);
-
- hmargin = 0.1f * (x2 - x1);
- vmargin = 0.05f * (y2 - y1);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, x1 + hmargin, y1 + vmargin, x2 - hmargin, y2 - vmargin, 2.0f);
+ if (ca->flag & CAM_SHOW_SAFE_MARGINS) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title,
+ scene->safe_areas.action);
- hmargin = 0.035f * (x2 - x1);
- vmargin = 0.035f * (y2 - y1);
- UI_draw_roundbox_gl_mode(GL_LINE_LOOP, x1 + hmargin, y1 + vmargin, x2 - hmargin, y2 - vmargin, 2.0f);
+ if (ca->flag & CAM_SHOW_SAFE_CENTER) {
+ UI_draw_safe_areas(
+ x1, x2, y1, y2,
+ scene->safe_areas.title_center,
+ scene->safe_areas.action_center);
+ }
}
+
if (ca->flag & CAM_SHOWSENSOR) {
/* determine sensor fit, and get sensor x/y, for auto fit we
* assume and square sensor and only use sensor_x */
@@ -1279,8 +1285,9 @@ static void drawviewborder(Scene *scene, ARegion *ar, View3D *v3d)
/* camera name - draw in highlighted text color */
if (ca && (ca->flag & CAM_SHOWNAME)) {
UI_ThemeColor(TH_TEXT_HI);
- BLF_draw_default(x1i, y1i - 15, 0.0f, v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2);
- UI_ThemeColor(TH_WIRE);
+ BLF_draw_default(
+ x1i, y1i - (0.7f * U.widget_unit), 0.0f,
+ v3d->camera->id.name + 2, sizeof(v3d->camera->id.name) - 2);
}
}
@@ -1608,7 +1615,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
{
float image_aspect[2];
float fac, asp, zoomx, zoomy;
- float x1, y1, x2, y2;
+ float x1, y1, x2, y2, centx, centy;
ImBuf *ibuf = NULL, *freeibuf, *releaseibuf;
void *lock;
@@ -1714,6 +1721,9 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
y2 += yof_scale;
}
+ centx = (x1 + x2) / 2.0f;
+ centy = (y1 + y2) / 2.0f;
+
/* aspect correction */
if (bgpic->flag & V3D_BGPIC_CAMERA_ASPECT) {
/* apply aspect from clip */
@@ -1731,16 +1741,14 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
if ((asp_src > asp_dst) == ((bgpic->flag & V3D_BGPIC_CAMERA_CROP) != 0)) {
/* fit X */
const float div = asp_src / asp_dst;
- const float cent = (x1 + x2) / 2.0f;
- x1 = ((x1 - cent) * div) + cent;
- x2 = ((x2 - cent) * div) + cent;
+ x1 = ((x1 - centx) * div) + centx;
+ x2 = ((x2 - centx) * div) + centx;
}
else {
/* fit Y */
const float div = asp_dst / asp_src;
- const float cent = (y1 + y2) / 2.0f;
- y1 = ((y1 - cent) * div) + cent;
- y2 = ((y2 - cent) * div) + cent;
+ y1 = ((y1 - centy) * div) + centy;
+ y2 = ((y2 - centy) * div) + centy;
}
}
}
@@ -1767,6 +1775,9 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
y1 = sco[1] + asp * fac * (bgpic->yof - bgpic->size);
x2 = sco[0] + fac * (bgpic->xof + bgpic->size);
y2 = sco[1] + asp * fac * (bgpic->yof + bgpic->size);
+
+ centx = (x1 + x2) / 2.0f;
+ centy = (y1 + y2) / 2.0f;
}
/* complete clip? */
@@ -1817,6 +1828,19 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
glPushMatrix();
ED_region_pixelspace(ar);
+ glTranslatef(centx, centy, 0.0);
+ if (rv3d->persp != RV3D_CAMOB) {
+ glRotatef(RAD2DEGF(-bgpic->rotation), 0.0f, 0.0f, 1.0f);
+ }
+
+ if (bgpic->flag & V3D_BGPIC_FLIP_X) {
+ zoomx *= -1.0f;
+ x1 = x2;
+ }
+ if (bgpic->flag & V3D_BGPIC_FLIP_Y) {
+ zoomy *= -1.0f;
+ y1 = y2;
+ }
glPixelZoom(zoomx, zoomy);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f - bgpic->blend);
@@ -1824,7 +1848,7 @@ static void view3d_draw_bgpic(Scene *scene, ARegion *ar, View3D *v3d,
* glaDrawPixelsSafe in some cases, which will end up in missing
* alpha transparency for the background image (sergey)
*/
- glaDrawPixelsTex(x1, y1, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
+ glaDrawPixelsTex(x1 - centx, y1 - centy, ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_LINEAR, ibuf->rect);
glPixelZoom(1.0, 1.0);
glPixelTransferf(GL_ALPHA_SCALE, 1.0f);
@@ -2566,6 +2590,7 @@ CustomDataMask ED_view3d_screen_datamask(bScreen *screen)
void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4])
{
RegionView3D *rv3d = ar->regiondata;
+ rctf cameraborder;
/* setup window matrices */
if (winmat)
@@ -2583,7 +2608,23 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view
mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat);
invert_m4_m4(rv3d->persinv, rv3d->persmat);
invert_m4_m4(rv3d->viewinv, rv3d->viewmat);
+
+ /* calculate GLSL view dependent values */
+ /* store window coordinates scaling/offset */
+ if (rv3d->persp == RV3D_CAMOB && v3d->camera) {
+ ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false);
+ rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder);
+ rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder);
+
+ rv3d->viewcamtexcofac[2] = -rv3d->viewcamtexcofac[0] * cameraborder.xmin / (float)ar->winx;
+ rv3d->viewcamtexcofac[3] = -rv3d->viewcamtexcofac[1] * cameraborder.ymin / (float)ar->winy;
+ }
+ else {
+ rv3d->viewcamtexcofac[0] = rv3d->viewcamtexcofac[1] = 1.0f;
+ rv3d->viewcamtexcofac[2] = rv3d->viewcamtexcofac[3] = 0.0f;
+ }
+
/* calculate pixelsize factor once, is used for lamps and obcenters */
{
/* note: '1.0f / len_v3(v1)' replaced 'len_v3(rv3d->viewmat[0])'
@@ -2815,15 +2856,15 @@ static void view3d_main_area_clear(Scene *scene, View3D *v3d, ARegion *ar, bool
{
/* clear background */
if (scene->world && ((v3d->flag3 & V3D_SHOW_WORLD) || force)) {
- float alpha = (force) ? 1.0f : 0.0;
+ float alpha = (force) ? 1.0f : 0.0f;
bool glsl = GPU_glsl_support() && BKE_scene_use_new_shading_nodes(scene) && scene->world->nodetree && scene->world->use_nodes;
if (glsl) {
RegionView3D *rv3d = ar->regiondata;
GPUMaterial *gpumat = GPU_material_world(scene, scene->world);
-
+
/* calculate full shader for background */
- GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, (v3d->scenelock != 0));
+ GPU_material_bind(gpumat, 1, 1, 1.0, false, rv3d->viewmat, rv3d->viewinv, rv3d->viewcamtexcofac, (v3d->scenelock != 0));
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_ALWAYS);
@@ -3082,15 +3123,6 @@ void ED_view3d_draw_offscreen(Scene *scene, View3D *v3d, ARegion *ar, int winx,
G.f &= ~G_RENDER_OGL;
}
-/* get a color used for offscreen sky, returns color in sRGB space */
-void ED_view3d_offscreen_sky_color_get(Scene *scene, float sky_color[3])
-{
- if (scene->world)
- linearrgb_to_srgb_v3_v3(sky_color, &scene->world->horr);
- else
- UI_GetThemeColor3fv(TH_BACK, sky_color);
-}
-
/* utility func for ED_view3d_draw_offscreen */
ImBuf *ED_view3d_draw_offscreen_imbuf(Scene *scene, View3D *v3d, ARegion *ar, int sizex, int sizey, unsigned int flag,
bool draw_background, int alpha_mode, char err_out[256])
@@ -3573,9 +3605,13 @@ void view3d_main_area_draw(const bContext *C, ARegion *ar)
/* draw viewport using opengl */
if (v3d->drawtype != OB_RENDER || !view3d_main_area_do_render_draw(scene) || clip_border) {
view3d_main_area_draw_objects(C, scene, v3d, ar, &grid_unit);
+
#ifdef DEBUG_DRAW
bl_debug_draw();
#endif
+ if (G.debug & G_DEBUG_SIMDATA)
+ draw_sim_debug_data(scene, v3d, ar);
+
ED_region_pixelspace(ar);
}
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index aab307babe8..e6f61fb4aca 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -1034,7 +1034,7 @@ static void viewrotate_apply(ViewOpsData *vod, int x, int y)
* - of rotation is linearly proportional
* - to the distance that the mouse is
* - dragged. */
- phi = si * (float)(M_PI / 2.0);
+ phi = si * (float)M_PI_2;
q1[0] = cosf(phi);
mul_v3_fl(q1 + 1, sinf(phi));
@@ -3373,7 +3373,8 @@ void VIEW3D_OT_render_border(wmOperatorType *ot)
/* rna */
WM_operator_properties_border(ot);
- prop = 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", false, "Camera Only",
+ "Set render border for camera view and final render only");
RNA_def_property_flag(prop, PROP_HIDDEN);
}
@@ -5003,8 +5004,9 @@ BGpic *ED_view3D_background_image_new(View3D *v3d)
{
BGpic *bgpic = MEM_callocN(sizeof(BGpic), "Background Image");
- bgpic->size = 5.0;
- bgpic->blend = 0.5;
+ bgpic->rotation = 0.0f;
+ bgpic->size = 5.0f;
+ bgpic->blend = 0.5f;
bgpic->iuser.fie_ima = 2;
bgpic->iuser.ok = 1;
bgpic->view = 0; /* 0 for all */
diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h
index d3a9f5ca967..25dbc8830fe 100644
--- a/source/blender/editors/space_view3d/view3d_intern.h
+++ b/source/blender/editors/space_view3d/view3d_intern.h
@@ -48,9 +48,11 @@ struct bMotionPath;
struct bPoseChannel;
struct bScreen;
struct Mesh;
+struct SimDebugData;
struct wmNDOFMotionData;
struct wmOperatorType;
struct wmWindowManager;
+struct wmKeyConfig;
/* drawing flags: */
enum {
@@ -177,6 +179,9 @@ void draw_mesh_paint_weight_edges(RegionView3D *rv3d, struct DerivedMesh *dm,
void draw_mesh_paint(View3D *v3d, RegionView3D *rv3d,
struct Object *ob, struct DerivedMesh *dm, const int draw_flags);
+/* drawsimdebug.c */
+void draw_sim_debug_data(Scene *scene, View3D *v3d, ARegion *ar);
+
/* view3d_draw.c */
void view3d_main_area_draw(const struct bContext *C, struct ARegion *ar);
void ED_view3d_draw_depth(Scene *scene, struct ARegion *ar, View3D *v3d, bool alphaoverride);
diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c
index 5df348408df..0457f5f2d52 100644
--- a/source/blender/editors/space_view3d/view3d_ops.c
+++ b/source/blender/editors/space_view3d/view3d_ops.c
@@ -344,8 +344,8 @@ void view3d_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "VIEW3D_OT_ndof_all", NDOF_MOTION, 0, KM_CTRL | KM_SHIFT, 0);
kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_view_selected", NDOF_BUTTON_FIT, KM_PRESS, 0, 0);
RNA_boolean_set(kmi->ptr, "use_all_regions", false);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "angle", M_PI / -2);
- RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CW, KM_PRESS, 0, 0)->ptr, "angle", M_PI / 2);
+ RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CCW, KM_PRESS, 0, 0)->ptr, "angle", -M_PI_2);
+ RNA_float_set(WM_keymap_add_item(keymap, "VIEW3D_OT_view_roll", NDOF_BUTTON_ROLL_CW, KM_PRESS, 0, 0)->ptr, "angle", M_PI_2);
RNA_enum_set(WM_keymap_add_item(keymap, "VIEW3D_OT_viewnumpad", NDOF_BUTTON_FRONT, KM_PRESS, 0, 0)->ptr, "type", RV3D_VIEW_FRONT);
diff --git a/source/blender/editors/space_view3d/view3d_toolbar.c b/source/blender/editors/space_view3d/view3d_toolbar.c
index f127f375a9f..af24a99a6f2 100644
--- a/source/blender/editors/space_view3d/view3d_toolbar.c
+++ b/source/blender/editors/space_view3d/view3d_toolbar.c
@@ -216,7 +216,7 @@ static void view3d_panel_tool_shelf(const bContext *C, Panel *pa)
CustomTool *ct;
for (ct = st->toolshelf.first; ct; ct = ct->next) {
- if (0 == strncmp(context, ct->context, OP_MAX_TYPENAME)) {
+ if (STREQLEN(context, ct->context, OP_MAX_TYPENAME)) {
col = uiLayoutColumn(pa->layout, true);
uiItemFullO(col, ct->opname, NULL, ICON_NONE, NULL, WM_OP_INVOKE_REGION_WIN, 0);
}
diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c
index b727b96c8cc..14bbdebd138 100644
--- a/source/blender/editors/transform/transform.c
+++ b/source/blender/editors/transform/transform.c
@@ -93,8 +93,8 @@
#define MAX_INFO_LEN 256
static void drawTransformApply(const struct bContext *C, ARegion *ar, void *arg);
-static int doEdgeSlide(TransInfo *t, float perc);
-static int doVertSlide(TransInfo *t, float perc);
+static void doEdgeSlide(TransInfo *t, float perc);
+static void doVertSlide(TransInfo *t, float perc);
static void drawEdgeSlide(const struct bContext *C, TransInfo *t);
static void drawVertSlide(const struct bContext *C, TransInfo *t);
@@ -671,8 +671,11 @@ static void viewRedrawPost(bContext *C, TransInfo *t)
WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
/* redraw UV editor */
- if (t->mode == TFM_EDGE_SLIDE && (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+ if (ELEM(t->mode, TFM_VERT_SLIDE, TFM_EDGE_SLIDE) &&
+ (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT))
+ {
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
+ }
/* XXX temp, first hack to get auto-render in compositor work (ton) */
WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, CTX_data_scene(C));
@@ -969,6 +972,7 @@ int transformEvent(TransInfo *t, const wmEvent *event)
{
char cmode = constraintModeToChar(t);
bool handled = false;
+ const int modifiers_prev = t->modifiers;
t->redraw |= handleMouseInput(t, &t->mouse, event);
@@ -1495,6 +1499,13 @@ int transformEvent(TransInfo *t, const wmEvent *event)
}
}
+ /* if we change snap options, get the unsnapped values back */
+ if ((t->modifiers & (MOD_SNAP | MOD_SNAP_INVERT)) !=
+ (modifiers_prev & (MOD_SNAP | MOD_SNAP_INVERT)))
+ {
+ applyMouseInput(t, &t->mouse, t->mval, t->values);
+ }
+
/* Per transform event, if present */
if (t->handleEvent &&
(!handled ||
@@ -3129,7 +3140,7 @@ static void initResize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerResize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
+static void headerResize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -4102,7 +4113,7 @@ static void initTranslation(TransInfo *t)
}
}
-static void headerTranslation(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
+static void headerTranslation(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
{
size_t ofs = 0;
char tvec[NUM_STR_REP_LEN * 3];
@@ -4195,7 +4206,7 @@ static void headerTranslation(TransInfo *t, float vec[3], char str[MAX_INFO_LEN]
}
}
-static void applyTranslationValue(TransInfo *t, float vec[3])
+static void applyTranslationValue(TransInfo *t, const float vec[3])
{
TransData *td = t->data;
float tvec[3];
@@ -4932,7 +4943,7 @@ static void initBoneSize(TransInfo *t)
t->num.unit_type[2] = B_UNIT_NONE;
}
-static void headerBoneSize(TransInfo *t, float vec[3], char str[MAX_INFO_LEN])
+static void headerBoneSize(TransInfo *t, const float vec[3], char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
if (hasNumInput(&t->num)) {
@@ -5102,6 +5113,85 @@ static void applyBoneEnvelope(TransInfo *t, const int UNUSED(mval[2]))
}
/** \} */
+/* -------------------------------------------------------------------- */
+/* Original Data Store */
+
+/** \name Orig-Data Store Utility Functions
+ * \{ */
+
+static void slide_origdata_init_flag(
+ TransInfo *t, SlideOrigData *sod)
+{
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+
+ if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
+ /* don't do this at all for non-basis shape keys, too easy to
+ * accidentally break uv maps or vertex colors then */
+ (bm->shapenr <= 1))
+ {
+ sod->use_origfaces = true;
+ }
+ else {
+ sod->use_origfaces = false;
+ }
+}
+
+static void slide_origdata_init_data(
+ TransInfo *t, SlideOrigData *sod)
+{
+ if (sod->use_origfaces) {
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+
+ sod->origfaces = BLI_ghash_ptr_new(__func__);
+ sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default);
+ /* we need to have matching customdata */
+ BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL);
+ }
+}
+
+static void slide_origdata_create_date(
+ TransInfo *t, SlideOrigData *sod,
+ BMVert **v_pt, unsigned int v_stride, unsigned int v_num)
+{
+ if (sod->use_origfaces) {
+ BMEditMesh *em = BKE_editmesh_from_object(t->obedit);
+ BMesh *bm = em->bm;
+
+ unsigned int i;
+ for (i = 0; i < v_num; i++, v_pt = (void *)(((char *)v_pt) + v_stride)) {
+ BMIter fiter;
+ BMFace *f;
+ BMVert *v = *v_pt;
+
+ BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) {
+ if (!BLI_ghash_haskey(sod->origfaces, f)) {
+ BMFace *f_copy = BM_face_copy(sod->bm_origfaces, bm, f, true, true);
+ BLI_ghash_insert(sod->origfaces, f, f_copy);
+ }
+ }
+ }
+ }
+}
+
+static void slide_origdata_free_date(
+ SlideOrigData *sod)
+{
+ if (sod->use_origfaces) {
+ if (sod->bm_origfaces) {
+ BM_mesh_free(sod->bm_origfaces);
+ sod->bm_origfaces = NULL;
+ }
+
+ if (sod->origfaces) {
+ BLI_ghash_free(sod->origfaces, NULL, NULL);
+ sod->origfaces = NULL;
+ }
+ }
+}
+
+/** \} */
/* -------------------------------------------------------------------- */
/* Transform (Edge Slide) */
@@ -5360,16 +5450,7 @@ static bool createEdgeSlideVerts(TransInfo *t)
rv3d = t->ar ? t->ar->regiondata : NULL;
}
- if ((t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT) &&
- /* don't do this at all for non-basis shape keys, too easy to
- * accidentally break uv maps or vertex colors then */
- (bm->shapenr <= 1))
- {
- sld->use_origfaces = true;
- }
- else {
- sld->use_origfaces = false;
- }
+ slide_origdata_init_flag(t, &sld->orig_data);
sld->is_proportional = true;
sld->curr_sv_index = 0;
@@ -5761,30 +5842,12 @@ static bool createEdgeSlideVerts(TransInfo *t)
}
bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
-
- if (sld->use_origfaces) {
- sld->origfaces = BLI_ghash_ptr_new(__func__);
- sld->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default);
- /* we need to have matching customdata */
- BM_mesh_copy_init_customdata(sld->bm_origfaces, bm, NULL);
- }
+ slide_origdata_init_data(t, &sld->orig_data);
+ slide_origdata_create_date(t, &sld->orig_data, &sld->sv->v, sizeof(*sld->sv), sld->totsv);
/*create copies of faces for customdata projection*/
sv_array = sld->sv;
for (i = 0; i < sld->totsv; i++, sv_array++) {
- BMIter fiter;
- BMFace *f;
-
-
- if (sld->use_origfaces) {
- BM_ITER_ELEM (f, &fiter, sv_array->v, BM_FACES_OF_VERT) {
- if (!BLI_ghash_haskey(sld->origfaces, f)) {
- BMFace *f_copy = BM_face_copy(sld->bm_origfaces, bm, f, true, true);
- BLI_ghash_insert(sld->origfaces, f, f_copy);
- }
- }
- }
-
/* switch a/b if loop direction is different from global direction */
l_nr = sv_array->loop_nr;
if (dot_v3v3(loop_dir[l_nr], mval_dir) < 0.0f) {
@@ -5828,11 +5891,12 @@ static bool createEdgeSlideVerts(TransInfo *t)
void projectEdgeSlideData(TransInfo *t, bool is_final)
{
EdgeSlideData *sld = t->customData;
+ SlideOrigData *sod = &sld->orig_data;
TransDataEdgeSlideVert *sv;
BMEditMesh *em = sld->em;
int i;
- if (sld->use_origfaces == false) {
+ if (sod->use_origfaces == false) {
return;
}
@@ -5844,7 +5908,7 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
BMFace *f_copy; /* the copy of 'f' */
BMFace *f_copy_flip; /* the copy of 'f' or detect if we need to flip to the shorter side. */
- f_copy = BLI_ghash_lookup(sld->origfaces, l->f);
+ f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
/* project onto copied projection face */
f_copy_flip = f_copy;
@@ -5858,12 +5922,12 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
if (sld->perc < 0.0f) {
if (BM_vert_in_face(sv->v_b, l_ed_sel->radial_next->f)) {
- f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f);
+ f_copy_flip = BLI_ghash_lookup(sod->origfaces, l_ed_sel->radial_next->f);
}
}
else if (sld->perc > 0.0f) {
if (BM_vert_in_face(sv->v_a, l_ed_sel->radial_next->f)) {
- f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_ed_sel->radial_next->f);
+ f_copy_flip = BLI_ghash_lookup(sod->origfaces, l_ed_sel->radial_next->f);
}
}
@@ -5949,7 +6013,7 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
l_adj = l;
}
- f_copy_flip = BLI_ghash_lookup(sld->origfaces, l_adj->f);
+ f_copy_flip = BLI_ghash_lookup(sod->origfaces, l_adj->f);
}
}
}
@@ -5966,34 +6030,23 @@ void projectEdgeSlideData(TransInfo *t, bool is_final)
}
/* make sure face-attributes are correct (e.g. MTexPoly) */
- BM_elem_attrs_copy(sld->bm_origfaces, em->bm, f_copy, l->f);
+ BM_elem_attrs_copy(sod->bm_origfaces, em->bm, f_copy, l->f);
}
}
}
void freeEdgeSlideTempFaces(EdgeSlideData *sld)
{
- if (sld->use_origfaces) {
- if (sld->bm_origfaces) {
- BM_mesh_free(sld->bm_origfaces);
- sld->bm_origfaces = NULL;
- }
-
- if (sld->origfaces) {
- BLI_ghash_free(sld->origfaces, NULL, NULL);
- sld->origfaces = NULL;
- }
- }
+ slide_origdata_free_date(&sld->orig_data);
}
-
void freeEdgeSlideVerts(TransInfo *t)
{
EdgeSlideData *sld = t->customData;
if (!sld)
return;
-
+
freeEdgeSlideTempFaces(sld);
bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
@@ -6167,7 +6220,7 @@ static void drawEdgeSlide(const struct bContext *C, TransInfo *t)
}
}
-static int doEdgeSlide(TransInfo *t, float perc)
+static void doEdgeSlide(TransInfo *t, float perc)
{
EdgeSlideData *sld = t->customData;
TransDataEdgeSlideVert *svlist = sld->sv, *sv;
@@ -6224,8 +6277,6 @@ static int doEdgeSlide(TransInfo *t, float perc)
}
projectEdgeSlideData(t, 0);
-
- return 1;
}
static void applyEdgeSlide(TransInfo *t, const int UNUSED(mval[2]))
@@ -6390,6 +6441,8 @@ static bool createVertSlideVerts(TransInfo *t)
rv3d = ar ? ar->regiondata : NULL;
}
+ slide_origdata_init_flag(t, &sld->orig_data);
+
sld->is_proportional = true;
sld->curr_sv_index = 0;
sld->flipped_vtx = false;
@@ -6485,6 +6538,10 @@ static bool createVertSlideVerts(TransInfo *t)
sld->sv = sv_array;
sld->totsv = j;
+ bmesh_edit_begin(bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
+ slide_origdata_init_data(t, &sld->orig_data);
+ slide_origdata_create_date(t, &sld->orig_data, &sld->sv->v, sizeof(*sld->sv), sld->totsv);
+
sld->em = em;
sld->perc = 0.0f;
@@ -6499,6 +6556,53 @@ static bool createVertSlideVerts(TransInfo *t)
return true;
}
+void projectVertSlideData(TransInfo *t, bool is_final)
+{
+ VertSlideData *sld = t->customData;
+ SlideOrigData *sod = &sld->orig_data;
+ TransDataVertSlideVert *sv;
+ BMEditMesh *em = sld->em;
+ int i;
+
+ if (sod->use_origfaces == false) {
+ return;
+ }
+
+ for (i = 0, sv = sld->sv; i < sld->totsv; sv++, i++) {
+ BMIter fiter;
+ BMLoop *l;
+
+ BM_ITER_ELEM (l, &fiter, sv->v, BM_LOOPS_OF_VERT) {
+ BMFace *f_copy; /* the copy of 'f' */
+ BMFace *f_copy_flip; /* the copy of 'f' or detect if we need to flip to the shorter side. */
+
+ f_copy = BLI_ghash_lookup(sod->origfaces, l->f);
+
+ /* project onto copied projection face */
+ f_copy_flip = f_copy;
+
+ /* only loop data, no vertex data since that contains shape keys,
+ * and we do not want to mess up other shape keys */
+ BM_loop_interp_from_face(em->bm, l, f_copy_flip, false, false);
+
+ if (is_final) {
+ BM_loop_interp_multires(em->bm, l, f_copy_flip);
+ if (f_copy != f_copy_flip) {
+ BM_loop_interp_multires(em->bm, l, f_copy);
+ }
+ }
+
+ /* make sure face-attributes are correct (e.g. MTexPoly) */
+ BM_elem_attrs_copy(sod->bm_origfaces, em->bm, f_copy, l->f);
+ }
+ }
+}
+
+void freeVertSlideTempFaces(VertSlideData *sld)
+{
+ slide_origdata_free_date(&sld->orig_data);
+}
+
void freeVertSlideVerts(TransInfo *t)
{
VertSlideData *sld = t->customData;
@@ -6506,6 +6610,9 @@ void freeVertSlideVerts(TransInfo *t)
if (!sld)
return;
+ freeVertSlideTempFaces(sld);
+
+ bmesh_edit_end(sld->em->bm, BMO_OPTYPE_FLAG_UNTAN_MULTIRES);
if (sld->totsv > 0) {
TransDataVertSlideVert *sv = sld->sv;
@@ -6702,7 +6809,7 @@ static void drawVertSlide(const struct bContext *C, TransInfo *t)
}
}
-static int doVertSlide(TransInfo *t, float perc)
+static void doVertSlide(TransInfo *t, float perc)
{
VertSlideData *sld = t->customData;
TransDataVertSlideVert *svlist = sld->sv, *sv;
@@ -6742,7 +6849,7 @@ static int doVertSlide(TransInfo *t, float perc)
}
}
- return 1;
+ projectVertSlideData(t, false);
}
static void applyVertSlide(TransInfo *t, const int UNUSED(mval[2]))
@@ -7117,7 +7224,7 @@ static void initSeqSlide(TransInfo *t)
t->num.unit_type[1] = B_UNIT_NONE;
}
-static void headerSeqSlide(TransInfo *t, float val[2], char str[MAX_INFO_LEN])
+static void headerSeqSlide(TransInfo *t, const float val[2], char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
size_t ofs = 0;
@@ -7516,7 +7623,7 @@ static void initTimeSlide(TransInfo *t)
t->num.unit_type[0] = B_UNIT_NONE;
}
-static void headerTimeSlide(TransInfo *t, float sval, char str[MAX_INFO_LEN])
+static void headerTimeSlide(TransInfo *t, const float sval, char str[MAX_INFO_LEN])
{
char tvec[NUM_STR_REP_LEN * 3];
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 0d824be862e..2330ec6e79e 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -213,18 +213,23 @@ typedef struct TransDataEdgeSlideVert {
int loop_nr;
} TransDataEdgeSlideVert;
+
+/* store original data so we can correct UV's and similar when sliding */
+typedef struct SlideOrigData {
+ /* flag that is set when origfaces is initialized */
+ bool use_origfaces;
+ struct GHash *origfaces;
+ struct BMesh *bm_origfaces;
+} SlideOrigData;
+
typedef struct EdgeSlideData {
TransDataEdgeSlideVert *sv;
int totsv;
-
- struct GHash *origfaces;
int mval_start[2], mval_end[2];
struct BMEditMesh *em;
- /* flag that is set when origfaces is initialized */
- bool use_origfaces;
- struct BMesh *bm_origfaces;
+ SlideOrigData orig_data;
float perc;
@@ -251,6 +256,8 @@ typedef struct VertSlideData {
struct BMEditMesh *em;
+ SlideOrigData orig_data;
+
float perc;
bool is_proportional;
@@ -699,7 +706,9 @@ void freeEdgeSlideTempFaces(EdgeSlideData *sld);
void freeEdgeSlideVerts(TransInfo *t);
void projectEdgeSlideData(TransInfo *t, bool is_final);
+void freeVertSlideTempFaces(VertSlideData *sld);
void freeVertSlideVerts(TransInfo *t);
+void projectVertSlideData(TransInfo *t, bool is_final);
/* TODO. transform_queries.c */
diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c
index d8f17315c01..ccb81c7342b 100644
--- a/source/blender/editors/transform/transform_constraints.c
+++ b/source/blender/editors/transform/transform_constraints.c
@@ -208,7 +208,7 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3],
viewAxisCorrectCenter(t, t_con_center);
angle = fabsf(angle_v3v3(axis, t->viewinv[2]));
- if (angle > (float)M_PI / 2.0f) {
+ if (angle > (float)M_PI_2) {
angle = (float)M_PI - angle;
}
angle = RAD2DEGF(angle);
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index c1350b1f076..42f7087d4a7 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -5354,7 +5354,7 @@ void autokeyframe_pose_cb_func(bContext *C, Scene *scene, View3D *v3d, Object *o
/* only if bone name matches too...
* NOTE: this will do constraints too, but those are ok to do here too?
*/
- if (pchanName && strcmp(pchanName, pchan->name) == 0)
+ if (pchanName && STREQ(pchanName, pchan->name))
insert_keyframe(reports, id, act, ((fcu->grp) ? (fcu->grp->name) : (NULL)), fcu->rna_path, fcu->array_index, cfra, flag);
if (pchanName) MEM_freeN(pchanName);
@@ -5597,6 +5597,12 @@ void special_aftertrans_update(bContext *C, TransInfo *t)
* during cleanup - psy-fi */
freeEdgeSlideTempFaces(sld);
}
+ else if (t->mode == TFM_VERT_SLIDE) {
+ /* as above */
+ VertSlideData *sld = t->customData;
+ projectVertSlideData(t, true);
+ freeVertSlideTempFaces(sld);
+ }
if (t->obedit->type == OB_MESH) {
special_aftertrans_update__mesh(C, t);
@@ -7321,6 +7327,11 @@ static void createTransGPencil(bContext *C, TransInfo *t)
bGPDstroke *gps;
for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+
if (propedit) {
/* Proportional Editing... */
if (propedit_connected) {
@@ -7424,6 +7435,11 @@ static void createTransGPencil(bContext *C, TransInfo *t)
TransData *tail = td;
bool stroke_ok;
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+
/* What we need to include depends on proportional editing settings... */
if (propedit) {
if (propedit_connected) {
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index fcf789546e8..3000b3e00bc 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -1874,9 +1874,12 @@ void calculatePropRatio(TransInfo *t)
TransData *td = t->data;
int i;
float dist;
- short connected = t->flag & T_PROP_CONNECTED;
+ const bool connected = (t->flag & T_PROP_CONNECTED) != 0;
+
+ t->proptext[0] = '\0';
if (t->flag & T_PROP_EDIT) {
+ const char *pet_id = NULL;
for (i = 0; i < t->total; i++, td++) {
if (td->flag & TD_SELECTED) {
td->factor = 1.0f;
@@ -1937,6 +1940,9 @@ void calculatePropRatio(TransInfo *t)
case PROP_RANDOM:
td->factor = BLI_frand() * dist;
break;
+ case PROP_INVSQUARE:
+ td->factor = dist * (2.0f - dist);
+ break;
default:
td->factor = 1;
break;
@@ -1945,35 +1951,40 @@ void calculatePropRatio(TransInfo *t)
}
switch (t->prop_mode) {
case PROP_SHARP:
- strcpy(t->proptext, IFACE_("(Sharp)"));
+ pet_id = N_("(Sharp)");
break;
case PROP_SMOOTH:
- strcpy(t->proptext, IFACE_("(Smooth)"));
+ pet_id = N_("(Smooth)");
break;
case PROP_ROOT:
- strcpy(t->proptext, IFACE_("(Root)"));
+ pet_id = N_("(Root)");
break;
case PROP_LIN:
- strcpy(t->proptext, IFACE_("(Linear)"));
+ pet_id = N_("(Linear)");
break;
case PROP_CONST:
- strcpy(t->proptext, IFACE_("(Constant)"));
+ pet_id = N_("(Constant)");
break;
case PROP_SPHERE:
- strcpy(t->proptext, IFACE_("(Sphere)"));
+ pet_id = N_("(Sphere)");
break;
case PROP_RANDOM:
- strcpy(t->proptext, IFACE_("(Random)"));
+ pet_id = N_("(Random)");
+ break;
+ case PROP_INVSQUARE:
+ pet_id = N_("(InvSquare)");
break;
default:
- t->proptext[0] = '\0';
break;
}
+
+ if (pet_id) {
+ BLI_strncpy(t->proptext, IFACE_(pet_id), sizeof(t->proptext));
+ }
}
else {
for (i = 0; i < t->total; i++, td++) {
td->factor = 1.0;
}
- t->proptext[0] = '\0';
}
}
diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c
index f2869843dd5..38190d407ab 100644
--- a/source/blender/editors/transform/transform_manipulator.c
+++ b/source/blender/editors/transform/transform_manipulator.c
@@ -177,7 +177,7 @@ static void axis_angle_to_gimbal_axis(float gmat[3][3], const float axis[3], con
mul_qt_v3(quat, gmat[0]);
/* Y-axis */
- axis_angle_to_quat(quat, axis, M_PI / 2.0);
+ axis_angle_to_quat(quat, axis, M_PI_2);
copy_v3_v3(gmat[1], gmat[0]);
mul_qt_v3(quat, gmat[1]);
diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c
index 25dee50a192..1498e2894d4 100644
--- a/source/blender/editors/transform/transform_ops.c
+++ b/source/blender/editors/transform/transform_ops.c
@@ -868,7 +868,7 @@ static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
- Transform_Properties(ot, P_MIRROR | P_SNAP);
+ Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
}
static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c
index 32d4f2e5a15..438eb1f3864 100644
--- a/source/blender/editors/util/ed_util.c
+++ b/source/blender/editors/util/ed_util.c
@@ -231,7 +231,7 @@ void unpack_menu(bContext *C, const char *opname, const char *id_name, const cha
BLI_split_file_part(abs_name, fi, sizeof(fi));
BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi);
- if (strcmp(abs_name, local_name) != 0) {
+ if (!STREQ(abs_name, local_name)) {
switch (checkPackedFile(local_name, pf)) {
case PF_NOFILE:
BLI_snprintf(line, sizeof(line), IFACE_("Create %s"), local_name);
diff --git a/source/blender/editors/util/editmode_undo.c b/source/blender/editors/util/editmode_undo.c
index 2428ee21367..7f5edb5ea9e 100644
--- a/source/blender/editors/util/editmode_undo.c
+++ b/source/blender/editors/util/editmode_undo.c
@@ -206,7 +206,7 @@ static void undo_clean_stack(bContext *C)
/* for when objects are converted, renamed, or global undo changes pointers... */
if (uel->type == obedit->type) {
- if (strcmp(uel->id.name, obedit->id.name) == 0) {
+ if (STREQ(uel->id.name, obedit->id.name)) {
if (uel->validate_undo == NULL)
is_valid = true;
else if (uel->validate_undo(uel->undodata, editdata))
@@ -305,7 +305,7 @@ void undo_editmode_name(bContext *C, const char *undoname)
UndoElem *uel;
for (uel = undobase.last; uel; uel = uel->prev) {
- if (strcmp(undoname, uel->name) == 0)
+ if (STREQ(undoname, uel->name))
break;
}
if (uel && uel->prev) {
@@ -321,7 +321,7 @@ int undo_editmode_valid(const char *undoname)
UndoElem *uel;
for (uel = undobase.last; uel; uel = uel->prev) {
- if (strcmp(undoname, uel->name) == 0)
+ if (STREQ(undoname, uel->name))
break;
}
return uel != NULL;
diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c
index fac57490b44..ab882a388ad 100644
--- a/source/blender/editors/util/undo.c
+++ b/source/blender/editors/util/undo.c
@@ -580,7 +580,7 @@ static int undo_history_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_GEOM | ND_DATA, NULL);
}
else if (undosys == UNDOSYSTEM_IMAPAINT) {
- ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item );
+ ED_undo_paint_step_num(C, UNDO_PAINT_IMAGE, item);
}
else {
ED_viewport_render_kill_jobs(CTX_wm_manager(C), CTX_data_main(C), true);
diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c
index 569fe1c326d..00615f9bef7 100644
--- a/source/blender/editors/uvedit/uvedit_parametrizer.c
+++ b/source/blender/editors/uvedit/uvedit_parametrizer.c
@@ -2672,8 +2672,8 @@ static PBool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
}
for (i = 0; i < ninterior; i++) {
- sys->lambdaPlanar[i] += nlGetVariable(0, i);
- sys->lambdaLength[i] += nlGetVariable(0, ninterior + i);
+ sys->lambdaPlanar[i] += (float)nlGetVariable(0, i);
+ sys->lambdaLength[i] += (float)nlGetVariable(0, ninterior + i);
}
}
@@ -4561,7 +4561,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 += sqrtf(box->w * box->h);
+ area += (double)sqrtf(box->w * box->h);
}
if (margin > 0.0f) {
diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c
index c5931cf2943..4cb1f8943f9 100644
--- a/source/blender/editors/uvedit/uvedit_smart_stitch.c
+++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c
@@ -1601,7 +1601,7 @@ static int stitch_init(bContext *C, wmOperator *op)
BMFace *efa;
BMLoop *l;
BMIter iter, liter;
- GHashIterator *ghi;
+ GHashIterator gh_iter;
UvEdge *all_edges;
StitchState *state;
Scene *scene = CTX_data_scene(C);
@@ -1748,14 +1748,11 @@ static int stitch_init(bContext *C, wmOperator *op)
}
}
-
- ghi = BLI_ghashIterator_new(edge_hash);
total_edges = BLI_ghash_size(edge_hash);
state->edges = edges = MEM_mallocN(sizeof(*edges) * total_edges, "stitch_edges");
/* I assume any system will be able to at least allocate an iterator :p */
if (!edges) {
- BLI_ghashIterator_free(ghi);
state_delete(state);
return 0;
}
@@ -1763,12 +1760,12 @@ static int stitch_init(bContext *C, wmOperator *op)
state->total_separate_edges = total_edges;
/* fill the edges with data */
- for (i = 0, BLI_ghashIterator_init(ghi, edge_hash); !BLI_ghashIterator_done(ghi); BLI_ghashIterator_step(ghi)) {
- edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
+ i = 0;
+ GHASH_ITER (gh_iter, edge_hash) {
+ edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(&gh_iter));
}
/* cleanup temporary stuff */
- BLI_ghashIterator_free(ghi);
MEM_freeN(all_edges);
BLI_ghash_free(edge_hash, NULL, NULL);
diff --git a/source/blender/editors/uvedit/uvedit_unwrap_ops.c b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
index b5e27ab0cf6..793f84b05ec 100644
--- a/source/blender/editors/uvedit/uvedit_unwrap_ops.c
+++ b/source/blender/editors/uvedit/uvedit_unwrap_ops.c
@@ -1130,7 +1130,7 @@ void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
ParamHandle *handle;
const bool fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0;
- const bool correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) != 0;
+ const bool correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0;
bool use_subsurf;
modifier_unwrap_state(obedit, scene, &use_subsurf);
diff --git a/source/blender/freestyle/intern/application/Controller.cpp b/source/blender/freestyle/intern/application/Controller.cpp
index f8931d32f56..8d9b1a4fb52 100644
--- a/source/blender/freestyle/intern/application/Controller.cpp
+++ b/source/blender/freestyle/intern/application/Controller.cpp
@@ -295,7 +295,7 @@ int Controller::LoadMesh(Render *re, SceneRenderLayer *srl)
}
cam->setProjectionMatrix(proj);
_RootNode->AddChild(cam);
- _RootNode->AddChild(new NodeSceneRenderLayer(*srl));
+ _RootNode->AddChild(new NodeSceneRenderLayer(*re->scene, *srl));
sceneHashFunc.reset();
//blenderScene->accept(sceneHashFunc);
@@ -869,7 +869,7 @@ void Controller::DrawStrokes()
real d = _Chrono.stop();
if (G.debug & G_DEBUG_FREESTYLE) {
cout << "Strokes generation : " << d << endl;
- cout << "Stroke count : " << _Canvas->stroke_count << endl;
+ cout << "Stroke count : " << _Canvas->getStrokeCount() << endl;
}
resetModified();
DeleteViewMap();
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
index 29f3bfe0d94..70de246a8de 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp
@@ -654,6 +654,12 @@ int BlenderStrokeRenderer::GenerateScene()
{
GenerateStrokeMesh(*it, true);
}
+ return get_stroke_count();
+}
+
+// Return the number of strokes
+int BlenderStrokeRenderer::get_stroke_count() const
+{
return strokeGroups.size() + texturedStrokeGroups.size();
}
@@ -912,7 +918,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex)
BLI_assert(mesh->totedge == edge_index);
BLI_assert(mesh->totloop == loop_index);
BLI_assert(mesh->totcol == material_index);
- BKE_mesh_validate(mesh, true);
+ BKE_mesh_validate(mesh, true, true);
#endif
}
@@ -956,7 +962,8 @@ Render *BlenderStrokeRenderer::RenderScene(Render *re, bool render)
Render *freestyle_render = RE_NewRender(freestyle_scene->id.name);
- RE_RenderFreestyleStrokes(freestyle_render, freestyle_bmain, freestyle_scene, render);
+ RE_RenderFreestyleStrokes(freestyle_render, freestyle_bmain, freestyle_scene,
+ render && get_stroke_count() > 0);
return freestyle_render;
}
diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
index a381932e9e7..ec53efa14cd 100644
--- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
+++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.h
@@ -85,6 +85,7 @@ protected:
static const char *uvNames[];
+ int get_stroke_count() const;
float get_stroke_vertex_z(void) const;
unsigned int get_stroke_mesh_id(void) const;
bool test_triangle_visibility(StrokeVertexRep *svRep[3]) const;
@@ -96,7 +97,6 @@ protected:
#ifdef WITH_CXX_GUARDEDALLOC
MEM_CXX_CLASS_ALLOC_FUNCS("Freestyle:BlenderStrokeRenderer")
#endif
-
};
} /* namespace Freestyle */
diff --git a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
index cfadf80dcf6..32b4c5455a7 100644
--- a/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
+++ b/source/blender/freestyle/intern/blender_interface/FRS_freestyle.cpp
@@ -496,7 +496,7 @@ void FRS_composite_result(Render *re, SceneRenderLayer *srl, Render *freestyle_r
rl = render_get_active_layer( freestyle_render, freestyle_render->result );
if (!rl || rl->rectf == NULL) {
if (G.debug & G_DEBUG_FREESTYLE) {
- cout << "Cannot find Freestyle result image" << endl;
+ cout << "No Freestyle result image to composite" << endl;
}
return;
}
diff --git a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
index f4ead300d5e..487a473b7bd 100644
--- a/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
+++ b/source/blender/freestyle/intern/python/BPy_Freestyle.cpp
@@ -87,24 +87,24 @@ static PyObject *Freestyle_getCurrentScene(PyObject *self)
static int ramp_blend_type(const char *type)
{
- if (!strcmp(type, "MIX")) return MA_RAMP_BLEND;
- if (!strcmp(type, "ADD")) return MA_RAMP_ADD;
- if (!strcmp(type, "MULTIPLY")) return MA_RAMP_MULT;
- if (!strcmp(type, "SUBTRACT")) return MA_RAMP_SUB;
- if (!strcmp(type, "SCREEN")) return MA_RAMP_SCREEN;
- if (!strcmp(type, "DIVIDE")) return MA_RAMP_DIV;
- if (!strcmp(type, "DIFFERENCE")) return MA_RAMP_DIFF;
- if (!strcmp(type, "DARKEN")) return MA_RAMP_DARK;
- if (!strcmp(type, "LIGHTEN")) return MA_RAMP_LIGHT;
- if (!strcmp(type, "OVERLAY")) return MA_RAMP_OVERLAY;
- if (!strcmp(type, "DODGE")) return MA_RAMP_DODGE;
- if (!strcmp(type, "BURN")) return MA_RAMP_BURN;
- if (!strcmp(type, "HUE")) return MA_RAMP_HUE;
- if (!strcmp(type, "SATURATION")) return MA_RAMP_SAT;
- if (!strcmp(type, "VALUE")) return MA_RAMP_VAL;
- if (!strcmp(type, "COLOR")) return MA_RAMP_COLOR;
- if (!strcmp(type, "SOFT_LIGHT")) return MA_RAMP_SOFT;
- if (!strcmp(type, "LINEAR_LIGHT")) return MA_RAMP_LINEAR;
+ if (STREQ(type, "MIX")) return MA_RAMP_BLEND;
+ if (STREQ(type, "ADD")) return MA_RAMP_ADD;
+ if (STREQ(type, "MULTIPLY")) return MA_RAMP_MULT;
+ if (STREQ(type, "SUBTRACT")) return MA_RAMP_SUB;
+ if (STREQ(type, "SCREEN")) return MA_RAMP_SCREEN;
+ if (STREQ(type, "DIVIDE")) return MA_RAMP_DIV;
+ if (STREQ(type, "DIFFERENCE")) return MA_RAMP_DIFF;
+ if (STREQ(type, "DARKEN")) return MA_RAMP_DARK;
+ if (STREQ(type, "LIGHTEN")) return MA_RAMP_LIGHT;
+ if (STREQ(type, "OVERLAY")) return MA_RAMP_OVERLAY;
+ if (STREQ(type, "DODGE")) return MA_RAMP_DODGE;
+ if (STREQ(type, "BURN")) return MA_RAMP_BURN;
+ if (STREQ(type, "HUE")) return MA_RAMP_HUE;
+ if (STREQ(type, "SATURATION")) return MA_RAMP_SAT;
+ if (STREQ(type, "VALUE")) return MA_RAMP_VAL;
+ if (STREQ(type, "COLOR")) return MA_RAMP_COLOR;
+ if (STREQ(type, "SOFT_LIGHT")) return MA_RAMP_SOFT;
+ if (STREQ(type, "LINEAR_LIGHT")) return MA_RAMP_LINEAR;
return -1;
}
diff --git a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
index 6c6e821a1e4..d933d9f6ed7 100644
--- a/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
+++ b/source/blender/freestyle/intern/python/BPy_ViewShape.cpp
@@ -220,7 +220,6 @@ static PyObject *ViewShape_vertices_get(BPy_ViewShape *self, void *UNUSED(closur
static int ViewShape_vertices_set(BPy_ViewShape *self, PyObject *value, void *UNUSED(closure))
{
- PyObject *list = 0;
PyObject *item;
vector< ViewVertex *> v;
@@ -229,9 +228,9 @@ static int ViewShape_vertices_set(BPy_ViewShape *self, PyObject *value, void *UN
return -1;
}
- v.reserve(PyList_Size(list));
- for (unsigned int i = 0; i < PyList_Size(list); i++) {
- item = PyList_GET_ITEM(list, i);
+ v.reserve(PyList_GET_SIZE(value));
+ for (unsigned int i = 0; i < PyList_GET_SIZE(value); i++) {
+ item = PyList_GET_ITEM(value, i);
if (BPy_ViewVertex_Check(item)) {
v.push_back(((BPy_ViewVertex *)item)->vv);
}
@@ -264,7 +263,6 @@ static PyObject *ViewShape_edges_get(BPy_ViewShape *self, void *UNUSED(closure))
static int ViewShape_edges_set(BPy_ViewShape *self, PyObject *value, void *UNUSED(closure))
{
- PyObject *list = 0;
PyObject *item;
vector<ViewEdge *> v;
@@ -273,9 +271,9 @@ static int ViewShape_edges_set(BPy_ViewShape *self, PyObject *value, void *UNUSE
return -1;
}
- v.reserve(PyList_Size(list));
- for (int i = 0; i < PyList_Size(list); i++) {
- item = PyList_GET_ITEM(list, i);
+ v.reserve(PyList_GET_SIZE(value));
+ for (int i = 0; i < PyList_GET_SIZE(value); i++) {
+ item = PyList_GET_ITEM(value, i);
if (BPy_ViewEdge_Check(item)) {
v.push_back(((BPy_ViewEdge *)item)->ve);
}
diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
index 9329bd40c76..edc49eb8004 100644
--- a/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
+++ b/source/blender/freestyle/intern/python/Iterator/BPy_AdjacencyIterator.cpp
@@ -117,7 +117,7 @@ static PyObject *AdjacencyIterator_iternext(BPy_AdjacencyIterator *self)
self->at_start = false;
else {
self->a_it->increment();
- if (self->a_it->isEnd()){
+ if (self->a_it->isEnd()) {
PyErr_SetNone(PyExc_StopIteration);
return NULL;
}
diff --git a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
index 2fc08bb1175..4b079df5632 100644
--- a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
+++ b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h
@@ -29,7 +29,7 @@
#include "Node.h"
extern "C" {
-#include "DNA_scene_types.h" /* for SceneRenderLayer */
+#include "DNA_scene_types.h" /* for Scene and SceneRenderLayer */
}
using namespace std;
@@ -39,14 +39,24 @@ namespace Freestyle {
class NodeSceneRenderLayer : public Node
{
public:
- inline NodeSceneRenderLayer(SceneRenderLayer& srl) : Node(), _SceneRenderLayer(srl) {}
+ inline NodeSceneRenderLayer(Scene& scene, SceneRenderLayer& srl) : Node(), _Scene(scene), _SceneRenderLayer(srl) {}
virtual ~NodeSceneRenderLayer() {}
+ inline struct Scene& scene() const
+ {
+ return _Scene;
+ }
+
inline struct SceneRenderLayer& sceneRenderLayer() const
{
return _SceneRenderLayer;
}
+ inline void setSceneRenderLayer(Scene& scene)
+ {
+ _Scene = scene;
+ }
+
inline void setSceneRenderLayer(SceneRenderLayer& srl)
{
_SceneRenderLayer = srl;
@@ -56,6 +66,8 @@ public:
virtual void accept(SceneVisitor& v);
protected:
+
+ Scene& _Scene;
SceneRenderLayer& _SceneRenderLayer;
};
diff --git a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
index ee1d0c53b87..22538736fbf 100644
--- a/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
+++ b/source/blender/freestyle/intern/scene_graph/SceneHash.cpp
@@ -35,13 +35,18 @@ string SceneHash::toString()
return ss.str();
}
-void SceneHash::visitNodeSceneRenderLayer(NodeSceneRenderLayer& srl)
+void SceneHash::visitNodeSceneRenderLayer(NodeSceneRenderLayer& node)
{
- struct FreestyleConfig *config = &srl.sceneRenderLayer().freestyleConfig;
- adler32((unsigned char *)&config->flags, sizeof(int));
- adler32((unsigned char *)&config->crease_angle, sizeof(float));
- adler32((unsigned char *)&config->sphere_radius, sizeof(float));
- adler32((unsigned char *)&config->dkr_epsilon, sizeof(float));
+ struct RenderData *r = &node.scene().r;
+ adler32((unsigned char *)&r->xsch, sizeof(r->xsch)); // resolution_x
+ adler32((unsigned char *)&r->ysch, sizeof(r->ysch)); // resolution_y
+ adler32((unsigned char *)&r->size, sizeof(r->size)); // resolution_percentage
+
+ struct FreestyleConfig *config = &node.sceneRenderLayer().freestyleConfig;
+ adler32((unsigned char *)&config->flags, sizeof(config->flags));
+ adler32((unsigned char *)&config->crease_angle, sizeof(config->crease_angle));
+ adler32((unsigned char *)&config->sphere_radius, sizeof(config->sphere_radius));
+ adler32((unsigned char *)&config->dkr_epsilon, sizeof(config->dkr_epsilon));
}
void SceneHash::visitNodeCamera(NodeCamera& cam)
diff --git a/source/blender/freestyle/intern/stroke/Canvas.h b/source/blender/freestyle/intern/stroke/Canvas.h
index b56b5f92c14..5919344b6e0 100644
--- a/source/blender/freestyle/intern/stroke/Canvas.h
+++ b/source/blender/freestyle/intern/stroke/Canvas.h
@@ -95,6 +95,7 @@ protected:
static const char *_MapsPath;
SteerableViewMap *_steerableViewMap;
bool _basic;
+ int stroke_count;
public:
/* Builds the Canvas */
@@ -213,7 +214,10 @@ public:
return false;
}
- int stroke_count;
+ inline int getStrokeCount() const
+ {
+ return stroke_count;
+ }
/*! modifiers */
inline void setSelectedFEdge(FEdge *iFEdge)
diff --git a/source/blender/freestyle/intern/stroke/StrokeRep.cpp b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
index f7857107006..ab06e207331 100644
--- a/source/blender/freestyle/intern/stroke/StrokeRep.cpp
+++ b/source/blender/freestyle/intern/stroke/StrokeRep.cpp
@@ -425,7 +425,7 @@ void Strip::cleanUpSingularities (const vector<StrokeVertex*>& iStrokeVertices)
Vec2r avP(0.0, 0.0);
for (j = i - timeSinceSingu1; j <= i; j++)
avP = Vec2r(avP + _vertices[2 * j]->point2d());
- avP = Vec2r( 1.0 / float(timeSinceSingu1 + 1) * avP);
+ avP = Vec2r(1.0 / float(timeSinceSingu1 + 1) * avP);
for (j = i - timeSinceSingu1; j <= i; j++)
_vertices[2 * j]->setPoint2d(avP);
//_vertex[2 * j] = _vertex[2 * i];
diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h
index 09a5653b1ec..64ce936e64a 100644
--- a/source/blender/gpu/GPU_material.h
+++ b/source/blender/gpu/GPU_material.h
@@ -32,6 +32,7 @@
#ifndef __GPU_MATERIAL_H__
#define __GPU_MATERIAL_H__
+#include "DNA_customdata_types.h" /* for CustomDataType */
#include "DNA_listBase.h"
#include "BLI_sys_types.h" /* for bool */
@@ -68,6 +69,7 @@ typedef struct GPULamp GPULamp;
/* Functions to create GPU Materials nodes */
typedef enum GPUType {
+ /* The value indicates the number of elements in each type */
GPU_NONE = 0,
GPU_FLOAT = 1,
GPU_VEC2 = 2,
@@ -75,20 +77,22 @@ typedef enum GPUType {
GPU_VEC4 = 4,
GPU_MAT3 = 9,
GPU_MAT4 = 16,
+
GPU_TEX2D = 1002,
GPU_SHADOW2D = 1003,
GPU_ATTRIB = 3001
} GPUType;
typedef enum GPUBuiltin {
- GPU_VIEW_MATRIX = 1,
- GPU_OBJECT_MATRIX = 2,
- GPU_INVERSE_VIEW_MATRIX = 4,
- GPU_INVERSE_OBJECT_MATRIX = 8,
- GPU_VIEW_POSITION = 16,
- GPU_VIEW_NORMAL = 32,
- GPU_OBCOLOR = 64,
- GPU_AUTO_BUMPSCALE = 128,
+ GPU_VIEW_MATRIX = (1 << 0),
+ GPU_OBJECT_MATRIX = (1 << 1),
+ GPU_INVERSE_VIEW_MATRIX = (1 << 2),
+ GPU_INVERSE_OBJECT_MATRIX = (1 << 3),
+ GPU_VIEW_POSITION = (1 << 4),
+ GPU_VIEW_NORMAL = (1 << 5),
+ GPU_OBCOLOR = (1 << 6),
+ GPU_AUTO_BUMPSCALE = (1 << 7),
+ GPU_CAMERA_TEXCO_FACTORS = (1 << 8),
} GPUBuiltin;
typedef enum GPUOpenGLBuiltin {
@@ -98,7 +102,7 @@ typedef enum GPUOpenGLBuiltin {
typedef enum GPUMatType {
GPU_MATERIAL_TYPE_MESH = 1,
- GPU_MATERIAL_TYPE_WORLD = 2,
+ GPU_MATERIAL_TYPE_WORLD = 2,
} GPUMatType;
@@ -120,13 +124,40 @@ typedef struct GPUNodeStack {
short sockettype;
} GPUNodeStack;
-GPUNodeLink *GPU_attribute(int type, const char *name);
+typedef enum GPUDynamicType {
+ GPU_DYNAMIC_NONE = 0,
+ GPU_DYNAMIC_OBJECT_VIEWMAT = 1,
+ GPU_DYNAMIC_OBJECT_MAT = 2,
+ GPU_DYNAMIC_OBJECT_VIEWIMAT = 3,
+ GPU_DYNAMIC_OBJECT_IMAT = 4,
+ GPU_DYNAMIC_OBJECT_COLOR = 5,
+ GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 15,
+
+ GPU_DYNAMIC_LAMP_FIRST = 6,
+ GPU_DYNAMIC_LAMP_DYNVEC = 6,
+ GPU_DYNAMIC_LAMP_DYNCO = 7,
+ GPU_DYNAMIC_LAMP_DYNIMAT = 8,
+ GPU_DYNAMIC_LAMP_DYNPERSMAT = 9,
+ GPU_DYNAMIC_LAMP_DYNENERGY = 10,
+ GPU_DYNAMIC_LAMP_DYNCOL = 11,
+ GPU_DYNAMIC_LAMP_LAST = 11,
+ GPU_DYNAMIC_SAMPLER_2DBUFFER = 12,
+ GPU_DYNAMIC_SAMPLER_2DIMAGE = 13,
+ GPU_DYNAMIC_SAMPLER_2DSHADOW = 14,
+ GPU_DYNAMIC_LAMP_DISTANCE = 16,
+ GPU_DYNAMIC_LAMP_ATT1 = 17,
+ GPU_DYNAMIC_LAMP_ATT2 = 18,
+ GPU_DYNAMIC_LAMP_SPOTSIZE = 19,
+ GPU_DYNAMIC_LAMP_SPOTBLEND = 20,
+} GPUDynamicType;
+
+GPUNodeLink *GPU_attribute(CustomDataType type, const char *name);
GPUNodeLink *GPU_uniform(float *num);
-GPUNodeLink *GPU_dynamic_uniform(float *num, int dynamictype, void *data);
+GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data);
GPUNodeLink *GPU_image(struct Image *ima, struct ImageUser *iuser, bool is_data);
GPUNodeLink *GPU_image_preview(struct PreviewImage *prv);
GPUNodeLink *GPU_texture(int size, float *pixels);
-GPUNodeLink *GPU_dynamic_texture(struct GPUTexture *tex, int dynamictype, void *data);
+GPUNodeLink *GPU_dynamic_texture(struct GPUTexture *tex, GPUDynamicType dynamictype, void *data);
GPUNodeLink *GPU_builtin(GPUBuiltin builtin);
GPUNodeLink *GPU_opengl_builtin(GPUOpenGLBuiltin builtin);
@@ -147,7 +178,7 @@ void GPU_material_free(struct ListBase *gpumaterial);
void GPU_materials_free(void);
bool GPU_lamp_override_visible(GPULamp *lamp, struct SceneRenderLayer *srl, struct Material *ma);
-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(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float cameraborder[4], bool scenelock);
void GPU_material_bind_uniforms(GPUMaterial *material, float obmat[4][4], float obcol[4], float autobumpscale);
void GPU_material_unbind(GPUMaterial *material);
int GPU_material_bound(GPUMaterial *material);
@@ -180,33 +211,6 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr);
/* Export GLSL shader */
-typedef enum GPUDynamicType {
- GPU_DYNAMIC_NONE = 0,
- GPU_DYNAMIC_OBJECT_VIEWMAT = 1,
- GPU_DYNAMIC_OBJECT_MAT = 2,
- GPU_DYNAMIC_OBJECT_VIEWIMAT = 3,
- GPU_DYNAMIC_OBJECT_IMAT = 4,
- GPU_DYNAMIC_OBJECT_COLOR = 5,
- GPU_DYNAMIC_OBJECT_AUTOBUMPSCALE = 15,
-
- GPU_DYNAMIC_LAMP_FIRST = 6,
- GPU_DYNAMIC_LAMP_DYNVEC = 6,
- GPU_DYNAMIC_LAMP_DYNCO = 7,
- GPU_DYNAMIC_LAMP_DYNIMAT = 8,
- GPU_DYNAMIC_LAMP_DYNPERSMAT = 9,
- GPU_DYNAMIC_LAMP_DYNENERGY = 10,
- GPU_DYNAMIC_LAMP_DYNCOL = 11,
- GPU_DYNAMIC_LAMP_LAST = 11,
- GPU_DYNAMIC_SAMPLER_2DBUFFER = 12,
- GPU_DYNAMIC_SAMPLER_2DIMAGE = 13,
- GPU_DYNAMIC_SAMPLER_2DSHADOW = 14,
- GPU_DYNAMIC_LAMP_DISTANCE = 16,
- GPU_DYNAMIC_LAMP_ATT1 = 17,
- GPU_DYNAMIC_LAMP_ATT2 = 18,
- GPU_DYNAMIC_LAMP_SPOTSIZE = 19,
- GPU_DYNAMIC_LAMP_SPOTBLEND = 20,
-} GPUDynamicType;
-
typedef enum GPUDataType {
GPU_DATA_NONE = 0,
GPU_DATA_1I = 1, // 1 integer
@@ -267,7 +271,7 @@ void GPU_lamp_update_colors(GPULamp *lamp, float r, float g, float b, float ener
void GPU_lamp_update_distance(GPULamp *lamp, float distance, float att1, float att2);
void GPU_lamp_update_spot(GPULamp *lamp, float spotsize, float spotblend);
int GPU_lamp_shadow_layer(GPULamp *lamp);
-GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow);
+GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow, GPUNodeLink **energy);
#ifdef __cplusplus
}
diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c
index f0ef55ae673..d1102b03e9a 100644
--- a/source/blender/gpu/intern/gpu_buffers.c
+++ b/source/blender/gpu/intern/gpu_buffers.c
@@ -187,8 +187,10 @@ static void gpu_buffer_pool_free_unused(GPUBufferPool *pool)
while (pool->totbuf)
gpu_buffer_pool_delete_last(pool);
- glDeleteBuffersARB(pool->totpbvhbufids, pool->pbvhbufids);
- pool->totpbvhbufids = 0;
+ if (pool->totpbvhbufids > 0) {
+ glDeleteBuffersARB(pool->totpbvhbufids, pool->pbvhbufids);
+ pool->totpbvhbufids = 0;
+ }
BLI_mutex_unlock(&buffer_mutex);
}
diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c
index 1f9efdcbefd..97064f43f5d 100644
--- a/source/blender/gpu/intern/gpu_codegen.c
+++ b/source/blender/gpu/intern/gpu_codegen.c
@@ -62,14 +62,32 @@ extern char datatoc_gpu_shader_vertex_world_glsl[];
static char *glsl_material_library = NULL;
-/* structs and defines */
-
+/* type definitions and constants */
+
+enum {
+ MAX_FUNCTION_NAME = 64
+};
+enum {
+ MAX_PARAMETER = 32
+};
+
+typedef enum {
+ FUNCTION_QUAL_IN,
+ FUNCTION_QUAL_OUT,
+ FUNCTION_QUAL_INOUT
+} GPUFunctionQual;
+
+typedef struct GPUFunction {
+ char name[MAX_FUNCTION_NAME];
+ GPUType paramtype[MAX_PARAMETER];
+ GPUFunctionQual paramqual[MAX_PARAMETER];
+ int totparam;
+} GPUFunction;
+
+/* Indices match the GPUType enum */
static const char *GPU_DATATYPE_STR[17] = {"", "float", "vec2", "vec3", "vec4",
NULL, NULL, NULL, NULL, "mat3", NULL, NULL, NULL, NULL, NULL, NULL, "mat4"};
-#define LINK_IMAGE_BLENDER 1
-#define LINK_IMAGE_PREVIEW 2
-
/* GLSL code parsing for finding function definitions.
* These are stored in a hash for lookup when creating a material. */
@@ -126,7 +144,9 @@ static char *gpu_str_skip_token(char *str, char *token, int max)
static void gpu_parse_functions_string(GHash *hash, char *code)
{
GPUFunction *function;
- int i, type, qual;
+ GPUType type;
+ GPUFunctionQual qual;
+ int i;
while ((code = strstr(code, "void "))) {
function = MEM_callocN(sizeof(GPUFunction), "GPUFunction");
@@ -146,7 +166,7 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
code = gpu_str_skip_token(code, NULL, 0);
/* test for type */
- type= 0;
+ type= GPU_NONE;
for (i=1; i<=16; i++) {
if (GPU_DATATYPE_STR[i] && gpu_str_prefix(code, GPU_DATATYPE_STR[i])) {
type= i;
@@ -160,7 +180,7 @@ static void gpu_parse_functions_string(GHash *hash, char *code)
type= GPU_TEX2D;
if (type) {
- /* add paramater */
+ /* add parameter */
code = gpu_str_skip_token(code, NULL, 0);
code = gpu_str_skip_token(code, NULL, 0);
function->paramqual[function->totparam]= qual;
@@ -231,7 +251,7 @@ static char *gpu_generate_function_prototyps(GHash *hash)
}
#endif
-GPUFunction *GPU_lookup_function(const char *name)
+static GPUFunction *gpu_lookup_function(const char *name)
{
if (!FUNCTION_HASH) {
FUNCTION_HASH = BLI_ghash_str_new("GPU_lookup_function gh");
@@ -320,7 +340,7 @@ static void codegen_convert_datatype(DynStr *ds, int from, int to, const char *t
}
}
-static void codegen_print_datatype(DynStr *ds, int type, float *data)
+static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data)
{
int i;
@@ -363,10 +383,28 @@ const char *GPU_builtin_name(GPUBuiltin builtin)
return "unfobcolor";
else if (builtin == GPU_AUTO_BUMPSCALE)
return "unfobautobumpscale";
+ else if (builtin == GPU_CAMERA_TEXCO_FACTORS)
+ return "unfcameratexfactors";
else
return "";
}
+/* assign only one texid per buffer to avoid sampling the same texture twice */
+static void codegen_set_texid(GHash *bindhash, GPUInput *input, int *texid, void *key)
+{
+ if (BLI_ghash_haskey(bindhash, key)) {
+ /* Reuse existing texid */
+ input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, key));
+ }
+ else {
+ /* Allocate new texid */
+ input->texid = *texid;
+ (*texid)++;
+ input->bindtex = true;
+ BLI_ghash_insert(bindhash, key, SET_INT_IN_POINTER(input->texid));
+ }
+}
+
static void codegen_set_unique_ids(ListBase *nodes)
{
GHash *bindhash, *definehash;
@@ -382,68 +420,43 @@ static void codegen_set_unique_ids(ListBase *nodes)
for (input=node->inputs.first; input; input=input->next) {
/* set id for unique names of uniform variables */
input->id = id++;
- input->bindtex = 0;
- input->definetex = 0;
+ input->bindtex = false;
+ input->definetex = false;
/* set texid used for settings texture slot with multitexture */
if (codegen_input_has_texture(input) &&
((input->source == GPU_SOURCE_TEX) || (input->source == GPU_SOURCE_TEX_PIXEL)))
{
+ /* assign only one texid per buffer to avoid sampling
+ * the same texture twice */
if (input->link) {
- /* input is texture from buffer, assign only one texid per
- * buffer to avoid sampling the same texture twice */
- if (!BLI_ghash_haskey(bindhash, input->link)) {
- input->texid = texid++;
- input->bindtex = 1;
- BLI_ghash_insert(bindhash, input->link, SET_INT_IN_POINTER(input->texid));
- }
- else
- input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->link));
+ /* input is texture from buffer */
+ codegen_set_texid(bindhash, input, &texid, input->link);
}
else if (input->ima) {
- /* input is texture from image, assign only one texid per
- * buffer to avoid sampling the same texture twice */
- if (!BLI_ghash_haskey(bindhash, input->ima)) {
- input->texid = texid++;
- input->bindtex = 1;
- BLI_ghash_insert(bindhash, input->ima, SET_INT_IN_POINTER(input->texid));
- }
- else
- input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->ima));
+ /* input is texture from image */
+ codegen_set_texid(bindhash, input, &texid, input->ima);
}
else if (input->prv) {
- /* input is texture from preview render, assign only one texid per
- * buffer to avoid sampling the same texture twice */
- if (!BLI_ghash_haskey(bindhash, input->prv)) {
- input->texid = texid++;
- input->bindtex = 1;
- BLI_ghash_insert(bindhash, input->prv, SET_INT_IN_POINTER(input->texid));
- }
- else
- input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->prv));
+ /* input is texture from preview render */
+ codegen_set_texid(bindhash, input, &texid, input->prv);
}
- else {
- if (!BLI_ghash_haskey(bindhash, input->tex)) {
- /* input is user created texture, check tex pointer */
- input->texid = texid++;
- input->bindtex = 1;
- BLI_ghash_insert(bindhash, input->tex, SET_INT_IN_POINTER(input->texid));
- }
- else
- input->texid = GET_INT_FROM_POINTER(BLI_ghash_lookup(bindhash, input->tex));
+ else if (input->tex) {
+ /* input is user created texture, check tex pointer */
+ codegen_set_texid(bindhash, input, &texid, input->tex);
}
/* make sure this pixel is defined exactly once */
if (input->source == GPU_SOURCE_TEX_PIXEL) {
if (input->ima) {
if (!BLI_ghash_haskey(definehash, input->ima)) {
- input->definetex = 1;
+ input->definetex = true;
BLI_ghash_insert(definehash, input->ima, SET_INT_IN_POINTER(input->texid));
}
}
else {
if (!BLI_ghash_haskey(definehash, input->link)) {
- input->definetex = 1;
+ input->definetex = true;
BLI_ghash_insert(definehash, input->link, SET_INT_IN_POINTER(input->texid));
}
}
@@ -604,7 +617,7 @@ static void codegen_call_functions(DynStr *ds, ListBase *nodes, GPUOutput *final
BLI_dynstr_append(ds, ";\n");
}
-static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, const char *UNUSED(name))
+static char *code_generate_fragment(ListBase *nodes, GPUOutput *output)
{
DynStr *ds = BLI_dynstr_new();
char *code;
@@ -638,7 +651,7 @@ static char *code_generate_fragment(ListBase *nodes, GPUOutput *output, const ch
return code;
}
-static char *code_generate_vertex(ListBase *nodes, int type)
+static char *code_generate_vertex(ListBase *nodes, const GPUMatType type)
{
DynStr *ds = BLI_dynstr_new();
GPUNode *node;
@@ -738,7 +751,7 @@ GPUShader *GPU_pass_shader(GPUPass *pass)
return pass->shader;
}
-static void GPU_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
+static void gpu_nodes_extract_dynamic_inputs(GPUPass *pass, ListBase *nodes)
{
GPUShader *shader = pass->shader;
GPUNode *node;
@@ -860,16 +873,16 @@ void GPU_pass_unbind(GPUPass *pass)
/* Node Link Functions */
-static GPUNodeLink *GPU_node_link_create(int type)
+static GPUNodeLink *GPU_node_link_create(void)
{
GPUNodeLink *link = MEM_callocN(sizeof(GPUNodeLink), "GPUNodeLink");
- link->type = type;
+ link->type = GPU_NONE;
link->users++;
return link;
}
-static void GPU_node_link_free(GPUNodeLink *link)
+static void gpu_node_link_free(GPUNodeLink *link)
{
link->users--;
@@ -894,12 +907,7 @@ static GPUNode *GPU_node_begin(const char *name)
return node;
}
-static void GPU_node_end(GPUNode *UNUSED(node))
-{
- /* empty */
-}
-
-static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type)
+static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const GPUType type)
{
GPUInput *input;
GPUNode *outnode;
@@ -909,7 +917,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type)
outnode = link->output->node;
name = outnode->name;
- if (strcmp(name, "set_value")==0 || strcmp(name, "set_rgb")==0) {
+ if (STREQ(name, "set_value") || STREQ(name, "set_rgb")) {
input = MEM_dupallocN(outnode->inputs.first);
input->type = type;
if (input->link)
@@ -953,7 +961,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type)
input->tex = link->dynamictex;
input->textarget = GL_TEXTURE_2D;
input->textype = type;
- input->dynamictex = 1;
+ input->dynamictex = true;
input->dynamicdata = link->ptr2;
MEM_freeN(link);
}
@@ -975,7 +983,7 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, int type)
input->type = GPU_VEC4;
input->source = GPU_SOURCE_TEX;
- if (link->image == LINK_IMAGE_PREVIEW)
+ if (link->image == GPU_NODE_LINK_IMAGE_PREVIEW)
input->prv = link->ptr1;
else {
input->ima = link->ptr1;
@@ -1020,13 +1028,13 @@ static void gpu_node_input_socket(GPUNode *node, GPUNodeStack *sock)
gpu_node_input_link(node, sock->link, sock->type);
}
else {
- link = GPU_node_link_create(0);
+ link = GPU_node_link_create();
link->ptr1 = sock->vec;
gpu_node_input_link(node, link, sock->type);
}
}
-static void GPU_node_output(GPUNode *node, int type, const char *UNUSED(name), GPUNodeLink **link)
+static void gpu_node_output(GPUNode *node, const GPUType type, GPUNodeLink **link)
{
GPUOutput *output = MEM_callocN(sizeof(GPUOutput), "GPUOutput");
@@ -1034,7 +1042,8 @@ static void GPU_node_output(GPUNode *node, int type, const char *UNUSED(name), G
output->node = node;
if (link) {
- *link = output->link = GPU_node_link_create(type);
+ *link = output->link = GPU_node_link_create();
+ output->link->type = type;
output->link->output = output;
/* note: the caller owns the reference to the linkfer, GPUOutput
@@ -1045,13 +1054,13 @@ static void GPU_node_output(GPUNode *node, int type, const char *UNUSED(name), G
BLI_addtail(&node->outputs, output);
}
-static void GPU_inputs_free(ListBase *inputs)
+static void gpu_inputs_free(ListBase *inputs)
{
GPUInput *input;
for (input=inputs->first; input; input=input->next) {
if (input->link)
- GPU_node_link_free(input->link);
+ gpu_node_link_free(input->link);
else if (input->tex && !input->dynamictex)
GPU_texture_free(input->tex);
}
@@ -1059,28 +1068,28 @@ static void GPU_inputs_free(ListBase *inputs)
BLI_freelistN(inputs);
}
-static void GPU_node_free(GPUNode *node)
+static void gpu_node_free(GPUNode *node)
{
GPUOutput *output;
- GPU_inputs_free(&node->inputs);
+ gpu_inputs_free(&node->inputs);
for (output=node->outputs.first; output; output=output->next)
if (output->link) {
output->link->output = NULL;
- GPU_node_link_free(output->link);
+ gpu_node_link_free(output->link);
}
BLI_freelistN(&node->outputs);
MEM_freeN(node);
}
-static void GPU_nodes_free(ListBase *nodes)
+static void gpu_nodes_free(ListBase *nodes)
{
GPUNode *node;
while ((node = BLI_pophead(nodes))) {
- GPU_node_free(node);
+ gpu_node_free(node);
}
}
@@ -1102,7 +1111,7 @@ static void gpu_nodes_get_vertex_attributes(ListBase *nodes, GPUVertexAttribs *a
if (input->source == GPU_SOURCE_ATTRIB) {
for (a=0; a<attribs->totlayer; a++) {
if (attribs->layer[a].type == input->attribtype &&
- strcmp(attribs->layer[a].name, input->attribname) == 0)
+ STREQ(attribs->layer[a].name, input->attribname))
{
break;
}
@@ -1142,9 +1151,9 @@ static void gpu_nodes_get_builtin_flag(ListBase *nodes, int *builtin)
/* varargs linking */
-GPUNodeLink *GPU_attribute(int type, const char *name)
+GPUNodeLink *GPU_attribute(const CustomDataType type, const char *name)
{
- GPUNodeLink *link = GPU_node_link_create(0);
+ GPUNodeLink *link = GPU_node_link_create();
link->attribtype= type;
link->attribname= name;
@@ -1154,7 +1163,7 @@ GPUNodeLink *GPU_attribute(int type, const char *name)
GPUNodeLink *GPU_uniform(float *num)
{
- GPUNodeLink *link = GPU_node_link_create(0);
+ GPUNodeLink *link = GPU_node_link_create();
link->ptr1= num;
link->ptr2= NULL;
@@ -1162,13 +1171,13 @@ GPUNodeLink *GPU_uniform(float *num)
return link;
}
-GPUNodeLink *GPU_dynamic_uniform(float *num, int dynamictype, void *data)
+GPUNodeLink *GPU_dynamic_uniform(float *num, GPUDynamicType dynamictype, void *data)
{
- GPUNodeLink *link = GPU_node_link_create(0);
+ GPUNodeLink *link = GPU_node_link_create();
link->ptr1= num;
link->ptr2= data;
- link->dynamic= 1;
+ link->dynamic= true;
link->dynamictype = dynamictype;
@@ -1177,9 +1186,9 @@ GPUNodeLink *GPU_dynamic_uniform(float *num, int dynamictype, void *data)
GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data)
{
- GPUNodeLink *link = GPU_node_link_create(0);
+ GPUNodeLink *link = GPU_node_link_create();
- link->image = LINK_IMAGE_BLENDER;
+ link->image = GPU_NODE_LINK_IMAGE_BLENDER;
link->ptr1 = ima;
link->ptr2 = iuser;
link->image_isdata = is_data;
@@ -1189,9 +1198,9 @@ GPUNodeLink *GPU_image(Image *ima, ImageUser *iuser, bool is_data)
GPUNodeLink *GPU_image_preview(PreviewImage *prv)
{
- GPUNodeLink *link = GPU_node_link_create(0);
+ GPUNodeLink *link = GPU_node_link_create();
- link->image= LINK_IMAGE_PREVIEW;
+ link->image= GPU_NODE_LINK_IMAGE_PREVIEW;
link->ptr1= prv;
return link;
@@ -1200,20 +1209,20 @@ GPUNodeLink *GPU_image_preview(PreviewImage *prv)
GPUNodeLink *GPU_texture(int size, float *pixels)
{
- GPUNodeLink *link = GPU_node_link_create(0);
+ GPUNodeLink *link = GPU_node_link_create();
- link->texture = 1;
+ link->texture = true;
link->texturesize = size;
link->ptr1= pixels;
return link;
}
-GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, int dynamictype, void *data)
+GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, GPUDynamicType dynamictype, void *data)
{
- GPUNodeLink *link = GPU_node_link_create(0);
+ GPUNodeLink *link = GPU_node_link_create();
- link->dynamic = 1;
+ link->dynamic = true;
link->dynamictex = tex;
link->dynamictype = dynamictype;
link->ptr2 = data;
@@ -1223,7 +1232,7 @@ GPUNodeLink *GPU_dynamic_texture(GPUTexture *tex, int dynamictype, void *data)
GPUNodeLink *GPU_builtin(GPUBuiltin builtin)
{
- GPUNodeLink *link = GPU_node_link_create(0);
+ GPUNodeLink *link = GPU_node_link_create();
link->builtin= builtin;
@@ -1232,7 +1241,7 @@ GPUNodeLink *GPU_builtin(GPUBuiltin builtin)
GPUNodeLink *GPU_opengl_builtin(GPUOpenGLBuiltin builtin)
{
- GPUNodeLink *link = GPU_node_link_create(0);
+ GPUNodeLink *link = GPU_node_link_create();
link->oglbuiltin = builtin;
@@ -1247,7 +1256,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
va_list params;
int i;
- function = GPU_lookup_function(name);
+ function = gpu_lookup_function(name);
if (!function) {
fprintf(stderr, "GPU failed to find function %s\n", name);
return 0;
@@ -1259,7 +1268,7 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
for (i=0; i<function->totparam; i++) {
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
linkptr= va_arg(params, GPUNodeLink**);
- GPU_node_output(node, function->paramtype[i], "", linkptr);
+ gpu_node_output(node, function->paramtype[i], linkptr);
}
else {
link= va_arg(params, GPUNodeLink*);
@@ -1268,8 +1277,6 @@ bool GPU_link(GPUMaterial *mat, const char *name, ...)
}
va_end(params);
- GPU_node_end(node);
-
gpu_material_add_node(mat, node);
return 1;
@@ -1283,7 +1290,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
va_list params;
int i, totin, totout;
- function = GPU_lookup_function(name);
+ function = gpu_lookup_function(name);
if (!function) {
fprintf(stderr, "GPU failed to find function %s\n", name);
return 0;
@@ -1302,7 +1309,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
if (out) {
for (i = 0; out[i].type != GPU_NONE; i++) {
- GPU_node_output(node, out[i].type, out[i].name, &out[i].link);
+ gpu_node_output(node, out[i].type, &out[i].link);
totout++;
}
}
@@ -1312,7 +1319,7 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
if (function->paramqual[i] != FUNCTION_QUAL_IN) {
if (totout == 0) {
linkptr= va_arg(params, GPUNodeLink**);
- GPU_node_output(node, function->paramtype[i], "", linkptr);
+ gpu_node_output(node, function->paramtype[i], linkptr);
}
else
totout--;
@@ -1331,8 +1338,6 @@ bool GPU_stack_link(GPUMaterial *mat, const char *name, GPUNodeStack *in, GPUNod
}
va_end(params);
- GPU_node_end(node);
-
gpu_material_add_node(mat, node);
return 1;
@@ -1348,7 +1353,7 @@ int GPU_link_changed(GPUNodeLink *link)
node = link->output->node;
name = node->name;
- if (strcmp(name, "set_value")==0 || strcmp(name, "set_rgb")==0) {
+ if (STREQ(name, "set_value") || STREQ(name, "set_rgb")) {
input = node->inputs.first;
return (input->link != NULL);
}
@@ -1373,7 +1378,7 @@ static void gpu_nodes_tag(GPUNodeLink *link)
if (node->tag)
return;
- node->tag= 1;
+ node->tag = true;
for (input=node->inputs.first; input; input=input->next)
if (input->link)
gpu_nodes_tag(input->link);
@@ -1384,7 +1389,7 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
GPUNode *node, *next;
for (node=nodes->first; node; node=node->next)
- node->tag= 0;
+ node->tag = false;
gpu_nodes_tag(outlink);
@@ -1393,12 +1398,14 @@ static void gpu_nodes_prune(ListBase *nodes, GPUNodeLink *outlink)
if (!node->tag) {
BLI_remlink(nodes, node);
- GPU_node_free(node);
+ gpu_node_free(node);
}
}
}
-GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttribs *attribs, int *builtins, int type, const char *name)
+GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink,
+ GPUVertexAttribs *attribs, int *builtins,
+ const GPUMatType type, const char *UNUSED(name))
{
GPUShader *shader;
GPUPass *pass;
@@ -1416,7 +1423,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri
gpu_nodes_get_builtin_flag(nodes, builtins);
/* generate code and compile with opengl */
- fragmentcode = code_generate_fragment(nodes, outlink->output, name);
+ fragmentcode = code_generate_fragment(nodes, outlink->output);
vertexcode = code_generate_vertex(nodes, type);
shader = GPU_shader_create(vertexcode, fragmentcode, glsl_material_library, NULL);
@@ -1428,7 +1435,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri
MEM_freeN(vertexcode);
memset(attribs, 0, sizeof(*attribs));
memset(builtins, 0, sizeof(*builtins));
- GPU_nodes_free(nodes);
+ gpu_nodes_free(nodes);
return NULL;
}
@@ -1442,8 +1449,8 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri
pass->libcode = glsl_material_library;
/* extract dynamic inputs and throw away nodes */
- GPU_nodes_extract_dynamic_inputs(pass, nodes);
- GPU_nodes_free(nodes);
+ gpu_nodes_extract_dynamic_inputs(pass, nodes);
+ gpu_nodes_free(nodes);
return pass;
}
@@ -1451,7 +1458,7 @@ GPUPass *GPU_generate_pass(ListBase *nodes, GPUNodeLink *outlink, GPUVertexAttri
void GPU_pass_free(GPUPass *pass)
{
GPU_shader_free(pass->shader);
- GPU_inputs_free(&pass->inputs);
+ gpu_inputs_free(&pass->inputs);
if (pass->fragmentcode)
MEM_freeN(pass->fragmentcode);
if (pass->vertexcode)
diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h
index a0698235db6..a6da5e018fd 100644
--- a/source/blender/gpu/intern/gpu_codegen.h
+++ b/source/blender/gpu/intern/gpu_codegen.h
@@ -33,6 +33,7 @@
#ifndef __GPU_CODEGEN_H__
#define __GPU_CODEGEN_H__
+#include "DNA_customdata_types.h"
#include "DNA_listBase.h"
#include "GPU_material.h"
#include "GPU_glew.h"
@@ -45,22 +46,6 @@ struct GPUVertexAttribs;
struct GPUFrameBuffer;
struct PreviewImage;
-#define MAX_FUNCTION_NAME 64
-#define MAX_PARAMETER 32
-
-#define FUNCTION_QUAL_IN 0
-#define FUNCTION_QUAL_OUT 1
-#define FUNCTION_QUAL_INOUT 2
-
-typedef struct GPUFunction {
- char name[MAX_FUNCTION_NAME];
- int paramtype[MAX_PARAMETER];
- int paramqual[MAX_PARAMETER];
- int totparam;
-} GPUFunction;
-
-GPUFunction *GPU_lookup_function(const char *name);
-
/* Pass Generation
* - Takes a list of nodes and a desired output, and makes a pass. This
* will take ownership of the nodes and free them early if unused or
@@ -76,11 +61,19 @@ typedef enum GPUDataSource {
GPU_SOURCE_ATTRIB
} GPUDataSource;
+typedef enum {
+ GPU_NODE_LINK_IMAGE_NONE = 0,
+ GPU_NODE_LINK_IMAGE_BLENDER = 1,
+ GPU_NODE_LINK_IMAGE_PREVIEW = 2
+} GPUNodeLinkImage;
+
struct GPUNode {
struct GPUNode *next, *prev;
const char *name;
- int tag;
+
+ /* Internal flag to mark nodes during pruning */
+ bool tag;
ListBase inputs;
ListBase outputs;
@@ -89,21 +82,23 @@ struct GPUNode {
struct GPUNodeLink {
GPUNodeStack *socket;
- int attribtype;
+ CustomDataType attribtype;
const char *attribname;
- int image;
- int image_isdata;
+ GPUNodeLinkImage image;
+ bool image_isdata;
- int texture;
+ bool texture;
int texturesize;
void *ptr1, *ptr2;
- int dynamic;
- int dynamictype;
+ bool dynamic;
+ GPUDynamicType dynamictype;
+
+ GPUType type;
- int type;
+ /* Refcount */
int users;
struct GPUTexture *dynamictex;
@@ -118,7 +113,7 @@ typedef struct GPUOutput {
struct GPUOutput *next, *prev;
GPUNode *node;
- int type; /* data type = length of vector/matrix */
+ GPUType type; /* data type = length of vector/matrix */
GPUNodeLink *link; /* output link */
int id; /* unique id as created by code generator */
} GPUOutput;
@@ -128,23 +123,23 @@ typedef struct GPUInput {
GPUNode *node;
- int type; /* datatype */
- int source; /* data source */
+ GPUType type; /* datatype */
+ GPUDataSource source; /* data source */
int id; /* unique id as created by code generator */
- int texid; /* number for multitexture */
+ int texid; /* number for multitexture, starting from zero */
int attribid; /* id for vertex attributes */
- int bindtex; /* input is responsible for binding the texture? */
- int definetex; /* input is responsible for defining the pixel? */
- int textarget; /* GL_TEXTURE_* */
- int textype; /* datatype */
+ bool bindtex; /* input is responsible for binding the texture? */
+ bool definetex; /* input is responsible for defining the pixel? */
+ int textarget; /* GL texture target, e.g. GL_TEXTURE_2D */
+ GPUType textype; /* datatype */
struct Image *ima; /* image */
struct ImageUser *iuser;/* image user */
struct PreviewImage *prv; /* preview images & icons */
- int image_isdata; /* image does not contain color data */
+ bool image_isdata; /* image does not contain color data */
float *dynamicvec; /* vector data in case it is dynamic */
- int dynamictype; /* origin of the dynamic uniform (GPUDynamicType) */
+ GPUDynamicType dynamictype; /* origin of the dynamic uniform */
void *dynamicdata; /* data source of the dynamic uniform */
struct GPUTexture *tex; /* input texture, only set at runtime */
int shaderloc; /* id from opengl */
@@ -152,9 +147,9 @@ typedef struct GPUInput {
float vec[16]; /* vector data */
GPUNodeLink *link;
- int dynamictex; /* dynamic? */
- int attribtype; /* attribute type */
- char attribname[32]; /* attribute name */
+ bool dynamictex; /* dynamic? */
+ CustomDataType attribtype; /* attribute type */
+ char attribname[MAX_CUSTOMDATA_LAYER_NAME]; /* attribute name */
int attribfirst; /* this is the first one that is bound */
GPUBuiltin builtin; /* builtin uniform */
GPUOpenGLBuiltin oglbuiltin; /* opengl built in varying */
@@ -175,7 +170,8 @@ struct GPUPass {
typedef struct GPUPass GPUPass;
GPUPass *GPU_generate_pass(ListBase *nodes, struct GPUNodeLink *outlink,
- struct GPUVertexAttribs *attribs, int *builtin, int type, const char *name);
+ struct GPUVertexAttribs *attribs, int *builtin,
+ const GPUMatType type, const char *name);
struct GPUShader *GPU_pass_shader(GPUPass *pass);
diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c
index 5f58e3fe65b..4a93fbac48e 100644
--- a/source/blender/gpu/intern/gpu_draw.c
+++ b/source/blender/gpu/intern/gpu_draw.c
@@ -1324,7 +1324,7 @@ void GPU_free_images_old(void)
{
Image *ima;
static int lasttime = 0;
- int ctime = (int)PIL_check_seconds_timer();
+ int ctime = PIL_check_seconds_timer_i();
/*
* Run garbage collector once for every collecting period of time
@@ -1384,6 +1384,7 @@ static struct GPUMaterialState {
bool gscenelock;
float (*gviewmat)[4];
float (*gviewinv)[4];
+ float (*gviewcamtexcofac);
bool backface_culling;
@@ -1492,6 +1493,7 @@ void GPU_begin_object_materials(View3D *v3d, RegionView3D *rv3d, Scene *scene, O
GMS.gscenelock = (v3d->scenelock != 0);
GMS.gviewmat= rv3d->viewmat;
GMS.gviewinv= rv3d->viewinv;
+ GMS.gviewcamtexcofac = rv3d->viewcamtexcofac;
/* alpha pass setup. there's various cases to handle here:
* - object transparency on: only solid materials draw in the first pass,
@@ -1650,7 +1652,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, GMS.gscenelock);
+ GPU_material_bind(gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT), GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gob->col, auto_bump_scale);
diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c
index 75a9572f54f..41049e8430a 100644
--- a/source/blender/gpu/intern/gpu_material.c
+++ b/source/blender/gpu/intern/gpu_material.c
@@ -101,6 +101,7 @@ struct GPUMaterial {
int viewmatloc, invviewmatloc;
int obmatloc, invobmatloc;
int obcolloc, obautobumpscaleloc;
+ int cameratexcofacloc;
ListBase lamps;
};
@@ -228,6 +229,8 @@ static int GPU_material_construct_end(GPUMaterial *material, const char *passnam
material->obcolloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_OBCOLOR));
if (material->builtins & GPU_AUTO_BUMPSCALE)
material->obautobumpscaleloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_AUTO_BUMPSCALE));
+ if (material->builtins & GPU_CAMERA_TEXCO_FACTORS)
+ material->cameratexcofacloc = GPU_shader_get_uniform(shader, GPU_builtin_name(GPU_CAMERA_TEXCO_FACTORS));
return 1;
}
@@ -277,7 +280,7 @@ 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], bool scenelock)
+void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double time, int mipmap, float viewmat[4][4], float viewinv[4][4], float camerafactors[4], bool scenelock)
{
if (material->pass) {
LinkData *nlink;
@@ -337,6 +340,16 @@ void GPU_material_bind(GPUMaterial *material, int oblay, int viewlay, double tim
if (material->builtins & GPU_INVERSE_VIEW_MATRIX) {
GPU_shader_uniform_vector(shader, material->invviewmatloc, 16, 1, (float*)viewinv);
}
+ if (material->builtins & GPU_CAMERA_TEXCO_FACTORS) {
+ if (camerafactors) {
+ GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float*)camerafactors);
+ }
+ else {
+ /* use default, no scaling no offset */
+ float borders[4] = {1.0f, 1.0f, 0.0f, 0.0f};
+ GPU_shader_uniform_vector(shader, material->cameratexcofacloc, 4, 1, (float*)borders);
+ }
+ }
GPU_pass_update_uniforms(material->pass);
@@ -1755,10 +1768,10 @@ static void gpu_lamp_calc_winmat(GPULamp *lamp)
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;
+ 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);
}
}
@@ -2096,13 +2109,14 @@ int GPU_lamp_shadow_layer(GPULamp *lamp)
return -1;
}
-GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow)
+GPUNodeLink *GPU_lamp_get_data(GPUMaterial *mat, GPULamp *lamp, GPUNodeLink **col, GPUNodeLink **lv, GPUNodeLink **dist, GPUNodeLink **shadow, GPUNodeLink **energy)
{
GPUNodeLink *visifac;
*col = GPU_dynamic_uniform(lamp->dyncol, GPU_DYNAMIC_LAMP_DYNCOL, lamp->ob);
+ *energy = GPU_dynamic_uniform(&lamp->dynenergy, GPU_DYNAMIC_LAMP_DYNENERGY, 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)) {
@@ -2208,30 +2222,46 @@ GPUShaderExport *GPU_shader_export(struct Scene *scene, struct Material *ma)
glBindTexture(GL_TEXTURE_2D, lastbindcode);
}
break;
+
+ case GPU_NONE:
+ case GPU_FLOAT:
+ case GPU_VEC2:
+ case GPU_VEC3:
+ case GPU_VEC4:
+ case GPU_MAT3:
+ case GPU_MAT4:
+ case GPU_ATTRIB:
+ break;
}
}
else {
uniform->type = input->dynamictype;
BLI_strncpy(uniform->varname, input->shadername, sizeof(uniform->varname));
switch (input->type) {
- case 1:
+ case GPU_FLOAT:
uniform->datatype = GPU_DATA_1F;
break;
- case 2:
+ case GPU_VEC2:
uniform->datatype = GPU_DATA_2F;
break;
- case 3:
+ case GPU_VEC3:
uniform->datatype = GPU_DATA_3F;
break;
- case 4:
+ case GPU_VEC4:
uniform->datatype = GPU_DATA_4F;
break;
- case 9:
+ case GPU_MAT3:
uniform->datatype = GPU_DATA_9F;
break;
- case 16:
+ case GPU_MAT4:
uniform->datatype = GPU_DATA_16F;
break;
+
+ case GPU_NONE:
+ case GPU_TEX2D:
+ case GPU_SHADOW2D:
+ case GPU_ATTRIB:
+ break;
}
if (uniform->type >= GPU_DYNAMIC_LAMP_FIRST && uniform->type <= GPU_DYNAMIC_LAMP_LAST)
diff --git a/source/blender/gpu/intern/gpu_select.c b/source/blender/gpu/intern/gpu_select.c
index d8e1fab9f80..35a39b2d7a1 100644
--- a/source/blender/gpu/intern/gpu_select.c
+++ b/source/blender/gpu/intern/gpu_select.c
@@ -82,7 +82,7 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c
g_query_state.oldhits = oldhits;
if (!g_query_state.use_gpu_select) {
- glSelectBuffer( bufsize, (GLuint *)buffer);
+ glSelectBuffer(bufsize, (GLuint *)buffer);
glRenderMode(GL_SELECT);
glInitNames();
glPushName(-1);
@@ -92,8 +92,8 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c
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");
+ 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);
@@ -135,7 +135,7 @@ void GPU_select_begin(unsigned int *buffer, unsigned int bufsize, rctf *input, c
bool GPU_select_load_id(unsigned int id)
{
/* if no selection mode active, ignore */
- if(!g_query_state.select_is_active)
+ if (!g_query_state.select_is_active)
return true;
if (!g_query_state.use_gpu_select) {
@@ -158,7 +158,7 @@ bool GPU_select_load_id(unsigned int 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.mode == GPU_SELECT_NEAREST_SECOND_PASS && g_query_state.index < g_query_state.oldhits) {
if (g_query_state.buffer[g_query_state.index * 4 + 3] == id) {
g_query_state.index++;
return true;
@@ -191,7 +191,7 @@ unsigned int GPU_select_end(void)
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) {
+ 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;
diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl
index 1e0927d90b3..a1a4a14e857 100644
--- a/source/blender/gpu/shaders/gpu_shader_material.glsl
+++ b/source/blender/gpu/shaders/gpu_shader_material.glsl
@@ -169,9 +169,9 @@ void camera(vec3 co, out vec3 outview, out float outdepth, out float outdist)
outview = normalize(co);
}
-void lamp(vec4 col, vec3 lv, float dist, vec3 shadow, float visifac, out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
+void lamp(vec4 col, float energy, vec3 lv, float dist, vec3 shadow, float visifac, out vec4 outcol, out vec3 outlv, out float outdist, out vec4 outshadow, out float outvisifac)
{
- outcol = col;
+ outcol = col * energy;
outlv = lv;
outdist = dist;
outshadow = vec4(shadow, 1.0);
@@ -297,6 +297,10 @@ void math_modulo(float val1, float val2, out float outval)
outval = 0.0;
else
outval = mod(val1, val2);
+
+ /* change sign to match C convention, mod in GLSL will take absolute for negative numbers,
+ * see https://www.opengl.org/sdk/docs/man/html/mod.xhtml */
+ outval = (val1 > 0.0) ? outval : -outval;
}
void math_abs(float val1, out float outval)
@@ -338,6 +342,7 @@ void vec_math_cross(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
{
outvec = cross(v1, v2);
outval = length(outvec);
+ outvec /= outval;
}
void vec_math_normalize(vec3 v, out vec3 outvec, out float outval)
@@ -2367,7 +2372,7 @@ void node_geometry(vec3 I, vec3 N, mat4 toworld,
backfacing = (gl_FrontFacing)? 0.0: 1.0;
}
-void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat,
+void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
vec3 attr_orco, vec3 attr_uv,
out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
out vec3 camera, out vec3 window, out vec3 reflection)
@@ -2378,7 +2383,7 @@ void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat,
object = (obinvmat*(viewinvmat*vec4(I, 1.0))).xyz;
camera = vec3(I.xy, -I.z);
vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0);
- window = vec3(mtex_2d_mapping(projvec.xyz/projvec.w).xy, 0.0);
+ window = vec3(mtex_2d_mapping(projvec.xyz/projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
vec3 shade_I;
shade_view(I, shade_I);
@@ -2386,7 +2391,7 @@ void node_tex_coord(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat,
reflection = (viewinvmat*vec4(view_reflection, 0.0)).xyz;
}
-void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat,
+void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat, vec4 camerafac,
vec3 attr_orco, vec3 attr_uv,
out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
out vec3 camera, out vec3 window, out vec3 reflection)
@@ -2405,7 +2410,9 @@ void node_tex_coord_background(vec3 I, vec3 N, mat4 viewinvmat, mat4 obinvmat,
object = coords;
camera = vec3(co.xy, -co.z);
- window = (gl_ProjectionMatrix[3][3] == 0.0) ? vec3(mtex_2d_mapping(I).xy, 0.0) : vec3(0.5, 0.5, 0.0);
+ window = (gl_ProjectionMatrix[3][3] == 0.0) ?
+ vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
+ vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
reflection = -coords;
}
diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h
index ce6a7eb1c47..17bb873cd98 100644
--- a/source/blender/imbuf/IMB_imbuf.h
+++ b/source/blender/imbuf/IMB_imbuf.h
@@ -86,6 +86,7 @@ struct anim;
struct ColorManagedDisplay;
+struct GSet;
/**
*
* \attention Defined in allocimbuf.c
@@ -236,11 +237,14 @@ void IMB_anim_set_index_dir(struct anim *anim, const char *dir);
int IMB_anim_index_get_frame_index(struct anim *anim, IMB_Timecode_Type tc,
int position);
+IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim);
+
struct IndexBuildContext;
/* prepare context for proxies/imecodes builder */
struct IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
- IMB_Proxy_Size proxy_sizes_in_use, int quality);
+ IMB_Proxy_Size proxy_sizes_in_use, int quality,
+ const bool overwite, struct GSet *file_list);
/* will rebuild all used indices and proxies at once */
void IMB_anim_index_rebuild(struct IndexBuildContext *context,
diff --git a/source/blender/imbuf/IMB_imbuf_types.h b/source/blender/imbuf/IMB_imbuf_types.h
index 44cb7f1211e..867c4a826fe 100644
--- a/source/blender/imbuf/IMB_imbuf_types.h
+++ b/source/blender/imbuf/IMB_imbuf_types.h
@@ -47,8 +47,6 @@
* contains an Amiga-format file).
*/
-struct ImMetaData;
-
#define IB_MIPMAP_LEVELS 20
#define IB_FILENAME_SIZE 1024
@@ -111,7 +109,7 @@ typedef struct ImBuf {
/* externally used data */
int index; /* reference index for ImBuf lists */
int userflags; /* used to set imbuf to dirty and other stuff */
- struct ImMetaData *metadata; /* image metadata */
+ struct IDProperty *metadata; /* image metadata */
void *userdata; /* temporary storage, only used by baking at the moment */
/* file information */
diff --git a/source/blender/imbuf/intern/IMB_metadata.h b/source/blender/imbuf/intern/IMB_metadata.h
index a717764b44f..5d4a0028ee1 100644
--- a/source/blender/imbuf/intern/IMB_metadata.h
+++ b/source/blender/imbuf/intern/IMB_metadata.h
@@ -35,13 +35,6 @@
struct ImBuf;
-typedef struct ImMetaData {
- struct ImMetaData *next, *prev;
- char *key;
- char *value;
- int len;
-} ImMetaData;
-
/** The metadata is a list of key/value pairs (both char *) that can me
* saved in the header of several image formats.
* Apart from some common keys like
diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c
index b8f6e66adfe..ffdecb793aa 100644
--- a/source/blender/imbuf/intern/anim_movie.c
+++ b/source/blender/imbuf/intern/anim_movie.c
@@ -1314,25 +1314,27 @@ struct ImBuf *IMB_anim_absolute(struct anim *anim, int position,
filter_y = (anim->ib_flags & IB_animdeinterlace);
- if (anim->curtype == 0) {
- ibuf = anim_getnew(anim);
- if (ibuf == NULL) {
- return(NULL);
+ if (preview_size == IMB_PROXY_NONE) {
+ if (anim->curtype == 0) {
+ ibuf = anim_getnew(anim);
+ if (ibuf == NULL) {
+ return(NULL);
+ }
+
+ IMB_freeImBuf(ibuf); /* ???? */
+ ibuf = NULL;
}
- IMB_freeImBuf(ibuf); /* ???? */
- ibuf = NULL;
+ if (position < 0) return(NULL);
+ if (position >= anim->duration) return(NULL);
}
-
- if (position < 0) return(NULL);
- if (position >= anim->duration) return(NULL);
-
- if (preview_size != IMB_PROXY_NONE) {
+ else {
struct anim *proxy = IMB_anim_open_proxy(anim, preview_size);
if (proxy) {
position = IMB_anim_index_get_frame_index(
anim, tc, position);
+
return IMB_anim_absolute(
proxy, position,
IMB_TC_NONE, IMB_PROXY_NONE);
diff --git a/source/blender/imbuf/intern/bmp.c b/source/blender/imbuf/intern/bmp.c
index 8853fe449ba..f8cf1164e4f 100644
--- a/source/blender/imbuf/intern/bmp.c
+++ b/source/blender/imbuf/intern/bmp.c
@@ -72,22 +72,24 @@ typedef struct BMPHEADER {
#define BMP_FILEHEADER_SIZE 14
+#define CHECK_HEADER_FIELD(_mem, _field) ((_mem[0] == _field[0]) && (_mem[1] == _field[1]))
+#define CHECK_HEADER_FIELD_BMP(_mem) \
+ (CHECK_HEADER_FIELD(_mem, "BM") || \
+ CHECK_HEADER_FIELD(_mem, "BA") || \
+ CHECK_HEADER_FIELD(_mem, "CI") || \
+ CHECK_HEADER_FIELD(_mem, "CP") || \
+ CHECK_HEADER_FIELD(_mem, "IC") || \
+ CHECK_HEADER_FIELD(_mem, "PT"))
+
static int checkbmp(unsigned char *mem)
{
-#define CHECK_HEADER_FIELD(mem, field) ((mem[0] == field[0]) && (mem[1] == field[1]))
int ret_val = 0;
BMPINFOHEADER bmi;
unsigned int u;
if (mem) {
- if (CHECK_HEADER_FIELD(mem, "BM") ||
- CHECK_HEADER_FIELD(mem, "BA") ||
- CHECK_HEADER_FIELD(mem, "CI") ||
- CHECK_HEADER_FIELD(mem, "CP") ||
- CHECK_HEADER_FIELD(mem, "IC") ||
- CHECK_HEADER_FIELD(mem, "PT"))
- {
+ if (CHECK_HEADER_FIELD_BMP(mem)) {
/* skip fileheader */
mem += BMP_FILEHEADER_SIZE;
}
@@ -111,8 +113,6 @@ static int checkbmp(unsigned char *mem)
}
return(ret_val);
-
-#undef CHECK_HEADER_FIELD
}
int imb_is_a_bmp(unsigned char *buf)
@@ -124,10 +124,11 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
{
struct ImBuf *ibuf = NULL;
BMPINFOHEADER bmi;
- int x, y, depth, ibuf_depth, skip, i;
+ int x, y, depth, ibuf_depth, skip, i, j;
unsigned char *bmp, *rect;
unsigned short col;
double xppm, yppm;
+ bool top_to_bottom = false;
(void)size; /* unused */
@@ -135,7 +136,7 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE);
- if ((mem[0] == 'B') && (mem[1] == 'M')) {
+ if (CHECK_HEADER_FIELD_BMP(mem)) {
/* skip fileheader */
mem += BMP_FILEHEADER_SIZE;
}
@@ -157,11 +158,14 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
ibuf_depth = depth;
}
+ if (y < 0) {
+ /* Negative height means bitmap is stored top-to-bottom... */
+ y = -y;
+ top_to_bottom = true;
+ }
+
#if 0
- printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y,
- depth, bmi.biBitCount);
- printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y,
- depth, bmi.biBitCount);
+ printf("skip: %d, x: %d y: %d, depth: %d (%x)\n", skip, x, y, depth, bmi.biBitCount);
#endif
if (flags & IB_test) {
@@ -177,7 +181,9 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
const char (*palette)[4] = (void *)bmp;
bmp += bmi.biClrUsed * 4;
for (i = y; i > 0; i--) {
- int j;
+ if (top_to_bottom) {
+ rect = (unsigned char *) &ibuf->rect[(i - 1) * x];
+ }
for (j = x; j > 0; j--) {
const char *pcol = palette[bmp[0]];
rect[0] = pcol[0];
@@ -192,21 +198,27 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
}
}
else if (depth == 16) {
- for (i = x * y; i > 0; i--) {
- col = bmp[0] + (bmp[1] << 8);
- rect[0] = ((col >> 10) & 0x1f) << 3;
- rect[1] = ((col >> 5) & 0x1f) << 3;
- rect[2] = ((col >> 0) & 0x1f) << 3;
-
- rect[3] = 255;
- rect += 4; bmp += 2;
- }
+ for (i = y; i > 0; i--) {
+ if (top_to_bottom) {
+ rect = (unsigned char *) &ibuf->rect[(i - 1) * x];
+ }
+ for (j = x; j > 0; j--) {
+ col = bmp[0] + (bmp[1] << 8);
+ rect[0] = ((col >> 10) & 0x1f) << 3;
+ rect[1] = ((col >> 5) & 0x1f) << 3;
+ rect[2] = ((col >> 0) & 0x1f) << 3;
+ rect[3] = 255;
+ rect += 4; bmp += 2;
+ }
+ }
}
else if (depth == 24) {
const int x_pad = x % 4;
for (i = y; i > 0; i--) {
- int j;
+ if (top_to_bottom) {
+ rect = (unsigned char *) &ibuf->rect[(i - 1) * x];
+ }
for (j = x; j > 0; j--) {
rect[0] = bmp[2];
rect[1] = bmp[1];
@@ -220,12 +232,17 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
}
}
else if (depth == 32) {
- for (i = x * y; i > 0; i--) {
- rect[0] = bmp[2];
- rect[1] = bmp[1];
- rect[2] = bmp[0];
- rect[3] = bmp[3];
- rect += 4; bmp += 4;
+ for (i = y; i > 0; i--) {
+ if (top_to_bottom) {
+ rect = (unsigned char *) &ibuf->rect[(i - 1) * x];
+ }
+ for (j = x; j > 0; j--) {
+ rect[0] = bmp[2];
+ rect[1] = bmp[1];
+ rect[2] = bmp[0];
+ rect[3] = bmp[3];
+ rect += 4; bmp += 4;
+ }
}
}
}
@@ -239,6 +256,9 @@ struct ImBuf *imb_bmp_decode(unsigned char *mem, size_t size, int flags, char co
return(ibuf);
}
+#undef CHECK_HEADER_FIELD_BMP
+#undef CHECK_HEADER_FIELD
+
/* Couple of helper functions for writing our data */
static int putIntLSB(unsigned int ui, FILE *ofile)
{
@@ -298,7 +318,9 @@ int imb_savebmp(struct ImBuf *ibuf, const char *name, int flags)
if (putc(data[ptr], ofile) == EOF) return 0;
}
/* add padding here */
- for (t = 0; t < extrabytes; t++) if (putc(0, ofile) == EOF) return 0;
+ for (t = 0; t < extrabytes; t++) {
+ if (putc(0, ofile) == EOF) return 0;
+ }
}
if (ofile) {
fflush(ofile);
diff --git a/source/blender/imbuf/intern/cineon/dpxlib.c b/source/blender/imbuf/intern/cineon/dpxlib.c
index f7362d76913..23e5517bb09 100644
--- a/source/blender/imbuf/intern/cineon/dpxlib.c
+++ b/source/blender/imbuf/intern/cineon/dpxlib.c
@@ -183,8 +183,10 @@ LogImageFile *dpxOpen(const unsigned char *byteStuff, int fromMemory, size_t buf
if (verbose) printf("DPX: File is LSB.\n");
}
else {
- if (verbose) printf("DPX: Bad magic number %lu in \"%s\".\n",
- (uintptr_t)header.fileHeader.magic_num, byteStuff);
+ if (verbose) {
+ printf("DPX: Bad magic number %lu in \"%s\".\n",
+ (uintptr_t)header.fileHeader.magic_num, byteStuff);
+ }
logImageClose(dpx);
return NULL;
}
diff --git a/source/blender/imbuf/intern/colormanagement.c b/source/blender/imbuf/intern/colormanagement.c
index 049d8bdcff1..95e166b2f8b 100644
--- a/source/blender/imbuf/intern/colormanagement.c
+++ b/source/blender/imbuf/intern/colormanagement.c
@@ -1141,7 +1141,7 @@ void IMB_colormanagement_validate_settings(ColorManagedDisplaySettings *display_
for (view_link = display->views.first; view_link; view_link = view_link->next) {
ColorManagedView *view = view_link->data;
- if (!strcmp(view->name, view_settings->view_transform))
+ if (STREQ(view->name, view_settings->view_transform))
break;
}
@@ -1496,7 +1496,7 @@ static bool is_ibuf_rect_in_display_space(ImBuf *ibuf, const ColorManagedViewSet
const char *from_colorspace = ibuf->rect_colorspace->name;
const char *to_colorspace = IMB_colormanagement_get_display_colorspace_name(view_settings, display_settings);
- if (to_colorspace && !strcmp(from_colorspace, to_colorspace))
+ if (to_colorspace && STREQ(from_colorspace, to_colorspace))
return true;
}
@@ -1625,7 +1625,7 @@ static void colormanagement_transform_ex(float *buffer, int width, int height, i
return;
}
- if (!strcmp(from_colorspace, to_colorspace)) {
+ if (STREQ(from_colorspace, to_colorspace)) {
/* if source and destination color spaces are identical, skip
* threading overhead and simply do nothing
*/
@@ -1666,7 +1666,7 @@ void IMB_colormanagement_transform_v4(float pixel[4], const char *from_colorspac
return;
}
- if (!strcmp(from_colorspace, to_colorspace)) {
+ if (STREQ(from_colorspace, to_colorspace)) {
/* if source and destination color spaces are identical, skip
* threading overhead and simply do nothing
*/
@@ -1918,7 +1918,7 @@ ImBuf *IMB_colormanagement_imbuf_for_write(ImBuf *ibuf, bool save_as_render, boo
* should be pretty safe since this image buffer is supposed to be used for
* saving only and ftype would be overwritten a bit later by BKE_imbuf_write
*/
- colormanaged_ibuf->ftype = BKE_imtype_to_ftype(image_format_data->imtype);
+ colormanaged_ibuf->ftype = BKE_image_imtype_to_ftype(image_format_data->imtype);
/* if file format isn't able to handle float buffer itself,
* we need to allocate byte buffer and store color managed
@@ -2152,7 +2152,7 @@ ColorManagedDisplay *colormanage_display_get_named(const char *name)
ColorManagedDisplay *display;
for (display = global_displays.first; display; display = display->next) {
- if (!strcmp(display->name, name))
+ if (STREQ(display->name, name))
return display;
}
@@ -2257,7 +2257,7 @@ ColorManagedView *colormanage_view_get_named(const char *name)
ColorManagedView *view;
for (view = global_views.first; view; view = view->next) {
- if (!strcmp(view->name, name))
+ if (STREQ(view->name, name))
return view;
}
@@ -2373,7 +2373,7 @@ ColorSpace *colormanage_colorspace_get_named(const char *name)
ColorSpace *colorspace;
for (colorspace = global_colorspaces.first; colorspace; colorspace = colorspace->next) {
- if (!strcmp(colorspace->name, name))
+ if (STREQ(colorspace->name, name))
return colorspace;
}
@@ -2459,7 +2459,7 @@ ColorManagedLook *colormanage_look_get_named(const char *name)
ColorManagedLook *look;
for (look = global_looks.first; look; look = look->next) {
- if (!strcmp(look->name, name)) {
+ if (STREQ(look->name, name)) {
return look;
}
}
diff --git a/source/blender/imbuf/intern/divers.c b/source/blender/imbuf/intern/divers.c
index 81aef4ac6e4..59d08128e5f 100644
--- a/source/blender/imbuf/intern/divers.c
+++ b/source/blender/imbuf/intern/divers.c
@@ -122,16 +122,6 @@ static void clear_dither_context(DitherContext *di)
MEM_freeN(di);
}
-MINLINE float dither_random_value(float s, float t)
-{
- static float vec[2] = {12.9898f, 78.233f};
- float st[2];
- float value;
- copy_v2_fl2(st, s, t);
-
- value = sinf(dot_v2v2(st, vec)) * 43758.5453f;
- return value - floorf(value);
-}
/************************* Generic Buffer Conversion *************************/
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index e66be77ecaf..d0281744830 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -35,6 +35,7 @@
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_fileops.h"
+#include "BLI_ghash.h"
#include "IMB_indexer.h"
#include "IMB_anim.h"
@@ -1148,19 +1149,64 @@ static void index_rebuild_fallback(FallbackIndexBuilderContext *context,
* ---------------------------------------------------------------------- */
IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim, IMB_Timecode_Type tcs_in_use,
- IMB_Proxy_Size proxy_sizes_in_use, int quality)
+ IMB_Proxy_Size proxy_sizes_in_use, int quality,
+ const bool overwrite, GSet *file_list)
{
IndexBuildContext *context = NULL;
+ IMB_Proxy_Size proxy_sizes_to_build = proxy_sizes_in_use;
+ int i;
+
+ /* Don't generate the same file twice! */
+ if (file_list) {
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; ++i) {
+ IMB_Proxy_Size proxy_size = proxy_sizes[i];
+ if (proxy_size & proxy_sizes_to_build) {
+ char filename[FILE_MAX];
+ get_proxy_filename(anim, proxy_size, filename, false);
+
+ if (BLI_gset_haskey(file_list, filename)) {
+ proxy_sizes_to_build &= ~proxy_size;
+ printf("Proxy: %s already registered for generation, skipping\n", filename);
+ }
+ else {
+ BLI_gset_insert(file_list, BLI_strdup(filename));
+ }
+ }
+ }
+ }
+
+ if (!overwrite) {
+ IMB_Proxy_Size built_proxies = IMB_anim_proxy_get_existing(anim);
+ if (built_proxies != 0) {
+
+ for (i = 0; i < IMB_PROXY_MAX_SLOT; ++i) {
+ IMB_Proxy_Size proxy_size = proxy_sizes[i];
+ if (proxy_size & built_proxies) {
+ char filename[FILE_MAX];
+ get_proxy_filename(anim, proxy_size, filename, false);
+ printf("Skipping proxy: %s\n", filename);
+ }
+ }
+ }
+ proxy_sizes_to_build &= ~built_proxies;
+ }
+
+ fflush(stdout);
+
+ if (proxy_sizes_to_build == 0) {
+ return NULL;
+ }
+
switch (anim->curtype) {
#ifdef WITH_FFMPEG
case ANIM_FFMPEG:
- context = index_ffmpeg_create_context(anim, tcs_in_use, proxy_sizes_in_use, quality);
+ context = index_ffmpeg_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
break;
#endif
#ifdef WITH_AVI
default:
- context = index_fallback_create_context(anim, tcs_in_use, proxy_sizes_in_use, quality);
+ context = index_fallback_create_context(anim, tcs_in_use, proxy_sizes_to_build, quality);
break;
#endif
}
@@ -1237,7 +1283,7 @@ void IMB_free_indices(struct anim *anim)
void IMB_anim_set_index_dir(struct anim *anim, const char *dir)
{
- if (strcmp(anim->index_dir, dir) == 0) {
+ if (STREQ(anim->index_dir, dir)) {
return;
}
BLI_strncpy(anim->index_dir, dir, sizeof(anim->index_dir));
@@ -1304,3 +1350,18 @@ int IMB_anim_index_get_frame_index(struct anim *anim, IMB_Timecode_Type tc,
return IMB_indexer_get_frame_index(idx, position);
}
+IMB_Proxy_Size IMB_anim_proxy_get_existing(struct anim *anim)
+{
+ const int num_proxy_sizes = IMB_PROXY_MAX_SLOT;
+ IMB_Proxy_Size existing = 0;
+ int i;
+ for (i = 0; i < num_proxy_sizes; ++i) {
+ IMB_Proxy_Size proxy_size = proxy_sizes[i];
+ char filename[FILE_MAX];
+ get_proxy_filename(anim, proxy_size, filename, false);
+ if (BLI_exists(filename)) {
+ existing |= proxy_size;
+ }
+ }
+ return existing;
+}
diff --git a/source/blender/imbuf/intern/jpeg.c b/source/blender/imbuf/intern/jpeg.c
index f4b5f987869..310e517e38d 100644
--- a/source/blender/imbuf/intern/jpeg.c
+++ b/source/blender/imbuf/intern/jpeg.c
@@ -37,9 +37,12 @@
#include "MEM_guardedalloc.h"
+#include "BLI_utildefines.h"
#include "BLI_string.h"
#include "BLI_fileops.h"
+#include "BKE_idprop.h"
+
#include "imbuf.h"
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -267,7 +270,7 @@ handle_app1(j_decompress_ptr cinfo)
if (length < 16) {
for (i = 0; i < length; i++) INPUT_BYTE(cinfo, neogeo[i], return false);
length = 0;
- if (strncmp(neogeo, "NeoGeo", 6) == 0) memcpy(&ibuf_ftype, neogeo + 6, 4);
+ if (STREQLEN(neogeo, "NeoGeo", 6)) memcpy(&ibuf_ftype, neogeo + 6, 4);
ibuf_ftype = BIG_LONG(ibuf_ftype);
}
INPUT_SYNC(cinfo); /* do before skip_input_data */
@@ -385,7 +388,7 @@ static ImBuf *ibJpegImageFromCinfo(struct jpeg_decompress_struct *cinfo, int fla
* That is why we need split it to the
* common key/value here.
*/
- if (strncmp(str, "Blender", 7)) {
+ if (!STREQLEN(str, "Blender", 7)) {
/*
* Maybe the file have text that
* we don't know "what it's", in that
@@ -478,7 +481,6 @@ static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf)
uchar *rect;
int x, y;
char neogeo[128];
- ImMetaData *iptr;
char *text;
jpeg_start_compress(cinfo, true);
@@ -490,28 +492,28 @@ static void write_jpeg(struct jpeg_compress_struct *cinfo, struct ImBuf *ibuf)
jpeg_write_marker(cinfo, 0xe1, (JOCTET *) neogeo, 10);
if (ibuf->metadata) {
+ IDProperty *prop;
/* key + max value + "Blender" */
text = MEM_mallocN(530, "stamp info read");
- iptr = ibuf->metadata;
- while (iptr) {
- if (!strcmp(iptr->key, "None")) {
- jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) iptr->value, strlen(iptr->value) + 1);
- goto next_stamp_info;
- }
+ for (prop = ibuf->metadata->data.group.first; prop; prop = prop->next) {
+ if (prop->type == IDP_STRING) {
+ int text_len;
+ if (!strcmp(prop->name, "None")) {
+ jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) IDP_String(prop), prop->len + 1);
+ }
- /*
- * The JPEG format don't support a pair "key/value"
- * like PNG, so we "encode" the stamp in a
- * single string:
- * "Blender:key:value"
- *
- * The first "Blender" is a simple identify to help
- * in the read process.
- */
- sprintf(text, "Blender:%s:%s", iptr->key, iptr->value);
- jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) text, strlen(text) + 1);
-next_stamp_info:
- iptr = iptr->next;
+ /*
+ * The JPEG format don't support a pair "key/value"
+ * like PNG, so we "encode" the stamp in a
+ * single string:
+ * "Blender:key:value"
+ *
+ * The first "Blender" is a simple identify to help
+ * in the read process.
+ */
+ text_len = sprintf(text, "Blender:%s:%s", prop->name, IDP_String(prop));
+ jpeg_write_marker(cinfo, JPEG_COM, (JOCTET *) text, text_len + 1);
+ }
}
MEM_freeN(text);
}
diff --git a/source/blender/imbuf/intern/metadata.c b/source/blender/imbuf/intern/metadata.c
index 797d34d118b..8cb5070dd62 100644
--- a/source/blender/imbuf/intern/metadata.c
+++ b/source/blender/imbuf/intern/metadata.c
@@ -36,6 +36,8 @@
#include "BLI_utildefines.h"
#include "BLI_string.h"
+#include "BKE_idprop.h"
+
#include "MEM_guardedalloc.h"
#include "IMB_imbuf_types.h"
@@ -47,119 +49,84 @@
void IMB_metadata_free(struct ImBuf *img)
{
- ImMetaData *info;
-
if (!img)
return;
if (!img->metadata) {
return;
}
- info = img->metadata;
- while (info) {
- ImMetaData *next = info->next;
- MEM_freeN(info->key);
- MEM_freeN(info->value);
- MEM_freeN(info);
- info = next;
- }
+
+ IDP_FreeProperty(img->metadata);
+ MEM_freeN(img->metadata);
}
bool IMB_metadata_get_field(struct ImBuf *img, const char *key, char *field, const size_t len)
{
- ImMetaData *info;
+ IDProperty *prop;
+
bool retval = false;
if (!img)
return false;
- if (!img->metadata) {
+ if (!img->metadata)
return false;
- }
- info = img->metadata;
- while (info) {
- if (strcmp(key, info->key) == 0) {
- BLI_strncpy(field, info->value, len);
- retval = true;
- break;
- }
- info = info->next;
+
+ prop = IDP_GetPropertyFromGroup(img->metadata, key);
+
+ if (prop && prop->type == IDP_STRING) {
+ BLI_strncpy(field, IDP_String(prop), len);
+ retval = true;
}
return retval;
}
bool IMB_metadata_add_field(struct ImBuf *img, const char *key, const char *value)
{
- ImMetaData *info;
- ImMetaData *last;
+ IDProperty *prop;
if (!img)
return false;
if (!img->metadata) {
- img->metadata = MEM_callocN(sizeof(ImMetaData), "ImMetaData");
- info = img->metadata;
- }
- else {
- info = img->metadata;
- last = info;
- while (info) {
- last = info;
- info = info->next;
- }
- info = MEM_callocN(sizeof(ImMetaData), "ImMetaData");
- last->next = info;
+ IDPropertyTemplate val;
+ img->metadata = IDP_New(IDP_GROUP, &val, "metadata");
}
- info->key = BLI_strdup(key);
- info->value = BLI_strdup(value);
- return true;
+
+ prop = IDP_NewString(value, key, 512);
+ return IDP_AddToGroup(img->metadata, prop);
}
bool IMB_metadata_del_field(struct ImBuf *img, const char *key)
{
- ImMetaData *p, *p1;
+ IDProperty *prop;
if ((!img) || (!img->metadata))
return false;
- p = img->metadata;
- p1 = NULL;
- while (p) {
- if (!strcmp(key, p->key)) {
- if (p1)
- p1->next = p->next;
- else
- img->metadata = p->next;
-
- MEM_freeN(p->key);
- MEM_freeN(p->value);
- MEM_freeN(p);
- return true;
- }
- p1 = p;
- p = p->next;
+ prop = IDP_GetPropertyFromGroup(img->metadata, key);
+
+ if (prop) {
+ IDP_FreeFromGroup(img->metadata, prop);
}
return false;
}
bool IMB_metadata_change_field(struct ImBuf *img, const char *key, const char *field)
{
- ImMetaData *p;
+ IDProperty *prop;
if (!img)
return false;
- if (!img->metadata)
- return (IMB_metadata_add_field(img, key, field));
+ prop = (img->metadata) ? IDP_GetPropertyFromGroup(img->metadata, key) : NULL;
- p = img->metadata;
- while (p) {
- if (!strcmp(key, p->key)) {
- MEM_freeN(p->value);
- p->value = BLI_strdup(field);
- return true;
- }
- p = p->next;
+ if (!prop) {
+ return (IMB_metadata_add_field(img, key, field));
+ }
+ else if (prop->type == IDP_STRING) {
+ IDP_AssignString(prop, field, 1024);
+ return true;
+ }
+ else {
+ return false;
}
-
- return (IMB_metadata_add_field(img, key, field));
}
-
diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c
index cb789cc8491..29bb35986e8 100644
--- a/source/blender/imbuf/intern/moviecache.c
+++ b/source/blender/imbuf/intern/moviecache.c
@@ -142,15 +142,16 @@ static void moviecache_valfree(void *val)
static void check_unused_keys(MovieCache *cache)
{
- GHashIterator *iter;
+ GHashIterator gh_iter;
- iter = BLI_ghashIterator_new(cache->hash);
- while (!BLI_ghashIterator_done(iter)) {
- MovieCacheKey *key = BLI_ghashIterator_getKey(iter);
- MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
- int remove = 0;
+ BLI_ghashIterator_init(&gh_iter, cache->hash);
+
+ while (!BLI_ghashIterator_done(&gh_iter)) {
+ MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+ MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
+ bool remove;
- BLI_ghashIterator_step(iter);
+ BLI_ghashIterator_step(&gh_iter);
remove = !item->ibuf;
@@ -161,8 +162,6 @@ static void check_unused_keys(MovieCache *cache)
if (remove)
BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
}
-
- BLI_ghashIterator_free(iter);
}
static int compare_int(const void *av, const void *bv)
@@ -473,16 +472,17 @@ void IMB_moviecache_free(MovieCache *cache)
void IMB_moviecache_cleanup(MovieCache *cache, bool (cleanup_check_cb) (ImBuf *ibuf, void *userkey, void *userdata), void *userdata)
{
- GHashIterator *iter;
+ GHashIterator gh_iter;
check_unused_keys(cache);
- iter = BLI_ghashIterator_new(cache->hash);
- while (!BLI_ghashIterator_done(iter)) {
- MovieCacheKey *key = BLI_ghashIterator_getKey(iter);
- MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
+ BLI_ghashIterator_init(&gh_iter, cache->hash);
+
+ while (!BLI_ghashIterator_done(&gh_iter)) {
+ MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+ MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
- BLI_ghashIterator_step(iter);
+ BLI_ghashIterator_step(&gh_iter);
if (cleanup_check_cb(item->ibuf, key->userkey, userdata)) {
PRINT("%s: cache '%s' remove item %p\n", __func__, cache->name, item);
@@ -490,8 +490,6 @@ void IMB_moviecache_cleanup(MovieCache *cache, bool (cleanup_check_cb) (ImBuf *i
BLI_ghash_remove(cache->hash, key, moviecache_keyfree, moviecache_valfree);
}
}
-
- BLI_ghashIterator_free(iter);
}
/* get segments of cached frames. useful for debugging cache policies */
@@ -518,13 +516,12 @@ void IMB_moviecache_get_cache_segments(MovieCache *cache, int proxy, int render_
int totframe = BLI_ghash_size(cache->hash);
int *frames = MEM_callocN(totframe * sizeof(int), "movieclip cache frames");
int a, totseg = 0;
- GHashIterator *iter;
+ GHashIterator gh_iter;
- iter = BLI_ghashIterator_new(cache->hash);
a = 0;
- while (!BLI_ghashIterator_done(iter)) {
- MovieCacheKey *key = BLI_ghashIterator_getKey(iter);
- MovieCacheItem *item = BLI_ghashIterator_getValue(iter);
+ GHASH_ITER(gh_iter, cache->hash) {
+ MovieCacheKey *key = BLI_ghashIterator_getKey(&gh_iter);
+ MovieCacheItem *item = BLI_ghashIterator_getValue(&gh_iter);
int framenr, curproxy, curflags;
if (item->ibuf) {
@@ -533,12 +530,8 @@ void IMB_moviecache_get_cache_segments(MovieCache *cache, int proxy, int render_
if (curproxy == proxy && curflags == render_flags)
frames[a++] = framenr;
}
-
- BLI_ghashIterator_step(iter);
}
- BLI_ghashIterator_free(iter);
-
qsort(frames, totframe, sizeof(int), compare_int);
/* count */
diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp
index ba1bda640a6..5de243845a4 100644
--- a/source/blender/imbuf/intern/openexr/openexr_api.cpp
+++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp
@@ -60,6 +60,8 @@ _CRTIMP void __cdecl _invalid_parameter_noinfo(void)
#include "BLI_math_color.h"
#include "BLI_threads.h"
+#include "BKE_idprop.h"
+
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
#include "IMB_allocimbuf.h"
@@ -305,10 +307,15 @@ static void openexr_header_compression(Header *header, int compression)
static void openexr_header_metadata(Header *header, struct ImBuf *ibuf)
{
- ImMetaData *info;
+ if (ibuf->metadata) {
+ IDProperty *prop;
- for (info = ibuf->metadata; info; info = info->next)
- header->insert(info->key, StringAttribute(info->value));
+ for (prop = (IDProperty *)ibuf->metadata->data.group.first; prop; prop = prop->next) {
+ if (prop->type == IDP_STRING) {
+ header->insert(prop->name, StringAttribute(IDP_String(prop)));
+ }
+ }
+ }
if (ibuf->ppm[0] > 0.0)
addXDensity(*header, ibuf->ppm[0] / 39.3700787); /* 1 meter = 39.3700787 inches */
@@ -784,7 +791,7 @@ void IMB_exr_read_channels(void *handle)
/* check if exr was saved with previous versions of blender which flipped images */
const StringAttribute *ta = data->ifile->header().findTypedAttribute <StringAttribute> ("BlenderMultiChannel");
- short flip = (ta && strncmp(ta->value().c_str(), "Blender V2.43", 13) == 0); /* 'previous multilayer attribute, flipped */
+ short flip = (ta && STREQLEN(ta->value().c_str(), "Blender V2.43", 13)); /* 'previous multilayer attribute, flipped */
for (echan = (ExrChannel *)data->channels.first; echan; echan = echan->next) {
@@ -982,7 +989,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname)
if (pass == NULL) {
pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass");
- if (strcmp(passname, "Combined") == 0)
+ if (STREQ(passname, "Combined"))
BLI_addhead(lb, pass);
else
BLI_addtail(lb, pass);
diff --git a/source/blender/imbuf/intern/png.c b/source/blender/imbuf/intern/png.c
index 3266dc97c78..683bdabcd6c 100644
--- a/source/blender/imbuf/intern/png.c
+++ b/source/blender/imbuf/intern/png.c
@@ -38,6 +38,7 @@
#include "BLI_math.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "MEM_guardedalloc.h"
@@ -397,24 +398,25 @@ int imb_savepng(struct ImBuf *ibuf, const char *name, int flags)
/* image text info */
if (ibuf->metadata) {
png_text *metadata;
- ImMetaData *iptr;
+ IDProperty *prop;
+
int num_text = 0;
- iptr = ibuf->metadata;
- while (iptr) {
- num_text++;
- iptr = iptr->next;
+
+ for (prop = ibuf->metadata->data.group.first; prop; prop = prop->next) {
+ if (prop->type == IDP_STRING) {
+ num_text++;
+ }
}
metadata = MEM_callocN(num_text * sizeof(png_text), "png_metadata");
- iptr = ibuf->metadata;
num_text = 0;
- while (iptr) {
-
- metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
- metadata[num_text].key = iptr->key;
- metadata[num_text].text = iptr->value;
- num_text++;
- iptr = iptr->next;
+ for (prop = ibuf->metadata->data.group.first; prop; prop = prop->next) {
+ if (prop->type == IDP_STRING) {
+ metadata[num_text].compression = PNG_TEXT_COMPRESSION_NONE;
+ metadata[num_text].key = prop->name;
+ metadata[num_text].text = IDP_String(prop);
+ num_text++;
+ }
}
png_set_text(png_ptr, info_ptr, metadata, num_text);
@@ -490,7 +492,7 @@ static void imb_png_warning(png_structp UNUSED(png_ptr), png_const_charp message
* 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)) {
+ if ((G.debug & G_DEBUG) == 0 && STREQLEN(message, "iCCP", 4)) {
return;
}
fprintf(stderr, "libpng warning: %s\n", message);
diff --git a/source/blender/imbuf/intern/thumbs_blend.c b/source/blender/imbuf/intern/thumbs_blend.c
index af353461f1f..aee465c49cc 100644
--- a/source/blender/imbuf/intern/thumbs_blend.c
+++ b/source/blender/imbuf/intern/thumbs_blend.c
@@ -55,7 +55,7 @@ static ImBuf *loadblend_thumb(gzFile gzfile)
/* read the blend file header */
if (gzread(gzfile, buf, 12) != 12)
return NULL;
- if (strncmp(buf, "BLENDER", 7))
+ if (!STREQLEN(buf, "BLENDER", 7))
return NULL;
if (buf[7] == '-')
diff --git a/source/blender/imbuf/intern/tiff.c b/source/blender/imbuf/intern/tiff.c
index e3b8e271387..4d58642e9c4 100644
--- a/source/blender/imbuf/intern/tiff.c
+++ b/source/blender/imbuf/intern/tiff.c
@@ -309,8 +309,8 @@ int imb_is_a_tiff(unsigned char *mem)
char big_endian[IMB_TIFF_NCB] = { 0x4d, 0x4d, 0x00, 0x2a };
char lil_endian[IMB_TIFF_NCB] = { 0x49, 0x49, 0x2a, 0x00 };
- return ( (memcmp(big_endian, mem, IMB_TIFF_NCB) == 0) ||
- (memcmp(lil_endian, mem, IMB_TIFF_NCB) == 0) );
+ return ((memcmp(big_endian, mem, IMB_TIFF_NCB) == 0) ||
+ (memcmp(lil_endian, mem, IMB_TIFF_NCB) == 0));
}
static void scanline_contig_16bit(float *rectf, const unsigned short *sbuf, int scanline_w, int spp)
@@ -594,7 +594,7 @@ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[
format = NULL;
TIFFGetField(image, TIFFTAG_PIXAR_TEXTUREFORMAT, &format);
- if (format && strcmp(format, "Plain Texture") == 0 && TIFFIsTiled(image)) {
+ if (format && STREQ(format, "Plain Texture") && TIFFIsTiled(image)) {
int numlevel = TIFFNumberOfDirectories(image);
/* create empty mipmap levels in advance */
diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h
index c00435faa9d..b51b53cc801 100644
--- a/source/blender/makesdna/DNA_ID.h
+++ b/source/blender/makesdna/DNA_ID.h
@@ -270,6 +270,8 @@ enum {
LIB_ID_RECALC = 1 << 12,
LIB_ID_RECALC_DATA = 1 << 13,
LIB_ANIM_NO_RECALC = 1 << 14,
+
+ LIB_ID_RECALC_ALL = (LIB_ID_RECALC|LIB_ID_RECALC_DATA),
};
#ifdef __cplusplus
diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h
index 243e747c006..7b331181a58 100644
--- a/source/blender/makesdna/DNA_action_types.h
+++ b/source/blender/makesdna/DNA_action_types.h
@@ -491,7 +491,7 @@ typedef struct bAction {
ID id; /* ID-serialisation for relinking */
ListBase curves; /* function-curves (FCurve) */
- ListBase chanbase; /* legacy data - Action Channels (bActionChannel) in pre-2.5 animation system */
+ ListBase chanbase DNA_DEPRECATED; /* legacy data - Action Channels (bActionChannel) in pre-2.5 animation system */
ListBase groups; /* groups of function-curves (bActionGroup) */
ListBase markers; /* markers local to the Action (used to provide Pose-Libraries) */
diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h
index 3d0d6b820d7..9e6b71fcbac 100644
--- a/source/blender/makesdna/DNA_anim_types.h
+++ b/source/blender/makesdna/DNA_anim_types.h
@@ -719,13 +719,13 @@ typedef struct KS_Path {
int idtype; /* ID-type that path can be used on */
short groupmode; /* group naming (eKSP_Grouping) */
- short pad;
+ short flag; /* various settings, etc. */
char *rna_path; /* dynamically (or statically in the case of predefined sets) path */
int array_index; /* index that path affects */
- short flag; /* various settings, etc. */
- short keyingflag; /* settings to supply insertkey() with */
+ short keyingflag; /* (eInsertKeyFlags) settings to supply insertkey() with */
+ short keyingoverride; /* (eInsertKeyFlags) for each flag set, the relevant keyingflag bit overrides the default */
} KS_Path;
/* KS_Path->flag */
@@ -770,10 +770,14 @@ typedef struct KeyingSet {
char description[240]; /* (RNA_DYN_DESCR_MAX) short help text. */
char typeinfo[64]; /* name of the typeinfo data used for the relative paths */
+ int active_path; /* index of the active path */
+
short flag; /* settings for KeyingSet */
- short keyingflag; /* settings to supply insertkey() with */
- int active_path; /* index of the active path */
+ short keyingflag; /* (eInsertKeyFlags) settings to supply insertkey() with */
+ short keyingoverride; /* (eInsertKeyFlags) for each flag set, the relevant keyingflag bit overrides the default */
+
+ char pad[6];
} KeyingSet;
/* KeyingSet settings */
diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h
index c99494ce00e..da7d98d2b22 100644
--- a/source/blender/makesdna/DNA_camera_types.h
+++ b/source/blender/makesdna/DNA_camera_types.h
@@ -56,7 +56,7 @@ typedef struct Camera {
float lens, ortho_scale, drawsize;
float sensor_x, sensor_y;
float shiftx, shifty;
-
+
/* yafray: dof params */
/* qdn: yafray var 'YF_dofdist' now enabled for defocus composite node as well.
* The name was not changed so that no other files need to be modified */
@@ -96,12 +96,13 @@ enum {
CAM_SHOWLIMITS = (1 << 0),
CAM_SHOWMIST = (1 << 1),
CAM_SHOWPASSEPARTOUT = (1 << 2),
- CAM_SHOWTITLESAFE = (1 << 3),
+ CAM_SHOW_SAFE_MARGINS = (1 << 3),
CAM_SHOWNAME = (1 << 4),
CAM_ANGLETOGGLE = (1 << 5),
CAM_DS_EXPAND = (1 << 6),
CAM_PANORAMA = (1 << 7), /* deprecated */
CAM_SHOWSENSOR = (1 << 8),
+ CAM_SHOW_SAFE_CENTER = (1 << 9),
};
#if (DNA_DEPRECATED_GCC_POISON == 1)
diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h
index 6c7d500e4e2..3144dadb680 100644
--- a/source/blender/makesdna/DNA_cloth_types.h
+++ b/source/blender/makesdna/DNA_cloth_types.h
@@ -69,10 +69,19 @@ typedef struct ClothSimSettings {
float goalspring;
float goalfrict;
float velocity_smooth; /* smoothing of velocities for hair */
+ float density_target; /* minimum density for hair */
+ float density_strength; /* influence of hair density */
float collider_friction; /* friction with colliders */
float vel_damping; /* damp the velocity to speed up getting to the resting position */
float shrink_min; /* min amount to shrink cloth by 0.0f (no shrink) - 1.0f (shrink to nothing) */
float shrink_max; /* max amount to shrink cloth by 0.0f (no shrink) - 1.0f (shrink to nothing) */
+
+ /* XXX various hair stuff
+ * should really be separate, this struct is a horrible mess already
+ */
+ float bending_damping; /* damping of bending springs */
+ float voxel_cell_size; /* size of voxel grid cells for continuum dynamics */
+ int pad;
int stepsPerFrame; /* Number of time steps per frame. */
int flags; /* flags, see CSIMSETT_FLAGS enum above. */
@@ -86,7 +95,6 @@ typedef struct ClothSimSettings {
short shapekey_rest; /* vertex group for scaling structural stiffness */
short presets; /* used for presets on GUI */
short reset;
- char pad[4];
struct EffectorWeights *effector_weights;
} ClothSimSettings;
@@ -97,15 +105,16 @@ typedef struct ClothCollSettings {
float epsilon; /* min distance for collisions. */
float self_friction; /* Fiction/damping with self contact. */
float friction; /* Friction/damping applied on contact with other object.*/
+ float damping; /* Collision restitution on contact with other object.*/
float selfepsilon; /* for selfcollision */
float repel_force, distance_repel;
int flags; /* collision flags defined in BKE_cloth.h */
short self_loop_count; /* How many iterations for the selfcollision loop */
short loop_count; /* How many iterations for the collision loop. */
+ int pad;
struct Group *group; /* Only use colliders from this group of objects */
short vgroup_selfcol; /* vgroup to paint which vertices are used for self collisions */
- short pad;
- int pad2;
+ short pad2[3];
} ClothCollSettings;
diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h
index 70dc43676ac..74f5967db13 100644
--- a/source/blender/makesdna/DNA_customdata_types.h
+++ b/source/blender/makesdna/DNA_customdata_types.h
@@ -63,9 +63,10 @@ typedef struct CustomDataExternal {
* layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */
typedef struct CustomData {
CustomDataLayer *layers; /* CustomDataLayers, ordered by type */
- int typemap[41]; /* runtime only! - maps types to indices of first layer of that type,
+ int typemap[42]; /* runtime only! - maps types to indices of first layer of that type,
* MUST be >= CD_NUMTYPES, but we cant use a define here.
* Correct size is ensured in CustomData_update_typemap assert() */
+ int pad_i1;
int totlayer, maxlayer; /* number of layers, size of layers array */
int totsize; /* in editmode, total size of all data layers */
struct BLI_mempool *pool; /* (BMesh Only): Memory pool for allocation of blocks */
@@ -73,7 +74,7 @@ typedef struct CustomData {
} CustomData;
/* CustomData.type */
-enum {
+typedef enum CustomDataType {
CD_MVERT = 0,
CD_MSTICKY = 1, /* DEPRECATED */
CD_MDEFORMVERT = 2,
@@ -119,9 +120,10 @@ enum {
CD_FREESTYLE_FACE = 38,
CD_MLOOPTANGENT = 39,
CD_TESSLOOPNORMAL = 40,
+ CD_CUSTOMLOOPNORMAL = 41,
- CD_NUMTYPES = 41
-};
+ CD_NUMTYPES = 42
+} CustomDataType;
/* Bits for CustomDataMask */
#define CD_MASK_MVERT (1 << CD_MVERT)
@@ -167,6 +169,7 @@ enum {
#define CD_MASK_FREESTYLE_FACE (1LL << CD_FREESTYLE_FACE)
#define CD_MASK_MLOOPTANGENT (1LL << CD_MLOOPTANGENT)
#define CD_MASK_TESSLOOPNORMAL (1LL << CD_TESSLOOPNORMAL)
+#define CD_MASK_CUSTOMLOOPNORMAL (1LL << CD_CUSTOMLOOPNORMAL)
/* CustomData.flag */
enum {
diff --git a/source/blender/makesdna/DNA_fileglobal_types.h b/source/blender/makesdna/DNA_fileglobal_types.h
index 040b55d9eb6..fc7959c0043 100644
--- a/source/blender/makesdna/DNA_fileglobal_types.h
+++ b/source/blender/makesdna/DNA_fileglobal_types.h
@@ -41,9 +41,9 @@ struct Scene;
*/
typedef struct FileGlobal {
char subvstr[4]; /* needs to be here, for human fileformat recognition */
- short subversion, pads;
+ short subversion;
short minversion, minsubversion;
- short displaymode, winpos;
+ char pad[6];
struct bScreen *curscreen;
struct Scene *curscene;
int fileflags;
diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h
index fcb894c9ebf..dca1c8330b0 100644
--- a/source/blender/makesdna/DNA_image_types.h
+++ b/source/blender/makesdna/DNA_image_types.h
@@ -143,6 +143,7 @@ enum {
IMA_USER_FRAME_IN_RANGE = (1 << 10), /* for image user, but these flags are mixed */
IMA_VIEW_AS_RENDER = (1 << 11),
IMA_IGNORE_ALPHA = (1 << 12),
+ IMA_DEINTERLACE = (1 << 13),
};
#if (DNA_DEPRECATED_GCC_POISON == 1)
diff --git a/source/blender/makesdna/DNA_material_types.h b/source/blender/makesdna/DNA_material_types.h
index 3f94a9cfebb..c3270430a3a 100644
--- a/source/blender/makesdna/DNA_material_types.h
+++ b/source/blender/makesdna/DNA_material_types.h
@@ -438,6 +438,7 @@ typedef struct Material {
#define MAP_PA_CLUMP 128
#define MAP_PA_KINK 256
#define MAP_PA_ROUGH 512
+#define MAP_PA_FREQ 1024
/* pr_type */
#define MA_FLAT 0
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 7b1a9bba3a2..8f394965664 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -83,7 +83,8 @@ typedef enum ModifierType {
eModifierType_LaplacianDeform = 47,
eModifierType_Wireframe = 48,
eModifierType_DataTransfer = 49,
- eModifierType_PointCache = 50,
+ eModifierType_NormalEdit = 50,
+ eModifierType_PointCache = 51,
NUM_MODIFIER_TYPES
} ModifierType;
@@ -536,16 +537,39 @@ typedef struct ArmatureModifierData {
char defgrp_name[64]; /* MAX_VGROUP_NAME */
} ArmatureModifierData;
+enum {
+ MOD_HOOK_UNIFORM_SPACE = (1 << 0),
+};
+
+/* same as WarpModifierFalloff */
+typedef enum {
+ eHook_Falloff_None = 0,
+ eHook_Falloff_Curve = 1,
+ eHook_Falloff_Sharp = 2, /* PROP_SHARP */
+ eHook_Falloff_Smooth = 3, /* PROP_SMOOTH */
+ eHook_Falloff_Root = 4, /* PROP_ROOT */
+ eHook_Falloff_Linear = 5, /* PROP_LIN */
+ eHook_Falloff_Const = 6, /* PROP_CONST */
+ eHook_Falloff_Sphere = 7, /* PROP_SPHERE */
+ eHook_Falloff_InvSquare = 8, /* PROP_INVSQUARE */
+ /* PROP_RANDOM not used */
+} HookModifierFalloff;
+
typedef struct HookModifierData {
ModifierData modifier;
struct Object *object;
char subtarget[64]; /* optional name of bone target, MAX_ID_NAME-2 */
+ char flag;
+ char falloff_type; /* use enums from WarpModifier (exact same functionality) */
+ char pad[6];
float parentinv[4][4]; /* matrix making current transform unmodified */
float cent[3]; /* visualization of hook */
float falloff; /* if not zero, falloff is distance where influence zero */
+ struct CurveMapping *curfalloff;
+
int *indexar; /* if NULL, it's using vertexgroup */
int totindex;
float force;
@@ -565,6 +589,15 @@ typedef struct ClothModifierData {
struct ClothCollSettings *coll_parms; /* definition is in DNA_cloth_types.h */
struct PointCache *point_cache; /* definition is in DNA_object_force.h */
struct ListBase ptcaches DNA_DEPRECATED;
+ /* XXX nasty hack, remove once hair can be separated from cloth modifier data */
+ struct ClothHairData *hairdata;
+ /* grid geometry values of hair continuum */
+ float hair_grid_min[3];
+ float hair_grid_max[3];
+ int hair_grid_res[3];
+ float hair_grid_cellsize;
+
+ struct ClothSolverResult *solver_result;
} ClothModifierData;
typedef struct CollisionModifierData {
@@ -970,6 +1003,7 @@ typedef enum {
eWarp_Falloff_Linear = 5, /* PROP_LIN */
eWarp_Falloff_Const = 6, /* PROP_CONST */
eWarp_Falloff_Sphere = 7, /* PROP_SPHERE */
+ eWarp_Falloff_InvSquare = 8, /* PROP_INVSQUARE */
/* PROP_RANDOM not used */
} WarpModifierFalloff;
@@ -1425,5 +1459,37 @@ typedef struct PointCacheModifierData {
struct DerivedMesh *output_dm;
} PointCacheModifierData;
+/* Set Split Normals modifier */
+typedef struct NormalEditModifierData {
+ ModifierData modifier;
+ char defgrp_name[64]; /* MAX_VGROUP_NAME */
+ struct Object *target; /* Source of normals, or center of ellipsoid. */
+ short mode;
+ short flag;
+ short mix_mode;
+ char pad[2];
+ float mix_factor;
+ float offset[3];
+} NormalEditModifierData;
+
+/* NormalEditModifierData.mode */
+enum {
+ MOD_NORMALEDIT_MODE_RADIAL = 0,
+ MOD_NORMALEDIT_MODE_DIRECTIONAL = 1,
+};
+
+/* NormalEditModifierData.flags */
+enum {
+ MOD_NORMALEDIT_INVERT_VGROUP = (1 << 0),
+ MOD_NORMALEDIT_USE_DIRECTION_PARALLEL = (1 << 1),
+};
+
+/* NormalEditModifierData.mix_mode */
+enum {
+ MOD_NORMALEDIT_MIX_COPY = 0,
+ MOD_NORMALEDIT_MIX_ADD = 1,
+ MOD_NORMALEDIT_MIX_SUB = 2,
+ MOD_NORMALEDIT_MIX_MUL = 3,
+};
#endif /* __DNA_MODIFIER_TYPES_H__ */
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index 02c451e8549..f08b3ea9590 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -825,6 +825,10 @@ typedef struct NodeTranslateData {
typedef struct NodePlaneTrackDeformData {
char tracking_object[64];
char plane_track_name[64];
+ char flag;
+ char motion_blur_samples;
+ char pad[2];
+ float motion_blur_shutter;
} NodePlaneTrackDeformData;
typedef struct NodeShaderScript {
@@ -962,6 +966,8 @@ typedef struct NodeSunBeams {
/* image texture */
#define SHD_PROJ_FLAT 0
#define SHD_PROJ_BOX 1
+#define SHD_PROJ_SPHERE 2
+#define SHD_PROJ_TUBE 3
/* image texture interpolation */
#define SHD_INTERP_LINEAR 0
@@ -1078,4 +1084,11 @@ enum {
/* viewer and cmposite output */
#define CMP_NODE_OUTPUT_IGNORE_ALPHA 1
+/* Plane track deform node */
+enum {
+ CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR = 1,
+};
+
+#define CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX 64
+
#endif
diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h
index af8f0b87454..ea58bf74e7d 100644
--- a/source/blender/makesdna/DNA_particle_types.h
+++ b/source/blender/makesdna/DNA_particle_types.h
@@ -44,6 +44,7 @@ typedef struct HairKey {
float weight; /* softbody weight */
short editflag; /* saved particled edit mode flags */
short pad;
+ float world_co[3];
} HairKey;
typedef struct ParticleKey { /* when changed update size of struct to copy_particleKey()!! */
@@ -207,6 +208,8 @@ typedef struct ParticleSettings {
/* length */
float randlength;
/* children */
+ int child_flag;
+ int pad3;
int child_nbr, ren_child_nbr;
float parents, childsize, childrandsize;
float childrad, childflat;
@@ -215,6 +218,8 @@ typedef struct ParticleSettings {
/* kink */
float kink_amp, kink_freq, kink_shape, kink_flat;
float kink_amp_clump;
+ int kink_extra_steps, pad4;
+ float kink_axis_random, kink_amp_random;
/* rough */
float rough1, rough1_size;
float rough2, rough2_size, rough2_thres;
@@ -232,6 +237,12 @@ typedef struct ParticleSettings {
int trail_count;
/* keyed particles */
int keyed_loops;
+ struct CurveMapping *clumpcurve;
+ struct CurveMapping *roughcurve;
+ float clump_noise_size;
+
+ /* hair dynamics */
+ float bending_random;
struct MTex *mtex[18]; /* MAX_MTEX */
@@ -246,7 +257,7 @@ typedef struct ParticleSettings {
/* modified dm support */
short use_modifier_stack;
- short pad[3];
+ short pad5[3];
} ParticleSettings;
@@ -314,6 +325,29 @@ typedef struct ParticleSystem {
float _pad; /* spare capacity */
} ParticleSystem;
+typedef enum eParticleDrawFlag {
+ PART_DRAW_VEL = (1 << 0),
+ PART_DRAW_GLOBAL_OB = (1 << 1),
+ PART_DRAW_SIZE = (1 << 2),
+ PART_DRAW_EMITTER = (1 << 3), /* render emitter also */
+ PART_DRAW_HEALTH = (1 << 4),
+ PART_ABS_PATH_TIME = (1 << 5),
+ PART_DRAW_COUNT_GR = (1 << 6),
+ PART_DRAW_BB_LOCK = (1 << 7), /* used with billboards */
+ PART_DRAW_ROTATE_OB = (1 << 7), /* used with dupliobjects/groups */
+ PART_DRAW_PARENT = (1 << 8),
+ PART_DRAW_NUM = (1 << 9),
+ PART_DRAW_RAND_GR = (1 << 10),
+ PART_DRAW_REN_ADAPT = (1 << 11),
+ PART_DRAW_VEL_LENGTH = (1 << 12),
+ PART_DRAW_MAT_COL = (1 << 13), /* deprecated, but used in do_versions */
+ PART_DRAW_WHOLE_GR = (1 << 14),
+ PART_DRAW_REN_STRAND = (1 << 15),
+ PART_DRAW_NO_SCALE_OB = (1 << 16), /* used with dupliobjects/groups */
+ PART_DRAW_GUIDE_HAIRS = (1 << 17),
+ PART_DRAW_HAIR_GRID = (1 << 18),
+} eParticleDrawFlag;
+
/* part->type */
/* hair is allways baked static in object/geometry space */
/* other types (normal particles) are in global space and not static baked */
@@ -386,31 +420,21 @@ typedef struct ParticleSystem {
#define PART_PHYS_FLUID 4
/* part->kink */
-#define PART_KINK_NO 0
-#define PART_KINK_CURL 1
-#define PART_KINK_RADIAL 2
-#define PART_KINK_WAVE 3
-#define PART_KINK_BRAID 4
-
-/* part->draw */
-#define PART_DRAW_VEL 1
-#define PART_DRAW_GLOBAL_OB 2
-#define PART_DRAW_SIZE 4
-#define PART_DRAW_EMITTER 8 /* render emitter also */
-#define PART_DRAW_HEALTH 16
-#define PART_ABS_PATH_TIME 32
-#define PART_DRAW_COUNT_GR 64
-#define PART_DRAW_BB_LOCK 128 /* used with billboards */
-#define PART_DRAW_ROTATE_OB 128 /* used with dupliobjects/groups */
-#define PART_DRAW_PARENT 256
-#define PART_DRAW_NUM 512
-#define PART_DRAW_RAND_GR 1024
-#define PART_DRAW_REN_ADAPT 2048
-#define PART_DRAW_VEL_LENGTH (1<<12)
-#define PART_DRAW_MAT_COL (1<<13) /* deprecated, but used in do_versions */
-#define PART_DRAW_WHOLE_GR (1<<14)
-#define PART_DRAW_REN_STRAND (1<<15)
-#define PART_DRAW_NO_SCALE_OB (1<<16) /* used with dupliobjects/groups */
+typedef enum eParticleKink {
+ PART_KINK_NO = 0,
+ PART_KINK_CURL = 1,
+ PART_KINK_RADIAL = 2,
+ PART_KINK_WAVE = 3,
+ PART_KINK_BRAID = 4,
+ PART_KINK_SPIRAL = 5,
+} eParticleKink;
+
+/* part->child_flag */
+typedef enum eParticleChildFlag {
+ PART_CHILD_USE_CLUMP_NOISE = (1<<0),
+ PART_CHILD_USE_CLUMP_CURVE = (1<<1),
+ PART_CHILD_USE_ROUGH_CURVE = (1<<2),
+} eParticleChildFlag;
/* part->draw_col */
#define PART_DRAW_COL_NONE 0
@@ -562,24 +586,27 @@ typedef struct ParticleSystem {
#define PTARGET_MODE_ENEMY 2
/* mapto */
-/* init */
-#define PAMAP_INIT (PAMAP_TIME | PAMAP_LIFE | PAMAP_DENS | PAMAP_SIZE)
-#define PAMAP_TIME (1<<0) /* emission time */
-#define PAMAP_LIFE (1<<1) /* life time */
-#define PAMAP_DENS (1<<2) /* density */
-#define PAMAP_SIZE (1<<3) /* physical size */
-/* reset */
-#define PAMAP_IVEL (1<<5) /* initial velocity */
-/* physics */
-#define PAMAP_PHYSICS (PAMAP_FIELD | PAMAP_GRAVITY | PAMAP_DAMP)
-#define PAMAP_FIELD (1<<6) /* force fields */
-#define PAMAP_GRAVITY (1<<10)
-#define PAMAP_DAMP (1<<11)
-/* children */
-#define PAMAP_CHILD (PAMAP_CLUMP | PAMAP_KINK | PAMAP_ROUGH | PAMAP_LENGTH)
-#define PAMAP_CLUMP (1<<7)
-#define PAMAP_KINK (1<<8)
-#define PAMAP_ROUGH (1<<9)
-#define PAMAP_LENGTH (1<<4)
+typedef enum eParticleTextureInfluence {
+ /* init */
+ PAMAP_TIME = (1<<0), /* emission time */
+ PAMAP_LIFE = (1<<1), /* life time */
+ PAMAP_DENS = (1<<2), /* density */
+ PAMAP_SIZE = (1<<3), /* physical size */
+ PAMAP_INIT = (PAMAP_TIME | PAMAP_LIFE | PAMAP_DENS | PAMAP_SIZE),
+ /* reset */
+ PAMAP_IVEL = (1<<5), /* initial velocity */
+ /* physics */
+ PAMAP_FIELD = (1<<6), /* force fields */
+ PAMAP_GRAVITY = (1<<10),
+ PAMAP_DAMP = (1<<11),
+ PAMAP_PHYSICS = (PAMAP_FIELD | PAMAP_GRAVITY | PAMAP_DAMP),
+ /* children */
+ PAMAP_CLUMP = (1<<7),
+ PAMAP_KINK_FREQ = (1<<8),
+ PAMAP_KINK_AMP = (1<<12),
+ PAMAP_ROUGH = (1<<9),
+ PAMAP_LENGTH = (1<<4),
+ PAMAP_CHILD = (PAMAP_CLUMP | PAMAP_KINK_FREQ | PAMAP_KINK_AMP | PAMAP_ROUGH | PAMAP_LENGTH),
+} eParticleTextureInfluence;
#endif
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 49f8b3cd4d0..9ac506696ad 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -849,7 +849,7 @@ typedef struct ImagePaintSettings {
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;
+ float dither; /* dither amount used when painting on byte images */
} ImagePaintSettings;
/* ------------------------------------------- */
@@ -882,6 +882,7 @@ typedef struct ParticleEditSettings {
struct Scene *scene;
struct Object *object;
+ struct Object *shape_object;
} ParticleEditSettings;
/* ------------------------------------------- */
@@ -1216,6 +1217,21 @@ typedef struct PhysicsSettings {
int flag, quick_cache_step, rt;
} PhysicsSettings;
+/* ------------------------------------------- */
+/* Safe Area options used in Camera View & VSE
+ */
+typedef struct DisplaySafeAreas {
+ /* each value represents the (x,y) margins as a multiplier.
+ * 'center' in this context is just the name for a different kind of safe-area */
+
+ float title[2]; /* Title Safe */
+ float action[2]; /* Image/Graphics Safe */
+
+ /* use for alternate aspect ratio */
+ float title_center[2];
+ float action_center[2];
+} DisplaySafeAreas;
+
/* *************************************************************** */
/* Scene ID-Block */
@@ -1251,6 +1267,7 @@ typedef struct Scene {
struct ToolSettings *toolsettings; /* default allocated now */
struct SceneStats *stats; /* default allocated now */
+ struct DisplaySafeAreas safe_areas;
/* migrate or replace? depends on some internal things... */
/* no, is on the right place (ton) */
@@ -1608,7 +1625,8 @@ extern const char *RE_engine_id_CYCLES;
#define PROP_LIN 4
#define PROP_CONST 5
#define PROP_RANDOM 6
-#define PROP_MODE_MAX 7
+#define PROP_INVSQUARE 7
+#define PROP_MODE_MAX 8
/* toolsettings->proportional */
#define PROP_EDIT_OFF 0
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index 7372f55c3de..3e02071c3dd 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -272,14 +272,16 @@ typedef struct ARegion {
/* area->flag */
enum {
- HEADER_NO_PULLDOWN = (1 << 0),
- AREA_FLAG_DRAWJOINTO = (1 << 1),
- AREA_FLAG_DRAWJOINFROM = (1 << 2),
- AREA_TEMP_INFO = (1 << 3),
- AREA_FLAG_DRAWSPLIT_H = (1 << 4),
- AREA_FLAG_DRAWSPLIT_V = (1 << 5),
+ HEADER_NO_PULLDOWN = (1 << 0),
+ AREA_FLAG_DRAWJOINTO = (1 << 1),
+ AREA_FLAG_DRAWJOINFROM = (1 << 2),
+ AREA_TEMP_INFO = (1 << 3),
+ AREA_FLAG_DRAWSPLIT_H = (1 << 4),
+ AREA_FLAG_DRAWSPLIT_V = (1 << 5),
/* used to check if we should switch back to prevspace (of a different type) */
- AREA_FLAG_TEMP_TYPE = (1 << 6),
+ AREA_FLAG_TEMP_TYPE = (1 << 6),
+ /* for temporary fullscreens (file browser, image editor render) that are opened above user set fullscreens */
+ AREA_FLAG_STACKED_FULLSCREEN = (1 << 7),
};
#define EDGEWIDTH 1
diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h
index 20678bdae49..c6748cca8e1 100644
--- a/source/blender/makesdna/DNA_sequence_types.h
+++ b/source/blender/makesdna/DNA_sequence_types.h
@@ -94,6 +94,8 @@ typedef struct StripProxy {
// to build
short build_tc_flags; // time code flags (see below) of all tc indices
// to build
+ short build_flags;
+ char pad[6];
} StripProxy;
typedef struct Strip {
@@ -398,6 +400,11 @@ enum {
#define SEQ_PROXY_TC_RECORD_RUN_NO_GAPS 8
#define SEQ_PROXY_TC_ALL 15
+/* SeqProxy->build_flags */
+enum {
+ SEQ_PROXY_SKIP_EXISTING = 1,
+};
+
/* seq->alpha_mode */
enum {
SEQ_ALPHA_STRAIGHT = 0,
diff --git a/source/blender/makesdna/DNA_sound_types.h b/source/blender/makesdna/DNA_sound_types.h
index 4ab22e4f7b7..cb132c1b550 100644
--- a/source/blender/makesdna/DNA_sound_types.h
+++ b/source/blender/makesdna/DNA_sound_types.h
@@ -95,8 +95,8 @@ typedef struct bSound {
*/
void *playback_handle;
- /* mutex for asynchronous loading of sounds */
- void *mutex;
+ /* spinlock for asynchronous loading of sounds */
+ void *spinlock;
/* XXX unused currently (SOUND_TYPE_LIMITER) */
/* float start, end; */
} bSound;
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index f65cef1a0d1..165f6113b6d 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -273,6 +273,7 @@ typedef enum eSpaceOutliner_Flag {
SO_NEWSELECTED = (1 << 1),
SO_HIDE_RESTRICTCOLS = (1 << 2),
SO_HIDE_KEYINGSETINFO = (1 << 3),
+ SO_SKIP_SORT_ALPHA = (1 << 4),
} eSpaceOutliner_Flag;
/* SpaceOops->outlinevis */
@@ -369,6 +370,8 @@ typedef enum eGraphEdit_Flag {
/* normalize curves on display */
SIPO_NORMALIZE = (1 << 14),
SIPO_NORMALIZE_FREEZE = (1 << 15),
+ /* automatically set view on selection */
+ SIPO_AUTO_VIEW_SELECTED = (1 << 16),
} eGraphEdit_Flag;
/* SpaceIpo->mode (Graph Editor Mode) */
@@ -461,6 +464,8 @@ typedef enum eScreen_Redraws_Flag {
// TIME_CONTINUE_PHYSICS = (1 << 7), /* UNUSED */
TIME_NODES = (1 << 8),
TIME_CLIPS = (1 << 9),
+
+ TIME_FOLLOW = (1 << 15),
} eScreen_Redraws_Flag;
/* time->cache */
@@ -527,12 +532,13 @@ typedef enum eSpaceSeq_Flag {
SEQ_DRAWFRAMES = (1 << 0),
SEQ_MARKER_TRANS = (1 << 1),
SEQ_DRAW_COLOR_SEPARATED = (1 << 2),
- SEQ_DRAW_SAFE_MARGINS = (1 << 3),
+ SEQ_SHOW_SAFE_MARGINS = (1 << 3),
SEQ_SHOW_GPENCIL = (1 << 4),
SEQ_NO_DRAW_CFRANUM = (1 << 5),
SEQ_USE_ALPHA = (1 << 6), /* use RGBA display mode for preview */
SEQ_ALL_WAVEFORMS = (1 << 7), /* draw all waveforms */
SEQ_NO_WAVEFORMS = (1 << 8), /* draw no waveforms */
+ SEQ_SHOW_SAFE_CENTER = (1 << 9),
} eSpaceSeq_Flag;
/* sseq->view */
@@ -932,7 +938,7 @@ typedef struct bNodeTreePath {
bNodeInstanceKey parent_key; /* base key for nodes in this tree instance */
int pad;
float view_center[2]; /* v2d center point, so node trees can have different offsets in editors */
- /* XXX this is not automatically updated when node names are changed! */
+
char node_name[64]; /* MAX_NAME */
} bNodeTreePath;
@@ -1200,6 +1206,9 @@ typedef enum eSpace_Type {
SPACEICONMAX = SPACE_CLIP
} eSpace_Type;
+/* use for function args */
+#define SPACE_TYPE_ANY -1
+
// TODO: SPACE_SCRIPT
#if (DNA_DEPRECATED_GCC_POISON == 1)
#pragma GCC poison SPACE_IMASEL SPACE_SOUND
diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h
index 042645eeb76..af6adbecd83 100644
--- a/source/blender/makesdna/DNA_texture_types.h
+++ b/source/blender/makesdna/DNA_texture_types.h
@@ -84,8 +84,9 @@ typedef struct MTex {
/* particles */
float timefac, lengthfac, clumpfac, dampfac;
- float kinkfac, roughfac, padensfac, gravityfac;
+ float kinkfac, kinkampfac, roughfac, padensfac, gravityfac;
float lifefac, sizefac, ivelfac, fieldfac;
+ int pad2;
/* lamp */
float shadowfac;
@@ -175,8 +176,8 @@ typedef struct VoxelData {
short flag;
short extend;
short smoked_type;
+ short hair_type;
short data_type;
- short pad;
int _pad;
struct Object *object; /* for rendering smoke sims */
@@ -617,6 +618,7 @@ enum {
#define TEX_VD_RAW_16BIT 2
#define TEX_VD_IMAGE_SEQUENCE 3
#define TEX_VD_SMOKE 4
+#define TEX_VD_HAIR 5
/* for voxels which use VoxelData->source_path */
#define TEX_VD_IS_SOURCE_PATH(_format) (ELEM(_format, TEX_VD_BLENDERVOXEL, TEX_VD_RAW_8BIT, TEX_VD_RAW_16BIT))
@@ -626,6 +628,11 @@ enum {
#define TEX_VD_SMOKEVEL 2
#define TEX_VD_SMOKEFLAME 3
+#define TEX_VD_HAIRDENSITY 0
+#define TEX_VD_HAIRVELOCITY 1
+#define TEX_VD_HAIRENERGY 2
+#define TEX_VD_HAIRRESTDENSITY 3
+
/* data_type */
#define TEX_VD_INTENSITY 0
#define TEX_VD_RGBA_PREMUL 1
diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h
index 11807ba5338..3ac923a72ef 100644
--- a/source/blender/makesdna/DNA_userdef_types.h
+++ b/source/blender/makesdna/DNA_userdef_types.h
@@ -288,9 +288,10 @@ typedef struct ThemeSpace {
char handle_vertex[4];
char handle_vertex_select[4];
- char pad2[4];
char handle_vertex_size;
+
+ char clipping_border_3d[4];
char marker_outline[4], marker[4], act_marker[4], sel_marker[4], dis_marker[4], lock_marker[4];
char bundle_solid[4];
@@ -461,7 +462,7 @@ typedef struct UserDef {
int scrollback; /* console scrollback limit */
int dpi; /* range 48-128? */
- short encoding;
+ char pad2[2];
short transopts;
short menuthreshold1, menuthreshold2;
diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h
index 0eee28e73d9..543a95cc120 100644
--- a/source/blender/makesdna/DNA_view3d_types.h
+++ b/source/blender/makesdna/DNA_view3d_types.h
@@ -74,10 +74,11 @@ typedef struct BGpic {
struct ImageUser iuser;
struct MovieClip *clip;
struct MovieClipUser cuser;
- float xof, yof, size, blend;
+ float xof, yof, size, blend, rotation;
short view;
short flag;
- short source, pad;
+ short source;
+ char pad[6];
} BGpic;
/* ********************************* */
@@ -89,12 +90,12 @@ typedef struct RegionView3D {
float viewinv[4][4]; /* inverse of viewmat */
float persmat[4][4]; /* viewmat*winmat */
float persinv[4][4]; /* inverse of persmat */
+ float viewcamtexcofac[4]; /* offset/scale for camera glsl texcoords */
/* viewmat/persmat multiplied with object matrix, while drawing and selection */
float viewmatob[4][4];
float persmatob[4][4];
-
/* user defined clipping planes */
float clip[6][4];
float clip_local[6][4]; /* clip in object space, means we can test for clipping in editmode without first going into worldspace */
@@ -340,7 +341,11 @@ enum {
/* Camera framing options */
V3D_BGPIC_CAMERA_ASPECT = (1 << 5), /* don't stretch to fit the camera view */
- V3D_BGPIC_CAMERA_CROP = (1 << 6) /* crop out the image */
+ V3D_BGPIC_CAMERA_CROP = (1 << 6), /* crop out the image */
+
+ /* Axis flip options */
+ V3D_BGPIC_FLIP_X = (1 << 7),
+ V3D_BGPIC_FLIP_Y = (1 << 8),
};
#define V3D_BGPIC_EXPANDED (V3D_BGPIC_EXPANDED | V3D_BGPIC_CAMERACLIP)
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 3e1a029567d..964196c1f7b 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -203,6 +203,7 @@ extern StructRNA RNA_DataTransferModifier;
extern StructRNA RNA_DecimateModifier;
extern StructRNA RNA_DelaySensor;
extern StructRNA RNA_DisplaceModifier;
+extern StructRNA RNA_DisplaySafeAreas;
extern StructRNA RNA_DistortedNoiseTexture;
extern StructRNA RNA_DomainFluidSettings;
extern StructRNA RNA_DopeSheet;
@@ -494,6 +495,7 @@ extern StructRNA RNA_SequenceEditor;
extern StructRNA RNA_SequenceElement;
extern StructRNA RNA_SequenceProxy;
extern StructRNA RNA_SequenceTransform;
+extern StructRNA RNA_NormalEditModifier;
extern StructRNA RNA_ShaderNode;
extern StructRNA RNA_ShaderNodeCameraData;
extern StructRNA RNA_ShaderNodeCombineRGB;
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index 2600f55bbc6..5c244f5e8f6 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -53,6 +53,7 @@ incs = [
'../imbuf',
'../makesdna',
'../nodes',
+ '../physics',
'../pointcache',
'../render/extern/include',
'../windowmanager',
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index c6c5b54f989..0515a6fc054 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -28,8 +28,6 @@ if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=implicit-function-declaration")
endif()
-# message(STATUS "Configuring makesrna")
-
# files rna_access.c rna_define.c makesrna.c intentionally excluded.
set(DEFSRC
rna_ID.c
@@ -118,15 +116,32 @@ set(APISRC
rna_scene_api.c
rna_sensor_api.c
rna_sequencer_api.c
+ rna_sound_api.c
rna_space_api.c
rna_text_api.c
rna_ui_api.c
+ rna_vfont_api.c
rna_wm_api.c
)
string(REGEX REPLACE "rna_([a-zA-Z0-9_-]*).c" "${CMAKE_CURRENT_BINARY_DIR}/rna_\\1_gen.c" GENSRC "${DEFSRC}")
set_source_files_properties(${GENSRC} PROPERTIES GENERATED TRUE)
+# --------------------------
+# CFLAGS for Generated Files
+#
+# less strict flags for generated source
+set(GENSRC_CFLAGS)
+if(CMAKE_COMPILER_IS_GNUCC OR (CMAKE_C_COMPILER_ID MATCHES "Clang"))
+ set(GENSRC_CFLAGS "-Wno-missing-prototypes")
+endif()
+
+if(GENSRC_CFLAGS)
+ set_source_files_properties(${GENSRC} PROPERTIES COMPILE_FLAGS "${GENSRC_CFLAGS}")
+endif()
+unset(GENSRC_CFLAGS)
+
+
set(SRC_RNA_INC
../RNA_access.h
../RNA_define.h
@@ -298,6 +313,7 @@ blender_include_dirs(
../../ikplugin
../../makesdna
../../nodes/
+ ../../physics
../../pointcache/
../../windowmanager
../../editors/include
@@ -319,9 +335,6 @@ add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC})
target_link_libraries(makesrna bf_dna)
target_link_libraries(makesrna bf_dna_blenlib)
-# too many warnings with clang
-remove_cc_flag("-Wmissing-prototypes")
-
# Output rna_*_gen.c
# note (linux only): with crashes try add this after COMMAND: valgrind --leak-check=full --track-origins=yes
add_custom_command(
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
index 7ff671a0e9b..9614b6ac1ca 100644
--- a/source/blender/makesrna/intern/SConscript
+++ b/source/blender/makesrna/intern/SConscript
@@ -72,6 +72,7 @@ incs = [
'../../imbuf',
'../../makesdna',
'../../makesrna',
+ '../../physics',
'../../pointcache',
'../../render/extern/include',
'../../windowmanager',
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 0c1701f6089..9058f715d87 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -221,11 +221,11 @@ static int replace_if_different(const char *tmpfile, const char *dep_files[])
static const char *rna_safe_id(const char *id)
{
- if (strcmp(id, "default") == 0)
+ if (STREQ(id, "default"))
return "default_value";
- else if (strcmp(id, "operator") == 0)
+ else if (STREQ(id, "operator"))
return "operator_value";
- else if (strcmp(id, "new") == 0)
+ else if (STREQ(id, "new"))
return "create";
return id;
@@ -246,11 +246,11 @@ static int cmp_property(const void *a, const void *b)
const PropertyRNA *propa = *(const PropertyRNA **)a;
const PropertyRNA *propb = *(const PropertyRNA **)b;
- if (strcmp(propa->identifier, "rna_type") == 0) return -1;
- else if (strcmp(propb->identifier, "rna_type") == 0) return 1;
+ if (STREQ(propa->identifier, "rna_type")) return -1;
+ else if (STREQ(propb->identifier, "rna_type")) return 1;
- if (strcmp(propa->identifier, "name") == 0) return -1;
- else if (strcmp(propb->identifier, "name") == 0) return 1;
+ if (STREQ(propa->identifier, "name")) return -1;
+ else if (STREQ(propb->identifier, "name")) return 1;
return strcmp(propa->name, propb->name);
}
@@ -372,7 +372,7 @@ static StructRNA *rna_find_struct(const char *identifier)
StructDefRNA *ds;
for (ds = DefRNA.structs.first; ds; ds = ds->cont.next)
- if (strcmp(ds->srna->identifier, identifier) == 0)
+ if (STREQ(ds->srna->identifier, identifier))
return ds->srna;
return NULL;
@@ -383,7 +383,7 @@ static const char *rna_find_type(const char *type)
StructDefRNA *ds;
for (ds = DefRNA.structs.first; ds; ds = ds->cont.next)
- if (ds->dnaname && strcmp(ds->dnaname, type) == 0)
+ if (ds->dnaname && STREQ(ds->dnaname, type))
return ds->srna->identifier;
return NULL;
@@ -394,7 +394,7 @@ static const char *rna_find_dna_type(const char *type)
StructDefRNA *ds;
for (ds = DefRNA.structs.first; ds; ds = ds->cont.next)
- if (strcmp(ds->srna->identifier, type) == 0)
+ if (STREQ(ds->srna->identifier, type))
return ds->dnaname;
return NULL;
@@ -621,9 +621,9 @@ static char *rna_def_property_get_func(FILE *f, StructRNA *srna, PropertyRNA *pr
fprintf(f, "static PointerRNA %s(CollectionPropertyIterator *iter)\n", func);
fprintf(f, "{\n");
if (manualfunc) {
- if (strcmp(manualfunc, "rna_iterator_listbase_get") == 0 ||
- strcmp(manualfunc, "rna_iterator_array_get") == 0 ||
- strcmp(manualfunc, "rna_iterator_array_dereference_get") == 0)
+ if (STREQ(manualfunc, "rna_iterator_listbase_get") ||
+ STREQ(manualfunc, "rna_iterator_array_get") ||
+ STREQ(manualfunc, "rna_iterator_array_dereference_get"))
{
fprintf(f, " return rna_pointer_inherit_refine(&iter->parent, &RNA_%s, %s(iter));\n",
(cprop->item_type) ? (const char *)cprop->item_type : "UnknownType", manualfunc);
@@ -1168,8 +1168,8 @@ static char *rna_def_property_lookup_int_func(FILE *f, StructRNA *srna, Property
return NULL;
/* only supported in case of standard next functions */
- if (strcmp(nextfunc, "rna_iterator_array_next") == 0) {}
- else if (strcmp(nextfunc, "rna_iterator_listbase_next") == 0) {}
+ if (STREQ(nextfunc, "rna_iterator_array_next")) {}
+ else if (STREQ(nextfunc, "rna_iterator_listbase_next")) {}
else return NULL;
}
@@ -1190,7 +1190,7 @@ static char *rna_def_property_lookup_int_func(FILE *f, StructRNA *srna, Property
fprintf(f, " %s_%s_begin(&iter, ptr);\n\n", srna->identifier, rna_safe_id(prop->identifier));
fprintf(f, " if (iter.valid) {\n");
- if (strcmp(nextfunc, "rna_iterator_array_next") == 0) {
+ if (STREQ(nextfunc, "rna_iterator_array_next")) {
fprintf(f, " ArrayIterator *internal = &iter.internal.array;\n");
fprintf(f, " if (index < 0 || index >= internal->length) {\n");
fprintf(f, "#ifdef __GNUC__\n");
@@ -1210,7 +1210,7 @@ static char *rna_def_property_lookup_int_func(FILE *f, StructRNA *srna, Property
fprintf(f, " found = 1;\n");
fprintf(f, " }\n");
}
- else if (strcmp(nextfunc, "rna_iterator_listbase_next") == 0) {
+ else if (STREQ(nextfunc, "rna_iterator_listbase_next")) {
fprintf(f, " ListBaseIterator *internal = &iter.internal.listbase;\n");
fprintf(f, " if (internal->skip) {\n");
fprintf(f, " while (index-- > 0 && iter.valid) {\n");
@@ -1396,23 +1396,23 @@ static void rna_set_raw_property(PropertyDefRNA *dp, PropertyRNA *prop)
if (!dp->dnatype || !dp->dnaname || !dp->dnastructname)
return;
- if (strcmp(dp->dnatype, "char") == 0) {
+ if (STREQ(dp->dnatype, "char")) {
prop->rawtype = PROP_RAW_CHAR;
prop->flag |= PROP_RAW_ACCESS;
}
- else if (strcmp(dp->dnatype, "short") == 0) {
+ else if (STREQ(dp->dnatype, "short")) {
prop->rawtype = PROP_RAW_SHORT;
prop->flag |= PROP_RAW_ACCESS;
}
- else if (strcmp(dp->dnatype, "int") == 0) {
+ else if (STREQ(dp->dnatype, "int")) {
prop->rawtype = PROP_RAW_INT;
prop->flag |= PROP_RAW_ACCESS;
}
- else if (strcmp(dp->dnatype, "float") == 0) {
+ else if (STREQ(dp->dnatype, "float")) {
prop->rawtype = PROP_RAW_FLOAT;
prop->flag |= PROP_RAW_ACCESS;
}
- else if (strcmp(dp->dnatype, "double") == 0) {
+ else if (STREQ(dp->dnatype, "double")) {
prop->rawtype = PROP_RAW_DOUBLE;
prop->flag |= PROP_RAW_ACCESS;
}
@@ -1525,7 +1525,7 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
const char *nextfunc = (const char *)cprop->next;
const char *item_type = (const char *)cprop->item_type;
- if (dp->dnatype && strcmp(dp->dnatype, "ListBase") == 0) {
+ if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) {
/* pass */
}
else if (dp->dnalengthname || dp->dnalengthfixed) {
@@ -1535,8 +1535,8 @@ static void rna_def_property_funcs(FILE *f, StructRNA *srna, PropertyDefRNA *dp)
/* test if we can allow raw array access, if it is using our standard
* array get/next function, we can be sure it is an actual array */
if (cprop->next && cprop->get)
- if (strcmp((const char *)cprop->next, "rna_iterator_array_next") == 0 &&
- strcmp((const char *)cprop->get, "rna_iterator_array_get") == 0)
+ if (STREQ((const char *)cprop->next, "rna_iterator_array_next") &&
+ STREQ((const char *)cprop->get, "rna_iterator_array_get"))
{
prop->flag |= PROP_RAW_ARRAY;
}
@@ -2419,11 +2419,11 @@ static void rna_auto_types(void)
for (ds = DefRNA.structs.first; ds; ds = ds->cont.next) {
/* DNA name for Screen is patched in 2.5, we do the reverse here .. */
- if (ds->dnaname && strcmp(ds->dnaname, "Screen") == 0)
+ if (ds->dnaname && STREQ(ds->dnaname, "Screen"))
ds->dnaname = "bScreen";
for (dp = ds->cont.properties.first; dp; dp = dp->next) {
- if (dp->dnastructname && strcmp(dp->dnastructname, "Screen") == 0)
+ if (dp->dnastructname && STREQ(dp->dnastructname, "Screen"))
dp->dnastructname = "bScreen";
if (dp->dnatype) {
@@ -2443,7 +2443,7 @@ static void rna_auto_types(void)
else if (dp->prop->type == PROP_COLLECTION) {
CollectionPropertyRNA *cprop = (CollectionPropertyRNA *)dp->prop;
- if (!cprop->item_type && !cprop->get && strcmp(dp->dnatype, "ListBase") == 0)
+ if (!cprop->item_type && !cprop->get && STREQ(dp->dnatype, "ListBase"))
cprop->item_type = (StructRNA *)rna_find_type(dp->dnatype);
}
}
@@ -2786,7 +2786,7 @@ static void rna_generate_struct_prototypes(FILE *f)
const char *struct_name = rna_parameter_type_name(dp->prop);
for (a = 0; a < all_structures; a++) {
- if (strcmp(struct_name, structures[a]) == 0) {
+ if (STREQ(struct_name, structures[a])) {
found = 1;
break;
}
@@ -3326,10 +3326,10 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_test.c", NULL, RNA_def_test},
{"rna_text.c", "rna_text_api.c", RNA_def_text},
{"rna_timeline.c", NULL, RNA_def_timeline_marker},
- {"rna_sound.c", NULL, RNA_def_sound},
+ {"rna_sound.c", "rna_sound_api.c", RNA_def_sound},
{"rna_ui.c", "rna_ui_api.c", RNA_def_ui},
{"rna_userdef.c", NULL, RNA_def_userdef},
- {"rna_vfont.c", NULL, RNA_def_vfont},
+ {"rna_vfont.c", "rna_vfont_api.c", RNA_def_vfont},
{"rna_wm.c", "rna_wm_api.c", RNA_def_wm},
{"rna_world.c", NULL, RNA_def_world},
{"rna_movieclip.c", NULL, RNA_def_movieclip},
@@ -3418,7 +3418,7 @@ static void rna_generate(BlenderRNA *brna, FILE *f, const char *filename, const
if (!filename || ds->filename == filename)
rna_generate_struct(brna, ds->srna, f);
- if (strcmp(filename, "rna_ID.c") == 0) {
+ if (STREQ(filename, "rna_ID.c")) {
/* this is ugly, but we cannot have c files compiled for both
* makesrna and blender with some build systems at the moment */
fprintf(f, "#include \"rna_define.c\"\n\n");
@@ -3780,7 +3780,7 @@ static int rna_is_collection_functions_struct(const char **collection_structs, c
int a = 0, found = 0;
while (collection_structs[a]) {
- if (!strcmp(collection_structs[a], struct_name)) {
+ if (STREQ(collection_structs[a], struct_name)) {
found = 1;
break;
}
@@ -3881,7 +3881,7 @@ static void rna_generate_header_cpp(BlenderRNA *UNUSED(brna), FILE *f)
for (ds = DefRNA.structs.first; ds; ds = ds->cont.next) {
srna = ds->srna;
- if (!strcmp(srna->identifier, first_collection_func_struct)) {
+ if (STREQ(srna->identifier, first_collection_func_struct)) {
StructDefRNA *ds2;
StructRNA *srna2;
diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c
index 09b970fe7fd..7096060e73b 100644
--- a/source/blender/makesrna/intern/rna_access.c
+++ b/source/blender/makesrna/intern/rna_access.c
@@ -241,13 +241,13 @@ static IDProperty *rna_idproperty_ui(PropertyRNA *prop)
IDProperty *idprop;
for (idprop = ((IDProperty *)prop)->prev; idprop; idprop = idprop->prev) {
- if (strcmp(RNA_IDP_UI, idprop->name) == 0)
+ if (STREQ(RNA_IDP_UI, idprop->name))
break;
}
if (idprop == NULL) {
for (idprop = ((IDProperty *)prop)->next; idprop; idprop = idprop->next) {
- if (strcmp(RNA_IDP_UI, idprop->name) == 0)
+ if (STREQ(RNA_IDP_UI, idprop->name))
break;
}
}
@@ -511,7 +511,7 @@ StructRNA *RNA_struct_find(const char *identifier)
StructRNA *type;
if (identifier) {
for (type = BLENDER_RNA.structs.first; type; type = type->cont.next)
- if (strcmp(type->identifier, identifier) == 0)
+ if (STREQ(type->identifier, identifier))
return type;
}
return NULL;
@@ -719,7 +719,7 @@ FunctionRNA *RNA_struct_find_function(StructRNA *srna, const char *identifier)
RNA_PROP_BEGIN (&tptr, funcptr, iterprop)
{
- if (strcmp(identifier, RNA_function_identifier(funcptr.data)) == 0) {
+ if (STREQ(identifier, RNA_function_identifier(funcptr.data))) {
func = funcptr.data;
break;
}
@@ -3229,7 +3229,7 @@ int RNA_property_collection_lookup_string(PointerRNA *ptr, PropertyRNA *prop, co
nameptr = RNA_property_string_get_alloc(&iter.ptr, nameprop, name, sizeof(name), &namelen);
- if ((keylen == namelen) && (strcmp(nameptr, key) == 0)) {
+ if ((keylen == namelen) && STREQ(nameptr, key)) {
*r_ptr = iter.ptr;
found = 1;
}
@@ -5264,7 +5264,7 @@ char *RNA_pointer_as_string_id(bContext *C, PointerRNA *ptr)
{
propname = RNA_property_identifier(prop);
- if (strcmp(propname, "rna_type") == 0)
+ if (STREQ(propname, "rna_type"))
continue;
if (first_time == 0)
@@ -5335,7 +5335,7 @@ char *RNA_pointer_as_string_keywords_ex(bContext *C, PointerRNA *ptr,
arg_name = RNA_property_identifier(prop);
- if (strcmp(arg_name, "rna_type") == 0) {
+ if (STREQ(arg_name, "rna_type")) {
continue;
}
@@ -5632,7 +5632,7 @@ PropertyRNA *RNA_function_find_parameter(PointerRNA *UNUSED(ptr), FunctionRNA *f
parm = func->cont.properties.first;
for (; parm; parm = parm->next)
- if (strcmp(RNA_property_identifier(parm), identifier) == 0)
+ if (STREQ(RNA_property_identifier(parm), identifier))
break;
return parm;
@@ -5830,7 +5830,7 @@ void RNA_parameter_get_lookup(ParameterList *parms, const char *identifier, void
parm = parms->func->cont.properties.first;
for (; parm; parm = parm->next)
- if (strcmp(RNA_property_identifier(parm), identifier) == 0)
+ if (STREQ(RNA_property_identifier(parm), identifier))
break;
if (parm)
@@ -5886,7 +5886,7 @@ void RNA_parameter_set_lookup(ParameterList *parms, const char *identifier, cons
parm = parms->func->cont.properties.first;
for (; parm; parm = parm->next)
- if (strcmp(RNA_property_identifier(parm), identifier) == 0)
+ if (STREQ(RNA_property_identifier(parm), identifier))
break;
if (parm)
@@ -6713,7 +6713,7 @@ bool RNA_property_equals(PointerRNA *a, PointerRNA *b, PropertyRNA *prop, eRNAEq
int len_a, len_b;
char *value_a = RNA_property_string_get_alloc(a, prop, fixed_a, sizeof(fixed_a), &len_a);
char *value_b = RNA_property_string_get_alloc(b, prop, fixed_b, sizeof(fixed_b), &len_b);
- bool equals = strcmp(value_a, value_b) == 0;
+ bool equals = STREQ(value_a, value_b);
if (value_a != fixed_a) MEM_freeN(value_a);
if (value_b != fixed_b) MEM_freeN(value_b);
diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c
index e256d145016..3fed505b9d6 100644
--- a/source/blender/makesrna/intern/rna_action.c
+++ b/source/blender/makesrna/intern/rna_action.c
@@ -533,7 +533,7 @@ static void rna_def_action_groups(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_struct_ui_text(srna, "Action Groups", "Collection of action groups");
func = RNA_def_function(srna, "new", "rna_Action_groups_new");
- RNA_def_function_ui_description(func, "Add a keyframe to the curve");
+ RNA_def_function_ui_description(func, "Create a new action group and add it to the action");
parm = RNA_def_string(func, "name", "Group", 0, "", "New name for the action group");
RNA_def_property_flag(parm, PROP_REQUIRED);
diff --git a/source/blender/makesrna/intern/rna_actuator.c b/source/blender/makesrna/intern/rna_actuator.c
index 6792dd7e5f8..691a7432275 100644
--- a/source/blender/makesrna/intern/rna_actuator.c
+++ b/source/blender/makesrna/intern/rna_actuator.c
@@ -120,14 +120,10 @@ static StructRNA *rna_Actuator_refine(struct PointerRNA *ptr)
static void rna_Actuator_name_set(PointerRNA *ptr, const char *value)
{
- bActuator *act = (bActuator *)ptr->data;
-
+ Object *ob = ptr->id.data;
+ bActuator *act = ptr->data;
BLI_strncpy_utf8(act->name, value, sizeof(act->name));
-
- if (ptr->id.data) {
- Object *ob = (Object *)ptr->id.data;
- BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
- }
+ BLI_uniquename(&ob->actuators, act, DATA_("Actuator"), '.', offsetof(bActuator, name), sizeof(act->name));
}
static void rna_Actuator_type_set(struct PointerRNA *ptr, int value)
@@ -494,11 +490,11 @@ static void rna_Actuator_Armature_update(Main *UNUSED(bmain), Scene *UNUSED(scen
bPoseChannel *pchan;
bPose *pose = ob->pose;
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (!strcmp(pchan->name, posechannel)) {
+ if (STREQ(pchan->name, posechannel)) {
/* found it, now look for constraint channel */
bConstraint *con;
for (con = pchan->constraints.first; con; con = con->next) {
- if (!strcmp(con->name, constraint)) {
+ if (STREQ(con->name, constraint)) {
/* found it, all ok */
return;
}
diff --git a/source/blender/makesrna/intern/rna_animation.c b/source/blender/makesrna/intern/rna_animation.c
index 12fa754e636..e4696d87992 100644
--- a/source/blender/makesrna/intern/rna_animation.c
+++ b/source/blender/makesrna/intern/rna_animation.c
@@ -343,7 +343,7 @@ static void rna_KeyingSet_name_set(PointerRNA *ptr, const char *value)
KeyingSet *ks = (KeyingSet *)ptr->data;
/* update names of corresponding groups if name changes */
- if (strcmp(ks->name, value)) {
+ if (!STREQ(ks->name, value)) {
KS_Path *ksp;
for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
@@ -359,7 +359,7 @@ static void rna_KeyingSet_name_set(PointerRNA *ptr, const char *value)
* conflicts
*/
for (agrp = adt->action->groups.first; agrp; agrp = agrp->next) {
- if (strcmp(ks->name, agrp->name) == 0) {
+ if (STREQ(ks->name, agrp->name)) {
/* there should only be one of these in the action, so can stop... */
BLI_strncpy(agrp->name, value, sizeof(agrp->name));
break;
@@ -554,16 +554,46 @@ static FCurve *rna_Driver_from_existing(AnimData *adt, bContext *C, FCurve *src_
#else
/* helper function for Keying Set -> keying settings */
-/* TODO: use reg option! */
-static void rna_def_common_keying_flags(StructRNA *srna, short UNUSED(reg))
+static void rna_def_common_keying_flags(StructRNA *srna, short reg)
{
PropertyRNA *prop;
-
- prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_sdna(prop, NULL, "keyingflag");
- RNA_def_property_enum_items(prop, keying_flag_items);
- RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
- RNA_def_property_ui_text(prop, "Options", "Keying set options");
+
+ /* override scene/userpref defaults? */
+ prop = RNA_def_property(srna, "use_insertkey_override_needed", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "keyingoverride", INSERTKEY_NEEDED);
+ RNA_def_property_ui_text(prop, "Override Insert Keyframes Default- Only Needed",
+ "Override default setting to only insert keyframes where they're needed in the relevant F-Curves");
+ if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
+ prop = RNA_def_property(srna, "use_insertkey_override_visual", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "keyingoverride", INSERTKEY_MATRIX);
+ RNA_def_property_ui_text(prop, "Override Insert Keyframes Default - Visual",
+ "Override default setting to insert keyframes based on 'visual transforms'");
+ if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
+ prop = RNA_def_property(srna, "use_insertkey_override_xyz_to_rgb", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "keyingoverride", INSERTKEY_XYZ2RGB);
+ RNA_def_property_ui_text(prop, "Override F-Curve Colors - XYZ to RGB",
+ "Override default setting to set color for newly added transformation F-Curves (Location, Rotation, Scale) "
+ "to be based on the transform axis");
+ if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
+
+ /* value to override defaults with */
+ prop = RNA_def_property(srna, "use_insertkey_needed", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_NEEDED);
+ RNA_def_property_ui_text(prop, "Insert Keyframes - Only Needed", "Only insert keyframes where they're needed in the relevant F-Curves");
+ if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
+ prop = RNA_def_property(srna, "use_insertkey_visual", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_MATRIX);
+ RNA_def_property_ui_text(prop, "Insert Keyframes - Visual", "Insert keyframes based on 'visual transforms'");
+ if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
+
+ prop = RNA_def_property(srna, "use_insertkey_xyz_to_rgb", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "keyingflag", INSERTKEY_XYZ2RGB);
+ RNA_def_property_ui_text(prop, "F-Curve Colors - XYZ to RGB", "Color for newly added transformation F-Curves (Location, Rotation, Scale) is based on the transform axis");
+ if (reg) RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
}
/* --- */
@@ -610,7 +640,20 @@ static void rna_def_keyingset_info(BlenderRNA *brna)
RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL);
RNA_def_property_ui_text(prop, "Description", "A short description of the keying set");
- rna_def_common_keying_flags(srna, 1); /* '1' arg here is to indicate that we need these to be set on registering */
+ /* Regarding why we don't use rna_def_common_keying_flags() here:
+ * - Using it would keep this case in sync with the other places
+ * where these options are exposed (which are optimised for being
+ * used in the UI).
+ * - Unlike all the other places, this case is used for defining
+ * new "built in" Keying Sets via the Python API. In that case,
+ * it makes more sense to expose these in a way more similar to
+ * other places featuring bl_idname/label/description (i.e. operators)
+ */
+ prop = RNA_def_property(srna, "bl_options", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "keyingflag");
+ RNA_def_property_enum_items(prop, keying_flag_items);
+ RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL | PROP_ENUM_FLAG);
+ RNA_def_property_ui_text(prop, "Options", "Keying Set options to use when inserting keyframes");
RNA_define_verify_sdna(1);
diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c
index be973ab33f8..5704004b4b6 100644
--- a/source/blender/makesrna/intern/rna_camera.c
+++ b/source/blender/makesrna/intern/rna_camera.c
@@ -137,7 +137,7 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_enum_items(prop, prop_draw_type_extra_items);
RNA_def_property_flag(prop, PROP_ENUM_FLAG);
RNA_def_property_ui_text(prop, "Composition Guides", "Draw overlay");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "sensor_fit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "sensor_fit");
@@ -150,7 +150,7 @@ void RNA_def_camera(BlenderRNA *brna)
prop = RNA_def_property(srna, "passepartout_alpha", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "passepartalpha");
RNA_def_property_ui_text(prop, "Passepartout Alpha", "Opacity (alpha) of the darkened overlay in Camera view");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "angle_x", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_range(prop, DEG2RAD(0.367), DEG2RAD(172.847));
@@ -256,22 +256,27 @@ void RNA_def_camera(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWPASSEPARTOUT);
RNA_def_property_ui_text(prop, "Show Passepartout",
"Show a darkened overlay outside the image area in Camera view");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
- prop = RNA_def_property(srna, "show_title_safe", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWTITLESAFE);
- RNA_def_property_ui_text(prop, "Show Safe Areas", "Show TV title safe and action safe zones in Camera view");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ prop = RNA_def_property(srna, "show_safe_areas", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOW_SAFE_MARGINS);
+ RNA_def_property_ui_text(prop, "Show Safe Areas", "Show TV title safe and action safe areas in Camera view");
+ RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
+
+ prop = RNA_def_property(srna, "show_safe_center", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOW_SAFE_CENTER);
+ RNA_def_property_ui_text(prop, "Show Center-cut safe areas", "Show safe areas to fit content in a different aspect ratio");
+ RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "show_name", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWNAME);
RNA_def_property_ui_text(prop, "Show Name", "Show the active Camera's name in Camera view");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "show_sensor", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CAM_SHOWSENSOR);
RNA_def_property_ui_text(prop, "Show Sensor Size", "Show sensor size (film gate) in Camera view");
- RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL);
+ RNA_def_property_update(prop, NC_CAMERA | ND_DRAW_RENDER_VIEWPORT, NULL);
prop = RNA_def_property(srna, "lens_unit", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag");
diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c
index cecc39c8e15..991020a1574 100644
--- a/source/blender/makesrna/intern/rna_cloth.c
+++ b/source/blender/makesrna/intern/rna_cloth.c
@@ -38,6 +38,8 @@
#include "BKE_cloth.h"
#include "BKE_modifier.h"
+#include "BPH_mass_spring.h"
+
#include "WM_api.h"
#include "WM_types.h"
@@ -268,6 +270,64 @@ static char *rna_ClothCollisionSettings_path(PointerRNA *ptr)
#else
+static void rna_def_cloth_solver_result(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem status_items[] = {
+ {BPH_SOLVER_SUCCESS, "SUCCESS", 0, "Success", "Computation was successful"},
+ {BPH_SOLVER_NUMERICAL_ISSUE, "NUMERICAL_ISSUE", 0, "Numerical Issue", "The provided data did not satisfy the prerequisites"},
+ {BPH_SOLVER_NO_CONVERGENCE, "NO_CONVERGENCE", 0, "No Convergence", "Iterative procedure did not converge"},
+ {BPH_SOLVER_INVALID_INPUT, "INVALID_INPUT", 0, "Invalid Input", "The inputs are invalid, or the algorithm has been improperly called"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "ClothSolverResult", NULL);
+ RNA_def_struct_ui_text(srna, "Solver Result", "Result of cloth solver iteration");
+
+ RNA_define_verify_sdna(0);
+
+ prop = RNA_def_property(srna, "status", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, status_items);
+ RNA_def_property_enum_sdna(prop, NULL, "status");
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Status", "Status of the solver iteration");
+
+ prop = RNA_def_property(srna, "max_error", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "max_error");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Maximum Error", "Maximum error during substeps");
+
+ prop = RNA_def_property(srna, "min_error", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "min_error");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Minimum Error", "Minimum error during substeps");
+
+ prop = RNA_def_property(srna, "avg_error", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "avg_error");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Average Error", "Average error during substeps");
+
+ prop = RNA_def_property(srna, "max_iterations", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "max_iterations");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Maximum Iterations", "Maximum iterations during substeps");
+
+ prop = RNA_def_property(srna, "min_iterations", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "min_iterations");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Minimum Iterations", "Minimum iterations during substeps");
+
+ prop = RNA_def_property(srna, "avg_iterations", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "avg_iterations");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Average Iterations", "Average iterations during substeps");
+
+ RNA_define_verify_sdna(1);
+}
+
static void rna_def_cloth_sim_settings(BlenderRNA *brna)
{
StructRNA *srna;
@@ -325,6 +385,18 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Collider Friction", "");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "density_target", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "density_target");
+ RNA_def_property_range(prop, 0.0f, 10000.0f);
+ RNA_def_property_ui_text(prop, "Target Density", "Maximum density of hair");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
+ prop = RNA_def_property(srna, "density_strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "density_strength");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Target Density Strength", "Influence of target density on the simulation");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
/* mass */
prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_NONE);
@@ -375,7 +447,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
prop = RNA_def_property(srna, "quality", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "stepsPerFrame");
- RNA_def_property_range(prop, 4, 80);
+ RNA_def_property_range(prop, 1, 80);
RNA_def_property_ui_text(prop, "Quality",
"Quality of the simulation in steps per frame (higher is better quality but slower)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
@@ -398,6 +470,13 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shrink Factor Max", "Max amount to shrink cloth by");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "voxel_cell_size", PROP_FLOAT, PROP_UNSIGNED);
+ RNA_def_property_float_sdna(prop, NULL, "voxel_cell_size");
+ RNA_def_property_range(prop, 0.0001f, 10000.0f);
+ RNA_def_property_float_default(prop, 0.1f);
+ RNA_def_property_ui_text(prop, "Voxel Grid Cell Size", "Size of the voxel grid cells for interaction effects");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
/* springs */
prop = RNA_def_property(srna, "use_stiffness_scale", PROP_BOOLEAN, PROP_NONE);
@@ -456,6 +535,13 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Bending Stiffness Maximum", "Maximum bending stiffness value");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "bending_damping", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "bending_damping");
+ RNA_def_property_range(prop, 0.0f, 1000.0f);
+ RNA_def_property_ui_text(prop, "Bending Spring Damping",
+ "Damping of bending motion");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
prop = RNA_def_property(srna, "use_sewing_springs", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flags", CLOTH_SIMSETTINGS_FLAG_SEW);
RNA_def_property_ui_text(prop, "Sew Cloth", "Pulls loose edges together");
@@ -577,6 +663,13 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Friction", "Friction force if a collision happened (higher = less movement)");
RNA_def_property_update(prop, 0, "rna_cloth_update");
+ prop = RNA_def_property(srna, "damping", PROP_FLOAT, PROP_FACTOR);
+ RNA_def_property_float_sdna(prop, NULL, "damping");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_default(prop, 1.0f);
+ RNA_def_property_ui_text(prop, "Restitution", "Amount of velocity lost on collision");
+ RNA_def_property_update(prop, 0, "rna_cloth_update");
+
prop = RNA_def_property(srna, "collision_quality", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "loop_count");
RNA_def_property_range(prop, 1, 20);
@@ -625,6 +718,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna)
void RNA_def_cloth(BlenderRNA *brna)
{
+ rna_def_cloth_solver_result(brna);
rna_def_cloth_sim_settings(brna);
rna_def_cloth_collision_settings(brna);
}
diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c
index 37201eca5f6..5e114a51ceb 100644
--- a/source/blender/makesrna/intern/rna_color.c
+++ b/source/blender/makesrna/intern/rna_color.c
@@ -46,6 +46,8 @@
#include "DNA_material_types.h"
#include "DNA_movieclip_types.h"
#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
#include "DNA_sequence_types.h"
#include "MEM_guardedalloc.h"
@@ -345,6 +347,13 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *
WM_main_add_notifier(NC_LINESTYLE, linestyle);
break;
}
+ case ID_PA:
+ {
+ ParticleSettings *part = ptr->id.data;
+
+ DAG_id_tag_update(&part->id, OB_RECALC_DATA | PSYS_RECALC_REDO);
+ WM_main_add_notifier(NC_OBJECT | ND_PARTICLE | NA_EDITED, part);
+ }
default:
break;
}
diff --git a/source/blender/makesrna/intern/rna_controller.c b/source/blender/makesrna/intern/rna_controller.c
index 8b5074eaf0d..ba0214d36ec 100644
--- a/source/blender/makesrna/intern/rna_controller.c
+++ b/source/blender/makesrna/intern/rna_controller.c
@@ -85,15 +85,10 @@ static StructRNA *rna_Controller_refine(struct PointerRNA *ptr)
static void rna_Constroller_name_set(PointerRNA *ptr, const char *value)
{
- bController *cont = (bController *)ptr->data;
-
+ Object *ob = ptr->id.data;
+ bController *cont = ptr->data;
BLI_strncpy_utf8(cont->name, value, sizeof(cont->name));
-
- if (ptr->id.data) {
- Object *ob = (Object *)ptr->id.data;
- BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name),
- sizeof(cont->name));
- }
+ BLI_uniquename(&ob->controllers, cont, DATA_("Controller"), '.', offsetof(bController, name), sizeof(cont->name));
}
static void rna_Controller_type_set(struct PointerRNA *ptr, int value)
diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c
index 54c08009792..6db1b46ff21 100644
--- a/source/blender/makesrna/intern/rna_define.c
+++ b/source/blender/makesrna/intern/rna_define.c
@@ -65,15 +65,15 @@ BlenderDefRNA DefRNA = {NULL, {NULL, NULL}, {NULL, NULL}, NULL, 0, 0, 0, 1, 1};
/* Duplicated code since we can't link in blenkernel or blenlib */
-/* pedantic check for '.', do this since its a hassle for translators */
+/* pedantic check for final '.', note '...' are allowed though. */
#ifndef NDEBUG
-# define DESCR_CHECK(description, id1, id2) \
- if (description && (description)[0]) { \
- int i = strlen(description); \
- if ((description)[i - 1] == '.') { \
- fprintf(stderr, "%s: '%s' '%s' description ends with a '.' !\n", \
- __func__, id1 ? id1 : "", id2 ? id2 : ""); \
- } \
+# define DESCR_CHECK(description, id1, id2) \
+ if (description && (description)[0]) { \
+ int i = strlen(description); \
+ if (i > 3 && (description)[i - 1] == '.' && (description)[i - 3] != '.') { \
+ fprintf(stderr, "%s: '%s' '%s' description ends with a '.' !\n", \
+ __func__, id1 ? id1 : "", id2 ? id2 : ""); \
+ } \
} (void)0
#else
@@ -109,7 +109,7 @@ PropertyDefRNA *rna_findlink(ListBase *listbase, const char *identifier)
for (link = listbase->first; link; link = link->next) {
PropertyRNA *prop = ((PropertyDefRNA *)link)->prop;
- if (prop && (strcmp(prop->identifier, identifier) == 0)) {
+ if (prop && (STREQ(prop->identifier, identifier))) {
return (PropertyDefRNA *)link;
}
}
@@ -428,7 +428,7 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro
}
for (a = 0; kwlist[a]; a++) {
- if (strcmp(identifier, kwlist[a]) == 0) {
+ if (STREQ(identifier, kwlist[a])) {
strcpy(error, "this keyword is reserved by python");
return 0;
}
@@ -442,7 +442,7 @@ static int rna_validate_identifier(const char *identifier, char *error, bool pro
};
for (a = 0; kwlist_prop[a]; a++) {
- if (strcmp(identifier, kwlist_prop[a]) == 0) {
+ if (STREQ(identifier, kwlist_prop[a])) {
strcpy(error, "this keyword is reserved by python");
return 0;
}
@@ -496,7 +496,7 @@ void RNA_identifier_sanitize(char *identifier, int property)
}
for (a = 0; kwlist[a]; a++) {
- if (strcmp(identifier, kwlist[a]) == 0) {
+ if (STREQ(identifier, kwlist[a])) {
/* this keyword is reserved by python.
* just replace the last character by '_' to keep it readable.
*/
@@ -513,7 +513,7 @@ void RNA_identifier_sanitize(char *identifier, int property)
};
for (a = 0; kwlist_prop[a]; a++) {
- if (strcmp(identifier, kwlist_prop[a]) == 0) {
+ if (STREQ(identifier, kwlist_prop[a])) {
/* this keyword is reserved by python.
* just replace the last character by '_' to keep it readable.
*/
@@ -814,7 +814,7 @@ StructRNA *RNA_def_struct(BlenderRNA *brna, const char *identifier, const char *
if (from) {
/* find struct to derive from */
for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next)
- if (strcmp(srnafrom->identifier, from) == 0)
+ if (STREQ(srnafrom->identifier, from))
break;
if (!srnafrom) {
@@ -896,7 +896,7 @@ void RNA_def_struct_nested(BlenderRNA *brna, StructRNA *srna, const char *struct
/* find struct to derive from */
for (srnafrom = brna->structs.first; srnafrom; srnafrom = srnafrom->cont.next)
- if (strcmp(srnafrom->identifier, structname) == 0)
+ if (STREQ(srnafrom->identifier, structname))
break;
if (!srnafrom) {
@@ -1871,15 +1871,15 @@ void RNA_def_property_int_sdna(PropertyRNA *prop, const char *structname, const
}
/* SDNA doesn't pass us unsigned unfortunately .. */
- if (dp->dnatype && strcmp(dp->dnatype, "char") == 0) {
+ if (dp->dnatype && STREQ(dp->dnatype, "char")) {
iprop->hardmin = iprop->softmin = CHAR_MIN;
iprop->hardmax = iprop->softmax = CHAR_MAX;
}
- else if (dp->dnatype && strcmp(dp->dnatype, "short") == 0) {
+ else if (dp->dnatype && STREQ(dp->dnatype, "short")) {
iprop->hardmin = iprop->softmin = SHRT_MIN;
iprop->hardmax = iprop->softmax = SHRT_MAX;
}
- else if (dp->dnatype && strcmp(dp->dnatype, "int") == 0) {
+ else if (dp->dnatype && STREQ(dp->dnatype, "int")) {
iprop->hardmin = INT_MIN;
iprop->hardmax = INT_MAX;
@@ -1923,7 +1923,7 @@ void RNA_def_property_float_sdna(PropertyRNA *prop, const char *structname, cons
}
}
- if (dp->dnatype && strcmp(dp->dnatype, "char") == 0) {
+ if (dp->dnatype && STREQ(dp->dnatype, "char")) {
fprop->hardmin = fprop->softmin = 0.0f;
fprop->hardmax = fprop->softmax = 1.0f;
}
@@ -2060,7 +2060,7 @@ void RNA_def_property_collection_sdna(PropertyRNA *prop, const char *structname,
}
}
- if (dp->dnatype && strcmp(dp->dnatype, "ListBase") == 0) {
+ if (dp->dnatype && STREQ(dp->dnatype, "ListBase")) {
cprop->next = (PropCollectionNextFunc)"rna_iterator_listbase_next";
cprop->get = (PropCollectionGetFunc)"rna_iterator_listbase_get";
cprop->end = (PropCollectionEndFunc)"rna_iterator_listbase_end";
@@ -3427,7 +3427,7 @@ int RNA_def_property_free_identifier(StructOrFunctionRNA *cont_, const char *ide
PropertyRNA *prop;
for (prop = cont->properties.first; prop; prop = prop->next) {
- if (strcmp(prop->identifier, identifier) == 0) {
+ if (STREQ(prop->identifier, identifier)) {
if (prop->flag & PROP_RUNTIME) {
rna_def_property_free(cont_, prop);
return 1;
diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c
index 3b9078153f3..6c893255601 100644
--- a/source/blender/makesrna/intern/rna_fcurve.c
+++ b/source/blender/makesrna/intern/rna_fcurve.c
@@ -1948,6 +1948,10 @@ static void rna_def_fcurve(BlenderRNA *brna)
parm = RNA_def_pointer(func, "data", "AnyType", "Data",
"Data containing the property controlled by given FCurve");
RNA_def_property_flag(parm, PROP_REQUIRED | PROP_RNAPTR | PROP_NEVER_NULL);
+
+
+ /* Functions */
+ RNA_api_fcurves(srna);
}
/* *********************** */
diff --git a/source/blender/makesrna/intern/rna_fcurve_api.c b/source/blender/makesrna/intern/rna_fcurve_api.c
index ab96f6f384d..8551ca609f4 100644
--- a/source/blender/makesrna/intern/rna_fcurve_api.c
+++ b/source/blender/makesrna/intern/rna_fcurve_api.c
@@ -39,6 +39,7 @@
#include "RNA_define.h"
#include "DNA_anim_types.h"
+#include "DNA_scene_types.h"
#include "rna_internal.h" /* own include */
@@ -49,8 +50,115 @@
#include "BKE_animsys.h"
#include "BKE_fcurve.h"
+#include "BLI_math.h"
+
+static void rna_FCurve_convert_to_samples(FCurve *fcu, ReportList *reports, int start, int end)
+{
+ /* XXX fcurve_store_samples uses end frame included, which is not consistent with usual behavior in Blender,
+ * nor python slices, etc. Let have public py API be consistent here at least. */
+ end--;
+ if (start > end) {
+ BKE_reportf(reports, RPT_ERROR, "Invalid frame range (%d - %d)", start, end + 1);
+ }
+ else if (fcu->fpt) {
+ BKE_report(reports, RPT_WARNING, "FCurve has already sample points");
+ }
+ else if (!fcu->bezt) {
+ BKE_report(reports, RPT_WARNING, "FCurve has no keyframes");
+ }
+ else {
+ fcurve_store_samples(fcu, NULL, start, end, fcurve_samplingcb_evalcurve);
+ WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+}
+
+static void rna_FCurve_convert_to_keyframes(FCurve *fcu, ReportList *reports, int start, int end)
+{
+ if (start >= end) {
+ BKE_reportf(reports, RPT_ERROR, "Invalid frame range (%d - %d)", start, end);
+ }
+ else if (fcu->bezt) {
+ BKE_report(reports, RPT_WARNING, "FCurve has already keyframes");
+ }
+ else if (!fcu->fpt) {
+ BKE_report(reports, RPT_WARNING, "FCurve has no sample points");
+ }
+ else {
+ BezTriple *bezt;
+ FPoint *fpt = fcu->fpt;
+ int tot_kf = end - start;
+ int tot_sp = fcu->totvert;
+
+ bezt = fcu->bezt = MEM_callocN(sizeof(*fcu->bezt) * (size_t)tot_kf, __func__);
+ fcu->totvert = tot_kf;
+
+ /* Get first sample point to 'copy' as keyframe. */
+ for (; tot_sp && (fpt->vec[0] < (float)start); fpt++, tot_sp--);
+
+ /* Add heading dummy flat points if needed. */
+ for (; tot_kf && (fpt->vec[0] > (float)start); start++, bezt++, tot_kf--) {
+ /* Linear interpolation, of course. */
+ bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
+ bezt->ipo = BEZT_IPO_LIN;
+ bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
+ bezt->vec[1][0] = (float)start;
+ bezt->vec[1][1] = fpt->vec[1];
+ }
+
+ /* Copy actual sample points. */
+ for (; tot_kf && tot_sp; start++, bezt++, tot_kf--, fpt++, tot_sp--) {
+ /* Linear interpolation, of course. */
+ bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
+ bezt->ipo = BEZT_IPO_LIN;
+ bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
+ copy_v2_v2(bezt->vec[1], fpt->vec);
+ }
+
+ /* Add leading dummy flat points if needed. */
+ for (fpt--; tot_kf; start++, bezt++, tot_kf--) {
+ /* Linear interpolation, of course. */
+ bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
+ bezt->ipo = BEZT_IPO_LIN;
+ bezt->h1 = bezt->h2 = HD_AUTO_ANIM;
+ bezt->vec[1][0] = (float)start;
+ bezt->vec[1][1] = fpt->vec[1];
+ }
+
+ MEM_SAFE_FREE(fcu->fpt);
+
+ /* Not strictly needed since we use linear interpolation, but better be consistent here. */
+ calchandles_fcurve(fcu);
+ WM_main_add_notifier(NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+ }
+}
+
#else
+void RNA_api_fcurves(StructRNA *srna)
+{
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ func = RNA_def_function(srna, "convert_to_samples", "rna_FCurve_convert_to_samples");
+ RNA_def_function_ui_description(func,
+ "Convert current FCurve from keyframes to sample points, if necessary");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_int(func, "start", 0, MINAFRAME, MAXFRAME, "Start Frame", "", MINAFRAME, MAXFRAME);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_int(func, "end", 0, MINAFRAME, MAXFRAME, "End Frame", "", MINAFRAME, MAXFRAME);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ func = RNA_def_function(srna, "convert_to_keyframes", "rna_FCurve_convert_to_keyframes");
+ RNA_def_function_ui_description(func,
+ "Convert current FCurve from sample points to keyframes (linear interpolation), "
+ "if necessary");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_int(func, "start", 0, MINAFRAME, MAXFRAME, "Start Frame", "", MINAFRAME, MAXFRAME);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+ parm = RNA_def_int(func, "end", 0, MINAFRAME, MAXFRAME, "End Frame", "", MINAFRAME, MAXFRAME);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+}
+
void RNA_api_drivers(StructRNA *UNUSED(srna))
{
/* FunctionRNA *func; */
diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c
index b1935b34251..5ab6d1a231b 100644
--- a/source/blender/makesrna/intern/rna_image.c
+++ b/source/blender/makesrna/intern/rna_image.c
@@ -193,7 +193,7 @@ static int rna_Image_file_format_get(PointerRNA *ptr)
{
Image *image = (Image *)ptr->data;
ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
- int imtype = BKE_ftype_to_imtype(ibuf ? ibuf->ftype : 0);
+ int imtype = BKE_image_ftype_to_imtype(ibuf ? ibuf->ftype : 0);
BKE_image_release_ibuf(image, ibuf, NULL);
@@ -204,7 +204,7 @@ static void rna_Image_file_format_set(PointerRNA *ptr, int value)
{
Image *image = (Image *)ptr->data;
if (BKE_imtype_is_movie(value) == 0) { /* should be able to throw an error here */
- int ftype = BKE_imtype_to_ftype(value);
+ int ftype = BKE_image_imtype_to_ftype(value);
BKE_image_file_format_set(image, ftype);
}
}
@@ -640,6 +640,11 @@ static void rna_def_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Use Alpha", "Use the alpha channel information from the image or make image fully opaque");
RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_colormanage_update");
+ prop = RNA_def_property(srna, "use_deinterlace", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", IMA_DEINTERLACE);
+ RNA_def_property_ui_text(prop, "Deinterlace", "Deinterlace movie file on load");
+ RNA_def_property_update(prop, NC_IMAGE | ND_DISPLAY, "rna_Image_reload_update");
+
prop = RNA_def_property(srna, "is_dirty", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_funcs(prop, "rna_Image_dirty_get", NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
diff --git a/source/blender/makesrna/intern/rna_image_api.c b/source/blender/makesrna/intern/rna_image_api.c
index 90f90ea8632..5fc65ea385c 100644
--- a/source/blender/makesrna/intern/rna_image_api.c
+++ b/source/blender/makesrna/intern/rna_image_api.c
@@ -52,8 +52,6 @@
#include "BKE_packedFile.h"
#include "BKE_main.h"
-#include "BKE_global.h" /* grr: G.main->name */
-
#include "IMB_imbuf.h"
#include "IMB_colormanagement.h"
@@ -109,13 +107,13 @@ static void rna_Image_save_render(Image *image, bContext *C, ReportList *reports
}
}
-static void rna_Image_save(Image *image, bContext *C, ReportList *reports)
+static void rna_Image_save(Image *image, Main *bmain, 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, ID_BLEND_PATH(G.main, &image->id));
+ BLI_path_abs(filename, ID_BLEND_PATH(bmain, &image->id));
if (image->packedfile) {
if (writePackedFile(reports, image->name, image->packedfile, 0) != RET_OK) {
@@ -144,7 +142,9 @@ static void rna_Image_save(Image *image, bContext *C, ReportList *reports)
WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, image);
}
-static void rna_Image_pack(Image *image, bContext *C, ReportList *reports, int as_png)
+static void rna_Image_pack(
+ Image *image, Main *bmain, bContext *C, ReportList *reports,
+ int as_png, const char *data, int data_len)
{
ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, NULL);
@@ -152,11 +152,20 @@ static void rna_Image_pack(Image *image, bContext *C, ReportList *reports, int a
BKE_report(reports, RPT_ERROR, "Cannot pack edited image from disk, only as internal PNG");
}
else {
+ if (image->packedfile) {
+ freePackedFile(image->packedfile);
+ image->packedfile = NULL;
+ }
if (as_png) {
BKE_image_memorypack(image);
}
+ else if (data) {
+ char *data_dup = MEM_mallocN(sizeof(*data_dup) * (size_t)data_len, __func__);
+ memcpy(data_dup, data, (size_t)data_len);
+ image->packedfile = newPackedFileMemory(data_dup, data_len);
+ }
else {
- image->packedfile = newPackedFile(reports, image->name, ID_BLEND_PATH(G.main, &image->id));
+ image->packedfile = newPackedFile(reports, image->name, ID_BLEND_PATH(bmain, &image->id));
}
}
@@ -301,12 +310,16 @@ 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_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_flag(func, FUNC_USE_MAIN | 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_CONTEXT | FUNC_USE_REPORTS);
+ RNA_def_function_flag(func, FUNC_USE_MAIN | 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)");
+ parm = RNA_def_property(func, "data", PROP_STRING, PROP_BYTESTRING);
+ RNA_def_property_ui_text(parm, "data", "Raw data (bytes, exact content of the embedded file)");
+ RNA_def_int(func, "data_len", 0, 0, INT_MAX,
+ "data_len", "length of given data (mandatory if data is provided)", 0, INT_MAX);
func = RNA_def_function(srna, "unpack", "rna_Image_unpack");
RNA_def_function_ui_description(func, "Save an image packed in the .blend file to disk");
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 2c00b70d1a9..e4aaa705fe0 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -260,6 +260,7 @@ void RNA_api_armature_edit_bone(StructRNA *srna);
void RNA_api_bone(StructRNA *srna);
void RNA_api_camera(StructRNA *srna);
void RNA_api_curve(StructRNA *srna);
+void RNA_api_fcurves(StructRNA *srna);
void RNA_api_drivers(StructRNA *srna);
void RNA_api_image(struct StructRNA *srna);
void RNA_api_lattice(struct StructRNA *srna);
@@ -297,6 +298,8 @@ void RNA_api_texture(struct StructRNA *srna);
void RNA_api_environment_map(struct StructRNA *srna);
void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop);
void RNA_api_sequence_elements(BlenderRNA *brna, PropertyRNA *cprop);
+void RNA_api_sound(struct StructRNA *srna);
+void RNA_api_vfont(struct StructRNA *srna);
/* main collection functions */
void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop);
diff --git a/source/blender/makesrna/intern/rna_material.c b/source/blender/makesrna/intern/rna_material.c
index 2e4f24fc0ce..7a06b647ae3 100644
--- a/source/blender/makesrna/intern/rna_material.c
+++ b/source/blender/makesrna/intern/rna_material.c
@@ -181,7 +181,7 @@ static void rna_Material_active_paint_texture_index_update(Main *bmain, Scene *s
bScreen *sc;
Material *ma = ptr->id.data;
- if (ma->use_nodes && ma->nodetree && BKE_scene_use_new_shading_nodes(scene)) {
+ if (ma->use_nodes && ma->nodetree) {
struct bNode *node;
int index = 0;
for (node = ma->nodetree->nodes.first; node; node = node->next) {
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index 3d6eab2bc88..44bae770186 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -207,6 +207,11 @@ static void rna_MeshAnyLayer_name_set(PointerRNA *ptr, const char *value)
rna_cd_layer_name_set(cd, (CustomDataLayer *)ptr->data, value);
}
+static int rna_Mesh_has_custom_normals_get(PointerRNA *ptr)
+{
+ Mesh *me = ptr->data;
+ return (int)BKE_mesh_has_custom_loop_normals(me);
+}
/* -------------------------------------------------------------------- */
/* Update Callbacks */
@@ -338,6 +343,17 @@ static void rna_MeshLoop_normal_get(PointerRNA *ptr, float *values)
}
}
+static void rna_MeshLoop_normal_set(PointerRNA *ptr, const float *values)
+{
+ Mesh *me = rna_mesh(ptr);
+ MLoop *ml = (MLoop *)ptr->data;
+ float (*vec)[3] = CustomData_get(&me->ldata, (int)(ml - me->mloop), CD_NORMAL);
+
+ if (vec) {
+ normalize_v3_v3(*vec, values);
+ }
+}
+
static void rna_MeshLoop_tangent_get(PointerRNA *ptr, float *values)
{
Mesh *me = rna_mesh(ptr);
@@ -1974,8 +1990,7 @@ static void rna_def_mloop(BlenderRNA *brna)
prop = RNA_def_property(srna, "normal", PROP_FLOAT, PROP_DIRECTION);
RNA_def_property_array(prop, 3);
RNA_def_property_range(prop, -1.0f, 1.0f);
- RNA_def_property_clear_flag(prop, PROP_EDITABLE);
- RNA_def_property_float_funcs(prop, "rna_MeshLoop_normal_get", NULL, NULL);
+ RNA_def_property_float_funcs(prop, "rna_MeshLoop_normal_get", "rna_MeshLoop_normal_set", NULL);
RNA_def_property_ui_text(prop, "Normal",
"Local space unit length split normal vector of this vertex for this polygon "
"(must be computed beforehand using calc_normals_split or calc_tangents)");
@@ -3186,8 +3201,8 @@ static void rna_def_mesh(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_auto_smooth", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_AUTOSMOOTH);
RNA_def_property_ui_text(prop, "Auto Smooth",
- "Treat all set-smoothed faces with angles less than the specified angle "
- "as 'smooth', unless they are linked by a sharp edge");
+ "Auto smooth (based on smooth/sharp faces/edges and angle between faces), "
+ "or use custom split normals data if available");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
prop = RNA_def_property(srna, "auto_smooth_angle", PROP_FLOAT, PROP_ANGLE);
@@ -3196,9 +3211,19 @@ static void rna_def_mesh(BlenderRNA *brna)
RNA_def_property_range(prop, 0.0f, DEG2RADF(180.0f));
RNA_def_property_ui_range(prop, DEG2RADF(0.0f), DEG2RADF(180.0f), 1.0, 1);
RNA_def_property_ui_text(prop, "Auto Smooth Angle",
- "Maximum angle between face normals that 'Auto Smooth' will operate on");
+ "Maximum angle between face normals that will be considered as smooth "
+ "(unused if custom split normals data are available)");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
+ RNA_define_verify_sdna(false);
+ prop = RNA_def_property(srna, "has_custom_normals", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "", 0);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Has Custom Normals",
+ "True if there are custom split normals data in this mesh");
+ RNA_def_property_boolean_funcs(prop, "rna_Mesh_has_custom_normals_get", NULL);
+ RNA_define_verify_sdna(true);
+
prop = RNA_def_property(srna, "show_double_sided", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_TWOSIDED);
RNA_def_property_ui_text(prop, "Double Sided", "Render/display the mesh with double or single sided lighting");
diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c
index cc1f57d8a14..53704e24bff 100644
--- a/source/blender/makesrna/intern/rna_mesh_api.c
+++ b/source/blender/makesrna/intern/rna_mesh_api.c
@@ -61,10 +61,19 @@ static const char *rna_Mesh_unit_test_compare(struct Mesh *mesh, struct Mesh *me
return ret;
}
-static void rna_Mesh_calc_normals_split(Mesh *mesh, float min_angle)
+static void rna_Mesh_create_normals_split(Mesh *mesh)
+{
+ if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
+ CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop);
+ CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
+ }
+}
+
+static void rna_Mesh_calc_normals_split(Mesh *mesh)
{
float (*r_loopnors)[3];
float (*polynors)[3];
+ short (*clnors)[2] = NULL;
bool free_polynors = false;
if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
@@ -76,6 +85,9 @@ static void rna_Mesh_calc_normals_split(Mesh *mesh, float min_angle)
CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
}
+ /* may be NULL */
+ clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
+
if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
/* This assume that layer is always up to date, not sure this is the case (esp. in Edit mode?)... */
polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
@@ -88,9 +100,10 @@ static void rna_Mesh_calc_normals_split(Mesh *mesh, float min_angle)
free_polynors = true;
}
- BKE_mesh_normals_loop_split(mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
- mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, polynors, mesh->totpoly,
- min_angle);
+ BKE_mesh_normals_loop_split(
+ mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge,
+ mesh->mloop, r_loopnors, mesh->totloop, mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly,
+ (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, NULL, clnors, NULL);
if (free_polynors) {
MEM_freeN(polynors);
@@ -117,7 +130,7 @@ static void rna_Mesh_calc_tangents(Mesh *mesh, ReportList *reports, const char *
/* Compute loop normals if needed. */
if (!CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
- rna_Mesh_calc_normals_split(mesh, (float)M_PI);
+ rna_Mesh_calc_normals_split(mesh);
}
BKE_mesh_loop_tangents(mesh, uvmap, r_looptangents, reports);
@@ -139,6 +152,78 @@ static void rna_Mesh_calc_smooth_groups(Mesh *mesh, int use_bitflags, int *r_pol
r_group_total, use_bitflags);
}
+static void rna_Mesh_normals_split_custom_do(Mesh *mesh, float (*custom_loopnors)[3], const bool use_vertices)
+{
+ float (*polynors)[3];
+ short (*clnors)[2];
+ const int numloops = mesh->totloop;
+ bool free_polynors = false;
+
+ clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
+ if (clnors) {
+ memset(clnors, 0, sizeof(*clnors) * numloops);
+ }
+ else {
+ clnors = CustomData_add_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, numloops);
+ }
+
+ if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) {
+ polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL);
+ }
+ else {
+ polynors = MEM_mallocN(sizeof(float[3]) * mesh->totpoly, __func__);
+ BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly,
+ polynors, false);
+ free_polynors = true;
+ }
+
+ if (use_vertices) {
+ BKE_mesh_normals_loop_custom_from_vertices_set(
+ mesh->mvert, custom_loopnors, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, mesh->totloop,
+ mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, clnors);
+ }
+ else {
+ BKE_mesh_normals_loop_custom_set(
+ mesh->mvert, mesh->totvert, mesh->medge, mesh->totedge, mesh->mloop, custom_loopnors, mesh->totloop,
+ mesh->mpoly, (const float (*)[3])polynors, mesh->totpoly, clnors);
+ }
+
+ if (free_polynors) {
+ MEM_freeN(polynors);
+ }
+}
+
+static void rna_Mesh_normals_split_custom_set(Mesh *mesh, ReportList *reports, int normals_len, float *normals)
+{
+ float (*loopnors)[3] = (float (*)[3])normals;
+ const int numloops = mesh->totloop;
+
+ if (normals_len != numloops * 3) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Number of custom normals is not number of loops (%f / %d)",
+ (float)normals_len / 3.0f, numloops);
+ return;
+ }
+
+ rna_Mesh_normals_split_custom_do(mesh, loopnors, false);
+}
+
+static void rna_Mesh_normals_split_custom_set_from_vertices(
+ Mesh *mesh, ReportList *reports, int normals_len, float *normals)
+{
+ float (*vertnors)[3] = (float (*)[3])normals;
+ const int numverts = mesh->totvert;
+
+ if (normals_len != numverts * 3) {
+ BKE_reportf(reports, RPT_ERROR,
+ "Number of custom normals is not number of vertices (%f / %d)",
+ (float)normals_len / 3.0f, numverts);
+ return;
+ }
+
+ rna_Mesh_normals_split_custom_do(mesh, vertnors, true);
+}
+
static void rna_Mesh_transform(Mesh *mesh, float *mat, int shape_keys)
{
BKE_mesh_transform(mesh, (float (*)[4])mat, shape_keys);
@@ -152,6 +237,7 @@ void RNA_api_mesh(StructRNA *srna)
{
FunctionRNA *func;
PropertyRNA *parm;
+ const int normals_array_dim[] = {1, 3};
func = RNA_def_function(srna, "transform", "rna_Mesh_transform");
RNA_def_function_ui_description(func, "Transform mesh vertices by a matrix");
@@ -162,12 +248,11 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "calc_normals", "BKE_mesh_calc_normals");
RNA_def_function_ui_description(func, "Calculate vertex normals");
+ func = RNA_def_function(srna, "create_normals_split", "rna_Mesh_create_normals_split");
+ RNA_def_function_ui_description(func, "Empty split vertex normals");
+
func = RNA_def_function(srna, "calc_normals_split", "rna_Mesh_calc_normals_split");
RNA_def_function_ui_description(func, "Calculate split vertex normals, which preserve sharp edges");
- parm = RNA_def_float(func, "split_angle", M_PI, 0.0f, M_PI, "",
- "Angle between polys' normals above which an edge is always sharp (180° to disable)",
- 0.0f, M_PI);
- RNA_def_property_subtype(parm, (PropertySubType)PROP_UNIT_ROTATION);
func = RNA_def_function(srna, "free_normals_split", "rna_Mesh_free_normals_split");
RNA_def_function_ui_description(func, "Free split vertex normals");
@@ -196,6 +281,26 @@ void RNA_api_mesh(StructRNA *srna)
parm = RNA_def_int(func, "groups", 0, 0, INT_MAX, "groups", "Total number of groups", 0, INT_MAX);
RNA_def_property_flag(parm, PROP_OUTPUT);
+ func = RNA_def_function(srna, "normals_split_custom_set", "rna_Mesh_normals_split_custom_set");
+ RNA_def_function_ui_description(func,
+ "Define custom split normals of this mesh "
+ "(use zero-vectors to keep auto ones)");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ /* TODO, see how array size of 0 works, this shouldnt be used */
+ parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f);
+ RNA_def_property_multi_array(parm, 2, normals_array_dim);
+ RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_REQUIRED);
+
+ func = RNA_def_function(srna, "normals_split_custom_set_from_vertices",
+ "rna_Mesh_normals_split_custom_set_from_vertices");
+ RNA_def_function_ui_description(func,
+ "Define custom split normals of this mesh, from vertices' normals "
+ "(use zero-vectors to keep auto ones)");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ /* TODO, see how array size of 0 works, this shouldnt be used */
+ parm = RNA_def_float_array(func, "normals", 1, NULL, -1.0f, 1.0f, "", "Normals", 0.0f, 0.0f);
+ RNA_def_property_multi_array(parm, 2, normals_array_dim);
+ RNA_def_property_flag(parm, PROP_DYNAMIC | PROP_REQUIRED);
func = RNA_def_function(srna, "update", "ED_mesh_update");
RNA_def_boolean(func, "calc_edges", 0, "Calculate Edges", "Force recalculation of edges");
@@ -211,7 +316,9 @@ void RNA_api_mesh(StructRNA *srna)
func = RNA_def_function(srna, "validate", "BKE_mesh_validate");
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");
+ RNA_def_boolean(func, "verbose", false, "Verbose", "Output information about the errors found");
+ RNA_def_boolean(func, "cleanup_cddata", true, "Cleanup CDData",
+ "Remove temp/cached cdlayers, like e.g. normals...");
parm = RNA_def_boolean(func, "result", 0, "Result", "");
RNA_def_function_return(func, parm);
diff --git a/source/blender/makesrna/intern/rna_mesh_utils.h b/source/blender/makesrna/intern/rna_mesh_utils.h
index c0ea1a153ff..f68a48c075b 100644
--- a/source/blender/makesrna/intern/rna_mesh_utils.h
+++ b/source/blender/makesrna/intern/rna_mesh_utils.h
@@ -20,7 +20,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file blender/source/blender/makesrna/intern/rna_mesh_utils.h
+/** \file blender/makesrna/intern/rna_mesh_utils.h
* \ingroup RNA
*/
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index d8d27a06bb5..b9aad6f5b42 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -46,6 +46,7 @@
#include "BKE_data_transfer.h"
#include "BKE_DerivedMesh.h"
#include "BKE_dynamicpaint.h"
+#include "BKE_effect.h"
#include "BKE_mesh_mapping.h"
#include "BKE_mesh_remap.h"
#include "BKE_multires.h"
@@ -62,9 +63,10 @@
EnumPropertyItem modifier_type_items[] = {
{0, "", 0, N_("Modify"), ""},
- {eModifierType_DataTransfer, "DATA_TRANSFER", ICON_MOD_DATA_TRANSFER, "Data Transfer", ""},
+ {eModifierType_DataTransfer, "DATA_TRANSFER", ICON_MOD_DATA_TRANSFER, "Data Transfer", ""},
{eModifierType_MeshCache, "MESH_CACHE", ICON_MOD_MESHDEFORM, "Mesh Cache", ""},
{eModifierType_PointCache, "POINT_CACHE", ICON_MOD_MESHDEFORM, "Point Cache", ""},
+ {eModifierType_NormalEdit, "NORMAL_EDIT", ICON_MOD_NORMALEDIT, "Normal Edit", ""},
{eModifierType_UVProject, "UV_PROJECT", ICON_MOD_UVPROJECT, "UV Project", ""},
{eModifierType_UVWarp, "UV_WARP", ICON_MOD_UVPROJECT, "UV Warp", ""},
{eModifierType_WeightVGEdit, "VERTEX_WEIGHT_EDIT", ICON_MOD_VERTEX_WEIGHT, "Vertex Weight Edit", ""},
@@ -134,6 +136,22 @@ EnumPropertyItem modifier_triangulate_ngon_method_items[] = {
{0, NULL, 0, NULL, NULL}
};
+#ifndef RNA_RUNTIME
+/* use eWarp_Falloff_*** & eHook_Falloff_***, they're in sync */
+static EnumPropertyItem modifier_warp_falloff_items[] = {
+ {eWarp_Falloff_None, "NONE", 0, "No Falloff", ""},
+ {eWarp_Falloff_Curve, "CURVE", 0, "Curve", ""},
+ {eWarp_Falloff_Smooth, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
+ {eWarp_Falloff_Sphere, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
+ {eWarp_Falloff_Root, "ROOT", ICON_ROOTCURVE, "Root", ""},
+ {eWarp_Falloff_InvSquare, "INVERSE_SQUARE", ICON_ROOTCURVE, "Inverse Square", ""},
+ {eWarp_Falloff_Sharp, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
+ {eWarp_Falloff_Linear, "LINEAR", ICON_LINCURVE, "Linear", ""},
+ {eWarp_Falloff_Const, "CONSTANT", ICON_NOCURVE, "Constant", ""},
+ {0, NULL, 0, NULL, NULL}
+};
+#endif
+
/* ***** Data Transfer ***** */
EnumPropertyItem DT_method_vertex_items[] = {
@@ -358,6 +376,8 @@ static StructRNA *rna_Modifier_refine(struct PointerRNA *ptr)
return &RNA_WireframeModifier;
case eModifierType_DataTransfer:
return &RNA_DataTransferModifier;
+ case eModifierType_NormalEdit:
+ return &RNA_NormalEditModifier;
case eModifierType_PointCache:
return &RNA_PointCacheModifier;
/* Default */
@@ -434,6 +454,7 @@ RNA_MOD_VGROUP_NAME_SET(LaplacianSmooth, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Lattice, name);
RNA_MOD_VGROUP_NAME_SET(Mask, vgroup);
RNA_MOD_VGROUP_NAME_SET(MeshDeform, defgrp_name);
+RNA_MOD_VGROUP_NAME_SET(NormalEdit, defgrp_name);
RNA_MOD_VGROUP_NAME_SET(Shrinkwrap, vgroup_name);
RNA_MOD_VGROUP_NAME_SET(SimpleDeform, vgroup_name);
RNA_MOD_VGROUP_NAME_SET(Smooth, defgrp_name);
@@ -520,6 +541,7 @@ RNA_MOD_OBJECT_SET(DataTransfer, ob_source, OB_MESH);
RNA_MOD_OBJECT_SET(Lattice, object, OB_LATTICE);
RNA_MOD_OBJECT_SET(Mask, ob_arm, OB_ARMATURE);
RNA_MOD_OBJECT_SET(MeshDeform, object, OB_MESH);
+RNA_MOD_OBJECT_SET(NormalEdit, target, OB_EMPTY);
RNA_MOD_OBJECT_SET(Shrinkwrap, target, OB_MESH);
RNA_MOD_OBJECT_SET(Shrinkwrap, auxTarget, OB_MESH);
@@ -613,7 +635,7 @@ static void rna_MultiresModifier_filepath_set(PointerRNA *ptr, const char *value
Object *ob = (Object *)ptr->id.data;
CustomDataExternal *external = ((Mesh *)ob->data)->ldata.external;
- if (external && strcmp(external->filename, value)) {
+ if (external && !STREQ(external->filename, value)) {
BLI_strncpy(external->filename, value, sizeof(external->filename));
multires_force_external_reload(ob);
}
@@ -1113,18 +1135,6 @@ static void rna_def_modifier_warp(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
- static EnumPropertyItem prop_falloff_items[] = {
- {eWarp_Falloff_None, "NONE", 0, "No Falloff", ""},
- {eWarp_Falloff_Curve, "CURVE", 0, "Curve", ""},
- {eWarp_Falloff_Smooth, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
- {eWarp_Falloff_Sphere, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
- {eWarp_Falloff_Root, "ROOT", ICON_ROOTCURVE, "Root", ""},
- {eWarp_Falloff_Sharp, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
- {eWarp_Falloff_Linear, "LINEAR", ICON_LINCURVE, "Linear", ""},
- {eWarp_Falloff_Const, "CONSTANT", ICON_NOCURVE, "Constant", ""},
- {0, NULL, 0, NULL, NULL}
- };
-
srna = RNA_def_struct(brna, "WarpModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Warp Modifier", "Warp modifier");
RNA_def_struct_sdna(srna, "WarpModifierData");
@@ -1147,7 +1157,7 @@ static void rna_def_modifier_warp(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "falloff_type", PROP_ENUM, PROP_NONE);
- RNA_def_property_enum_items(prop, prop_falloff_items);
+ RNA_def_property_enum_items(prop, modifier_warp_falloff_items);
RNA_def_property_ui_text(prop, "Falloff Type", "");
RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@@ -1679,15 +1689,28 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "HookModifierData");
RNA_def_struct_ui_icon(srna, ICON_HOOK);
- prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_DISTANCE);
+ prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "force");
+ RNA_def_property_range(prop, 0, 1);
+ RNA_def_property_ui_text(prop, "Strength", "Relative force of the hook");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "falloff_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, modifier_warp_falloff_items); /* share the enum */
+ RNA_def_property_ui_text(prop, "Falloff Type", "");
+ RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "falloff_radius", PROP_FLOAT, PROP_DISTANCE);
+ RNA_def_property_float_sdna(prop, NULL, "falloff");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 100, 2);
- RNA_def_property_ui_text(prop, "Falloff", "If not zero, the distance from the hook where influence ends");
+ RNA_def_property_ui_text(prop, "Radius", "If not zero, the distance from the hook where influence ends");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
- prop = RNA_def_property(srna, "force", PROP_FLOAT, PROP_NONE);
- RNA_def_property_range(prop, 0, 1);
- RNA_def_property_ui_text(prop, "Force", "Relative force of the hook");
+ prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
+ RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Lamp Falloff Curve");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
@@ -1707,6 +1730,11 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
"Name of Parent Bone for hook (if applicable), also recalculates and clears offset");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+ prop = RNA_def_property(srna, "use_falloff_uniform", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_HOOK_UNIFORM_SPACE);
+ RNA_def_property_ui_text(prop, "Uniform Falloff", "Compensate for non-uniform object scale");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "Vertex Group",
@@ -2468,9 +2496,29 @@ static void rna_def_modifier_cloth(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "coll_parms");
RNA_def_property_ui_text(prop, "Cloth Collision Settings", "");
+ prop = RNA_def_property(srna, "solver_result", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "ClothSolverResult");
+ RNA_def_property_pointer_sdna(prop, NULL, "solver_result");
+ RNA_def_property_ui_text(prop, "Solver Result", "");
+
prop = RNA_def_property(srna, "point_cache", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_NEVER_NULL);
RNA_def_property_ui_text(prop, "Point Cache", "");
+
+ prop = RNA_def_property(srna, "hair_grid_min", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "hair_grid_min");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Hair Grid Minimum", "");
+
+ prop = RNA_def_property(srna, "hair_grid_max", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "hair_grid_max");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Hair Grid Maximum", "");
+
+ prop = RNA_def_property(srna, "hair_grid_resolution", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "hair_grid_res");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Hair Grid Resolution", "");
}
static void rna_def_modifier_smoke(BlenderRNA *brna)
@@ -3158,24 +3206,24 @@ static void rna_def_modifier_uvwarp(BlenderRNA *brna)
prop = RNA_def_property(srna, "object_from", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "object_src");
- RNA_def_property_ui_text(prop, "Target", "Object defining offset");
+ RNA_def_property_ui_text(prop, "Object From", "Object defining offset");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "bone_from", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "bone_src");
- RNA_def_property_ui_text(prop, "Sub-Target", "Bone defining offset");
+ RNA_def_property_ui_text(prop, "Bone From", "Bone defining offset");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "object_to", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "object_dst");
- RNA_def_property_ui_text(prop, "Target", "Object defining offset");
+ RNA_def_property_ui_text(prop, "Object To", "Object defining offset");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "bone_to", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "bone_dst");
- RNA_def_property_ui_text(prop, "Sub-Target", "Bone defining offset");
+ RNA_def_property_ui_text(prop, "Bone To", "Bone defining offset");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
@@ -4108,6 +4156,7 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
};
static EnumPropertyItem DT_layer_loop_items[] = {
+ {DT_TYPE_LNOR, "CUSTOM_NORMAL", 0, "Custom Normals", "Transfer custom normals"},
{0, NULL, 0, NULL, NULL}
};
static EnumPropertyItem DT_layer_loop_vcol_items[] = {
@@ -4320,6 +4369,77 @@ static void rna_def_modifier_datatransfer(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
+static void rna_def_modifier_normaledit(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static EnumPropertyItem prop_mode_items[] = {
+ {MOD_NORMALEDIT_MODE_RADIAL, "RADIAL", 0, "Radial",
+ "From an ellipsoid (shape defined by the boundbox's dimensions, target is optional)"},
+ {MOD_NORMALEDIT_MODE_DIRECTIONAL, "DIRECTIONAL", 0, "Directional",
+ "Normals 'track' (point to) the target object"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ static EnumPropertyItem prop_mix_mode_items[] = {
+ {MOD_NORMALEDIT_MIX_COPY, "COPY", 0, "Copy", "Copy new normals (overwrite existing)"},
+ {MOD_NORMALEDIT_MIX_ADD, "ADD", 0, "Add", "Copy sum of new and old normals"},
+ {MOD_NORMALEDIT_MIX_SUB, "SUB", 0, "Subtract", "Copy new normals minus old normals"},
+ {MOD_NORMALEDIT_MIX_MUL, "MUL", 0, "Multiply", "Copy product of old and new normals (*not* cross product)"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
+ srna = RNA_def_struct(brna, "NormalEditModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Normal Edit Modifier", "Modifier affecting/generating custom normals");
+ RNA_def_struct_sdna(srna, "NormalEditModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MOD_NORMALEDIT);
+
+ prop = RNA_def_property(srna, "mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "How to affect (generate) normals");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_float_array(srna, "offset", 3, NULL, -FLT_MAX, FLT_MAX, "Offset",
+ "Offset from object's center", -100.0f, 100.0f);
+ RNA_def_property_subtype(prop, PROP_COORDS);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "mix_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, prop_mix_mode_items);
+ RNA_def_property_ui_text(prop, "Mix Mode", "How to mix generated normals with existing ones");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_float(srna, "mix_factor", 1.0f, 0.0f, 1.0f, "Mix Factor",
+ "How much of generated normals to mix with exiting ones", 0.0f, 1.0f);
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_sdna(prop, NULL, "defgrp_name");
+ RNA_def_property_ui_text(prop, "Vertex Group", "Vertex group name for selecting/weighting the affected areas");
+ RNA_def_property_string_funcs(prop, NULL, NULL, "rna_NormalEditModifier_defgrp_name_set");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "use_invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_NORMALEDIT_INVERT_VGROUP);
+ RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "target", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Target", "Target object used to affect normals");
+ RNA_def_property_pointer_funcs(prop, NULL, "rna_NormalEditModifier_target_set", NULL, NULL);
+ RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
+ prop = RNA_def_property(srna, "use_direction_parallel", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_NORMALEDIT_USE_DIRECTION_PARALLEL);
+ RNA_def_property_boolean_default(prop, true);
+ RNA_def_property_ui_text(prop, "Parallel Normals",
+ "Use same direction for all normals, from origin to target's center "
+ "(Directional mode only)");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+}
+
static void rna_def_modifier_pointcache(BlenderRNA *brna)
{
StructRNA *srna;
@@ -4451,6 +4571,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_laplaciandeform(brna);
rna_def_modifier_wireframe(brna);
rna_def_modifier_datatransfer(brna);
+ rna_def_modifier_normaledit(brna);
rna_def_modifier_pointcache(brna);
}
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index fa8d2669161..8d2a44136e8 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -3038,6 +3038,13 @@ static void def_frame(StructRNA *srna)
{
PropertyRNA *prop;
+ prop = RNA_def_property(srna, "text", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "id");
+ RNA_def_property_struct_type(prop, "Text");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Text", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
RNA_def_struct_sdna_from(srna, "NodeFrame", "storage");
prop = RNA_def_property(srna, "shrink", PROP_BOOLEAN, PROP_NONE);
@@ -3431,10 +3438,14 @@ static void def_sh_tex_image(StructRNA *srna)
};
static const EnumPropertyItem prop_projection_items[] = {
- {SHD_PROJ_FLAT, "FLAT", 0, "Flat",
- "Image is projected flat using the X and Y coordinates of the texture vector"},
- {SHD_PROJ_BOX, "BOX", 0, "Box",
- "Image is projected using different components for each side of the object space bounding box"},
+ {SHD_PROJ_FLAT, "FLAT", 0, "Flat",
+ "Image is projected flat using the X and Y coordinates of the texture vector"},
+ {SHD_PROJ_BOX, "BOX", 0, "Box",
+ "Image is projected using different components for each side of the object space bounding box"},
+ {SHD_PROJ_SPHERE, "SPHERE", 0, "Sphere",
+ "Image is projected spherically using the Z axis as central"},
+ {SHD_PROJ_TUBE, "TUBE", 0, "Tube",
+ "Image is projected from the tube using the Z axis as central"},
{0, NULL, 0, NULL, NULL}
};
@@ -3444,7 +3455,7 @@ static void def_sh_tex_image(StructRNA *srna)
{SHD_INTERP_CLOSEST, "Closest", 0, "Closest",
"No interpolation (sample closest texel)"},
{SHD_INTERP_CUBIC, "Cubic", 0, "Cubic",
- "Cubic interpolation (OSL only)"},
+ "Cubic interpolation (CPU only)"},
{SHD_INTERP_SMART, "Smart", 0, "Smart",
"Bicubic when magnifying, else bilinear (OSL only)"},
{0, NULL, 0, NULL, NULL}
@@ -3643,7 +3654,14 @@ static void def_sh_tex_wave(StructRNA *srna)
static void def_sh_tex_coord(StructRNA *srna)
{
PropertyRNA *prop;
-
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "id");
+ RNA_def_property_struct_type(prop, "Object");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Use coordinates from this object (for object texture coordinates output)");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
prop = RNA_def_property(srna, "from_dupli", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "custom1", 1);
RNA_def_property_ui_text(prop, "From Dupli", "Use the parent of the dupli object if possible");
@@ -6213,6 +6231,21 @@ static void def_cmp_planetrackdeform(StructRNA *srna)
RNA_def_property_string_sdna(prop, NULL, "plane_track_name");
RNA_def_property_ui_text(prop, "Plane Track", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "use_motion_blur", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR);
+ RNA_def_property_ui_text(prop, "Motion Blur", "Use multi-sampled motion blur of the mask");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "motion_blur_samples", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, CMP_NODE_PLANETRACKDEFORM_MBLUR_SAMPLES_MAX);
+ RNA_def_property_ui_text(prop, "Samples", "Number of motion blur samples");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+
+ prop = RNA_def_property(srna, "motion_blur_shutter", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0f);
+ RNA_def_property_ui_text(prop, "Shutter", "Exposure for motion blur as a factor of FPS");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
}
static void def_cmp_sunbeams(StructRNA *srna)
@@ -7105,7 +7138,13 @@ static void rna_def_node(BlenderRNA *brna)
static EnumPropertyItem dummy_static_type_items[] = {
{NODE_CUSTOM, "CUSTOM", 0, "Custom", "Custom Node"},
{0, NULL, 0, NULL, NULL}};
-
+
+ static EnumPropertyItem node_shading_compatibilities[] = {
+ {NODE_OLD_SHADING, "OLD_SHADING", 0, "Old Shading", "Old shading system compatibility"},
+ {NODE_NEW_SHADING, "NEW_SHADING", 0, "New Shading", "New shading system compatibility"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "Node", NULL);
RNA_def_struct_ui_text(srna, "Node", "Node in a node tree");
RNA_def_struct_sdna(srna, "bNode");
@@ -7245,6 +7284,12 @@ static void rna_def_node(BlenderRNA *brna)
parm = RNA_def_boolean(func, "result", false, "Result", "");
RNA_def_function_return(func, parm);
+ prop = RNA_def_property(srna, "shading_compatibility", PROP_ENUM, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_ENUM_FLAG);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_sdna(prop, NULL, "typeinfo->compatibility");
+ RNA_def_property_enum_items(prop, node_shading_compatibilities);
+
/* registration */
prop = RNA_def_property(srna, "bl_idname", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "typeinfo->idname");
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index f9a76005df8..60cf7535135 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -640,7 +640,7 @@ void rna_object_uvlayer_name_set(PointerRNA *ptr, const char *value, char *resul
for (a = 0; a < me->pdata.totlayer; a++) {
layer = &me->pdata.layers[a];
- if (layer->type == CD_MTEXPOLY && strcmp(layer->name, value) == 0) {
+ if (layer->type == CD_MTEXPOLY && STREQ(layer->name, value)) {
BLI_strncpy(result, value, maxlen);
return;
}
@@ -663,7 +663,7 @@ void rna_object_vcollayer_name_set(PointerRNA *ptr, const char *value, char *res
for (a = 0; a < me->fdata.totlayer; a++) {
layer = &me->fdata.layers[a];
- if (layer->type == CD_MCOL && strcmp(layer->name, value) == 0) {
+ if (layer->type == CD_MCOL && STREQ(layer->name, value)) {
BLI_strncpy(result, value, maxlen);
return;
}
diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c
index 5c5f0c1ec36..d2417f0a93e 100644
--- a/source/blender/makesrna/intern/rna_particle.c
+++ b/source/blender/makesrna/intern/rna_particle.c
@@ -131,6 +131,7 @@ static EnumPropertyItem part_hair_ren_as_items[] = {
#include "BKE_context.h"
#include "BKE_cloth.h"
+#include "BKE_colortools.h"
#include "BKE_deform.h"
#include "BKE_depsgraph.h"
#include "BKE_DerivedMesh.h"
@@ -356,13 +357,15 @@ static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *o
return;
if (part->ren_as == PART_DRAW_PATH && particlesystem->pathcache)
- path_nbr = (int)pow(2.0, step_nbr);
+ path_nbr = 1 << step_nbr;
+ if (part->kink == PART_KINK_SPIRAL)
+ path_nbr += part->kink_extra_steps;
if (particle_no < totpart) {
if (path_nbr) {
cache = particlesystem->pathcache[particle_no];
- max_k = (int)cache->steps;
+ max_k = (int)cache->segments;
}
}
@@ -371,10 +374,10 @@ static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *o
if (path_nbr) {
cache = particlesystem->childcache[particle_no - totpart];
- if (cache->steps < 0)
+ if (cache->segments < 0)
max_k = 0;
else
- max_k = (int)cache->steps;
+ max_k = (int)cache->segments;
}
}
@@ -645,6 +648,15 @@ static void rna_Particle_redo_child(Main *bmain, Scene *scene, PointerRNA *ptr)
particle_recalc(bmain, scene, ptr, PSYS_RECALC_CHILD);
}
+static void rna_Particle_cloth_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+ Object *ob = (Object *)ptr->id.data;
+
+ DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, ob);
+}
+
+
static ParticleSystem *rna_particle_system_for_target(Object *ob, ParticleTarget *target)
{
ParticleSystem *psys;
@@ -716,6 +728,7 @@ static void rna_Particle_hair_dynamics(Main *bmain, Scene *scene, PointerRNA *pt
psys->clmd->sim_parms->goalspring = 0.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;
+ psys->clmd->coll_parms->flags |= CLOTH_COLLSETTINGS_FLAG_POINTS;
rna_Particle_redo(bmain, scene, ptr);
}
else
@@ -864,6 +877,32 @@ static int rna_PartSettings_is_fluid_get(PointerRNA *ptr)
return part->type == PART_FLUID;
}
+static void rna_ParticleSettings_use_clump_curve_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ ParticleSettings *part = ptr->data;
+
+ if (part->child_flag & PART_CHILD_USE_CLUMP_CURVE) {
+ if (!part->clumpcurve) {
+ BKE_particlesettings_clump_curve_init(part);
+ }
+ }
+
+ rna_Particle_redo_child(bmain, scene, ptr);
+}
+
+static void rna_ParticleSettings_use_roughness_curve_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+{
+ ParticleSettings *part = ptr->data;
+
+ if (part->child_flag & PART_CHILD_USE_ROUGH_CURVE) {
+ if (!part->roughcurve) {
+ BKE_particlesettings_rough_curve_init(part);
+ }
+ }
+
+ rna_Particle_redo_child(bmain, scene, ptr);
+}
+
static void rna_ParticleSystem_name_set(PointerRNA *ptr, const char *value)
{
Object *ob = ptr->id.data;
@@ -1770,9 +1809,14 @@ static void rna_def_particle_settings_mtex(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Clump", "Affect the child clumping");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
- prop = RNA_def_property(srna, "use_map_kink", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "mapto", PAMAP_KINK);
- RNA_def_property_ui_text(prop, "Kink", "Affect the child kink");
+ prop = RNA_def_property(srna, "use_map_kink_amp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mapto", PAMAP_KINK_AMP);
+ RNA_def_property_ui_text(prop, "Kink Amplitude", "Affect the child kink amplitude");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+ prop = RNA_def_property(srna, "use_map_kink_freq", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "mapto", PAMAP_KINK_FREQ);
+ RNA_def_property_ui_text(prop, "Kink Frequency", "Affect the child kink frequency");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
prop = RNA_def_property(srna, "use_map_rough", PROP_BOOLEAN, PROP_NONE);
@@ -1849,10 +1893,16 @@ static void rna_def_particle_settings_mtex(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Clump Factor", "Amount texture affects child clump");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
- prop = RNA_def_property(srna, "kink_factor", PROP_FLOAT, PROP_NONE);
+ prop = RNA_def_property(srna, "kink_amp_factor", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "kinkampfac");
+ RNA_def_property_ui_range(prop, 0, 1, 10, 3);
+ RNA_def_property_ui_text(prop, "Kink Amplitude Factor", "Amount texture affects child kink amplitude");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+ prop = RNA_def_property(srna, "kink_freq_factor", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "kinkfac");
RNA_def_property_ui_range(prop, 0, 1, 10, 3);
- RNA_def_property_ui_text(prop, "Kink Factor", "Amount texture affects child kink");
+ RNA_def_property_ui_text(prop, "Kink Frequency Factor", "Amount texture affects child kink frequency");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
prop = RNA_def_property(srna, "rough_factor", PROP_FLOAT, PROP_NONE);
@@ -1938,6 +1988,7 @@ static void rna_def_particle_settings(BlenderRNA *brna)
{PART_KINK_RADIAL, "RADIAL", 0, "Radial", ""},
{PART_KINK_WAVE, "WAVE", 0, "Wave", ""},
{PART_KINK_BRAID, "BRAID", 0, "Braid", ""},
+ {PART_KINK_SPIRAL, "SPIRAL", 0, "Spiral", ""},
{0, NULL, 0, NULL, NULL}
};
@@ -2170,6 +2221,16 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Particle_reset");
/*draw flag*/
+ prop = RNA_def_property(srna, "show_guide_hairs", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_GUIDE_HAIRS);
+ RNA_def_property_ui_text(prop, "Guide Hairs", "Show guide hairs");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo");
+
+ prop = RNA_def_property(srna, "show_hair_grid", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_HAIR_GRID);
+ RNA_def_property_ui_text(prop, "Guide Hairs", "Show guide hairs");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo");
+
prop = RNA_def_property(srna, "show_velocity", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "draw", PART_DRAW_VEL);
RNA_def_property_ui_text(prop, "Velocity", "Show particle velocity");
@@ -2301,6 +2362,11 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Segments", "Number of hair segments");
RNA_def_property_update(prop, 0, "rna_Particle_reset");
+ prop = RNA_def_property(srna, "bending_random", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "bending_random");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Random Bending Stiffness", "Random stiffness of hairs");
+ RNA_def_property_update(prop, 0, "rna_Particle_cloth_update");
/*TODO: not found in UI, readonly? */
prop = RNA_def_property(srna, "keys_step", PROP_INT, PROP_NONE);
@@ -2766,6 +2832,29 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shape", "Shape of clumping");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+ prop = RNA_def_property(srna, "use_clump_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "child_flag", PART_CHILD_USE_CLUMP_CURVE);
+ RNA_def_property_ui_text(prop, "Use Clump Curve", "Use a curve to define clump tapering");
+ RNA_def_property_update(prop, 0, "rna_ParticleSettings_use_clump_curve_update");
+
+ prop = RNA_def_property(srna, "clump_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "clumpcurve");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Clump Curve", "Curve defining clump tapering");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+ prop = RNA_def_property(srna, "use_clump_noise", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "child_flag", PART_CHILD_USE_CLUMP_NOISE);
+ RNA_def_property_ui_text(prop, "Use Clump Noise", "Create random clumps around the parent");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+ prop = RNA_def_property(srna, "clump_noise_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "clump_noise_size");
+ RNA_def_property_range(prop, 0.00001f, 100000.0f);
+ RNA_def_property_ui_range(prop, 0.01f, 10.0f, 0.1f, 3);
+ RNA_def_property_ui_text(prop, "Clump Noise Size", "Size of clump noise");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
/* kink */
prop = RNA_def_property(srna, "kink_amplitude", PROP_FLOAT, PROP_NONE);
@@ -2781,6 +2870,12 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Amplitude Clump", "How much clump affects kink amplitude");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+ prop = RNA_def_property(srna, "kink_amplitude_random", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "kink_amp_random");
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Amplitude Random", "Random variation of the amplitude");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
prop = RNA_def_property(srna, "kink_frequency", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "kink_freq");
RNA_def_property_range(prop, -100000.0f, 100000.0f);
@@ -2798,6 +2893,17 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Flatness", "How flat the hairs are");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+ prop = RNA_def_property(srna, "kink_extra_steps", PROP_INT, PROP_NONE);
+ RNA_def_property_range(prop, 1, INT_MAX);
+ RNA_def_property_ui_range(prop, 1, 100, 1, -1);
+ RNA_def_property_ui_text(prop, "Extra Steps", "Extra steps for resolution of special kink features");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
+ prop = RNA_def_property(srna, "kink_axis_random", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Axis Random", "Random variation of the orientation");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
/* rough */
prop = RNA_def_property(srna, "roughness_1", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "rough1");
@@ -2846,6 +2952,18 @@ static void rna_def_particle_settings(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Shape", "Shape of end point rough");
RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+ prop = RNA_def_property(srna, "use_roughness_curve", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "child_flag", PART_CHILD_USE_ROUGH_CURVE);
+ RNA_def_property_ui_text(prop, "Use Roughness Curve", "Use a curve to define roughness");
+ RNA_def_property_update(prop, 0, "rna_ParticleSettings_use_roughness_curve_update");
+
+ prop = RNA_def_property(srna, "roughness_curve", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "roughcurve");
+ RNA_def_property_struct_type(prop, "CurveMapping");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Roughness Curve", "Curve defining roughness");
+ RNA_def_property_update(prop, 0, "rna_Particle_redo_child");
+
prop = RNA_def_property(srna, "child_length", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "clength");
RNA_def_property_range(prop, 0.0f, 1.0f);
diff --git a/source/blender/makesrna/intern/rna_property.c b/source/blender/makesrna/intern/rna_property.c
index c6b8e89c282..a2c19e55056 100644
--- a/source/blender/makesrna/intern/rna_property.c
+++ b/source/blender/makesrna/intern/rna_property.c
@@ -28,6 +28,11 @@
#include <stdlib.h>
#include "DNA_property_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_path_util.h"
+
+#include "BLF_translation.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -97,9 +102,11 @@ static void rna_GameProperty_type_set(PointerRNA *ptr, int value)
static void rna_GameProperty_name_set(PointerRNA *ptr, const char *value)
{
- bProperty *prop = (bProperty *)(ptr->data);
+ Object *ob = ptr->id.data;
+ bProperty *prop = ptr->data;
BLI_strncpy_utf8(prop->name, value, sizeof(prop->name));
- BKE_bproperty_unique(NULL, prop, 1);
+
+ BLI_uniquename(&ob->prop, prop, DATA_("Property"), '.', offsetof(bProperty, name), sizeof(prop->name));
}
diff --git a/source/blender/makesrna/intern/rna_render.c b/source/blender/makesrna/intern/rna_render.c
index 6db9c8e9cd9..124a83a5f30 100644
--- a/source/blender/makesrna/intern/rna_render.c
+++ b/source/blender/makesrna/intern/rna_render.c
@@ -267,7 +267,7 @@ static StructRNA *rna_RenderEngine_register(Main *bmain, ReportList *reports, vo
/* check if we have registered this engine type before, and remove it */
for (et = R_engines.first; et; et = et->next) {
- if (strcmp(et->idname, dummyet.idname) == 0) {
+ if (STREQ(et->idname, dummyet.idname)) {
if (et->ext.srna)
rna_RenderEngine_unregister(bmain, et->ext.srna);
break;
diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c
index 4f51ec5468c..b2c135cd1f9 100644
--- a/source/blender/makesrna/intern/rna_rna.c
+++ b/source/blender/makesrna/intern/rna_rna.c
@@ -179,7 +179,7 @@ static int rna_idproperty_known(CollectionPropertyIterator *iter, void *data)
* for the second loop where we go over unknown id properties */
do {
for (prop = ptype->cont.properties.first; prop; prop = prop->next)
- if ((prop->flag & PROP_BUILTIN) == 0 && strcmp(prop->identifier, idprop->name) == 0)
+ if ((prop->flag & PROP_BUILTIN) == 0 && STREQ(prop->identifier, idprop->name))
return 1;
} while ((ptype = ptype->base));
@@ -386,7 +386,7 @@ int rna_builtin_properties_lookup_string(PointerRNA *ptr, const char *key, Point
}
else {
for (prop = srna->cont.properties.first; prop; prop = prop->next) {
- if (!(prop->flag & PROP_BUILTIN) && strcmp(prop->identifier, key) == 0) {
+ if (!(prop->flag & PROP_BUILTIN) && STREQ(prop->identifier, key)) {
propptr.type = &RNA_Property;
propptr.data = prop;
@@ -408,7 +408,7 @@ int rna_builtin_properties_lookup_string(PointerRNA *ptr, const char *key, Point
if (group) {
for (idp = group->data.group.first; idp; idp = idp->next) {
- if (strcmp(idp->name, key) == 0) {
+ if (STREQ(idp->name, key)) {
propptr.type = &RNA_Property;
propptr.data = idp;
@@ -1002,7 +1002,7 @@ static int rna_BlenderRNA_structs_lookup_string(PointerRNA *ptr, const char *key
{
StructRNA *srna = ((BlenderRNA *)ptr->data)->structs.first;
for (; srna; srna = srna->cont.next) {
- if (key[0] == srna->identifier[0] && strcmp(key, srna->identifier) == 0) {
+ if (key[0] == srna->identifier[0] && STREQ(key, srna->identifier)) {
RNA_pointer_create(NULL, &RNA_Struct, srna, r_ptr);
return true;
}
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d9587b8d983..1c133db37b7 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -112,6 +112,7 @@ EnumPropertyItem proportional_falloff_items[] = {
{PROP_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", "Smooth falloff"},
{PROP_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", "Spherical falloff"},
{PROP_ROOT, "ROOT", ICON_ROOTCURVE, "Root", "Root falloff"},
+ {PROP_INVSQUARE, "INVERSE_SQUARE", ICON_ROOTCURVE, "Inverse Square", "Inverse Square falloff"},
{PROP_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", "Sharp falloff"},
{PROP_LIN, "LINEAR", ICON_LINCURVE, "Linear", "Linear falloff"},
{PROP_CONST, "CONSTANT", ICON_NOCURVE, "Constant", "Constant falloff"},
@@ -385,7 +386,7 @@ static int rna_Scene_object_bases_lookup_string(PointerRNA *ptr, const char *key
Base *base;
for (base = scene->base.first; base; base = base->next) {
- if (strncmp(base->object->id.name + 2, key, sizeof(base->object->id.name) - 2) == 0) {
+ if (STREQLEN(base->object->id.name + 2, key, sizeof(base->object->id.name) - 2)) {
*r_ptr = rna_pointer_inherit_refine(ptr, &RNA_ObjectBase, base);
return true;
}
@@ -942,7 +943,7 @@ static int rna_SceneRender_file_ext_length(PointerRNA *ptr)
RenderData *rd = (RenderData *)ptr->data;
char ext[8];
ext[0] = '\0';
- BKE_add_image_extension(ext, &rd->im_format);
+ BKE_image_path_ensure_ext_from_imformat(ext, &rd->im_format);
return strlen(ext);
}
@@ -950,7 +951,7 @@ static void rna_SceneRender_file_ext_get(PointerRNA *ptr, char *str)
{
RenderData *rd = (RenderData *)ptr->data;
str[0] = '\0';
- BKE_add_image_extension(str, &rd->im_format);
+ BKE_image_path_ensure_ext_from_imformat(str, &rd->im_format);
}
#ifdef WITH_QUICKTIME
@@ -1158,7 +1159,7 @@ static int rna_RenderSettings_engine_get(PointerRNA *ptr)
int a = 0;
for (type = R_engines.first; type; type = type->next, a++)
- if (strcmp(type->idname, rd->engine) == 0)
+ if (STREQ(type->idname, rd->engine))
return a;
return 0;
@@ -1243,7 +1244,7 @@ static int rna_RenderSettings_use_game_engine_get(PointerRNA *ptr)
RenderEngineType *type;
for (type = R_engines.first; type; type = type->next)
- if (strcmp(type->idname, rd->engine) == 0)
+ if (STREQ(type->idname, rd->engine))
return (type->flag & RE_GAME);
return 0;
@@ -3207,7 +3208,7 @@ static void rna_def_scene_game_recast_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "slope_max", PROP_FLOAT, PROP_ANGLE);
RNA_def_property_float_sdna(prop, NULL, "agentmaxslope");
- RNA_def_property_range(prop, 0, M_PI / 2);
+ RNA_def_property_range(prop, 0, M_PI_2);
RNA_def_property_ui_text(prop, "Max Slope", "Maximum walkable slope angle");
RNA_def_property_update(prop, NC_SCENE, NULL);
@@ -3622,8 +3623,8 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "logic_step_max", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "maxlogicstep");
- RNA_def_property_ui_range(prop, 1, 5, 1, 1);
- RNA_def_property_range(prop, 1, 5);
+ RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_ui_range(prop, 1, 50, 1, 1);
RNA_def_property_ui_text(prop, "Max Logic Steps",
"Maximum number of logic frame per game frame if graphics slows down the game, "
"higher value allows better synchronization with physics");
@@ -3631,8 +3632,8 @@ static void rna_def_scene_game_data(BlenderRNA *brna)
prop = RNA_def_property(srna, "physics_step_max", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "maxphystep");
- RNA_def_property_ui_range(prop, 1, 5, 1, 1);
- RNA_def_property_range(prop, 1, 5);
+ RNA_def_property_range(prop, 1, 10000);
+ RNA_def_property_ui_range(prop, 1, 50, 1, 1);
RNA_def_property_ui_text(prop, "Max Physics Steps",
"Maximum number of physics step per game frame if graphics slows down the game, "
"higher value allows physics to keep up with realtime");
@@ -4681,6 +4682,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
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_clear_flag(prop, PROP_ANIMATABLE);
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, "rna_Scene_freestyle_update");
@@ -5390,6 +5392,55 @@ static void rna_def_selected_uv_element(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Face Index", "");
}
+static void rna_def_display_safe_areas(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ static float default_title[2] = {0.035f, 0.035f};
+ static float default_action[2] = {0.1f, 0.05f};
+
+ static float default_title_center[2] = {0.175f, 0.05f};
+ static float default_action_center[2] = {0.15f, 0.05f};
+
+ srna = RNA_def_struct(brna, "DisplaySafeAreas", NULL);
+ RNA_def_struct_ui_text(srna, "Safe Areas", "Safe Areas used in 3D view and the VSE");
+ RNA_def_struct_sdna(srna, "DisplaySafeAreas");
+
+ /* SAFE AREAS */
+ prop = RNA_def_property(srna, "title", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "title");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_float_array_default(prop, default_title);
+ RNA_def_property_ui_text(prop, "Title Safe margins", "Safe area for text and graphics");
+ RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
+
+ prop = RNA_def_property(srna, "action", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "action");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_float_array_default(prop, default_action);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Action Safe Margins", "Safe area for general elements");
+ RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
+
+
+ prop = RNA_def_property(srna, "title_center", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "title_center");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_float_array_default(prop, default_title_center);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Center Title Safe Margins", "Safe area for text and graphics in a different aspect ratio");
+ RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
+
+ prop = RNA_def_property(srna, "action_center", PROP_FLOAT, PROP_XYZ);
+ RNA_def_property_float_sdna(prop, NULL, "action_center");
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_float_array_default(prop, default_action_center);
+ RNA_def_property_range(prop, 0.0f, 1.0f);
+ RNA_def_property_ui_text(prop, "Center Action Safe Margins", "Safe area for general elements in a different aspect ratio");
+ RNA_def_property_update(prop, NC_SCENE | ND_DRAW_RENDER_VIEWPORT, NULL);
+}
void RNA_def_scene(BlenderRNA *brna)
@@ -5685,6 +5736,13 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "RenderSettings");
RNA_def_property_ui_text(prop, "Render Data", "");
+ /* Safe Areas */
+ prop = RNA_def_property(srna, "safe_areas", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "safe_areas");
+ RNA_def_property_flag(prop, PROP_NEVER_NULL);
+ RNA_def_property_struct_type(prop, "DisplaySafeAreas");
+ RNA_def_property_ui_text(prop, "Safe Areas", "");
+
/* Markers */
prop = RNA_def_property(srna, "timeline_markers", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "markers", NULL);
@@ -5799,6 +5857,7 @@ void RNA_def_scene(BlenderRNA *brna)
rna_def_scene_game_data(brna);
rna_def_transform_orientation(brna);
rna_def_selected_uv_element(brna);
+ rna_def_display_safe_areas(brna);
RNA_define_animate_sdna(true);
/* *** Animated *** */
rna_def_scene_render_data(brna);
diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c
index be618c5d1a3..36657c8a898 100644
--- a/source/blender/makesrna/intern/rna_scene_api.c
+++ b/source/blender/makesrna/intern/rna_scene_api.c
@@ -121,11 +121,14 @@ static void rna_Scene_update_tagged(Scene *scene)
static void rna_SceneRender_get_frame_path(RenderData *rd, int frame, char *name)
{
- if (BKE_imtype_is_movie(rd->im_format.imtype))
+ if (BKE_imtype_is_movie(rd->im_format.imtype)) {
BKE_movie_filepath_get(name, rd);
- else
- BKE_makepicstring(name, rd->pic, G.main->name, (frame == INT_MIN) ? rd->cfra : frame,
- &rd->im_format, (rd->scemode & R_EXTENSION) != 0, true);
+ }
+ else {
+ BKE_image_path_from_imformat(
+ name, rd->pic, G.main->name, (frame == INT_MIN) ? rd->cfra : frame,
+ &rd->im_format, (rd->scemode & R_EXTENSION) != 0, true);
+ }
}
static void rna_Scene_ray_cast(Scene *scene, float ray_start[3], float ray_end[3],
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 7b01acff6a5..86d20e6e239 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -413,6 +413,11 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "All 3D View Editors", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, "rna_Screen_redraw_update");
+ prop = RNA_def_property(srna, "use_follow", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_FOLLOW);
+ RNA_def_property_ui_text(prop, "Follow", "Follow current frame in editors that update");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, "rna_Screen_redraw_update");
+
prop = RNA_def_property(srna, "use_play_animation_editors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_ALL_ANIM_WIN);
RNA_def_property_ui_text(prop, "Animation Editors", "");
diff --git a/source/blender/makesrna/intern/rna_sculpt_paint.c b/source/blender/makesrna/intern/rna_sculpt_paint.c
index 8e83543812d..0a282eeb7ac 100644
--- a/source/blender/makesrna/intern/rna_sculpt_paint.c
+++ b/source/blender/makesrna/intern/rna_sculpt_paint.c
@@ -709,6 +709,11 @@ static void rna_def_image_paint(BlenderRNA *brna)
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, "dither", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 2.0);
+ RNA_def_property_ui_text(prop, "Dither", "Amount of dithering when painting on byte images");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL);
prop = RNA_def_property(srna, "use_clone_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", IMAGEPAINT_PROJECT_LAYER_CLONE);
@@ -888,6 +893,10 @@ static void rna_def_particle_edit(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Object", "The edited object");
+ prop = RNA_def_property(srna, "shape_object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Shape Object", "Outer shape to use for tools");
+ RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, "rna_ParticleEdit_redo");
/* brush */
diff --git a/source/blender/makesrna/intern/rna_sensor.c b/source/blender/makesrna/intern/rna_sensor.c
index 3944b59dff7..5d7bb6d2d94 100644
--- a/source/blender/makesrna/intern/rna_sensor.c
+++ b/source/blender/makesrna/intern/rna_sensor.c
@@ -107,14 +107,10 @@ static StructRNA *rna_Sensor_refine(struct PointerRNA *ptr)
static void rna_Sensor_name_set(PointerRNA *ptr, const char *value)
{
- bSensor *sens = (bSensor *)ptr->data;
-
+ Object *ob = ptr->id.data;
+ bSensor *sens = ptr->data;
BLI_strncpy_utf8(sens->name, value, sizeof(sens->name));
-
- if (ptr->id.data) {
- Object *ob = (Object *)ptr->id.data;
- BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
- }
+ BLI_uniquename(&ob->sensors, sens, DATA_("Sensor"), '.', offsetof(bSensor, name), sizeof(sens->name));
}
static void rna_Sensor_type_set(struct PointerRNA *ptr, int value)
@@ -246,11 +242,11 @@ static void rna_Sensor_Armature_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
bPoseChannel *pchan;
bPose *pose = ob->pose;
for (pchan = pose->chanbase.first; pchan; pchan = pchan->next) {
- if (!strcmp(pchan->name, posechannel)) {
+ if (STREQ(pchan->name, posechannel)) {
/* found it, now look for constraint channel */
bConstraint *con;
for (con = pchan->constraints.first; con; con = con->next) {
- if (!strcmp(con->name, constraint)) {
+ if (STREQ(con->name, constraint)) {
/* found it, all ok */
return;
}
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index dda0e8493d9..f628112a19a 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -310,18 +310,7 @@ static void rna_Sequence_frame_offset_range(PointerRNA *ptr, int *min, int *max,
static void rna_Sequence_use_proxy_set(PointerRNA *ptr, int value)
{
Sequence *seq = (Sequence *)ptr->data;
- if (value) {
- seq->flag |= SEQ_USE_PROXY;
- if (seq->strip->proxy == NULL) {
- seq->strip->proxy = MEM_callocN(sizeof(struct StripProxy), "StripProxy");
- seq->strip->proxy->quality = 90;
- seq->strip->proxy->build_tc_flags = SEQ_PROXY_TC_ALL;
- seq->strip->proxy->build_size_flags = SEQ_PROXY_IMAGE_SIZE_25;
- }
- }
- else {
- seq->flag ^= SEQ_USE_PROXY;
- }
+ BKE_sequencer_proxy_set(seq, value != 0);
}
static void rna_Sequence_use_translation_set(PointerRNA *ptr, int value)
@@ -1187,6 +1176,10 @@ static void rna_def_strip_proxy(BlenderRNA *brna)
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_SequenceProxy_update");
+ prop = RNA_def_property(srna, "use_overwrite", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "build_flags", SEQ_PROXY_SKIP_EXISTING);
+ RNA_def_property_ui_text(prop, "Overwrite", "Overwrite existing proxy files when building");
+
prop = RNA_def_property(srna, "build_25", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "build_size_flags", SEQ_PROXY_IMAGE_SIZE_25);
RNA_def_property_ui_text(prop, "25%", "Build 25% proxy resolution");
diff --git a/source/blender/makesrna/intern/rna_sound.c b/source/blender/makesrna/intern/rna_sound.c
index aa39e81d390..4b745c60b5b 100644
--- a/source/blender/makesrna/intern/rna_sound.c
+++ b/source/blender/makesrna/intern/rna_sound.c
@@ -98,6 +98,8 @@ static void rna_def_sound(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Mono",
"If the file contains multiple audio channels they are rendered to a single one");
RNA_def_property_update(prop, 0, "rna_Sound_update");
+
+ RNA_api_sound(srna);
}
void RNA_def_sound(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_sound_api.c b/source/blender/makesrna/intern/rna_sound_api.c
new file mode 100644
index 00000000000..0164daa98d0
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_sound_api.c
@@ -0,0 +1,73 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_sound_api.c
+ * \ingroup RNA
+ */
+
+#include "DNA_packedFile_types.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_packedFile.h"
+
+static void rna_Sound_pack(bSound *sound, Main *bmain, ReportList *reports)
+{
+ sound->packedfile = newPackedFile(reports, sound->name, ID_BLEND_PATH(bmain, &sound->id));
+}
+
+static void rna_Sound_unpack(bSound *sound, Main *bmain, ReportList *reports, int method)
+{
+ if (!sound->packedfile) {
+ BKE_report(reports, RPT_ERROR, "Sound not packed");
+ }
+ else {
+ /* reports its own error on failure */
+ unpackSound(bmain, reports, sound, method);
+ }
+}
+
+#else
+
+void RNA_api_sound(StructRNA *srna)
+{
+ FunctionRNA *func;
+
+ func = RNA_def_function(srna, "pack", "rna_Sound_pack");
+ RNA_def_function_ui_description(func, "Pack the sound into the current blend file");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
+
+ func = RNA_def_function(srna, "unpack", "rna_Sound_unpack");
+ RNA_def_function_ui_description(func, "Unpack the sound to the samples filename");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
+ RNA_def_enum(func, "method", unpack_method_items, PF_USE_LOCAL, "method", "How to unpack");
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index af0e69cdc3e..382ed358e12 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -791,7 +791,7 @@ static void rna_SpaceImageEditor_cursor_location_set(PointerRNA *ptr, const floa
}
}
-static void rna_SpaceImageEditor_scopes_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr)
+static void rna_SpaceImageEditor_scopes_update(struct bContext *C, struct PointerRNA *ptr)
{
SpaceImage *sima = (SpaceImage *)ptr->data;
ImBuf *ibuf;
@@ -799,7 +799,7 @@ static void rna_SpaceImageEditor_scopes_update(Main *UNUSED(bmain), Scene *scene
ibuf = ED_space_image_acquire_buffer(sima, &lock);
if (ibuf) {
- scopes_update(&sima->scopes, ibuf, &scene->view_settings, &scene->display_settings);
+ ED_space_image_scopes_update(C, sima, ibuf, true);
WM_main_add_notifier(NC_IMAGE, sima->image);
}
ED_space_image_release_buffer(sima, ibuf, lock);
@@ -1249,7 +1249,7 @@ static int rna_SpaceNodeEditor_node_tree_poll(PointerRNA *ptr, const PointerRNA
bNodeTree *ntree = (bNodeTree *)value.data;
/* node tree type must match the selected type in node editor */
- return (strcmp(snode->tree_idname, ntree->idname) == 0);
+ return (STREQ(snode->tree_idname, ntree->idname));
}
static void rna_SpaceNodeEditor_node_tree_update(const bContext *C, PointerRNA *UNUSED(ptr))
@@ -1593,7 +1593,12 @@ static void rna_def_space_outliner(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "search_flags", SO_FIND_COMPLETE);
RNA_def_property_ui_text(prop, "Complete Matches Only", "Only use complete matches of search string");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
-
+
+ prop = RNA_def_property(srna, "use_sort_alpha", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_SKIP_SORT_ALPHA);
+ RNA_def_property_ui_text(prop, "Sort Alphabetically", "");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_OUTLINER, NULL);
+
prop = RNA_def_property(srna, "show_restrict_columns", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SO_HIDE_RESTRICTCOLS);
RNA_def_property_ui_text(prop, "Show Restriction Columns", "Show column");
@@ -1695,7 +1700,22 @@ static void rna_def_background_image(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Size", "Scaling factor for the background image");
RNA_def_property_range(prop, 0.0, FLT_MAX);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
-
+
+ prop = RNA_def_property(srna, "rotation", PROP_FLOAT, PROP_EULER);
+ RNA_def_property_float_sdna(prop, NULL, "rotation");
+ RNA_def_property_ui_text(prop, "Rotation", "Rotation for the background image");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_flip_x", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_FLIP_X);
+ RNA_def_property_ui_text(prop, "Flip Horizontally", "Flip the background image horizontally");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
+ prop = RNA_def_property(srna, "use_flip_y", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_BGPIC_FLIP_Y);
+ RNA_def_property_ui_text(prop, "Flip Vertically", "Flip the background image vertically");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
+
prop = RNA_def_property(srna, "opacity", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "blend");
RNA_def_property_float_funcs(prop, "rna_BackgroundImage_opacity_get", "rna_BackgroundImage_opacity_set", NULL);
@@ -2361,6 +2381,7 @@ static void rna_def_space_image(BlenderRNA *brna)
RNA_def_property_pointer_sdna(prop, NULL, "scopes");
RNA_def_property_struct_type(prop, "Scopes");
RNA_def_property_ui_text(prop, "Scopes", "Scopes to visualize image statistics");
+ RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE);
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_IMAGE, "rna_SpaceImageEditor_scopes_update");
prop = RNA_def_property(srna, "use_image_pin", PROP_BOOLEAN, PROP_NONE);
@@ -2565,11 +2586,16 @@ static void rna_def_space_sequencer(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Separate Colors", "Separate color channels in preview");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
- prop = RNA_def_property(srna, "show_safe_margin", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_DRAW_SAFE_MARGINS);
- RNA_def_property_ui_text(prop, "Safe Margin", "Draw title safe margins in preview");
+ prop = RNA_def_property(srna, "show_safe_areas", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_SAFE_MARGINS);
+ RNA_def_property_ui_text(prop, "Safe Areas", "Show TV title safe and action safe areas in preview");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
-
+
+ prop = RNA_def_property(srna, "show_safe_center", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_SAFE_CENTER);
+ RNA_def_property_ui_text(prop, "Center-Cut Safe Areas", "Show safe areas to fit content in a different aspect ratio");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL);
+
prop = RNA_def_property(srna, "show_seconds", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SEQ_DRAWFRAMES);
RNA_def_property_ui_text(prop, "Show Seconds", "Show timing in seconds not frames");
@@ -2814,7 +2840,8 @@ static void rna_def_space_dopesheet(BlenderRNA *brna)
prop = RNA_def_property(srna, "show_group_colors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SACTION_NODRAWGCOLORS);
RNA_def_property_ui_text(prop, "Show Group Colors",
- "Draw groups and channels with colors matching their corresponding groups");
+ "Draw groups and channels with colors matching their corresponding groups "
+ "(pose bones only currently)");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, NULL);
/* editing */
@@ -2976,6 +3003,12 @@ static void rna_def_space_graph(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Has Ghost Curves", "Graph Editor instance has some ghost curves stored");
+ /* auto view */
+ prop = RNA_def_property(srna, "use_auto_view_selected", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_AUTO_VIEW_SELECTED);
+ RNA_def_property_ui_text(prop, "Auto View Selected", "Automatically adjust view based on selection");
+ RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL);
+
/* nromalize curves */
prop = RNA_def_property(srna, "use_normalization", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SIPO_NORMALIZE);
diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c
index 188a30d23ce..c1882e7767d 100644
--- a/source/blender/makesrna/intern/rna_texture.c
+++ b/source/blender/makesrna/intern/rna_texture.c
@@ -440,15 +440,13 @@ static void rna_ImageTexture_mipmap_set(PointerRNA *ptr, int value)
else tex->imaflag &= ~TEX_MIPMAP;
}
-static void rna_Envmap_source_update(Main *bmain, Scene *scene, PointerRNA *ptr)
+static void rna_Envmap_update_generic(Main *bmain, Scene *scene, PointerRNA *ptr)
{
Tex *tex = ptr->id.data;
-
if (tex->env) {
ED_preview_kill_jobs(bmain->wm.first, bmain);
BKE_free_envmapdata(tex->env);
}
-
rna_Texture_update(bmain, scene, ptr);
}
@@ -806,7 +804,7 @@ static void rna_def_environment_map(BlenderRNA *brna)
RNA_def_property_enum_sdna(prop, NULL, "stype");
RNA_def_property_enum_items(prop, prop_source_items);
RNA_def_property_ui_text(prop, "Source", "");
- RNA_def_property_update(prop, 0, "rna_Envmap_source_update");
+ RNA_def_property_update(prop, 0, "rna_Envmap_update_generic");
prop = RNA_def_property(srna, "viewpoint_object", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "object");
@@ -1394,7 +1392,7 @@ static void rna_def_texture_environment_map(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "Image");
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Image", "Source image file to read the environment map from");
- RNA_def_property_update(prop, 0, "rna_Texture_update");
+ RNA_def_property_update(prop, 0, "rna_Envmap_update_generic");
prop = RNA_def_property(srna, "image_user", PROP_POINTER, PROP_NEVER_NULL);
RNA_def_property_pointer_sdna(prop, NULL, "iuser");
@@ -1851,6 +1849,7 @@ static void rna_def_texture_voxeldata(BlenderRNA *brna)
{TEX_VD_IMAGE_SEQUENCE, "IMAGE_SEQUENCE", 0, "Image Sequence",
"Generate voxels from a sequence of image slices"},
{TEX_VD_SMOKE, "SMOKE", 0, "Smoke", "Render voxels from a Blender smoke simulation"},
+ {TEX_VD_HAIR, "HAIR", 0, "Hair", "Render voxels from a Blender hair simulation"},
{0, NULL, 0, NULL, NULL}
};
@@ -1869,6 +1868,14 @@ static void rna_def_texture_voxeldata(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
+ static EnumPropertyItem hair_type_items[] = {
+ {TEX_VD_HAIRDENSITY, "HAIRDENSITY", 0, "Density", "Use hair density as texture data"},
+ {TEX_VD_HAIRRESTDENSITY, "HAIRRESTDENSITY", 0, "Rest Density", "Use hair rest density as texture data"},
+ {TEX_VD_HAIRVELOCITY, "HAIRVELOCITY", 0, "Velocity", "Use hair velocity as texture data"},
+ {TEX_VD_HAIRENERGY, "HAIRENERGY", 0, "Energy", "Use potential hair energy as texture data"},
+ {0, NULL, 0, NULL, NULL}
+ };
+
srna = RNA_def_struct(brna, "VoxelData", NULL);
RNA_def_struct_sdna(srna, "VoxelData");
RNA_def_struct_ui_text(srna, "VoxelData", "Voxel data settings");
@@ -1886,6 +1893,12 @@ static void rna_def_texture_voxeldata(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Source", "Simulation value to be used as a texture");
RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
+ prop = RNA_def_property(srna, "hair_data_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "hair_type");
+ RNA_def_property_enum_items(prop, hair_type_items);
+ RNA_def_property_ui_text(prop, "Source", "Simulation value to be used as a texture");
+ RNA_def_property_update(prop, 0, "rna_Texture_voxeldata_update");
+
prop = RNA_def_property(srna, "extension", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "extend");
RNA_def_property_enum_items(prop, voxeldata_extension);
diff --git a/source/blender/makesrna/intern/rna_texture_api.c b/source/blender/makesrna/intern/rna_texture_api.c
index 695a3e0548e..acf8333d6dc 100644
--- a/source/blender/makesrna/intern/rna_texture_api.c
+++ b/source/blender/makesrna/intern/rna_texture_api.c
@@ -74,7 +74,7 @@ static void texture_evaluate(struct Tex *tex, float value[3], float r_color[4])
TexResult texres = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
/* TODO(sergey): always use color management now. */
- multitex_ext(tex, value, NULL, NULL, 1, &texres, NULL, true);
+ multitex_ext(tex, value, NULL, NULL, 1, &texres, NULL, true, false);
r_color[0] = texres.tr;
r_color[1] = texres.tg;
diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c
index a61846fa028..fde43abe9fb 100644
--- a/source/blender/makesrna/intern/rna_ui.c
+++ b/source/blender/makesrna/intern/rna_ui.c
@@ -221,7 +221,7 @@ static StructRNA *rna_Panel_register(Main *bmain, ReportList *reports, void *dat
/* check if we have registered this panel type before, and remove it */
for (pt = art->paneltypes.first; pt; pt = pt->next) {
- if (strcmp(pt->idname, dummypt.idname) == 0) {
+ if (STREQ(pt->idname, dummypt.idname)) {
if (pt->ext.srna)
rna_Panel_unregister(bmain, pt->ext.srna);
else
@@ -587,7 +587,7 @@ static StructRNA *rna_Header_register(Main *bmain, ReportList *reports, void *da
/* check if we have registered this header type before, and remove it */
for (ht = art->headertypes.first; ht; ht = ht->next) {
- if (strcmp(ht->idname, dummyht.idname) == 0) {
+ if (STREQ(ht->idname, dummyht.idname)) {
if (ht->ext.srna)
rna_Header_unregister(bmain, ht->ext.srna);
break;
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 4f889c91665..b5eeebae664 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -295,7 +295,7 @@ static const char *rna_ui_get_enum_name(bContext *C, PointerRNA *ptr, const char
if (items) {
for (item = items; item->identifier; item++) {
- if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) {
+ if (item->identifier[0] && STREQ(item->identifier, identifier)) {
name = item->name;
break;
}
@@ -326,7 +326,7 @@ static const char *rna_ui_get_enum_description(bContext *C, PointerRNA *ptr, con
if (items) {
for (item = items; item->identifier; item++) {
- if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) {
+ if (item->identifier[0] && STREQ(item->identifier, identifier)) {
desc = item->description;
break;
}
@@ -356,7 +356,7 @@ static int rna_ui_get_enum_icon(bContext *C, PointerRNA *ptr, const char *propna
if (items) {
for (item = items; item->identifier; item++) {
- if (item->identifier[0] && strcmp(item->identifier, identifier) == 0) {
+ if (item->identifier[0] && STREQ(item->identifier, identifier)) {
icon = item->icon;
break;
}
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index fa0e1db10e2..15ecf70a938 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -1682,6 +1682,11 @@ static void rna_def_userdef_theme_space_view3d(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Skin Root", "");
RNA_def_property_update(prop, 0, "rna_userdef_update");
+ prop = RNA_def_property(srna, "clipping_border_3d", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Clipping Border", "");
+ RNA_def_property_update(prop, 0, "rna_userdef_update");
+
rna_def_userdef_theme_spaces_paint_curves(srna);
}
@@ -3530,7 +3535,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
/* Undo */
prop = RNA_def_property(srna, "undo_steps", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, NULL, "undosteps");
- RNA_def_property_range(prop, 0, 64);
+ RNA_def_property_range(prop, 0, 256);
RNA_def_property_int_funcs(prop, NULL, "rna_userdef_undo_steps_set", NULL);
RNA_def_property_ui_text(prop, "Undo Steps", "Number of undo steps available (smaller values conserve memory)");
@@ -3863,6 +3868,11 @@ static void rna_def_userdef_system(BlenderRNA *brna)
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, "pixel_size", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_sdna(prop, NULL, "pixelsize");
+ RNA_def_property_ui_text(prop, "Pixel Size", "");
+
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");
diff --git a/source/blender/makesrna/intern/rna_vfont.c b/source/blender/makesrna/intern/rna_vfont.c
index f24f94282b6..0879f4d355d 100644
--- a/source/blender/makesrna/intern/rna_vfont.c
+++ b/source/blender/makesrna/intern/rna_vfont.c
@@ -84,6 +84,8 @@ void RNA_def_vfont(BlenderRNA *brna)
prop = RNA_def_property(srna, "packed_file", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "packedfile");
RNA_def_property_ui_text(prop, "Packed File", "");
+
+ RNA_api_vfont(srna);
}
#endif
diff --git a/source/blender/makesrna/intern/rna_vfont_api.c b/source/blender/makesrna/intern/rna_vfont_api.c
new file mode 100644
index 00000000000..d92e75daf0a
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_vfont_api.c
@@ -0,0 +1,73 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 by the Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Kevin Dietrich
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_vfont_api.c
+ * \ingroup RNA
+ */
+
+#include "DNA_packedFile_types.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_packedFile.h"
+
+static void rna_VectorFont_pack(VFont *vfont, Main *bmain, ReportList *reports)
+{
+ vfont->packedfile = newPackedFile(reports, vfont->name, ID_BLEND_PATH(bmain, &vfont->id));
+}
+
+static void rna_VectorFont_unpack(VFont *vfont, ReportList *reports, int method)
+{
+ if (!vfont->packedfile) {
+ BKE_report(reports, RPT_ERROR, "Font not packed");
+ }
+ else {
+ /* reports its own error on failure */
+ unpackVFont(reports, vfont, method);
+ }
+}
+
+#else
+
+void RNA_api_vfont(StructRNA *srna)
+{
+ FunctionRNA *func;
+
+ func = RNA_def_function(srna, "pack", "rna_VectorFont_pack");
+ RNA_def_function_ui_description(func, "Pack the font into the current blend file");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS | FUNC_USE_MAIN);
+
+ func = RNA_def_function(srna, "unpack", "rna_VectorFont_unpack");
+ RNA_def_function_ui_description(func, "Unpack the font to the samples filename");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ RNA_def_enum(func, "method", unpack_method_items, PF_USE_LOCAL, "method", "How to unpack");
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index 3b97508dd67..347b669812e 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -835,7 +835,7 @@ static void rna_wmKeyMapItem_idname_set(PointerRNA *ptr, const char *value)
WM_operator_bl_idname(idname, value);
- if (strcmp(idname, kmi->idname) != 0) {
+ if (!STREQ(idname, kmi->idname)) {
BLI_strncpy(kmi->idname, idname, sizeof(kmi->idname));
WM_keymap_properties_reset(kmi, NULL);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 876a95d8d8c..2c32627a89e 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -74,6 +74,7 @@ set(SRC
intern/MOD_mirror.c
intern/MOD_multires.c
intern/MOD_none.c
+ intern/MOD_normal_edit.c
intern/MOD_ocean.c
intern/MOD_particleinstance.c
intern/MOD_particlesystem.c
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 8edcb7e0380..06e0906c758 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -82,6 +82,7 @@ extern ModifierTypeInfo modifierType_MeshCache;
extern ModifierTypeInfo modifierType_LaplacianDeform;
extern ModifierTypeInfo modifierType_Wireframe;
extern ModifierTypeInfo modifierType_DataTransfer;
+extern ModifierTypeInfo modifierType_NormalEdit;
extern ModifierTypeInfo modifierType_PointCache;
/* MOD_util.c */
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index b6d75afaf23..7430a4300a5 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -201,7 +201,7 @@ static void dm_mvert_map_doubles(
const float dist,
const bool with_follow)
{
- const float dist3 = (M_SQRT3 + 0.00005f) * dist; /* Just above sqrt(3) */
+ const float dist3 = ((float)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;
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index f30529bc40f..1dc1a1f8d64 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -86,7 +86,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
float frac;
MPoly *mpoly_dst;
MLoop *ml_dst, *ml_src /*, *mloop_dst */;
- GHashIterator *hashIter;
+ GHashIterator gh_iter;
/* maps vert indices in old mesh to indices in new mesh */
GHash *vertHash = BLI_ghash_int_new("build ve apply gh");
/* maps edge indices in new mesh to indices in old mesh */
@@ -230,15 +230,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
BLI_ghash_size(edgeHash), 0, numLoops_dst, numFaces_dst);
/* copy the vertices across */
- for (hashIter = BLI_ghashIterator_new(vertHash);
- BLI_ghashIterator_done(hashIter) == false;
- BLI_ghashIterator_step(hashIter)
- )
- {
+ GHASH_ITER (gh_iter, vertHash) {
MVert source;
MVert *dest;
- int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
- int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
+ int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
+ int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
source = mvert_src[oldIndex];
dest = CDDM_get_vert(result, newIndex);
@@ -246,7 +242,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *UNUSED(ob),
DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
*dest = source;
}
- BLI_ghashIterator_free(hashIter);
/* copy the edges across, remapping indices */
for (i = 0; i < BLI_ghash_size(edgeHash); i++) {
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 11455a6461f..394b2ff412f 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -48,6 +48,7 @@
#include "BKE_cloth.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_effect.h"
#include "BKE_global.h"
#include "BKE_key.h"
#include "BKE_modifier.h"
@@ -177,6 +178,8 @@ static void copyData(ModifierData *md, ModifierData *target)
tclmd->point_cache = BKE_ptcache_new();
tclmd->point_cache->step = 1;
tclmd->clothObject = NULL;
+ tclmd->hairdata = NULL;
+ tclmd->solver_result = NULL;
}
static bool dependsOnTime(ModifierData *UNUSED(md))
@@ -204,6 +207,12 @@ static void freeData(ModifierData *md)
BKE_ptcache_free(clmd->point_cache);
clmd->point_cache = NULL;
+
+ if (clmd->hairdata)
+ MEM_freeN(clmd->hairdata);
+
+ if (clmd->solver_result)
+ MEM_freeN(clmd->solver_result);
}
}
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index f6d7c03df32..2b512a6ba25 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -43,6 +43,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
+#include "BKE_colortools.h"
#include "depsgraph_private.h"
@@ -55,6 +56,9 @@ static void initData(ModifierData *md)
HookModifierData *hmd = (HookModifierData *) md;
hmd->force = 1.0;
+ hmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ hmd->falloff_type = eHook_Falloff_Smooth;
+ hmd->flag = 0;
}
static void copyData(ModifierData *md, ModifierData *target)
@@ -64,6 +68,8 @@ static void copyData(ModifierData *md, ModifierData *target)
modifier_copyData_generic(md, target);
+ thmd->curfalloff = curvemapping_copy(hmd->curfalloff);
+
thmd->indexar = MEM_dupallocN(hmd->indexar);
}
@@ -83,6 +89,8 @@ static void freeData(ModifierData *md)
{
HookModifierData *hmd = (HookModifierData *) md;
+ curvemapping_free(hmd->curfalloff);
+
if (hmd->indexar) MEM_freeN(hmd->indexar);
}
@@ -120,32 +128,172 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
-static float hook_falloff(const float co_1[3], const float co_2[3], const float falloff_squared, float fac)
+struct HookData_cb {
+ float (*vertexCos)[3];
+
+ MDeformVert *dvert;
+ int defgrp_index;
+
+ struct CurveMapping *curfalloff;
+
+ char falloff_type;
+ float falloff;
+ float falloff_sq;
+ float fac_orig;
+
+ unsigned int use_falloff : 1;
+ unsigned int use_uniform : 1;
+
+ float cent[3];
+
+ float mat_uniform[3][3];
+ float mat[4][4];
+};
+
+static float hook_falloff(
+ const struct HookData_cb *hd,
+ const float len_sq)
+{
+ BLI_assert(hd->falloff_sq);
+ if (len_sq > hd->falloff_sq) {
+ return 0.0f;
+ }
+ else if (len_sq > 0.0f) {
+ float fac;
+
+ if (hd->falloff_type == eHook_Falloff_Const) {
+ fac = 1.0f;
+ goto finally;
+ }
+ else if (hd->falloff_type == eHook_Falloff_InvSquare) {
+ /* avoid sqrt below */
+ fac = 1.0f - (len_sq / hd->falloff_sq);
+ goto finally;
+ }
+
+ fac = 1.0f - (sqrtf(len_sq) / hd->falloff);
+
+ /* closely match PROP_SMOOTH and similar */
+ switch (hd->falloff_type) {
+#if 0
+ case eHook_Falloff_None:
+ fac = 1.0f;
+ break;
+#endif
+ case eHook_Falloff_Curve:
+ fac = curvemapping_evaluateF(hd->curfalloff, 0, fac);
+ break;
+ case eHook_Falloff_Sharp:
+ fac = fac * fac;
+ break;
+ case eHook_Falloff_Smooth:
+ fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
+ break;
+ case eHook_Falloff_Root:
+ fac = sqrtf(fac);
+ break;
+ case eHook_Falloff_Linear:
+ /* pass */
+ break;
+#if 0
+ case eHook_Falloff_Const:
+ fac = 1.0f;
+ break;
+#endif
+ case eHook_Falloff_Sphere:
+ fac = sqrtf(2 * fac - fac * fac);
+ break;
+#if 0
+ case eHook_Falloff_InvSquare:
+ fac = fac * (2.0f - fac);
+ break;
+#endif
+ }
+
+finally:
+ return fac * hd->fac_orig;
+ }
+ else {
+ return hd->fac_orig;
+ }
+}
+
+static void hook_co_apply(struct HookData_cb *hd, const int j)
{
- if (falloff_squared) {
- float len_squared = len_squared_v3v3(co_1, co_2);
- if (len_squared > falloff_squared) {
- return 0.0f;
+ float *co = hd->vertexCos[j];
+ float fac;
+
+ if (hd->use_falloff) {
+ float len_sq;
+
+ if (hd->use_uniform) {
+ float co_uniform[3];
+ mul_v3_m3v3(co_uniform, hd->mat_uniform, co);
+ len_sq = len_squared_v3v3(hd->cent, co_uniform);
}
- else if (len_squared > 0.0f) {
- return fac * (1.0f - (len_squared / falloff_squared));
+ else {
+ len_sq = len_squared_v3v3(hd->cent, co);
}
+
+ fac = hook_falloff(hd, len_sq);
}
+ else {
+ fac = hd->fac_orig;
+ }
+
+ if (fac) {
+ if (hd->dvert) {
+ fac *= defvert_find_weight(&hd->dvert[j], hd->defgrp_index);
+ }
- return fac;
+ if (fac) {
+ float co_tmp[3];
+ mul_v3_m4v3(co_tmp, hd->mat, co);
+ interp_v3_v3v3(co, co, co_tmp, fac);
+ }
+ }
}
static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
{
bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
- float vec[3], mat[4][4], dmat[4][4];
+ float dmat[4][4];
int i, *index_pt;
- const float falloff_squared = hmd->falloff * hmd->falloff; /* for faster comparisons */
-
- MDeformVert *dvert;
- int defgrp_index, max_dvert;
+ struct HookData_cb hd;
+ if (hmd->curfalloff == NULL) {
+ /* should never happen, but bad lib linking could cause it */
+ hmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
+ }
+
+ if (hmd->curfalloff) {
+ curvemapping_initialize(hmd->curfalloff);
+ }
+
+ /* Generic data needed for applying per-vertex calculations (initialize all members) */
+ hd.vertexCos = vertexCos;
+ modifier_get_vgroup(ob, dm, hmd->name, &hd.dvert, &hd.defgrp_index);
+
+ hd.curfalloff = hmd->curfalloff;
+
+ hd.falloff_type = hmd->falloff_type;
+ hd.falloff = (hmd->falloff_type == eHook_Falloff_None) ? 0.0f : hmd->falloff;
+ hd.falloff_sq = SQUARE(hd.falloff);
+ hd.fac_orig = hmd->force;
+
+ hd.use_falloff = (hd.falloff_sq != 0.0f);
+ hd.use_uniform = (hmd->flag & MOD_HOOK_UNIFORM_SPACE) != 0;
+
+ if (hd.use_uniform) {
+ copy_m3_m4(hd.mat_uniform, hmd->parentinv);
+ mul_v3_m3v3(hd.cent, hd.mat_uniform, hmd->cent);
+ }
+ else {
+ unit_m3(hd.mat_uniform); /* unused */
+ copy_v3_v3(hd.cent, hmd->cent);
+ }
+
/* get world-space matrix of target, corrected for the space the verts are in */
if (hmd->subtarget[0] && pchan) {
/* bone target if there's a matching pose-channel */
@@ -156,10 +304,9 @@ 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_m4_series(mat, ob->imat, dmat, hmd->parentinv);
+ mul_m4_series(hd.mat, ob->imat, dmat, hmd->parentinv);
+ /* --- done with 'hd' init --- */
- modifier_get_vgroup(ob, dm, hmd->name, &dvert, &defgrp_index);
- max_dvert = (dvert) ? numVerts : 0;
/* Regarding index range checking below.
*
@@ -168,13 +315,11 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
* indices that are out of range because old blender did
* not correct them on exit editmode. - zr
*/
-
+
if (hmd->force == 0.0f) {
/* do nothing, avoid annoying checks in the loop */
}
else if (hmd->indexar) { /* vertex indices? */
- const float fac_orig = hmd->force;
- float fac;
const int *origindex_ar;
/* if DerivedMesh is present and has original index data, use it */
@@ -185,16 +330,7 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
for (j = 0; j < numVerts; j++) {
if (origindex_ar[j] == *index_pt) {
- float *co = vertexCos[j];
- if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
- if (dvert)
- fac *= defvert_find_weight(dvert + j, defgrp_index);
-
- if (fac) {
- mul_v3_m4v3(vec, mat, co);
- interp_v3_v3v3(co, co, vec, fac);
- }
- }
+ hook_co_apply(&hd, j);
}
}
}
@@ -203,34 +339,14 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
else { /* missing dm or ORIGINDEX */
for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) {
if (*index_pt < numVerts) {
- float *co = vertexCos[*index_pt];
- if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
- if (dvert)
- fac *= defvert_find_weight(dvert + (*index_pt), defgrp_index);
-
- if (fac) {
- mul_v3_m4v3(vec, mat, co);
- interp_v3_v3v3(co, co, vec, fac);
- }
- }
+ hook_co_apply(&hd, *index_pt);
}
}
}
}
- else if (dvert) { /* vertex group hook */
- const float fac_orig = hmd->force;
-
- for (i = 0; i < max_dvert; i++, dvert++) {
- float fac;
- float *co = vertexCos[i];
-
- if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
- fac *= defvert_find_weight(dvert, defgrp_index);
- if (fac) {
- mul_v3_m4v3(vec, mat, co);
- interp_v3_v3v3(co, co, vec, fac);
- }
- }
+ else if (hd.dvert) { /* vertex group hook */
+ for (i = 0; i < numVerts; i++) {
+ hook_co_apply(&hd, i);
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 6f33bfa73fc..93cd92196b2 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -466,13 +466,13 @@ static void validate_solution(LaplacianSystem *sys, short flag, float lambda, fl
if (sys->zerola[i] == 0) {
lam = sys->numNeEd[i] == sys->numNeFa[i] ? (lambda >= 0.0f ? 1.0f : -1.0f) : (lambda_border >= 0.0f ? 1.0f : -1.0f);
if (flag & MOD_LAPLACIANSMOOTH_X) {
- sys->vertexCos[i][0] += lam * (nlGetVariable(0, i) - sys->vertexCos[i][0]);
+ sys->vertexCos[i][0] += lam * ((float)nlGetVariable(0, i) - sys->vertexCos[i][0]);
}
if (flag & MOD_LAPLACIANSMOOTH_Y) {
- sys->vertexCos[i][1] += lam * (nlGetVariable(1, i) - sys->vertexCos[i][1]);
+ sys->vertexCos[i][1] += lam * ((float)nlGetVariable(1, i) - sys->vertexCos[i][1]);
}
if (flag & MOD_LAPLACIANSMOOTH_Z) {
- sys->vertexCos[i][2] += lam * (nlGetVariable(2, i) - sys->vertexCos[i][2]);
+ sys->vertexCos[i][2] += lam * ((float)nlGetVariable(2, i) - sys->vertexCos[i][2]);
}
}
}
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index 254ca0bda08..174f3df73d4 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -99,7 +99,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
const bool found_test = (mmd->flag & MOD_MASK_INV) == 0;
DerivedMesh *result = NULL;
GHash *vertHash = NULL, *edgeHash, *polyHash;
- GHashIterator *hashIter;
+ GHashIterator gh_iter;
MDeformVert *dvert, *dv;
int numPolys = 0, numLoops = 0, numEdges = 0, numVerts = 0;
int maxVerts, maxEdges, maxPolys;
@@ -291,14 +291,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
/* using ghash-iterators, map data into new mesh */
/* vertices */
- for (hashIter = BLI_ghashIterator_new(vertHash);
- BLI_ghashIterator_done(hashIter) == false;
- BLI_ghashIterator_step(hashIter))
- {
+ GHASH_ITER (gh_iter, vertHash) {
MVert source;
MVert *dest;
- int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
- int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
+ int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
+ int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
dm->getVert(dm, oldIndex, &source);
dest = &mvert_new[newIndex];
@@ -306,17 +303,13 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DM_copy_vert_data(dm, result, oldIndex, newIndex, 1);
*dest = source;
}
- BLI_ghashIterator_free(hashIter);
/* edges */
- for (hashIter = BLI_ghashIterator_new(edgeHash);
- BLI_ghashIterator_done(hashIter) == false;
- BLI_ghashIterator_step(hashIter))
- {
+ GHASH_ITER (gh_iter, edgeHash) {
MEdge source;
MEdge *dest;
- int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
- int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
+ int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
+ int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
dm->getEdge(dm, oldIndex, &source);
dest = &medge_new[newIndex];
@@ -327,15 +320,11 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DM_copy_edge_data(dm, result, oldIndex, newIndex, 1);
*dest = source;
}
- BLI_ghashIterator_free(hashIter);
/* faces */
- for (hashIter = BLI_ghashIterator_new(polyHash);
- BLI_ghashIterator_done(hashIter) == false;
- BLI_ghashIterator_step(hashIter))
- {
- int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(hashIter));
- int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(hashIter));
+ GHASH_ITER (gh_iter, polyHash) {
+ int oldIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getKey(&gh_iter));
+ int newIndex = GET_INT_FROM_POINTER(BLI_ghashIterator_getValue(&gh_iter));
MPoly *source = &mpoly[oldIndex];
MPoly *dest = &mpoly_new[newIndex];
int oldLoopIndex = source->loopstart;
@@ -354,8 +343,6 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
}
}
- BLI_ghashIterator_free(hashIter);
-
MEM_freeN(loop_mapping);
/* why is this needed? - campbell */
diff --git a/source/blender/modifiers/intern/MOD_meshcache_pc2.c b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
index 679bdcd1d47..219eae4ecca 100644
--- a/source/blender/modifiers/intern/MOD_meshcache_pc2.c
+++ b/source/blender/modifiers/intern/MOD_meshcache_pc2.c
@@ -57,7 +57,7 @@ static bool meshcache_read_pc2_head(FILE *fp, const int verts_tot,
return false;
}
- if (strcmp(pc2_head->header, "POINTCACHE2") != 0) {
+ if (!STREQ(pc2_head->header, "POINTCACHE2")) {
*err_str = "Invalid header";
return false;
}
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
new file mode 100644
index 00000000000..58ef850bb4f
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -0,0 +1,501 @@
+/*
+ * ***** 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/modifiers/intern/MOD_normal_edit.c
+ * \ingroup modifiers
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_object_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_mesh_types.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+#include "BLI_bitmap.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_mesh.h"
+#include "BKE_deform.h"
+
+#include "depsgraph_private.h"
+
+#include "MOD_util.h"
+
+
+static void generate_vert_coordinates(
+ DerivedMesh *dm, Object *ob, Object *ob_center, const float offset[3],
+ const int num_verts, float (*r_cos)[3], float r_size[3])
+{
+ float min_co[3], max_co[3];
+ float diff[3];
+ bool do_diff = false;
+
+ INIT_MINMAX(min_co, max_co);
+
+ dm->getVertCos(dm, r_cos);
+
+ /* Get size (i.e. deformation of the spheroid generating normals), either from target object, or own geometry. */
+ if (ob_center) {
+ copy_v3_v3(r_size, ob_center->size);
+ }
+ else {
+ minmax_v3v3_v3_array(min_co, max_co, r_cos, num_verts);
+ /* Set size. */
+ sub_v3_v3v3(r_size, max_co, min_co);
+ }
+
+ /* Error checks - we do not want one or more of our sizes to be null! */
+ if (is_zero_v3(r_size)) {
+ r_size[0] = r_size[1] = r_size[2] = 1.0f;
+ }
+ else {
+ CLAMP_MIN(r_size[0], FLT_EPSILON);
+ CLAMP_MIN(r_size[1], FLT_EPSILON);
+ CLAMP_MIN(r_size[2], FLT_EPSILON);
+ }
+
+ if (ob_center) {
+ /* Translate our coordinates so that center of ob_center is at (0, 0, 0). */
+ float mat[4][4];
+
+ /* Get ob_center coordinates in ob local coordinates. */
+ invert_m4_m4(mat, ob_center->obmat);
+ mul_m4_m4m4(mat, mat, ob->obmat);
+ copy_v3_v3(diff, mat[3]);
+
+ do_diff = true;
+ }
+ else if (!is_zero_v3(offset)) {
+ negate_v3_v3(diff, offset);
+
+ do_diff = true;
+ }
+ /* Else, no need to change coordinates! */
+
+ if (do_diff) {
+ int i = num_verts;
+ while (i--) {
+ add_v3_v3(r_cos[i], diff);
+ }
+ }
+}
+
+/* Note this modifies nos_new in-place. */
+static void mix_normals(
+ const float mix_factor, MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
+ const short mix_mode,
+ const int num_verts, MLoop *mloop, float (*nos_old)[3], float (*nos_new)[3], const int num_loops)
+{
+ /* Mix with org normals... */
+ float *facs = NULL, *wfac;
+ float (*no_new)[3], (*no_old)[3];
+ int i;
+
+ if (dvert) {
+ facs = MEM_mallocN(sizeof(*facs) * (size_t)num_loops, __func__);
+ BKE_defvert_extract_vgroup_to_loopweights(
+ dvert, defgrp_index, num_verts, mloop, num_loops, facs, use_invert_vgroup);
+ }
+
+ for (i = num_loops, no_new = nos_new, no_old = nos_old, wfac = facs; i--; no_new++, no_old++, wfac++) {
+ const float fac = facs ? *wfac * mix_factor : mix_factor;
+
+ switch (mix_mode) {
+ case MOD_NORMALEDIT_MIX_ADD:
+ add_v3_v3(*no_new, *no_old);
+ normalize_v3(*no_new);
+ break;
+ case MOD_NORMALEDIT_MIX_SUB:
+ sub_v3_v3(*no_new, *no_old);
+ normalize_v3(*no_new);
+ break;
+ case MOD_NORMALEDIT_MIX_MUL:
+ mul_v3_v3(*no_new, *no_old);
+ normalize_v3(*no_new);
+ break;
+ case MOD_NORMALEDIT_MIX_COPY:
+ break;
+ }
+ interp_v3_v3v3_slerp_safe(*no_new, *no_old, *no_new, fac);
+ }
+
+ MEM_SAFE_FREE(facs);
+}
+
+static void normalEditModifier_do_radial(
+ NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
+ short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
+ const short mix_mode, const float mix_factor,
+ MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
+ MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
+ MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
+{
+ int i;
+
+ float (*cos)[3] = MEM_mallocN(sizeof(*cos) * num_verts, __func__);
+ float (*nos)[3] = MEM_mallocN(sizeof(*nos) * num_loops, __func__);
+ float size[3];
+
+ BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__);
+
+ generate_vert_coordinates(dm, ob, smd->target, smd->offset, num_verts, cos, size);
+
+ /**
+ * size gives us our spheroid coefficients ``(A, B, C)``.
+ * Then, we want to find out for each vert its (a, b, c) triple (proportional to (A, B, C) one).
+ *
+ * Ellipsoid basic equation: ``(x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1.``
+ * Since we want to find (a, b, c) matching this equation and proportional to (A, B, C), we can do:
+ * <pre>
+ * m = B / A
+ * n = C / A
+ * </pre>
+ *
+ * hence:
+ * <pre>
+ * (x^2/a^2) + (y^2/b^2) + (z^2/c^2) = 1
+ * -> b^2*c^2*x^2 + a^2*c^2*y^2 + a^2*b^2*z^2 = a^2*b^2*c^2
+ * b = ma
+ * c = na
+ * -> m^2*a^2*n^2*a^2*x^2 + a^2*n^2*a^2*y^2 + a^2*m^2*a^2*z^2 = a^2*m^2*a^2*n^2*a^2
+ * -> m^2*n^2*a^4*x^2 + n^2*a^4*y^2 + m^2*a^4*z^2 = m^2*n^2*a^6
+ * -> a^2 = (m^2*n^2*x^2 + n^2y^2 + m^2z^2) / (m^2*n^2) = x^2 + (y^2 / m^2) + (z^2 / n^2)
+ * -> b^2 = (m^2*n^2*x^2 + n^2y^2 + m^2z^2) / (n^2) = (m^2 * x^2) + y^2 + (m^2 * z^2 / n^2)
+ * -> c^2 = (m^2*n^2*x^2 + n^2y^2 + m^2z^2) / (m^2) = (n^2 * x^2) + (n^2 * y^2 / m^2) + z^2
+ * </pre>
+ *
+ * All we have to do now is compute normal of the spheroid at that point:
+ * <pre>
+ * n = (x / a^2, y / b^2, z / c^2)
+ * </pre>
+ * And we are done!
+ */
+ {
+ const float a = size[0], b = size[1], c = size[2];
+ const float m2 = (b * b) / (a * a);
+ const float n2 = (c * c) / (a * a);
+
+ MLoop *ml;
+ float (*no)[3];
+
+ /* We reuse cos to now store the ellipsoid-normal of the verts! */
+ for (i = num_loops, ml = mloop, no = nos; i-- ; ml++, no++) {
+ const int vidx = ml->v;
+ float *co = cos[vidx];
+
+ if (!BLI_BITMAP_TEST(done_verts, vidx)) {
+ const float x2 = co[0] * co[0];
+ const float y2 = co[1] * co[1];
+ const float z2 = co[2] * co[2];
+ const float a2 = x2 + (y2 / m2) + (z2 / n2);
+ const float b2 = (m2 * x2) + y2 + (m2 * z2 / n2);
+ const float c2 = (n2 * x2) + (n2 * y2 / m2) + z2;
+
+ co[0] /= a2;
+ co[1] /= b2;
+ co[2] /= c2;
+ normalize_v3(co);
+
+ BLI_BITMAP_ENABLE(done_verts, vidx);
+ }
+ copy_v3_v3(*no, co);
+ }
+ }
+
+ if (loopnors) {
+ mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ }
+
+ BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
+ mpoly, (const float(*)[3])polynors, num_polys, clnors);
+
+ MEM_freeN(cos);
+ MEM_freeN(nos);
+ MEM_freeN(done_verts);
+}
+
+static void normalEditModifier_do_directional(
+ NormalEditModifierData *smd, Object *ob, DerivedMesh *dm,
+ short (*clnors)[2], float (*loopnors)[3], float (*polynors)[3],
+ const short mix_mode, const float mix_factor,
+ MDeformVert *dvert, const int defgrp_index, const bool use_invert_vgroup,
+ MVert *mvert, const int num_verts, MEdge *medge, const int num_edges,
+ MLoop *mloop, const int num_loops, MPoly *mpoly, const int num_polys)
+{
+ const bool use_parallel_normals = (smd->flag & MOD_NORMALEDIT_USE_DIRECTION_PARALLEL) != 0;
+
+ float (*cos)[3] = MEM_mallocN(sizeof(*cos) * num_verts, __func__);
+ float (*nos)[3] = MEM_mallocN(sizeof(*nos) * num_loops, __func__);
+
+ float target_co[3];
+ int i;
+
+ dm->getVertCos(dm, cos);
+
+ /* Get target's center coordinates in ob local coordinates. */
+ {
+ float mat[4][4];
+
+ invert_m4_m4(mat, ob->obmat);
+ mul_m4_m4m4(mat, mat, smd->target->obmat);
+ copy_v3_v3(target_co, mat[3]);
+ }
+
+ if (use_parallel_normals) {
+ float no[3];
+
+ sub_v3_v3v3(no, target_co, smd->offset);
+ normalize_v3(no);
+
+ for (i = num_loops; i--; ) {
+ copy_v3_v3(nos[i], no);
+ }
+ }
+ else {
+ BLI_bitmap *done_verts = BLI_BITMAP_NEW((size_t)num_verts, __func__);
+ MLoop *ml;
+ float (*no)[3];
+
+ /* We reuse cos to now store the 'to target' normal of the verts! */
+ for (i = num_loops, no = nos, ml = mloop; i--; no++, ml++) {
+ const int vidx = ml->v;
+ float *co = cos[vidx];
+
+ if (!BLI_BITMAP_TEST(done_verts, vidx)) {
+ sub_v3_v3v3(co, target_co, co);
+ normalize_v3(co);
+
+ BLI_BITMAP_ENABLE(done_verts, vidx);
+ }
+
+ copy_v3_v3(*no, co);
+ }
+
+ MEM_freeN(done_verts);
+ }
+
+ if (loopnors) {
+ mix_normals(mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ mix_mode, num_verts, mloop, loopnors, nos, num_loops);
+ }
+
+ BKE_mesh_normals_loop_custom_set(mvert, num_verts, medge, num_edges, mloop, nos, num_loops,
+ mpoly, (const float(*)[3])polynors, num_polys, clnors);
+
+ MEM_freeN(cos);
+ MEM_freeN(nos);
+}
+
+static bool is_valid_target(NormalEditModifierData *smd)
+{
+ if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
+ return true;
+ }
+ else if ((smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) && smd->target) {
+ return true;
+ }
+ modifier_setError((ModifierData *)smd, "Invalid target settings");
+ return false;
+}
+
+static void normalEditModifier_do(NormalEditModifierData *smd, Object *ob, DerivedMesh *dm)
+{
+ Mesh *me = ob->data;
+
+ const int num_verts = dm->getNumVerts(dm);
+ const int num_edges = dm->getNumEdges(dm);
+ const int num_loops = dm->getNumLoops(dm);
+ const int num_polys = dm->getNumPolys(dm);
+ MVert *mvert = dm->getVertArray(dm);
+ MEdge *medge = dm->getEdgeArray(dm);
+ MLoop *mloop = dm->getLoopArray(dm);
+ MPoly *mpoly = dm->getPolyArray(dm);
+
+ const bool use_invert_vgroup = ((smd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
+ const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
+ (smd->mix_factor == 1.0f) &&
+ (smd->defgrp_name[0] == '\0'));
+
+ int defgrp_index;
+ MDeformVert *dvert;
+
+ float (*loopnors)[3] = NULL;
+ short (*clnors)[2];
+
+ float (*polynors)[3];
+ bool free_polynors = false;
+
+ /* Do not run that modifier at all if autosmooth is disabled! */
+ if (!is_valid_target(smd) || !num_loops) {
+ return;
+ }
+
+ if (!(me->flag & ME_AUTOSMOOTH)) {
+ modifier_setError((ModifierData *)smd, "Enable 'Auto Smooth' option in mesh settings");
+ return;
+ }
+
+
+ if (use_current_clnors) {
+ dm->calcLoopNormals(dm, true, me->smoothresh);
+ loopnors = dm->getLoopDataArray(dm, CD_NORMAL);
+ }
+
+ clnors = CustomData_duplicate_referenced_layer(&dm->loopData, CD_CUSTOMLOOPNORMAL, num_loops);
+ if (!clnors) {
+ DM_add_loop_layer(dm, CD_CUSTOMLOOPNORMAL, CD_CALLOC, NULL);
+ clnors = dm->getLoopDataArray(dm, CD_CUSTOMLOOPNORMAL);
+ }
+
+ polynors = dm->getPolyDataArray(dm, CD_NORMAL);
+ if (!polynors) {
+ polynors = MEM_mallocN(sizeof(*polynors) * num_polys, __func__);
+ BKE_mesh_calc_normals_poly(mvert, num_verts, mloop, mpoly, num_loops, num_polys, polynors, false);
+ free_polynors = true;
+ }
+
+ modifier_get_vgroup(ob, dm, smd->defgrp_name, &dvert, &defgrp_index);
+
+ if (smd->mode == MOD_NORMALEDIT_MODE_RADIAL) {
+ normalEditModifier_do_radial(
+ smd, ob, dm, clnors, loopnors, polynors,
+ smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
+ }
+ else if (smd->mode == MOD_NORMALEDIT_MODE_DIRECTIONAL) {
+ normalEditModifier_do_directional(
+ smd, ob, dm, clnors, loopnors, polynors,
+ smd->mix_mode, smd->mix_factor, dvert, defgrp_index, use_invert_vgroup,
+ mvert, num_verts, medge, num_edges, mloop, num_loops, mpoly, num_polys);
+ }
+
+ if (free_polynors) {
+ MEM_freeN(polynors);
+ }
+}
+
+static void initData(ModifierData *md)
+{
+ NormalEditModifierData *smd = (NormalEditModifierData *)md;
+
+ smd->mode = MOD_NORMALEDIT_MODE_RADIAL;
+
+ smd->mix_mode = MOD_NORMALEDIT_MIX_COPY;
+ smd->mix_factor = 1.0f;
+}
+
+static void copyData(ModifierData *md, ModifierData *target)
+{
+ modifier_copyData_generic(md, target);
+}
+
+static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
+{
+ NormalEditModifierData *smd = (NormalEditModifierData *)md;
+ CustomDataMask dataMask = CD_CUSTOMLOOPNORMAL;
+
+ /* Ask for vertexgroups if we need them. */
+ if (smd->defgrp_name[0]) {
+ dataMask |= (CD_MASK_MDEFORMVERT);
+ }
+
+ return dataMask;
+}
+
+static bool dependsOnNormals(ModifierData *UNUSED(md))
+{
+ return true;
+}
+
+static void foreachObjectLink(ModifierData *md, Object *ob, ObjectWalkFunc walk, void *userData)
+{
+ NormalEditModifierData *smd = (NormalEditModifierData *) md;
+
+ walk(userData, ob, &smd->target);
+}
+
+static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ NormalEditModifierData *smd = (NormalEditModifierData *) md;
+
+ walk(userData, ob, (ID **)&smd->target);
+}
+
+static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
+{
+ NormalEditModifierData *smd = (NormalEditModifierData *)md;
+
+ return !is_valid_target(smd);
+}
+
+static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UNUSED(scene),
+ Object *UNUSED(ob), DagNode *obNode)
+{
+ NormalEditModifierData *smd = (NormalEditModifierData *) md;
+
+ if (smd->target) {
+ DagNode *Node = dag_get_node(forest, smd->target);
+
+ dag_add_relation(forest, Node, obNode, DAG_RL_OB_DATA, "NormalEdit Modifier");
+ }
+}
+
+static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag))
+{
+ normalEditModifier_do((NormalEditModifierData *)md, ob, dm);
+ return dm;
+}
+
+ModifierTypeInfo modifierType_NormalEdit = {
+ /* name */ "Set Split Normals",
+ /* structName */ "NormalEditModifierData",
+ /* structSize */ sizeof(NormalEditModifierData),
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_AcceptsCVs |
+ eModifierTypeFlag_SupportsMapping |
+ eModifierTypeFlag_SupportsEditmode |
+ eModifierTypeFlag_EnableInEditmode,
+ /* copyData */ copyData,
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* applyModifier */ applyModifier,
+ /* applyModifierEM */ NULL,
+ /* initData */ initData,
+ /* requiredDataMask */ requiredDataMask,
+ /* freeData */ NULL,
+ /* isDisabled */ isDisabled,
+ /* updateDepgraph */ updateDepgraph,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ dependsOnNormals,
+ /* foreachObjectLink */ foreachObjectLink,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+};
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 56197bfcca8..557d136965b 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -43,6 +43,8 @@
#include "BLI_utildefines.h"
#include "BKE_cdderivedmesh.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
#include "BKE_lattice.h"
#include "BKE_modifier.h"
#include "BKE_particle.h"
@@ -183,7 +185,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
int maxvert, maxpoly, maxloop, totpart = 0, first_particle = 0;
int k, p, p_skip;
short track = ob->trackflag % 3, trackneg, axis = pimd->axis;
- float max_co = 0.0, min_co = 0.0, temp_co[3], cross[3];
+ float max_co = 0.0, min_co = 0.0, temp_co[3];
float *size = NULL;
trackneg = ((ob->trackflag > 2) ? 1 : 0);
@@ -276,6 +278,9 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
orig_mloop = dm->getLoopArray(dm);
for (p = 0, p_skip = 0; p < totpart; p++) {
+ float prev_dir[3];
+ float frame[4]; /* frame orientation quaternion */
+
/* skip particle? */
if (particle_skip(pimd, psys, p))
continue;
@@ -321,19 +326,55 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
normalize_v3(state.vel);
- /* TODO: incremental rotations somehow */
+ /* Incrementally Rotating Frame (Bishop Frame) */
+ if (k == 0) {
+ float hairmat[4][4];
+ float mat[3][3];
+
+ if (first_particle + p < psys->totpart)
+ pa = psys->particles + first_particle + p;
+ else {
+ ChildParticle *cpa = psys->child + (p - psys->totpart);
+ pa = psys->particles + cpa->parent;
+ }
+ psys_mat_hair_to_global(sim.ob, sim.psmd->dm, sim.psys->part->from, pa, hairmat);
+ copy_m3_m4(mat, hairmat);
+ /* to quaternion */
+ mat3_to_quat(frame, mat);
+
+ /* note: direction is same as normal vector currently,
+ * but best to keep this separate so the frame can be
+ * rotated later if necessary
+ */
+ copy_v3_v3(prev_dir, state.vel);
+ }
+ else {
+ float rot[4];
+
+ /* incrementally rotate along bend direction */
+ rotation_between_vecs_to_quat(rot, prev_dir, state.vel);
+ mul_qt_qtqt(frame, rot, frame);
+
+ copy_v3_v3(prev_dir, state.vel);
+ }
+
+ copy_qt_qt(state.rot, frame);
+#if 0
+ /* Absolute Frame (Frenet Frame) */
if (state.vel[axis] < -0.9999f || state.vel[axis] > 0.9999f) {
unit_qt(state.rot);
}
else {
+ float cross[3];
float temp[3] = {0.0f, 0.0f, 0.0f};
temp[axis] = 1.0f;
-
+
cross_v3_v3v3(cross, temp, state.vel);
-
+
/* state.vel[axis] is the only component surviving from a dot product with the axis */
axis_angle_to_quat(state.rot, cross, saacos(state.vel[axis]));
}
+#endif
}
else {
state.time = -1.0;
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index a41fbb03462..9860daeda4c 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -85,37 +85,7 @@ static void copyData(ModifierData *md, ModifierData *target)
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md;
- CustomDataMask dataMask = 0;
- MTex *mtex;
- int i;
-
- if (!psmd->psys->part)
- return 0;
-
- for (i = 0; i < MAX_MTEX; i++) {
- mtex = psmd->psys->part->mtex[i];
- if (mtex && mtex->mapto && (mtex->texco & TEXCO_UV))
- dataMask |= CD_MASK_MTFACE;
- }
-
- if (psmd->psys->part->tanfac != 0.0f)
- dataMask |= CD_MASK_MTFACE;
-
- /* ask for vertexgroups if we need them */
- for (i = 0; i < PSYS_TOT_VG; i++) {
- if (psmd->psys->vgroup[i]) {
- dataMask |= CD_MASK_MDEFORMVERT;
- break;
- }
- }
-
- /* particles only need this if they are after a non deform modifier, and
- * the modifier stack will only create them in that case. */
- dataMask |= CD_MASK_ORIGSPACE_MLOOP | CD_MASK_ORIGINDEX;
-
- dataMask |= CD_MASK_ORCO;
-
- return dataMask;
+ return psys_emitter_customdata_mask(psmd->psys);
}
/* saves the current emitter state for a particle system and calculates particles */
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index 228c42e526c..2f6297371b2 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -159,8 +159,8 @@ DerivedMesh *get_cddm(Object *ob, struct BMEditMesh *em, DerivedMesh *dm, float
if (dm) {
if (dm->type != DM_TYPE_CDDM) {
dm = CDDM_copy(dm);
- CDDM_apply_vert_coords(dm, vertexCos);
}
+ CDDM_apply_vert_coords(dm, vertexCos);
if (use_normals) {
DM_ensure_normals(dm);
@@ -305,6 +305,7 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(LaplacianDeform);
INIT_TYPE(Wireframe);
INIT_TYPE(DataTransfer);
+ INIT_TYPE(NormalEdit);
INIT_TYPE(PointCache);
#undef INIT_TYPE
}
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index f6714e79401..3eb34e56700 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -167,6 +167,7 @@ static void warpModifier_do(WarpModifierData *wmd, Object *ob,
float tmat[4][4];
+ const float falloff_radius_sq = SQUARE(wmd->falloff_radius);
float strength = wmd->strength;
float fac = 1.0f, weight;
int i;
@@ -179,6 +180,9 @@ static void warpModifier_do(WarpModifierData *wmd, Object *ob,
return;
modifier_get_vgroup(ob, dm, wmd->defgrp_name, &dvert, &defgrp_index);
+ if (dvert == NULL) {
+ defgrp_index = -1;
+ }
if (wmd->curfalloff == NULL) /* should never happen, but bad lib linking could cause it */
wmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
@@ -222,17 +226,15 @@ static void warpModifier_do(WarpModifierData *wmd, Object *ob,
float *co = vertexCos[i];
if (wmd->falloff_type == eWarp_Falloff_None ||
- ((fac = len_v3v3(co, mat_from[3])) < wmd->falloff_radius &&
- (fac = (wmd->falloff_radius - fac) / wmd->falloff_radius)))
+ ((fac = len_squared_v3v3(co, mat_from[3])) < falloff_radius_sq &&
+ (fac = (wmd->falloff_radius - sqrtf(fac)) / wmd->falloff_radius)))
{
/* skip if no vert group found */
- if (dvert && defgrp_index != -1) {
+ if (defgrp_index != -1) {
dv = &dvert[i];
-
- if (dv) {
- weight = defvert_find_weight(dv, defgrp_index) * strength;
- if (weight <= 0.0f) /* Should never occure... */
- continue;
+ weight = defvert_find_weight(dv, defgrp_index) * strength;
+ if (weight <= 0.0f) {
+ continue;
}
}
@@ -263,6 +265,9 @@ static void warpModifier_do(WarpModifierData *wmd, Object *ob,
case eWarp_Falloff_Sphere:
fac = sqrtf(2 * fac - fac * fac);
break;
+ case eWarp_Falloff_InvSquare:
+ fac = fac * (2.0f - fac);
+ break;
}
fac *= weight;
@@ -274,27 +279,29 @@ static void warpModifier_do(WarpModifierData *wmd, Object *ob,
fac *= texres.tin;
}
- /* into the 'from' objects space */
- mul_m4_v3(mat_from_inv, co);
+ if (fac != 0.0f) {
+ /* into the 'from' objects space */
+ mul_m4_v3(mat_from_inv, co);
- if (fac >= 1.0f) {
- mul_m4_v3(mat_final, co);
- }
- else if (fac > 0.0f) {
- if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
- /* interpolate the matrix for nicer locations */
- blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
- mul_m4_v3(tmat, co);
+ if (fac == 1.0f) {
+ mul_m4_v3(mat_final, co);
}
else {
- float tvec[3];
- mul_v3_m4v3(tvec, mat_final, co);
- interp_v3_v3v3(co, co, tvec, fac);
+ if (wmd->flag & MOD_WARP_VOLUME_PRESERVE) {
+ /* interpolate the matrix for nicer locations */
+ blend_m4_m4m4(tmat, mat_unit, mat_final, fac);
+ mul_m4_v3(tmat, co);
+ }
+ else {
+ float tvec[3];
+ mul_v3_m4v3(tvec, mat_final, co);
+ interp_v3_v3v3(co, co, tvec, fac);
+ }
}
- }
- /* out of the 'from' objects space */
- mul_m4_v3(mat_from, co);
+ /* out of the 'from' objects space */
+ mul_m4_v3(mat_from, co);
+ }
}
}
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index 8b611f9e6da..aa5e6116516 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -74,7 +74,7 @@ static bool dependsOnNormals(ModifierData *UNUSED(md))
return true;
}
-static DerivedMesh *WireframeModifier_do( WireframeModifierData *wmd, Object *ob, DerivedMesh *dm)
+static DerivedMesh *WireframeModifier_do(WireframeModifierData *wmd, Object *ob, DerivedMesh *dm)
{
DerivedMesh *result;
BMesh *bm;
diff --git a/source/blender/nodes/composite/nodes/node_composite_image.c b/source/blender/nodes/composite/nodes/node_composite_image.c
index ecc02e732ce..e8845b543b8 100644
--- a/source/blender/nodes/composite/nodes/node_composite_image.c
+++ b/source/blender/nodes/composite/nodes/node_composite_image.c
@@ -439,7 +439,7 @@ static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr)
static int node_composit_poll_rlayers(bNodeType *UNUSED(ntype), bNodeTree *ntree)
{
- if (strcmp(ntree->idname, "CompositorNodeTree") == 0) {
+ if (STREQ(ntree->idname, "CompositorNodeTree")) {
Scene *scene;
/* XXX ugly: check if ntree is a local scene node tree.
diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c
index 7a15d6364dc..415427c360f 100644
--- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c
+++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.c
@@ -47,7 +47,8 @@ static bNodeSocketTemplate cmp_node_planetrackdeform_out[] = {
static void init(bNodeTree *UNUSED(ntree), bNode *node)
{
NodePlaneTrackDeformData *data = MEM_callocN(sizeof(NodePlaneTrackDeformData), "node plane track deform data");
-
+ data->motion_blur_samples = 16;
+ data->motion_blur_shutter = 0.5f;
node->storage = data;
}
diff --git a/source/blender/nodes/intern/node_socket.c b/source/blender/nodes/intern/node_socket.c
index 282567b797f..01c642b063d 100644
--- a/source/blender/nodes/intern/node_socket.c
+++ b/source/blender/nodes/intern/node_socket.c
@@ -108,7 +108,7 @@ static bNodeSocket *verify_socket_template(bNodeTree *ntree, bNode *node, int in
bNodeSocket *sock;
for (sock = socklist->first; sock; sock = sock->next) {
- if (strncmp(sock->name, stemp->name, NODE_MAXSTR) == 0)
+ if (STREQLEN(sock->name, stemp->name, NODE_MAXSTR))
break;
}
if (sock) {
diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c
index 503fe034754..0264abe451f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_gamma.c
+++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c
@@ -48,9 +48,9 @@ static void node_shader_exec_gamma(void *UNUSED(data), int UNUSED(thread), bNode
nodestack_get_vec(col, SOCK_VECTOR, in[0]);
nodestack_get_vec(&gamma, SOCK_FLOAT, in[1]);
- out[0]->vec[0] = col[0] > 0.0 ? pow(col[0], gamma) : col[0];
- out[0]->vec[1] = col[1] > 0.0 ? pow(col[1], gamma) : col[1];
- out[0]->vec[2] = col[2] > 0.0 ? pow(col[2], gamma) : col[2];
+ out[0]->vec[0] = col[0] > 0.0f ? powf(col[0], gamma) : col[0];
+ out[0]->vec[1] = col[1] > 0.0f ? powf(col[1], gamma) : col[1];
+ out[0]->vec[2] = col[2] > 0.0f ? powf(col[2], gamma) : col[2];
}
static int node_shader_gpu_gamma(GPUMaterial *mat, bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
diff --git a/source/blender/nodes/shader/nodes/node_shader_geom.c b/source/blender/nodes/shader/nodes/node_shader_geom.c
index 7c598f92bed..2fb03536bbe 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geom.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geom.c
@@ -63,7 +63,7 @@ static void node_shader_exec_geom(void *data, int UNUSED(thread), bNode *node, b
if (ngeo->uvname[0]) {
/* find uv map by name */
for (i = 0; i < shi->totuv; i++) {
- if (strcmp(shi->uv[i].name, ngeo->uvname) == 0) {
+ if (STREQ(shi->uv[i].name, ngeo->uvname)) {
suv = &shi->uv[i];
break;
}
@@ -84,7 +84,7 @@ static void node_shader_exec_geom(void *data, int UNUSED(thread), bNode *node, b
if (ngeo->colname[0]) {
for (i = 0; i < shi->totcol; i++) {
- if (strcmp(shi->col[i].name, ngeo->colname) == 0) {
+ if (STREQ(shi->col[i].name, ngeo->colname)) {
scol = &shi->col[i];
break;
}
diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.c
index 01851b51c27..553ea65154f 100644
--- a/source/blender/nodes/shader/nodes/node_shader_geometry.c
+++ b/source/blender/nodes/shader/nodes/node_shader_geometry.c
@@ -37,6 +37,7 @@ static bNodeSocketTemplate sh_node_geometry_out[] = {
{ SOCK_VECTOR, 0, N_("Incoming"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_VECTOR, 0, N_("Parametric"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 0, N_("Backfacing"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
+ { SOCK_FLOAT, 0, N_("Pointiness"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
{ -1, 0, "" }
};
diff --git a/source/blender/nodes/shader/nodes/node_shader_lamp.c b/source/blender/nodes/shader/nodes/node_shader_lamp.c
index adf53ba9b52..3b000d49822 100644
--- a/source/blender/nodes/shader/nodes/node_shader_lamp.c
+++ b/source/blender/nodes/shader/nodes/node_shader_lamp.c
@@ -62,11 +62,11 @@ static int gpu_shader_lamp(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(
{
if (node->id) {
GPULamp *lamp = GPU_lamp_from_blender(GPU_material_scene(mat), (Object *)node->id, NULL);
- GPUNodeLink *col, *lv, *dist, *visifac, *shadow;
+ GPUNodeLink *col, *lv, *dist, *visifac, *shadow, *energy;
- visifac = GPU_lamp_get_data(mat, lamp, &col, &lv, &dist, &shadow);
+ visifac = GPU_lamp_get_data(mat, lamp, &col, &lv, &dist, &shadow, &energy);
- return GPU_stack_link(mat, "lamp", in, out, col, lv, dist, shadow, visifac);
+ return GPU_stack_link(mat, "lamp", in, out, col, energy, lv, dist, shadow, visifac);
}
return 0;
diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
index fd864f1c7c6..9fe56d4f01d 100644
--- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
+++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c
@@ -51,7 +51,7 @@ static void node_shader_init_subsurface_scattering(bNodeTree *UNUSED(ntree), bNo
node->custom1 = SHD_SUBSURFACE_CUBIC;
/*for (sock = node->inputs.first; sock; sock = sock->next) {
- if (strcmp(sock->name, "Sharpness") == 0) {
+ if (STREQ(sock->name, "Sharpness")) {
bNodeSocketValueFloat *dval = sock->default_value;
dval->value = 0.0f;
}
@@ -72,7 +72,7 @@ static void node_shader_update_subsurface_scattering(bNodeTree *UNUSED(ntree), b
int falloff = node->custom1;
for (sock = node->inputs.first; sock; sock = sock->next) {
- if (strcmp(sock->name, "Sharpness") == 0) {
+ if (STREQ(sock->name, "Sharpness")) {
if (falloff == SHD_SUBSURFACE_CUBIC)
sock->flag &= ~SOCK_UNAVAIL;
else
diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
index 85eca6ae990..be393582a42 100644
--- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
+++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.c
@@ -51,12 +51,14 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, bNode *UNUSED(node), bNod
if (type == GPU_MATERIAL_TYPE_MESH) {
return GPU_stack_link(mat, "node_tex_coord", in, out,
GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), orco, mtface);
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
+ GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, mtface);
}
else {
return GPU_stack_link(mat, "node_tex_coord_background", in, out,
GPU_builtin(GPU_VIEW_POSITION), GPU_builtin(GPU_VIEW_NORMAL),
- GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX), orco, mtface);
+ GPU_builtin(GPU_INVERSE_VIEW_MATRIX), GPU_builtin(GPU_INVERSE_OBJECT_MATRIX),
+ GPU_builtin(GPU_CAMERA_TEXCO_FACTORS), orco, mtface);
}
}
diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c
index 1984ee506e0..19bc16fb82d 100644
--- a/source/blender/nodes/texture/nodes/node_texture_math.c
+++ b/source/blender/nodes/texture/nodes/node_texture_math.c
@@ -195,6 +195,10 @@ static void valuefn(float *out, TexParams *p, bNode *node, bNodeStack **in, shor
break;
}
}
+
+ if (node->custom2 & SHD_MATH_CLAMP) {
+ CLAMP(*out, 0.0f, 1.0f);
+ }
}
static void exec(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
diff --git a/source/blender/physics/BPH_mass_spring.h b/source/blender/physics/BPH_mass_spring.h
new file mode 100644
index 00000000000..c189dea28a4
--- /dev/null
+++ b/source/blender/physics/BPH_mass_spring.h
@@ -0,0 +1,62 @@
+/*
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BPH_MASS_SPRING_H__
+#define __BPH_MASS_SPRING_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct Implicit_Data;
+struct Object;
+struct ClothModifierData;
+struct ListBase;
+struct VoxelData;
+
+typedef enum eMassSpringSolverStatus {
+ BPH_SOLVER_SUCCESS = (1 << 0),
+ BPH_SOLVER_NUMERICAL_ISSUE = (1 << 1),
+ BPH_SOLVER_NO_CONVERGENCE = (1 << 2),
+ BPH_SOLVER_INVALID_INPUT = (1 << 3),
+} eMassSpringSolverStatus;
+
+struct Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings);
+void BPH_mass_spring_solver_free(struct Implicit_Data *id);
+
+int BPH_cloth_solver_init(struct Object *ob, struct ClothModifierData *clmd);
+void BPH_cloth_solver_free(struct ClothModifierData *clmd);
+int BPH_cloth_solve(struct Object *ob, float frame, struct ClothModifierData *clmd, struct ListBase *effectors);
+void BKE_cloth_solver_set_positions(struct ClothModifierData *clmd);
+
+bool BPH_cloth_solver_get_texture_data(struct Object *ob, struct ClothModifierData *clmd, struct VoxelData *vd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/physics/CMakeLists.txt b/source/blender/physics/CMakeLists.txt
new file mode 100644
index 00000000000..08ff1faca49
--- /dev/null
+++ b/source/blender/physics/CMakeLists.txt
@@ -0,0 +1,53 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2014, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Lukas Toenne
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ intern
+ ../blenlib
+ ../blenkernel
+ ../imbuf
+ ../makesdna
+ ../../../intern/guardedalloc
+ ../../../extern/Eigen3
+)
+
+set(INC_SYS
+
+)
+
+set(SRC
+ intern/BPH_mass_spring.cpp
+ intern/ConstrainedConjugateGradient.h
+ intern/hair_volume.cpp
+ intern/implicit.h
+ intern/implicit_blender.c
+ intern/implicit_eigen.cpp
+ intern/eigen_utils.h
+
+ BPH_mass_spring.h
+)
+
+blender_add_lib(bf_physics "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/physics/SConscript b/source/blender/physics/SConscript
new file mode 100644
index 00000000000..c8165886cab
--- /dev/null
+++ b/source/blender/physics/SConscript
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2011, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Jeroen Bakker, Monique Dewanchand, Blender Developers Fund.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+Import ('env')
+defs = []
+
+sources = env.Glob('intern/*.cpp') + env.Glob('intern/*.c')
+
+incs = [
+ '.',
+ 'intern',
+ '../blenlib',
+ '../blenkernel',
+ '../imbuf',
+ '../makesdna',
+ '../../../intern/guardedalloc',
+ '../../../extern/Eigen3',
+ ]
+
+env.BlenderLib('bf_physics', sources, incs, defines=defs, libtype=['core', 'player'], priority=[180, 190])
diff --git a/source/blender/physics/intern/BPH_mass_spring.cpp b/source/blender/physics/intern/BPH_mass_spring.cpp
new file mode 100644
index 00000000000..6cddbc6aa46
--- /dev/null
+++ b/source/blender/physics/intern/BPH_mass_spring.cpp
@@ -0,0 +1,1017 @@
+/*
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/physics/intern/BPH_mass_spring.cpp
+ * \ingroup bph
+ */
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "DNA_cloth_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_object_force.h"
+#include "DNA_object_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+
+#include "BLI_math.h"
+#include "BLI_linklist.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_cloth.h"
+#include "BKE_collision.h"
+#include "BKE_effect.h"
+}
+
+#include "BPH_mass_spring.h"
+#include "implicit.h"
+
+static float I3[3][3] = {{1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0}};
+
+/* Number of off-diagonal non-zero matrix blocks.
+ * Basically there is one of these for each vertex-vertex interaction.
+ */
+static int cloth_count_nondiag_blocks(Cloth *cloth)
+{
+ LinkNode *link;
+ int nondiag = 0;
+
+ for (link = cloth->springs; link; link = link->next) {
+ ClothSpring *spring = (ClothSpring *)link->link;
+ switch (spring->type) {
+ case CLOTH_SPRING_TYPE_BENDING_ANG:
+ /* angular bending combines 3 vertices */
+ nondiag += 3;
+ break;
+
+ default:
+ /* all other springs depend on 2 vertices only */
+ nondiag += 1;
+ break;
+ }
+ }
+
+ return nondiag;
+}
+
+int BPH_cloth_solver_init(Object *UNUSED(ob), ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *verts = cloth->verts;
+ const float ZERO[3] = {0.0f, 0.0f, 0.0f};
+ Implicit_Data *id;
+ unsigned int i, nondiag;
+
+ nondiag = cloth_count_nondiag_blocks(cloth);
+ cloth->implicit = id = BPH_mass_spring_solver_create(cloth->numverts, nondiag);
+
+ for (i = 0; i < cloth->numverts; i++) {
+ BPH_mass_spring_set_vertex_mass(id, i, verts[i].mass);
+ }
+
+ for (i = 0; i < cloth->numverts; i++) {
+ BPH_mass_spring_set_motion_state(id, i, verts[i].x, ZERO);
+ }
+
+ return 1;
+}
+
+void BPH_cloth_solver_free(ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+
+ if (cloth->implicit) {
+ BPH_mass_spring_solver_free(cloth->implicit);
+ cloth->implicit = NULL;
+ }
+}
+
+void BKE_cloth_solver_set_positions(ClothModifierData *clmd)
+{
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *verts = cloth->verts;
+ unsigned int numverts = cloth->numverts, i;
+ ClothHairData *cloth_hairdata = clmd->hairdata;
+ Implicit_Data *id = cloth->implicit;
+
+ for (i = 0; i < numverts; i++) {
+ if (cloth_hairdata) {
+ ClothHairData *root = &cloth_hairdata[i];
+ BPH_mass_spring_set_rest_transform(id, i, root->rot);
+ }
+ else
+ BPH_mass_spring_set_rest_transform(id, i, I3);
+
+ BPH_mass_spring_set_motion_state(id, i, verts[i].x, verts[i].v);
+ }
+}
+
+static bool collision_response(ClothModifierData *clmd, CollisionModifierData *collmd, CollPair *collpair, float dt, float restitution, float r_impulse[3])
+{
+ Cloth *cloth = clmd->clothObject;
+ int index = collpair->ap1;
+ bool result = false;
+
+ float v1[3], v2_old[3], v2_new[3], v_rel_old[3], v_rel_new[3];
+ float epsilon2 = BLI_bvhtree_getepsilon(collmd->bvhtree);
+
+ float margin_distance = collpair->distance - epsilon2;
+ float mag_v_rel;
+
+ zero_v3(r_impulse);
+
+ if (margin_distance > 0.0f)
+ return false; /* XXX tested before already? */
+
+ /* only handle static collisions here */
+ if ( collpair->flag & COLLISION_IN_FUTURE )
+ return false;
+
+ /* velocity */
+ copy_v3_v3(v1, cloth->verts[index].v);
+ collision_get_collider_velocity(v2_old, v2_new, collmd, collpair);
+ /* relative velocity = velocity of the cloth point relative to the collider */
+ sub_v3_v3v3(v_rel_old, v1, v2_old);
+ sub_v3_v3v3(v_rel_new, v1, v2_new);
+ /* normal component of the relative velocity */
+ mag_v_rel = dot_v3v3(v_rel_old, collpair->normal);
+
+ /* only valid when moving toward the collider */
+ if (mag_v_rel < -ALMOST_ZERO) {
+ float v_nor_old, v_nor_new;
+ float v_tan_old[3], v_tan_new[3];
+ float bounce, repulse;
+
+ /* Collision response based on
+ * "Simulating Complex Hair with Robust Collision Handling" (Choe, Choi, Ko, ACM SIGGRAPH 2005)
+ * http://graphics.snu.ac.kr/publications/2005-choe-HairSim/Choe_2005_SCA.pdf
+ */
+
+ v_nor_old = mag_v_rel;
+ v_nor_new = dot_v3v3(v_rel_new, collpair->normal);
+
+ madd_v3_v3v3fl(v_tan_old, v_rel_old, collpair->normal, -v_nor_old);
+ madd_v3_v3v3fl(v_tan_new, v_rel_new, collpair->normal, -v_nor_new);
+
+ bounce = -v_nor_old * restitution;
+
+ repulse = -margin_distance / dt; /* base repulsion velocity in normal direction */
+ /* XXX this clamping factor is quite arbitrary ...
+ * not sure if there is a more scientific approach, but seems to give good results
+ */
+ CLAMP(repulse, 0.0f, 4.0f * bounce);
+
+ if (margin_distance < -epsilon2) {
+ mul_v3_v3fl(r_impulse, collpair->normal, max_ff(repulse, bounce) - v_nor_new);
+ }
+ else {
+ bounce = 0.0f;
+ mul_v3_v3fl(r_impulse, collpair->normal, repulse - v_nor_new);
+ }
+
+ result = true;
+ }
+
+ return result;
+}
+
+/* Init constraint matrix
+ * This is part of the modified CG method suggested by Baraff/Witkin in
+ * "Large Steps in Cloth Simulation" (Siggraph 1998)
+ */
+static void cloth_setup_constraints(ClothModifierData *clmd, ColliderContacts *contacts, int totcolliders, float dt)
+{
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ ClothVertex *verts = cloth->verts;
+ int numverts = cloth->numverts;
+ int i, j, v;
+
+ const float ZERO[3] = {0.0f, 0.0f, 0.0f};
+
+ for (v = 0; v < numverts; v++) {
+ if (verts[v].flags & CLOTH_VERT_FLAG_PINNED) {
+ /* pinned vertex constraints */
+ BPH_mass_spring_add_constraint_ndof0(data, v, ZERO); /* velocity is defined externally */
+ }
+
+ verts[v].impulse_count = 0;
+ }
+
+ for (i = 0; i < totcolliders; ++i) {
+ ColliderContacts *ct = &contacts[i];
+ for (j = 0; j < ct->totcollisions; ++j) {
+ CollPair *collpair = &ct->collisions[j];
+// float restitution = (1.0f - clmd->coll_parms->damping) * (1.0f - ct->ob->pd->pdef_sbdamp);
+ float restitution = 0.0f;
+ int v = collpair->face1;
+ float impulse[3];
+
+ /* pinned verts handled separately */
+ if (verts[v].flags & CLOTH_VERT_FLAG_PINNED)
+ continue;
+
+ /* XXX cheap way of avoiding instability from multiple collisions in the same step
+ * this should eventually be supported ...
+ */
+ if (verts[v].impulse_count > 0)
+ continue;
+
+ /* calculate collision response */
+ if (!collision_response(clmd, ct->collmd, collpair, dt, restitution, impulse))
+ continue;
+
+ BPH_mass_spring_add_constraint_ndof2(data, v, collpair->normal, impulse);
+ ++verts[v].impulse_count;
+ }
+ }
+}
+
+/* computes where the cloth would be if it were subject to perfectly stiff edges
+ * (edge distance constraints) in a lagrangian solver. then add forces to help
+ * guide the implicit solver to that state. this function is called after
+ * collisions*/
+static int UNUSED_FUNCTION(cloth_calc_helper_forces)(Object *UNUSED(ob), ClothModifierData *clmd, float (*initial_cos)[3], float UNUSED(step), float dt)
+{
+ Cloth *cloth= clmd->clothObject;
+ float (*cos)[3] = (float (*)[3])MEM_callocN(sizeof(float)*3*cloth->numverts, "cos cloth_calc_helper_forces");
+ float *masses = (float *)MEM_callocN(sizeof(float)*cloth->numverts, "cos cloth_calc_helper_forces");
+ LinkNode *node;
+ ClothSpring *spring;
+ ClothVertex *cv;
+ int i, steps;
+
+ cv = cloth->verts;
+ for (i=0; i<cloth->numverts; i++, cv++) {
+ copy_v3_v3(cos[i], cv->tx);
+
+ if (cv->goal == 1.0f || len_squared_v3v3(initial_cos[i], cv->tx) != 0.0f) {
+ masses[i] = 1e+10;
+ }
+ else {
+ masses[i] = cv->mass;
+ }
+ }
+
+ steps = 55;
+ for (i=0; i<steps; i++) {
+ for (node=cloth->springs; node; node=node->next) {
+ /* ClothVertex *cv1, *cv2; */ /* UNUSED */
+ int v1, v2;
+ float len, c, l, vec[3];
+
+ spring = (ClothSpring *)node->link;
+ if (spring->type != CLOTH_SPRING_TYPE_STRUCTURAL && spring->type != CLOTH_SPRING_TYPE_SHEAR)
+ continue;
+
+ v1 = spring->ij; v2 = spring->kl;
+ /* cv1 = cloth->verts + v1; */ /* UNUSED */
+ /* cv2 = cloth->verts + v2; */ /* UNUSED */
+ len = len_v3v3(cos[v1], cos[v2]);
+
+ sub_v3_v3v3(vec, cos[v1], cos[v2]);
+ normalize_v3(vec);
+
+ c = (len - spring->restlen);
+ if (c == 0.0f)
+ continue;
+
+ l = c / ((1.0f / masses[v1]) + (1.0f / masses[v2]));
+
+ mul_v3_fl(vec, -(1.0f / masses[v1]) * l);
+ add_v3_v3(cos[v1], vec);
+
+ sub_v3_v3v3(vec, cos[v2], cos[v1]);
+ normalize_v3(vec);
+
+ mul_v3_fl(vec, -(1.0f / masses[v2]) * l);
+ add_v3_v3(cos[v2], vec);
+ }
+ }
+
+ cv = cloth->verts;
+ for (i=0; i<cloth->numverts; i++, cv++) {
+ float vec[3];
+
+ /*compute forces*/
+ sub_v3_v3v3(vec, cos[i], cv->tx);
+ mul_v3_fl(vec, cv->mass*dt*20.0f);
+ add_v3_v3(cv->tv, vec);
+ //copy_v3_v3(cv->tx, cos[i]);
+ }
+
+ MEM_freeN(cos);
+ MEM_freeN(masses);
+
+ return 1;
+}
+
+BLI_INLINE void cloth_calc_spring_force(ClothModifierData *clmd, ClothSpring *s, float time)
+{
+ Cloth *cloth = clmd->clothObject;
+ ClothSimSettings *parms = clmd->sim_parms;
+ Implicit_Data *data = cloth->implicit;
+ ClothVertex *verts = cloth->verts;
+
+ bool no_compress = parms->flags & CLOTH_SIMSETTINGS_FLAG_NO_SPRING_COMPRESS;
+
+ zero_v3(s->f);
+ zero_m3(s->dfdx);
+ zero_m3(s->dfdv);
+
+ s->flags &= ~CLOTH_SPRING_FLAG_NEEDED;
+
+ // calculate force of structural + shear springs
+ if ((s->type & CLOTH_SPRING_TYPE_STRUCTURAL) || (s->type & CLOTH_SPRING_TYPE_SHEAR) || (s->type & CLOTH_SPRING_TYPE_SEWING) ) {
+#ifdef CLOTH_FORCE_SPRING_STRUCTURAL
+ float k, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ scaling = parms->structural + s->stiffness * fabsf(parms->max_struct - parms->structural);
+ k = scaling / (parms->avg_spring_len + FLT_EPSILON);
+
+ if (s->type & CLOTH_SPRING_TYPE_SEWING) {
+ // TODO: verify, half verified (couldn't see error)
+ // sewing springs usually have a large distance at first so clamp the force so we don't get tunnelling through colission objects
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, parms->max_sewing, s->f, s->dfdx, s->dfdv);
+ }
+ else {
+ BPH_mass_spring_force_spring_linear(data, s->ij, s->kl, s->restlen, k, parms->Cdis, no_compress, 0.0f, s->f, s->dfdx, s->dfdv);
+ }
+#endif
+ }
+ else if (s->type & CLOTH_SPRING_TYPE_GOAL) {
+#ifdef CLOTH_FORCE_SPRING_GOAL
+ float goal_x[3], goal_v[3];
+ float k, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ // current_position = xold + t * (newposition - xold)
+ interp_v3_v3v3(goal_x, verts[s->ij].xold, verts[s->ij].xconst, time);
+ sub_v3_v3v3(goal_v, verts[s->ij].xconst, verts[s->ij].xold); // distance covered over dt==1
+
+ scaling = parms->goalspring + s->stiffness * fabsf(parms->max_struct - parms->goalspring);
+ k = verts[s->ij].goal * scaling / (parms->avg_spring_len + FLT_EPSILON);
+
+ BPH_mass_spring_force_spring_goal(data, s->ij, goal_x, goal_v, k, parms->goalfrict * 0.01f, s->f, s->dfdx, s->dfdv);
+#endif
+ }
+ else if (s->type & CLOTH_SPRING_TYPE_BENDING) { /* calculate force of bending springs */
+#ifdef CLOTH_FORCE_SPRING_BEND
+ float kb, cb, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ scaling = parms->bending + s->stiffness * fabsf(parms->max_bend - parms->bending);
+ kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ scaling = parms->bending_damping;
+ cb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ BPH_mass_spring_force_spring_bending(data, s->ij, s->kl, s->restlen, kb, cb, s->f, s->dfdx, s->dfdv);
+#endif
+ }
+ else if (s->type & CLOTH_SPRING_TYPE_BENDING_ANG) {
+#ifdef CLOTH_FORCE_SPRING_BEND
+ float kb, cb, scaling;
+
+ s->flags |= CLOTH_SPRING_FLAG_NEEDED;
+
+ /* XXX WARNING: angular bending springs for hair apply stiffness factor as an overall factor, unlike cloth springs!
+ * this is crap, but needed due to cloth/hair mixing ...
+ * max_bend factor is not even used for hair, so ...
+ */
+ scaling = s->stiffness * parms->bending;
+ kb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ scaling = parms->bending_damping;
+ cb = scaling / (20.0f * (parms->avg_spring_len + FLT_EPSILON));
+
+ /* XXX assuming same restlen for ij and jk segments here, this can be done correctly for hair later */
+ BPH_mass_spring_force_spring_bending_angular(data, s->ij, s->kl, s->mn, s->target, kb, cb);
+
+#if 0
+ {
+ float x_kl[3], x_mn[3], v[3], d[3];
+
+ BPH_mass_spring_get_motion_state(data, s->kl, x_kl, v);
+ BPH_mass_spring_get_motion_state(data, s->mn, x_mn, v);
+
+ BKE_sim_debug_data_add_dot(clmd->debug_data, x_kl, 0.9, 0.9, 0.9, "target", 7980, s->kl);
+ BKE_sim_debug_data_add_line(clmd->debug_data, x_kl, x_mn, 0.8, 0.8, 0.8, "target", 7981, s->kl);
+
+ copy_v3_v3(d, s->target);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, x_kl, d, 0.8, 0.8, 0.2, "target", 7982, s->kl);
+
+// copy_v3_v3(d, s->target_ij);
+// BKE_sim_debug_data_add_vector(clmd->debug_data, x, d, 1, 0.4, 0.4, "target", 7983, s->kl);
+ }
+#endif
+#endif
+ }
+}
+
+static void hair_get_boundbox(ClothModifierData *clmd, float gmin[3], float gmax[3])
+{
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ unsigned int numverts = cloth->numverts;
+ int i;
+
+ INIT_MINMAX(gmin, gmax);
+ for (i = 0; i < numverts; i++) {
+ float x[3];
+ BPH_mass_spring_get_motion_state(data, i, x, NULL);
+ DO_MINMAX(x, gmin, gmax);
+ }
+}
+
+static void cloth_calc_force(ClothModifierData *clmd, float UNUSED(frame), ListBase *effectors, float time)
+{
+ /* Collect forces and derivatives: F, dFdX, dFdV */
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ unsigned int i = 0;
+ float drag = clmd->sim_parms->Cvi * 0.01f; /* viscosity of air scaled in percent */
+ float gravity[3] = {0.0f, 0.0f, 0.0f};
+ MFace *mfaces = cloth->mfaces;
+ unsigned int numverts = cloth->numverts;
+ ClothVertex *vert;
+
+#ifdef CLOTH_FORCE_GRAVITY
+ /* global acceleration (gravitation) */
+ if (clmd->scene->physics_settings.flag & PHYS_GLOBAL_GRAVITY) {
+ /* scale gravity force */
+ mul_v3_v3fl(gravity, clmd->scene->physics_settings.gravity, 0.001f * clmd->sim_parms->effector_weights->global_gravity);
+ }
+ vert = cloth->verts;
+ for (i = 0; i < cloth->numverts; i++, vert++) {
+ BPH_mass_spring_force_gravity(data, i, vert->mass, gravity);
+ }
+#endif
+
+ /* cloth_calc_volume_force(clmd); */
+
+#ifdef CLOTH_FORCE_DRAG
+ BPH_mass_spring_force_drag(data, drag);
+#endif
+
+ /* handle external forces like wind */
+ if (effectors) {
+ /* cache per-vertex forces to avoid redundant calculation */
+ float (*winvec)[3] = (float (*)[3])MEM_callocN(sizeof(float) * 3 * numverts, "effector forces");
+ for (i = 0; i < cloth->numverts; i++) {
+ float x[3], v[3];
+ EffectedPoint epoint;
+
+ BPH_mass_spring_get_motion_state(data, i, x, v);
+ pd_point_from_loc(clmd->scene, x, v, i, &epoint);
+ pdDoEffectors(effectors, NULL, clmd->sim_parms->effector_weights, &epoint, winvec[i], NULL);
+ }
+
+ for (i = 0; i < cloth->numfaces; i++) {
+ MFace *mf = &mfaces[i];
+ BPH_mass_spring_force_face_wind(data, mf->v1, mf->v2, mf->v3, mf->v4, winvec);
+ }
+
+ /* Hair has only edges */
+ if (cloth->numfaces == 0) {
+#if 0
+ ClothHairData *hairdata = clmd->hairdata;
+ ClothHairData *hair_ij, *hair_kl;
+
+ for (LinkNode *link = cloth->springs; link; link = link->next) {
+ ClothSpring *spring = (ClothSpring *)link->link;
+ if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL) {
+ if (hairdata) {
+ hair_ij = &hairdata[spring->ij];
+ hair_kl = &hairdata[spring->kl];
+ BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, hair_ij->radius, hair_kl->radius, winvec);
+ }
+ else
+ BPH_mass_spring_force_edge_wind(data, spring->ij, spring->kl, 1.0f, 1.0f, winvec);
+ }
+ }
+#else
+ ClothHairData *hairdata = clmd->hairdata;
+
+ vert = cloth->verts;
+ for (i = 0; i < cloth->numverts; i++, vert++) {
+ if (hairdata) {
+ ClothHairData *hair = &hairdata[i];
+ BPH_mass_spring_force_vertex_wind(data, i, hair->radius, winvec);
+ }
+ else
+ BPH_mass_spring_force_vertex_wind(data, i, 1.0f, winvec);
+ }
+ }
+#endif
+
+ MEM_freeN(winvec);
+ }
+
+ // calculate spring forces
+ for (LinkNode *link = cloth->springs; link; link = link->next) {
+ ClothSpring *spring = (ClothSpring *)link->link;
+ // only handle active springs
+ if (!(spring->flags & CLOTH_SPRING_FLAG_DEACTIVATE))
+ cloth_calc_spring_force(clmd, spring, time);
+ }
+}
+
+/* returns vertexes' motion state */
+BLI_INLINE void cloth_get_grid_location(Implicit_Data *data, float cell_scale, const float cell_offset[3],
+ int index, float x[3], float v[3])
+{
+ BPH_mass_spring_get_position(data, index, x);
+ BPH_mass_spring_get_new_velocity(data, index, v);
+
+ mul_v3_fl(x, cell_scale);
+ add_v3_v3(x, cell_offset);
+}
+
+/* returns next spring forming a continous hair sequence */
+BLI_INLINE LinkNode *hair_spring_next(LinkNode *spring_link)
+{
+ ClothSpring *spring = (ClothSpring *)spring_link->link;
+ LinkNode *next = spring_link->next;
+ if (next) {
+ ClothSpring *next_spring = (ClothSpring *)next->link;
+ if (next_spring->type == CLOTH_SPRING_TYPE_STRUCTURAL && next_spring->kl == spring->ij)
+ return next;
+ }
+ return NULL;
+}
+
+/* XXX this is nasty: cloth meshes do not explicitly store
+ * the order of hair segments!
+ * We have to rely on the spring build function for now,
+ * which adds structural springs in reverse order:
+ * (3,4), (2,3), (1,2)
+ * This is currently the only way to figure out hair geometry inside this code ...
+ */
+static LinkNode *cloth_continuum_add_hair_segments(HairGrid *grid, const float cell_scale, const float cell_offset[3], Cloth *cloth, LinkNode *spring_link)
+{
+ Implicit_Data *data = cloth->implicit;
+ LinkNode *next_spring_link = NULL; /* return value */
+ ClothSpring *spring1, *spring2, *spring3;
+ // ClothVertex *verts = cloth->verts;
+ // ClothVertex *vert3, *vert4;
+ float x1[3], v1[3], x2[3], v2[3], x3[3], v3[3], x4[3], v4[3];
+ float dir1[3], dir2[3], dir3[3];
+
+ spring1 = NULL;
+ spring2 = NULL;
+ spring3 = (ClothSpring *)spring_link->link;
+
+ zero_v3(x1); zero_v3(v1);
+ zero_v3(dir1);
+ zero_v3(x2); zero_v3(v2);
+ zero_v3(dir2);
+
+ // vert3 = &verts[spring3->kl];
+ cloth_get_grid_location(data, cell_scale, cell_offset, spring3->kl, x3, v3);
+ // vert4 = &verts[spring3->ij];
+ cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4);
+ sub_v3_v3v3(dir3, x4, x3);
+ normalize_v3(dir3);
+
+ while (spring_link) {
+ /* move on */
+ spring1 = spring2;
+ spring2 = spring3;
+
+ // vert3 = vert4;
+
+ copy_v3_v3(x1, x2); copy_v3_v3(v1, v2);
+ copy_v3_v3(x2, x3); copy_v3_v3(v2, v3);
+ copy_v3_v3(x3, x4); copy_v3_v3(v3, v4);
+
+ copy_v3_v3(dir1, dir2);
+ copy_v3_v3(dir2, dir3);
+
+ /* read next segment */
+ next_spring_link = spring_link->next;
+ spring_link = hair_spring_next(spring_link);
+
+ if (spring_link) {
+ spring3 = (ClothSpring *)spring_link->link;
+ // vert4 = &verts[spring3->ij];
+ cloth_get_grid_location(data, cell_scale, cell_offset, spring3->ij, x4, v4);
+ sub_v3_v3v3(dir3, x4, x3);
+ normalize_v3(dir3);
+ }
+ else {
+ spring3 = NULL;
+ // vert4 = NULL;
+ zero_v3(x4); zero_v3(v4);
+ zero_v3(dir3);
+ }
+
+ BPH_hair_volume_add_segment(grid, x1, v1, x2, v2, x3, v3, x4, v4,
+ spring1 ? dir1 : NULL,
+ dir2,
+ spring3 ? dir3 : NULL);
+ }
+
+ return next_spring_link;
+}
+
+static void cloth_continuum_fill_grid(HairGrid *grid, Cloth *cloth)
+{
+#if 0
+ Implicit_Data *data = cloth->implicit;
+ int numverts = cloth->numverts;
+ ClothVertex *vert;
+ int i;
+
+ for (i = 0, vert = cloth->verts; i < numverts; i++, vert++) {
+ float x[3], v[3];
+
+ cloth_get_vertex_motion_state(data, vert, x, v);
+ BPH_hair_volume_add_vertex(grid, x, v);
+ }
+#else
+ LinkNode *link;
+ float cellsize, gmin[3], cell_scale, cell_offset[3];
+
+ /* scale and offset for transforming vertex locations into grid space
+ * (cell size is 0..1, gmin becomes origin)
+ */
+ BPH_hair_volume_grid_geometry(grid, &cellsize, NULL, gmin, NULL);
+ cell_scale = cellsize > 0.0f ? 1.0f / cellsize : 0.0f;
+ mul_v3_v3fl(cell_offset, gmin, cell_scale);
+ negate_v3(cell_offset);
+
+ link = cloth->springs;
+ while (link) {
+ ClothSpring *spring = (ClothSpring *)link->link;
+ if (spring->type == CLOTH_SPRING_TYPE_STRUCTURAL)
+ link = cloth_continuum_add_hair_segments(grid, cell_scale, cell_offset, cloth, link);
+ else
+ link = link->next;
+ }
+#endif
+ BPH_hair_volume_normalize_vertex_grid(grid);
+}
+
+static void cloth_continuum_step(ClothModifierData *clmd, float dt)
+{
+ ClothSimSettings *parms = clmd->sim_parms;
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ int numverts = cloth->numverts;
+ ClothVertex *vert;
+
+ const float fluid_factor = 0.95f; /* blend between PIC and FLIP methods */
+ float smoothfac = parms->velocity_smooth;
+ /* XXX FIXME arbitrary factor!!! this should be based on some intuitive value instead,
+ * like number of hairs per cell and time decay instead of "strength"
+ */
+ float density_target = parms->density_target;
+ float density_strength = parms->density_strength;
+ float gmin[3], gmax[3];
+ int i;
+
+ /* clear grid info */
+ zero_v3_int(clmd->hair_grid_res);
+ zero_v3(clmd->hair_grid_min);
+ zero_v3(clmd->hair_grid_max);
+ clmd->hair_grid_cellsize = 0.0f;
+
+ hair_get_boundbox(clmd, gmin, gmax);
+
+ /* gather velocities & density */
+ if (smoothfac > 0.0f || density_strength > 0.0f) {
+ HairGrid *grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax);
+
+ cloth_continuum_fill_grid(grid, cloth);
+
+ /* main hair continuum solver */
+ BPH_hair_volume_solve_divergence(grid, dt, density_target, density_strength);
+
+ for (i = 0, vert = cloth->verts; i < numverts; i++, vert++) {
+ float x[3], v[3], nv[3];
+
+ /* calculate volumetric velocity influence */
+ BPH_mass_spring_get_position(data, i, x);
+ BPH_mass_spring_get_new_velocity(data, i, v);
+
+ BPH_hair_volume_grid_velocity(grid, x, v, fluid_factor, nv);
+
+ interp_v3_v3v3(nv, v, nv, smoothfac);
+
+ /* apply on hair data */
+ BPH_mass_spring_set_new_velocity(data, i, nv);
+ }
+
+ /* store basic grid info in the modifier data */
+ BPH_hair_volume_grid_geometry(grid, &clmd->hair_grid_cellsize, clmd->hair_grid_res, clmd->hair_grid_min, clmd->hair_grid_max);
+
+#if 0 /* DEBUG hair velocity vector field */
+ {
+ const int size = 64;
+ int i, j;
+ float offset[3], a[3], b[3];
+ const int axis = 0;
+ const float shift = 0.0f;
+
+ copy_v3_v3(offset, clmd->hair_grid_min);
+ zero_v3(a);
+ zero_v3(b);
+
+ offset[axis] = shift * clmd->hair_grid_cellsize;
+ a[(axis+1) % 3] = clmd->hair_grid_max[(axis+1) % 3] - clmd->hair_grid_min[(axis+1) % 3];
+ b[(axis+2) % 3] = clmd->hair_grid_max[(axis+2) % 3] - clmd->hair_grid_min[(axis+2) % 3];
+
+ BKE_sim_debug_data_clear_category(clmd->debug_data, "grid velocity");
+ for (j = 0; j < size; ++j) {
+ for (i = 0; i < size; ++i) {
+ float x[3], v[3], gvel[3], gvel_smooth[3], gdensity;
+
+ madd_v3_v3v3fl(x, offset, a, (float)i / (float)(size-1));
+ madd_v3_v3fl(x, b, (float)j / (float)(size-1));
+ zero_v3(v);
+
+ BPH_hair_volume_grid_interpolate(grid, x, &gdensity, gvel, gvel_smooth, NULL, NULL);
+
+// BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity, 0.7, 0.3, 1, "grid density", i, j, 3111);
+ if (!is_zero_v3(gvel) || !is_zero_v3(gvel_smooth)) {
+ float dvel[3];
+ sub_v3_v3v3(dvel, gvel_smooth, gvel);
+// BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel, 0.4, 0, 1, "grid velocity", i, j, 3112);
+// BKE_sim_debug_data_add_vector(clmd->debug_data, x, gvel_smooth, 0.6, 1, 1, "grid velocity", i, j, 3113);
+ BKE_sim_debug_data_add_vector(clmd->debug_data, x, dvel, 0.4, 1, 0.7, "grid velocity", i, j, 3114);
+#if 0
+ if (gdensity > 0.0f) {
+ float col0[3] = {0.0, 0.0, 0.0};
+ float col1[3] = {0.0, 1.0, 0.0};
+ float col[3];
+
+ interp_v3_v3v3(col, col0, col1, CLAMPIS(gdensity * clmd->sim_parms->density_strength, 0.0, 1.0));
+// BKE_sim_debug_data_add_circle(clmd->debug_data, x, gdensity * clmd->sim_parms->density_strength, 0, 1, 0.4, "grid velocity", i, j, 3115);
+// BKE_sim_debug_data_add_dot(clmd->debug_data, x, col[0], col[1], col[2], "grid velocity", i, j, 3115);
+ BKE_sim_debug_data_add_circle(clmd->debug_data, x, 0.01f, col[0], col[1], col[2], "grid velocity", i, j, 3115);
+ }
+#endif
+ }
+ }
+ }
+ }
+#endif
+
+ BPH_hair_volume_free_vertex_grid(grid);
+ }
+}
+
+#if 0
+static void cloth_calc_volume_force(ClothModifierData *clmd)
+{
+ ClothSimSettings *parms = clmd->sim_parms;
+ Cloth *cloth = clmd->clothObject;
+ Implicit_Data *data = cloth->implicit;
+ int numverts = cloth->numverts;
+ ClothVertex *vert;
+
+ /* 2.0f is an experimental value that seems to give good results */
+ float smoothfac = 2.0f * parms->velocity_smooth;
+ float collfac = 2.0f * parms->collider_friction;
+ float pressfac = parms->pressure;
+ float minpress = parms->pressure_threshold;
+ float gmin[3], gmax[3];
+ int i;
+
+ hair_get_boundbox(clmd, gmin, gmax);
+
+ /* gather velocities & density */
+ if (smoothfac > 0.0f || pressfac > 0.0f) {
+ HairVertexGrid *vertex_grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_res, gmin, gmax);
+
+ vert = cloth->verts;
+ for (i = 0; i < numverts; i++, vert++) {
+ float x[3], v[3];
+
+ if (vert->solver_index < 0) {
+ copy_v3_v3(x, vert->x);
+ copy_v3_v3(v, vert->v);
+ }
+ else {
+ BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v);
+ }
+ BPH_hair_volume_add_vertex(vertex_grid, x, v);
+ }
+ BPH_hair_volume_normalize_vertex_grid(vertex_grid);
+
+ vert = cloth->verts;
+ for (i = 0; i < numverts; i++, vert++) {
+ float x[3], v[3], f[3], dfdx[3][3], dfdv[3][3];
+
+ if (vert->solver_index < 0)
+ continue;
+
+ /* calculate volumetric forces */
+ BPH_mass_spring_get_motion_state(data, vert->solver_index, x, v);
+ BPH_hair_volume_vertex_grid_forces(vertex_grid, x, v, smoothfac, pressfac, minpress, f, dfdx, dfdv);
+ /* apply on hair data */
+ BPH_mass_spring_force_extern(data, vert->solver_index, f, dfdx, dfdv);
+ }
+
+ BPH_hair_volume_free_vertex_grid(vertex_grid);
+ }
+}
+#endif
+
+static void cloth_clear_result(ClothModifierData *clmd)
+{
+ ClothSolverResult *sres = clmd->solver_result;
+
+ sres->status = 0;
+ sres->max_error = sres->min_error = sres->avg_error = 0.0f;
+ sres->max_iterations = sres->min_iterations = 0;
+ sres->avg_iterations = 0.0f;
+}
+
+static void cloth_record_result(ClothModifierData *clmd, ImplicitSolverResult *result, int steps)
+{
+ ClothSolverResult *sres = clmd->solver_result;
+
+ if (sres->status) { /* already initialized ? */
+ /* error only makes sense for successful iterations */
+ if (result->status == BPH_SOLVER_SUCCESS) {
+ sres->min_error = min_ff(sres->min_error, result->error);
+ sres->max_error = max_ff(sres->max_error, result->error);
+ sres->avg_error += result->error / (float)steps;
+ }
+
+ sres->min_iterations = min_ii(sres->min_iterations, result->iterations);
+ sres->max_iterations = max_ii(sres->max_iterations, result->iterations);
+ sres->avg_iterations += (float)result->iterations / (float)steps;
+ }
+ else {
+ /* error only makes sense for successful iterations */
+ if (result->status == BPH_SOLVER_SUCCESS) {
+ sres->min_error = sres->max_error = result->error;
+ sres->avg_error += result->error / (float)steps;
+ }
+
+ sres->min_iterations = sres->max_iterations = result->iterations;
+ sres->avg_iterations += (float)result->iterations / (float)steps;
+ }
+
+ sres->status |= result->status;
+}
+
+int BPH_cloth_solve(Object *ob, float frame, ClothModifierData *clmd, ListBase *effectors)
+{
+ unsigned int i=0;
+ float step=0.0f, tf=clmd->sim_parms->timescale;
+ Cloth *cloth = clmd->clothObject;
+ ClothVertex *verts = cloth->verts/*, *cv*/;
+ unsigned int numverts = cloth->numverts;
+ float dt = clmd->sim_parms->timescale / clmd->sim_parms->stepsPerFrame;
+ Implicit_Data *id = cloth->implicit;
+ ColliderContacts *contacts = NULL;
+ int totcolliders = 0;
+
+ BKE_sim_debug_data_clear_category("collision");
+
+ if (!clmd->solver_result)
+ clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), "cloth solver result");
+ cloth_clear_result(clmd);
+
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) { /* do goal stuff */
+ for (i = 0; i < numverts; i++) {
+ // update velocities with constrained velocities from pinned verts
+ if (verts [i].flags & CLOTH_VERT_FLAG_PINNED) {
+ float v[3];
+ sub_v3_v3v3(v, verts[i].xconst, verts[i].xold);
+ // mul_v3_fl(v, clmd->sim_parms->stepsPerFrame);
+ BPH_mass_spring_set_velocity(id, i, v);
+ }
+ }
+ }
+
+ while (step < tf) {
+ ImplicitSolverResult result;
+
+ /* initialize forces to zero */
+ BPH_mass_spring_clear_forces(id);
+ BPH_mass_spring_clear_constraints(id);
+
+ /* copy velocities for collision */
+ for (i = 0; i < numverts; i++) {
+ BPH_mass_spring_get_motion_state(id, i, NULL, verts[i].tv);
+ copy_v3_v3(verts[i].v, verts[i].tv);
+ }
+
+ /* determine contact points */
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_ENABLED) {
+ if (clmd->coll_parms->flags & CLOTH_COLLSETTINGS_FLAG_POINTS) {
+ cloth_find_point_contacts(ob, clmd, 0.0f, tf, &contacts, &totcolliders);
+ }
+ }
+
+ /* setup vertex constraints for pinned vertices and contacts */
+ cloth_setup_constraints(clmd, contacts, totcolliders, dt);
+
+ // damping velocity for artistic reasons
+ // this is a bad way to do it, should be removed imo - lukas_t
+ if (clmd->sim_parms->vel_damping != 1.0f) {
+ for (i = 0; i < numverts; i++) {
+ float v[3];
+ BPH_mass_spring_get_motion_state(id, i, NULL, v);
+ mul_v3_fl(v, clmd->sim_parms->vel_damping);
+ BPH_mass_spring_set_velocity(id, i, v);
+ }
+ }
+
+ // calculate forces
+ cloth_calc_force(clmd, frame, effectors, step);
+
+ // calculate new velocity and position
+ BPH_mass_spring_solve_velocities(id, dt, &result);
+ cloth_record_result(clmd, &result, clmd->sim_parms->stepsPerFrame);
+
+ cloth_continuum_step(clmd, dt);
+
+ BPH_mass_spring_solve_positions(id, dt);
+
+ BPH_mass_spring_apply_result(id);
+
+ /* move pinned verts to correct position */
+ for (i = 0; i < numverts; i++) {
+ if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_GOAL) {
+ if (verts[i].flags & CLOTH_VERT_FLAG_PINNED) {
+ float x[3];
+ interp_v3_v3v3(x, verts[i].xold, verts[i].xconst, step + dt);
+ BPH_mass_spring_set_position(id, i, x);
+ }
+ }
+
+ BPH_mass_spring_get_motion_state(id, i, verts[i].txold, NULL);
+ }
+
+ /* free contact points */
+ if (contacts) {
+ cloth_free_contacts(contacts, totcolliders);
+ }
+
+ step += dt;
+ }
+
+ /* copy results back to cloth data */
+ for (i = 0; i < numverts; i++) {
+ BPH_mass_spring_get_motion_state(id, i, verts[i].x, verts[i].v);
+ copy_v3_v3(verts[i].txold, verts[i].x);
+ }
+
+ return 1;
+}
+
+bool BPH_cloth_solver_get_texture_data(Object *UNUSED(ob), ClothModifierData *clmd, VoxelData *vd)
+{
+ Cloth *cloth = clmd->clothObject;
+ HairGrid *grid;
+ float gmin[3], gmax[3];
+
+ if (!clmd->clothObject || !clmd->clothObject->implicit)
+ return false;
+
+ hair_get_boundbox(clmd, gmin, gmax);
+
+ grid = BPH_hair_volume_create_vertex_grid(clmd->sim_parms->voxel_cell_size, gmin, gmax);
+ cloth_continuum_fill_grid(grid, cloth);
+
+ BPH_hair_volume_get_texture_data(grid, vd);
+
+ BPH_hair_volume_free_vertex_grid(grid);
+
+ return true;
+}
diff --git a/source/blender/physics/intern/ConstrainedConjugateGradient.h b/source/blender/physics/intern/ConstrainedConjugateGradient.h
new file mode 100644
index 00000000000..2d4389f6766
--- /dev/null
+++ b/source/blender/physics/intern/ConstrainedConjugateGradient.h
@@ -0,0 +1,294 @@
+
+#ifndef EIGEN_CONSTRAINEDCG_H
+#define EIGEN_CONSTRAINEDCG_H
+
+#include <Eigen/Core>
+
+namespace Eigen {
+
+namespace internal {
+
+/** \internal Low-level conjugate gradient algorithm
+ * \param mat The matrix A
+ * \param rhs The right hand side vector b
+ * \param x On input and initial solution, on output the computed solution.
+ * \param precond A preconditioner being able to efficiently solve for an
+ * approximation of Ax=b (regardless of b)
+ * \param iters On input the max number of iteration, on output the number of performed iterations.
+ * \param tol_error On input the tolerance error, on output an estimation of the relative error.
+ */
+template<typename MatrixType, typename Rhs, typename Dest, typename FilterMatrixType, typename Preconditioner>
+EIGEN_DONT_INLINE
+void constrained_conjugate_gradient(const MatrixType& mat, const Rhs& rhs, Dest& x,
+ const FilterMatrixType &filter,
+ const Preconditioner& precond, int& iters,
+ typename Dest::RealScalar& tol_error)
+{
+ using std::sqrt;
+ using std::abs;
+ typedef typename Dest::RealScalar RealScalar;
+ typedef typename Dest::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,1> VectorType;
+
+ RealScalar tol = tol_error;
+ int maxIters = iters;
+
+ int n = mat.cols();
+
+ VectorType residual = filter * (rhs - mat * x); //initial residual
+
+ RealScalar rhsNorm2 = (filter * rhs).squaredNorm();
+ if(rhsNorm2 == 0)
+ {
+ /* XXX TODO set constrained result here */
+ x.setZero();
+ iters = 0;
+ tol_error = 0;
+ return;
+ }
+ RealScalar threshold = tol*tol*rhsNorm2;
+ RealScalar residualNorm2 = residual.squaredNorm();
+ if (residualNorm2 < threshold)
+ {
+ iters = 0;
+ tol_error = sqrt(residualNorm2 / rhsNorm2);
+ return;
+ }
+
+ VectorType p(n);
+ p = filter * precond.solve(residual); //initial search direction
+
+ VectorType z(n), tmp(n);
+ RealScalar absNew = numext::real(residual.dot(p)); // the square of the absolute value of r scaled by invM
+ int i = 0;
+ while(i < maxIters)
+ {
+ tmp.noalias() = filter * (mat * p); // the bottleneck of the algorithm
+
+ Scalar alpha = absNew / p.dot(tmp); // the amount we travel on dir
+ x += alpha * p; // update solution
+ residual -= alpha * tmp; // update residue
+
+ residualNorm2 = residual.squaredNorm();
+ if(residualNorm2 < threshold)
+ break;
+
+ z = precond.solve(residual); // approximately solve for "A z = residual"
+
+ RealScalar absOld = absNew;
+ absNew = numext::real(residual.dot(z)); // update the absolute value of r
+ RealScalar beta = absNew / absOld; // calculate the Gram-Schmidt value used to create the new search direction
+ p = filter * (z + beta * p); // update search direction
+ i++;
+ }
+ tol_error = sqrt(residualNorm2 / rhsNorm2);
+ iters = i;
+}
+
+}
+
+#if 0 /* unused */
+template<typename MatrixType>
+struct MatrixFilter
+{
+ MatrixFilter() :
+ m_cmat(NULL)
+ {
+ }
+
+ MatrixFilter(const MatrixType &cmat) :
+ m_cmat(&cmat)
+ {
+ }
+
+ void setMatrix(const MatrixType &cmat) { m_cmat = &cmat; }
+
+ template <typename VectorType>
+ void apply(VectorType v) const
+ {
+ v = (*m_cmat) * v;
+ }
+
+protected:
+ const MatrixType *m_cmat;
+};
+#endif
+
+template< typename _MatrixType, int _UpLo=Lower,
+ typename _FilterMatrixType = _MatrixType,
+ typename _Preconditioner = DiagonalPreconditioner<typename _MatrixType::Scalar> >
+class ConstrainedConjugateGradient;
+
+namespace internal {
+
+template< typename _MatrixType, int _UpLo, typename _FilterMatrixType, typename _Preconditioner>
+struct traits<ConstrainedConjugateGradient<_MatrixType,_UpLo,_FilterMatrixType,_Preconditioner> >
+{
+ typedef _MatrixType MatrixType;
+ typedef _FilterMatrixType FilterMatrixType;
+ typedef _Preconditioner Preconditioner;
+};
+
+}
+
+/** \ingroup IterativeLinearSolvers_Module
+ * \brief A conjugate gradient solver for sparse self-adjoint problems with additional constraints
+ *
+ * This class allows to solve for A.x = b sparse linear problems using a conjugate gradient algorithm.
+ * The sparse matrix A must be selfadjoint. The vectors x and b can be either dense or sparse.
+ *
+ * \tparam _MatrixType the type of the sparse matrix A, can be a dense or a sparse matrix.
+ * \tparam _UpLo the triangular part that will be used for the computations. It can be Lower
+ * or Upper. Default is Lower.
+ * \tparam _Preconditioner the type of the preconditioner. Default is DiagonalPreconditioner
+ *
+ * The maximal number of iterations and tolerance value can be controlled via the setMaxIterations()
+ * and setTolerance() methods. The defaults are the size of the problem for the maximal number of iterations
+ * and NumTraits<Scalar>::epsilon() for the tolerance.
+ *
+ * This class can be used as the direct solver classes. Here is a typical usage example:
+ * \code
+ * int n = 10000;
+ * VectorXd x(n), b(n);
+ * SparseMatrix<double> A(n,n);
+ * // fill A and b
+ * ConjugateGradient<SparseMatrix<double> > cg;
+ * cg.compute(A);
+ * x = cg.solve(b);
+ * std::cout << "#iterations: " << cg.iterations() << std::endl;
+ * std::cout << "estimated error: " << cg.error() << std::endl;
+ * // update b, and solve again
+ * x = cg.solve(b);
+ * \endcode
+ *
+ * By default the iterations start with x=0 as an initial guess of the solution.
+ * One can control the start using the solveWithGuess() method. Here is a step by
+ * step execution example starting with a random guess and printing the evolution
+ * of the estimated error:
+ * * \code
+ * x = VectorXd::Random(n);
+ * cg.setMaxIterations(1);
+ * int i = 0;
+ * do {
+ * x = cg.solveWithGuess(b,x);
+ * std::cout << i << " : " << cg.error() << std::endl;
+ * ++i;
+ * } while (cg.info()!=Success && i<100);
+ * \endcode
+ * Note that such a step by step excution is slightly slower.
+ *
+ * \sa class SimplicialCholesky, DiagonalPreconditioner, IdentityPreconditioner
+ */
+template< typename _MatrixType, int _UpLo, typename _FilterMatrixType, typename _Preconditioner>
+class ConstrainedConjugateGradient : public IterativeSolverBase<ConstrainedConjugateGradient<_MatrixType,_UpLo,_FilterMatrixType,_Preconditioner> >
+{
+ typedef IterativeSolverBase<ConstrainedConjugateGradient> Base;
+ using Base::mp_matrix;
+ using Base::m_error;
+ using Base::m_iterations;
+ using Base::m_info;
+ using Base::m_isInitialized;
+public:
+ typedef _MatrixType MatrixType;
+ typedef typename MatrixType::Scalar Scalar;
+ typedef typename MatrixType::Index Index;
+ typedef typename MatrixType::RealScalar RealScalar;
+ typedef _FilterMatrixType FilterMatrixType;
+ typedef _Preconditioner Preconditioner;
+
+ enum {
+ UpLo = _UpLo
+ };
+
+public:
+
+ /** Default constructor. */
+ ConstrainedConjugateGradient() : Base() {}
+
+ /** Initialize the solver with matrix \a A for further \c Ax=b solving.
+ *
+ * This constructor is a shortcut for the default constructor followed
+ * by a call to compute().
+ *
+ * \warning this class stores a reference to the matrix A as well as some
+ * precomputed values that depend on it. Therefore, if \a A is changed
+ * this class becomes invalid. Call compute() to update it with the new
+ * matrix A, or modify a copy of A.
+ */
+ ConstrainedConjugateGradient(const MatrixType& A) : Base(A) {}
+
+ ~ConstrainedConjugateGradient() {}
+
+ FilterMatrixType &filter() { return m_filter; }
+ const FilterMatrixType &filter() const { return m_filter; }
+
+ /** \returns the solution x of \f$ A x = b \f$ using the current decomposition of A
+ * \a x0 as an initial solution.
+ *
+ * \sa compute()
+ */
+ template<typename Rhs,typename Guess>
+ inline const internal::solve_retval_with_guess<ConstrainedConjugateGradient, Rhs, Guess>
+ solveWithGuess(const MatrixBase<Rhs>& b, const Guess& x0) const
+ {
+ eigen_assert(m_isInitialized && "ConjugateGradient is not initialized.");
+ eigen_assert(Base::rows()==b.rows()
+ && "ConjugateGradient::solve(): invalid number of rows of the right hand side matrix b");
+ return internal::solve_retval_with_guess
+ <ConstrainedConjugateGradient, Rhs, Guess>(*this, b.derived(), x0);
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solveWithGuess(const Rhs& b, Dest& x) const
+ {
+ m_iterations = Base::maxIterations();
+ m_error = Base::m_tolerance;
+
+ for(int j=0; j<b.cols(); ++j)
+ {
+ m_iterations = Base::maxIterations();
+ m_error = Base::m_tolerance;
+
+ typename Dest::ColXpr xj(x,j);
+ internal::constrained_conjugate_gradient(mp_matrix->template selfadjointView<UpLo>(), b.col(j), xj, m_filter,
+ Base::m_preconditioner, m_iterations, m_error);
+ }
+
+ m_isInitialized = true;
+ m_info = m_error <= Base::m_tolerance ? Success : NoConvergence;
+ }
+
+ /** \internal */
+ template<typename Rhs,typename Dest>
+ void _solve(const Rhs& b, Dest& x) const
+ {
+ x.setOnes();
+ _solveWithGuess(b,x);
+ }
+
+protected:
+ FilterMatrixType m_filter;
+};
+
+
+namespace internal {
+
+template<typename _MatrixType, int _UpLo, typename _Filter, typename _Preconditioner, typename Rhs>
+struct solve_retval<ConstrainedConjugateGradient<_MatrixType,_UpLo,_Filter,_Preconditioner>, Rhs>
+ : solve_retval_base<ConstrainedConjugateGradient<_MatrixType,_UpLo,_Filter,_Preconditioner>, Rhs>
+{
+ typedef ConstrainedConjugateGradient<_MatrixType,_UpLo,_Filter,_Preconditioner> Dec;
+ EIGEN_MAKE_SOLVE_HELPERS(Dec,Rhs)
+
+ template<typename Dest> void evalTo(Dest& dst) const
+ {
+ dec()._solve(rhs(),dst);
+ }
+};
+
+} // end namespace internal
+
+} // end namespace Eigen
+
+#endif // EIGEN_CONSTRAINEDCG_H
diff --git a/source/blender/physics/intern/eigen_utils.h b/source/blender/physics/intern/eigen_utils.h
new file mode 100644
index 00000000000..cd3bd5ee45d
--- /dev/null
+++ b/source/blender/physics/intern/eigen_utils.h
@@ -0,0 +1,230 @@
+/*
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __EIGEN_UTILS_H__
+#define __EIGEN_UTILS_H__
+
+/** \file eigen_utils.h
+ * \ingroup bph
+ */
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+/* XXX suppress verbose warnings in eigen */
+# pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+
+#include <Eigen/Sparse>
+#include <Eigen/src/Core/util/DisableStupidWarnings.h>
+
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+#include "BLI_utildefines.h"
+
+
+typedef float Scalar;
+
+/* slightly extended Eigen vector class
+ * with conversion to/from plain C float array
+ */
+class Vector3 : public Eigen::Vector3f {
+public:
+ typedef float *ctype;
+
+ Vector3()
+ {
+ }
+
+ Vector3(const ctype &v)
+ {
+ for (int k = 0; k < 3; ++k)
+ coeffRef(k) = v[k];
+ }
+
+ Vector3& operator = (const ctype &v)
+ {
+ for (int k = 0; k < 3; ++k)
+ coeffRef(k) = v[k];
+ return *this;
+ }
+
+ operator ctype()
+ {
+ return data();
+ }
+};
+
+/* slightly extended Eigen matrix class
+ * with conversion to/from plain C float array
+ */
+class Matrix3 : public Eigen::Matrix3f {
+public:
+ typedef float (*ctype)[3];
+
+ Matrix3()
+ {
+ }
+
+ Matrix3(const ctype &v)
+ {
+ for (int k = 0; k < 3; ++k)
+ for (int l = 0; l < 3; ++l)
+ coeffRef(l, k) = v[k][l];
+ }
+
+ Matrix3& operator = (const ctype &v)
+ {
+ for (int k = 0; k < 3; ++k)
+ for (int l = 0; l < 3; ++l)
+ coeffRef(l, k) = v[k][l];
+ return *this;
+ }
+
+ operator ctype()
+ {
+ return (ctype)data();
+ }
+};
+
+typedef Eigen::VectorXf lVector;
+
+/* Extension of dense Eigen vectors,
+ * providing 3-float block access for blenlib math functions
+ */
+class lVector3f : public Eigen::VectorXf {
+public:
+ typedef Eigen::VectorXf base_t;
+
+ lVector3f()
+ {
+ }
+
+ template <typename T>
+ lVector3f& operator = (T rhs)
+ {
+ base_t::operator=(rhs);
+ return *this;
+ }
+
+ float* v3(int vertex)
+ {
+ return &coeffRef(3 * vertex);
+ }
+
+ const float* v3(int vertex) const
+ {
+ return &coeffRef(3 * vertex);
+ }
+};
+
+typedef Eigen::Triplet<Scalar> Triplet;
+typedef std::vector<Triplet> TripletList;
+
+typedef Eigen::SparseMatrix<Scalar> lMatrix;
+
+/* Constructor type that provides more convenient handling of Eigen triplets
+ * for efficient construction of sparse 3x3 block matrices.
+ * This should be used for building lMatrix instead of writing to such lMatrix directly (which is very inefficient).
+ * After all elements have been defined using the set() method, the actual matrix can be filled using construct().
+ */
+struct lMatrix3fCtor {
+ lMatrix3fCtor()
+ {
+ }
+
+ void reset()
+ {
+ m_trips.clear();
+ }
+
+ void reserve(int numverts)
+ {
+ /* reserve for diagonal entries */
+ m_trips.reserve(numverts * 9);
+ }
+
+ void add(int i, int j, const Matrix3 &m)
+ {
+ i *= 3;
+ j *= 3;
+ for (int k = 0; k < 3; ++k)
+ for (int l = 0; l < 3; ++l)
+ m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k)));
+ }
+
+ void sub(int i, int j, const Matrix3 &m)
+ {
+ i *= 3;
+ j *= 3;
+ for (int k = 0; k < 3; ++k)
+ for (int l = 0; l < 3; ++l)
+ m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k)));
+ }
+
+ inline void construct(lMatrix &m)
+ {
+ m.setFromTriplets(m_trips.begin(), m_trips.end());
+ m_trips.clear();
+ }
+
+private:
+ TripletList m_trips;
+};
+
+typedef Eigen::ConjugateGradient<lMatrix, Eigen::Lower, Eigen::DiagonalPreconditioner<Scalar> > ConjugateGradient;
+
+using Eigen::ComputationInfo;
+
+BLI_INLINE void print_lvector(const lVector3f &v)
+{
+ for (int i = 0; i < v.rows(); ++i) {
+ if (i > 0 && i % 3 == 0)
+ printf("\n");
+
+ printf("%f,\n", v[i]);
+ }
+}
+
+BLI_INLINE void print_lmatrix(const lMatrix &m)
+{
+ for (int j = 0; j < m.rows(); ++j) {
+ if (j > 0 && j % 3 == 0)
+ printf("\n");
+
+ for (int i = 0; i < m.cols(); ++i) {
+ if (i > 0 && i % 3 == 0)
+ printf(" ");
+
+ implicit_print_matrix_elem(m.coeff(j, i));
+ }
+ printf("\n");
+ }
+}
+
+#endif
diff --git a/source/blender/physics/intern/hair_volume.cpp b/source/blender/physics/intern/hair_volume.cpp
new file mode 100644
index 00000000000..b07af1d201c
--- /dev/null
+++ b/source/blender/physics/intern/hair_volume.cpp
@@ -0,0 +1,1154 @@
+/*
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Janne Karhu, Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/physics/intern/hair_volume.cpp
+ * \ingroup bph
+ */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_texture_types.h"
+
+#include "BKE_effect.h"
+}
+
+#include "implicit.h"
+#include "eigen_utils.h"
+
+/* ================ Volumetric Hair Interaction ================
+ * adapted from
+ *
+ * Volumetric Methods for Simulation and Rendering of Hair
+ * (Petrovic, Henne, Anderson, Pixar Technical Memo #06-08, Pixar Animation Studios)
+ *
+ * as well as
+ *
+ * "Detail Preserving Continuum Simulation of Straight Hair"
+ * (McAdams, Selle 2009)
+ */
+
+/* Note about array indexing:
+ * Generally the arrays here are one-dimensional.
+ * The relation between 3D indices and the array offset is
+ * offset = x + res_x * y + res_x * res_y * z
+ */
+
+static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+
+BLI_INLINE int floor_int(float value)
+{
+ return value > 0.0f ? (int)value : ((int)value) - 1;
+}
+
+BLI_INLINE float floor_mod(float value)
+{
+ return value - floorf(value);
+}
+
+BLI_INLINE int hair_grid_size(const int res[3])
+{
+ return res[0] * res[1] * res[2];
+}
+
+typedef struct HairGridVert {
+ int samples;
+ float velocity[3];
+ float density;
+
+ float velocity_smooth[3];
+} HairGridVert;
+
+typedef struct HairGrid {
+ HairGridVert *verts;
+ int res[3];
+ float gmin[3], gmax[3];
+ float cellsize, inv_cellsize;
+} HairGrid;
+
+#define HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, axis) ( min_ii( max_ii( (int)((vec[axis] - gmin[axis]) * scale), 0), res[axis]-2 ) )
+
+BLI_INLINE int hair_grid_offset(const float vec[3], const int res[3], const float gmin[3], float scale)
+{
+ int i, j, k;
+ i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0);
+ j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1);
+ k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2);
+ return i + (j + k*res[1])*res[0];
+}
+
+BLI_INLINE int hair_grid_interp_weights(const int res[3], const float gmin[3], float scale, const float vec[3], float uvw[3])
+{
+ int i, j, k, offset;
+
+ i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0);
+ j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1);
+ k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2);
+ offset = i + (j + k*res[1])*res[0];
+
+ uvw[0] = (vec[0] - gmin[0]) * scale - (float)i;
+ uvw[1] = (vec[1] - gmin[1]) * scale - (float)j;
+ uvw[2] = (vec[2] - gmin[2]) * scale - (float)k;
+
+// BLI_assert(0.0f <= uvw[0] && uvw[0] <= 1.0001f);
+// BLI_assert(0.0f <= uvw[1] && uvw[1] <= 1.0001f);
+// BLI_assert(0.0f <= uvw[2] && uvw[2] <= 1.0001f);
+
+ return offset;
+}
+
+BLI_INLINE void hair_grid_interpolate(const HairGridVert *grid, const int res[3], const float gmin[3], float scale, const float vec[3],
+ float *density, float velocity[3], float vel_smooth[3], float density_gradient[3], float velocity_gradient[3][3])
+{
+ HairGridVert data[8];
+ float uvw[3], muvw[3];
+ int res2 = res[1] * res[0];
+ int offset;
+
+ offset = hair_grid_interp_weights(res, gmin, scale, vec, uvw);
+ muvw[0] = 1.0f - uvw[0];
+ muvw[1] = 1.0f - uvw[1];
+ muvw[2] = 1.0f - uvw[2];
+
+ data[0] = grid[offset ];
+ data[1] = grid[offset +1];
+ data[2] = grid[offset +res[0] ];
+ data[3] = grid[offset +res[0]+1];
+ data[4] = grid[offset+res2 ];
+ data[5] = grid[offset+res2 +1];
+ data[6] = grid[offset+res2+res[0] ];
+ data[7] = grid[offset+res2+res[0]+1];
+
+ if (density) {
+ *density = muvw[2]*( muvw[1]*( muvw[0]*data[0].density + uvw[0]*data[1].density ) +
+ uvw[1]*( muvw[0]*data[2].density + uvw[0]*data[3].density ) ) +
+ uvw[2]*( muvw[1]*( muvw[0]*data[4].density + uvw[0]*data[5].density ) +
+ uvw[1]*( muvw[0]*data[6].density + uvw[0]*data[7].density ) );
+ }
+
+ if (velocity) {
+ int k;
+ for (k = 0; k < 3; ++k) {
+ velocity[k] = muvw[2]*( muvw[1]*( muvw[0]*data[0].velocity[k] + uvw[0]*data[1].velocity[k] ) +
+ uvw[1]*( muvw[0]*data[2].velocity[k] + uvw[0]*data[3].velocity[k] ) ) +
+ uvw[2]*( muvw[1]*( muvw[0]*data[4].velocity[k] + uvw[0]*data[5].velocity[k] ) +
+ uvw[1]*( muvw[0]*data[6].velocity[k] + uvw[0]*data[7].velocity[k] ) );
+ }
+ }
+
+ if (vel_smooth) {
+ int k;
+ for (k = 0; k < 3; ++k) {
+ vel_smooth[k] = muvw[2]*( muvw[1]*( muvw[0]*data[0].velocity_smooth[k] + uvw[0]*data[1].velocity_smooth[k] ) +
+ uvw[1]*( muvw[0]*data[2].velocity_smooth[k] + uvw[0]*data[3].velocity_smooth[k] ) ) +
+ uvw[2]*( muvw[1]*( muvw[0]*data[4].velocity_smooth[k] + uvw[0]*data[5].velocity_smooth[k] ) +
+ uvw[1]*( muvw[0]*data[6].velocity_smooth[k] + uvw[0]*data[7].velocity_smooth[k] ) );
+ }
+ }
+
+ if (density_gradient) {
+ density_gradient[0] = muvw[1] * muvw[2] * ( data[0].density - data[1].density ) +
+ uvw[1] * muvw[2] * ( data[2].density - data[3].density ) +
+ muvw[1] * uvw[2] * ( data[4].density - data[5].density ) +
+ uvw[1] * uvw[2] * ( data[6].density - data[7].density );
+
+ density_gradient[1] = muvw[2] * muvw[0] * ( data[0].density - data[2].density ) +
+ uvw[2] * muvw[0] * ( data[4].density - data[6].density ) +
+ muvw[2] * uvw[0] * ( data[1].density - data[3].density ) +
+ uvw[2] * uvw[0] * ( data[5].density - data[7].density );
+
+ density_gradient[2] = muvw[2] * muvw[0] * ( data[0].density - data[4].density ) +
+ uvw[2] * muvw[0] * ( data[1].density - data[5].density ) +
+ muvw[2] * uvw[0] * ( data[2].density - data[6].density ) +
+ uvw[2] * uvw[0] * ( data[3].density - data[7].density );
+ }
+
+ if (velocity_gradient) {
+ /* XXX TODO */
+ zero_m3(velocity_gradient);
+ }
+}
+
+void BPH_hair_volume_vertex_grid_forces(HairGrid *grid, const float x[3], const float v[3],
+ float smoothfac, float pressurefac, float minpressure,
+ float f[3], float dfdx[3][3], float dfdv[3][3])
+{
+ float gdensity, gvelocity[3], ggrad[3], gvelgrad[3][3], gradlen;
+
+ hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, &gdensity, gvelocity, NULL, ggrad, gvelgrad);
+
+ zero_v3(f);
+ sub_v3_v3(gvelocity, v);
+ mul_v3_v3fl(f, gvelocity, smoothfac);
+
+ gradlen = normalize_v3(ggrad) - minpressure;
+ if (gradlen > 0.0f) {
+ mul_v3_fl(ggrad, gradlen);
+ madd_v3_v3fl(f, ggrad, pressurefac);
+ }
+
+ zero_m3(dfdx);
+
+ sub_m3_m3m3(dfdv, gvelgrad, I);
+ mul_m3_fl(dfdv, smoothfac);
+}
+
+void BPH_hair_volume_grid_interpolate(HairGrid *grid, const float x[3],
+ float *density, float velocity[3], float velocity_smooth[3], float density_gradient[3], float velocity_gradient[3][3])
+{
+ hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, density, velocity, velocity_smooth, density_gradient, velocity_gradient);
+}
+
+void BPH_hair_volume_grid_velocity(HairGrid *grid, const float x[3], const float v[3],
+ float fluid_factor,
+ float r_v[3])
+{
+ float gdensity, gvelocity[3], gvel_smooth[3], ggrad[3], gvelgrad[3][3];
+ float v_pic[3], v_flip[3];
+
+ hair_grid_interpolate(grid->verts, grid->res, grid->gmin, grid->inv_cellsize, x, &gdensity, gvelocity, gvel_smooth, ggrad, gvelgrad);
+
+ /* velocity according to PIC method (Particle-in-Cell) */
+ copy_v3_v3(v_pic, gvel_smooth);
+
+ /* velocity according to FLIP method (Fluid-Implicit-Particle) */
+ sub_v3_v3v3(v_flip, gvel_smooth, gvelocity);
+ add_v3_v3(v_flip, v);
+
+ interp_v3_v3v3(r_v, v_pic, v_flip, fluid_factor);
+}
+
+void BPH_hair_volume_grid_clear(HairGrid *grid)
+{
+ const int size = hair_grid_size(grid->res);
+ int i;
+ for (i = 0; i < size; ++i) {
+ zero_v3(grid->verts[i].velocity);
+ zero_v3(grid->verts[i].velocity_smooth);
+ grid->verts[i].density = 0.0f;
+ grid->verts[i].samples = 0;
+ }
+}
+
+BLI_INLINE bool hair_grid_point_valid(const float vec[3], float gmin[3], float gmax[3])
+{
+ return !(vec[0] < gmin[0] || vec[1] < gmin[1] || vec[2] < gmin[2] ||
+ vec[0] > gmax[0] || vec[1] > gmax[1] || vec[2] > gmax[2]);
+}
+
+BLI_INLINE float dist_tent_v3f3(const float a[3], float x, float y, float z)
+{
+ float w = (1.0f - fabsf(a[0] - x)) * (1.0f - fabsf(a[1] - y)) * (1.0f - fabsf(a[2] - z));
+ return w;
+}
+
+BLI_INLINE float weights_sum(const float weights[8])
+{
+ float totweight = 0.0f;
+ int i;
+ for (i = 0; i < 8; ++i)
+ totweight += weights[i];
+ return totweight;
+}
+
+/* returns the grid array offset as well to avoid redundant calculation */
+BLI_INLINE int hair_grid_weights(const int res[3], const float gmin[3], float scale, const float vec[3], float weights[8])
+{
+ int i, j, k, offset;
+ float uvw[3];
+
+ i = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 0);
+ j = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 1);
+ k = HAIR_GRID_INDEX_AXIS(vec, res, gmin, scale, 2);
+ offset = i + (j + k*res[1])*res[0];
+
+ uvw[0] = (vec[0] - gmin[0]) * scale;
+ uvw[1] = (vec[1] - gmin[1]) * scale;
+ uvw[2] = (vec[2] - gmin[2]) * scale;
+
+ weights[0] = dist_tent_v3f3(uvw, (float)i , (float)j , (float)k );
+ weights[1] = dist_tent_v3f3(uvw, (float)(i+1), (float)j , (float)k );
+ weights[2] = dist_tent_v3f3(uvw, (float)i , (float)(j+1), (float)k );
+ weights[3] = dist_tent_v3f3(uvw, (float)(i+1), (float)(j+1), (float)k );
+ weights[4] = dist_tent_v3f3(uvw, (float)i , (float)j , (float)(k+1));
+ weights[5] = dist_tent_v3f3(uvw, (float)(i+1), (float)j , (float)(k+1));
+ weights[6] = dist_tent_v3f3(uvw, (float)i , (float)(j+1), (float)(k+1));
+ weights[7] = dist_tent_v3f3(uvw, (float)(i+1), (float)(j+1), (float)(k+1));
+
+// BLI_assert(fabsf(weights_sum(weights) - 1.0f) < 0.0001f);
+
+ return offset;
+}
+
+BLI_INLINE void grid_to_world(HairGrid *grid, float vecw[3], const float vec[3])
+{
+ copy_v3_v3(vecw, vec);
+ mul_v3_fl(vecw, grid->cellsize);
+ add_v3_v3(vecw, grid->gmin);
+}
+
+void BPH_hair_volume_add_vertex(HairGrid *grid, const float x[3], const float v[3])
+{
+ const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
+ float weights[8];
+ int di, dj, dk;
+ int offset;
+
+ if (!hair_grid_point_valid(x, grid->gmin, grid->gmax))
+ return;
+
+ offset = hair_grid_weights(res, grid->gmin, grid->inv_cellsize, x, weights);
+
+ for (di = 0; di < 2; ++di) {
+ for (dj = 0; dj < 2; ++dj) {
+ for (dk = 0; dk < 2; ++dk) {
+ int voffset = offset + di + (dj + dk*res[1])*res[0];
+ int iw = di + dj*2 + dk*4;
+
+ grid->verts[voffset].density += weights[iw];
+ madd_v3_v3fl(grid->verts[voffset].velocity, v, weights[iw]);
+ }
+ }
+ }
+}
+
+#if 0
+BLI_INLINE void hair_volume_eval_grid_vertex(HairGridVert *vert, const float loc[3], float radius, float dist_scale,
+ const float x2[3], const float v2[3], const float x3[3], const float v3[3])
+{
+ float closest[3], lambda, dist, weight;
+
+ lambda = closest_to_line_v3(closest, loc, x2, x3);
+ dist = len_v3v3(closest, loc);
+
+ weight = (radius - dist) * dist_scale;
+
+ if (weight > 0.0f) {
+ float vel[3];
+
+ interp_v3_v3v3(vel, v2, v3, lambda);
+ madd_v3_v3fl(vert->velocity, vel, weight);
+ vert->density += weight;
+ vert->samples += 1;
+ }
+}
+
+BLI_INLINE int major_axis_v3(const float v[3])
+{
+ const float a = fabsf(v[0]);
+ const float b = fabsf(v[1]);
+ const float c = fabsf(v[2]);
+ return a > b ? (a > c ? 0 : 2) : (b > c ? 1 : 2);
+}
+
+BLI_INLINE void hair_volume_add_segment_2D(HairGrid *grid,
+ const float UNUSED(x1[3]), const float UNUSED(v1[3]), const float x2[3], const float v2[3],
+ const float x3[3], const float v3[3], const float UNUSED(x4[3]), const float UNUSED(v4[3]),
+ const float UNUSED(dir1[3]), const float dir2[3], const float UNUSED(dir3[3]),
+ int resj, int resk, int jmin, int jmax, int kmin, int kmax,
+ HairGridVert *vert, int stride_j, int stride_k, const float loc[3], int axis_j, int axis_k,
+ int debug_i)
+{
+ const float radius = 1.5f;
+ const float dist_scale = grid->inv_cellsize;
+
+ int j, k;
+
+ /* boundary checks to be safe */
+ CLAMP_MIN(jmin, 0);
+ CLAMP_MAX(jmax, resj-1);
+ CLAMP_MIN(kmin, 0);
+ CLAMP_MAX(kmax, resk-1);
+
+ HairGridVert *vert_j = vert + jmin * stride_j;
+ float loc_j[3] = { loc[0], loc[1], loc[2] };
+ loc_j[axis_j] += (float)jmin;
+ for (j = jmin; j <= jmax; ++j, vert_j += stride_j, loc_j[axis_j] += 1.0f) {
+
+ HairGridVert *vert_k = vert_j + kmin * stride_k;
+ float loc_k[3] = { loc_j[0], loc_j[1], loc_j[2] };
+ loc_k[axis_k] += (float)kmin;
+ for (k = kmin; k <= kmax; ++k, vert_k += stride_k, loc_k[axis_k] += 1.0f) {
+
+ hair_volume_eval_grid_vertex(vert_k, loc_k, radius, dist_scale, x2, v2, x3, v3);
+
+#if 0
+ {
+ float wloc[3], x2w[3], x3w[3];
+ grid_to_world(grid, wloc, loc_k);
+ grid_to_world(grid, x2w, x2);
+ grid_to_world(grid, x3w, x3);
+
+ if (vert_k->samples > 0)
+ BKE_sim_debug_data_add_circle(wloc, 0.01f, 1.0, 1.0, 0.3, "grid", 2525, debug_i, j, k);
+
+ if (grid->debug_value) {
+ BKE_sim_debug_data_add_dot(wloc, 1, 0, 0, "grid", 93, debug_i, j, k);
+ BKE_sim_debug_data_add_dot(x2w, 0.1, 0.1, 0.7, "grid", 649, debug_i, j, k);
+ BKE_sim_debug_data_add_line(wloc, x2w, 0.3, 0.8, 0.3, "grid", 253, debug_i, j, k);
+ BKE_sim_debug_data_add_line(wloc, x3w, 0.8, 0.3, 0.3, "grid", 254, debug_i, j, k);
+// BKE_sim_debug_data_add_circle(x2w, len_v3v3(wloc, x2w), 0.2, 0.7, 0.2, "grid", 255, i, j, k);
+ }
+ }
+#endif
+ }
+ }
+}
+
+/* Uses a variation of Bresenham's algorithm for rasterizing a 3D grid with a line segment.
+ *
+ * The radius of influence around a segment is assumed to be at most 2*cellsize,
+ * i.e. only cells containing the segment and their direct neighbors are examined.
+ *
+ *
+ */
+void BPH_hair_volume_add_segment(HairGrid *grid,
+ const float x1[3], const float v1[3], const float x2[3], const float v2[3],
+ const float x3[3], const float v3[3], const float x4[3], const float v4[3],
+ const float dir1[3], const float dir2[3], const float dir3[3])
+{
+ const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
+
+ /* find the primary direction from the major axis of the direction vector */
+ const int axis0 = major_axis_v3(dir2);
+ const int axis1 = (axis0 + 1) % 3;
+ const int axis2 = (axis0 + 2) % 3;
+
+ /* vertex buffer offset factors along cardinal axes */
+ const int strides[3] = { 1, res[0], res[0] * res[1] };
+ const int stride0 = strides[axis0];
+ const int stride1 = strides[axis1];
+ const int stride2 = strides[axis2];
+
+ /* increment of secondary directions per step in the primary direction
+ * note: we always go in the positive direction along axis0, so the sign can be inverted
+ */
+ const float inc1 = dir2[axis1] / dir2[axis0];
+ const float inc2 = dir2[axis2] / dir2[axis0];
+
+ /* start/end points, so increment along axis0 is always positive */
+ const float *start = x2[axis0] < x3[axis0] ? x2 : x3;
+ const float *end = x2[axis0] < x3[axis0] ? x3 : x2;
+ const float start0 = start[axis0], start1 = start[axis1], start2 = start[axis2];
+ const float end0 = end[axis0];
+
+ /* range along primary direction */
+ const int imin = max_ii(floor_int(start[axis0]) - 1, 0);
+ const int imax = min_ii(floor_int(end[axis0]) + 2, res[axis0]-1);
+
+ float h = 0.0f;
+ HairGridVert *vert0;
+ float loc0[3];
+ int j0, k0, j0_prev, k0_prev;
+ int i;
+
+ for (i = imin; i <= imax; ++i) {
+ float shift1, shift2; /* fraction of a full cell shift [0.0, 1.0) */
+ int jmin, jmax, kmin, kmax;
+
+ h = CLAMPIS((float)i, start0, end0);
+
+ shift1 = start1 + (h - start0) * inc1;
+ shift2 = start2 + (h - start0) * inc2;
+
+ j0_prev = j0;
+ j0 = floor_int(shift1);
+
+ k0_prev = k0;
+ k0 = floor_int(shift2);
+
+ if (i > imin) {
+ jmin = min_ii(j0, j0_prev);
+ jmax = max_ii(j0, j0_prev);
+ kmin = min_ii(k0, k0_prev);
+ kmax = max_ii(k0, k0_prev);
+ }
+ else {
+ jmin = jmax = j0;
+ kmin = kmax = k0;
+ }
+
+ vert0 = grid->verts + i * stride0;
+ loc0[axis0] = (float)i;
+ loc0[axis1] = 0.0f;
+ loc0[axis2] = 0.0f;
+
+ hair_volume_add_segment_2D(grid, x1, v1, x2, v2, x3, v3, x4, v4, dir1, dir2, dir3,
+ res[axis1], res[axis2], jmin-1, jmax+2, kmin-1, kmax+2,
+ vert0, stride1, stride2, loc0, axis1, axis2,
+ i);
+ }
+}
+#else
+BLI_INLINE void hair_volume_eval_grid_vertex_sample(HairGridVert *vert, const float loc[3], float radius, float dist_scale,
+ const float x[3], const float v[3])
+{
+ float dist, weight;
+
+ dist = len_v3v3(x, loc);
+
+ weight = (radius - dist) * dist_scale;
+
+ if (weight > 0.0f) {
+ madd_v3_v3fl(vert->velocity, v, weight);
+ vert->density += weight;
+ vert->samples += 1;
+ }
+}
+
+/* XXX simplified test implementation using a series of discrete sample along the segment,
+ * instead of finding the closest point for all affected grid vertices.
+ */
+void BPH_hair_volume_add_segment(HairGrid *grid,
+ const float UNUSED(x1[3]), const float UNUSED(v1[3]), const float x2[3], const float v2[3],
+ const float x3[3], const float v3[3], const float UNUSED(x4[3]), const float UNUSED(v4[3]),
+ const float UNUSED(dir1[3]), const float UNUSED(dir2[3]), const float UNUSED(dir3[3]))
+{
+ const float radius = 1.5f;
+ const float dist_scale = grid->inv_cellsize;
+
+ const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
+ const int stride[3] = { 1, res[0], res[0] * res[1] };
+ const int num_samples = 10;
+
+ int s;
+
+ for (s = 0; s < num_samples; ++s) {
+ float x[3], v[3];
+ int i, j, k;
+
+ float f = (float)s / (float)(num_samples-1);
+ interp_v3_v3v3(x, x2, x3, f);
+ interp_v3_v3v3(v, v2, v3, f);
+
+ int imin = max_ii(floor_int(x[0]) - 2, 0);
+ int imax = min_ii(floor_int(x[0]) + 2, res[0]-1);
+ int jmin = max_ii(floor_int(x[1]) - 2, 0);
+ int jmax = min_ii(floor_int(x[1]) + 2, res[1]-1);
+ int kmin = max_ii(floor_int(x[2]) - 2, 0);
+ int kmax = min_ii(floor_int(x[2]) + 2, res[2]-1);
+
+ for (k = kmin; k <= kmax; ++k) {
+ for (j = jmin; j <= jmax; ++j) {
+ for (i = imin; i <= imax; ++i) {
+ float loc[3] = { (float)i, (float)j, (float)k };
+ HairGridVert *vert = grid->verts + i * stride[0] + j * stride[1] + k * stride[2];
+
+ hair_volume_eval_grid_vertex_sample(vert, loc, radius, dist_scale, x, v);
+ }
+ }
+ }
+ }
+}
+#endif
+
+void BPH_hair_volume_normalize_vertex_grid(HairGrid *grid)
+{
+ int i, size = hair_grid_size(grid->res);
+ /* divide velocity with density */
+ for (i = 0; i < size; i++) {
+ float density = grid->verts[i].density;
+ if (density > 0.0f)
+ mul_v3_fl(grid->verts[i].velocity, 1.0f/density);
+ }
+}
+
+static const float density_threshold = 0.001f; /* cells with density below this are considered empty */
+
+/* Contribution of target density pressure to the laplacian in the pressure poisson equation.
+ * This is based on the model found in
+ * "Two-way Coupled SPH and Particle Level Set Fluid Simulation" (Losasso et al., 2008)
+ */
+BLI_INLINE float hair_volume_density_divergence(float density, float target_density, float strength)
+{
+ if (density > density_threshold && density > target_density)
+ return strength * logf(target_density / density);
+ else
+ return 0.0f;
+}
+
+bool BPH_hair_volume_solve_divergence(HairGrid *grid, float dt, float target_density, float target_strength)
+{
+ const float flowfac = grid->cellsize;
+ const float inv_flowfac = 1.0f / grid->cellsize;
+
+ /*const int num_cells = hair_grid_size(grid->res);*/
+ const int res[3] = { grid->res[0], grid->res[1], grid->res[2] };
+ const int resA[3] = { grid->res[0] + 2, grid->res[1] + 2, grid->res[2] + 2 };
+
+ const int stride0 = 1;
+ const int stride1 = grid->res[0];
+ const int stride2 = grid->res[1] * grid->res[0];
+ const int strideA0 = 1;
+ const int strideA1 = grid->res[0] + 2;
+ const int strideA2 = (grid->res[1] + 2) * (grid->res[0] + 2);
+
+ const int num_cells = res[0] * res[1] * res[2];
+ const int num_cellsA = (res[0] + 2) * (res[1] + 2) * (res[2] + 2);
+
+ HairGridVert *vert_start = grid->verts - (stride0 + stride1 + stride2);
+ HairGridVert *vert;
+ int i, j, k;
+
+#define MARGIN_i0 (i < 1)
+#define MARGIN_j0 (j < 1)
+#define MARGIN_k0 (k < 1)
+#define MARGIN_i1 (i >= resA[0]-1)
+#define MARGIN_j1 (j >= resA[1]-1)
+#define MARGIN_k1 (k >= resA[2]-1)
+
+#define NEIGHBOR_MARGIN_i0 (i < 2)
+#define NEIGHBOR_MARGIN_j0 (j < 2)
+#define NEIGHBOR_MARGIN_k0 (k < 2)
+#define NEIGHBOR_MARGIN_i1 (i >= resA[0]-2)
+#define NEIGHBOR_MARGIN_j1 (j >= resA[1]-2)
+#define NEIGHBOR_MARGIN_k1 (k >= resA[2]-2)
+
+ BLI_assert(num_cells >= 1);
+
+ /* Calculate divergence */
+ lVector B(num_cellsA);
+ for (k = 0; k < resA[2]; ++k) {
+ for (j = 0; j < resA[1]; ++j) {
+ for (i = 0; i < resA[0]; ++i) {
+ int u = i * strideA0 + j * strideA1 + k * strideA2;
+ bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
+
+ if (is_margin) {
+ B[u] = 0.0f;
+ continue;
+ }
+
+ vert = vert_start + i * stride0 + j * stride1 + k * stride2;
+
+ const float *v0 = vert->velocity;
+ float dx = 0.0f, dy = 0.0f, dz = 0.0f;
+ if (!NEIGHBOR_MARGIN_i0)
+ dx += v0[0] - (vert - stride0)->velocity[0];
+ if (!NEIGHBOR_MARGIN_i1)
+ dx += (vert + stride0)->velocity[0] - v0[0];
+ if (!NEIGHBOR_MARGIN_j0)
+ dy += v0[1] - (vert - stride1)->velocity[1];
+ if (!NEIGHBOR_MARGIN_j1)
+ dy += (vert + stride1)->velocity[1] - v0[1];
+ if (!NEIGHBOR_MARGIN_k0)
+ dz += v0[2] - (vert - stride2)->velocity[2];
+ if (!NEIGHBOR_MARGIN_k1)
+ dz += (vert + stride2)->velocity[2] - v0[2];
+
+ float divergence = -0.5f * flowfac * (dx + dy + dz);
+
+ /* adjustment term for target density */
+ float target = hair_volume_density_divergence(vert->density, target_density, target_strength);
+
+ /* B vector contains the finite difference approximation of the velocity divergence.
+ * Note: according to the discretized Navier-Stokes equation the rhs vector
+ * and resulting pressure gradient should be multiplied by the (inverse) density;
+ * however, this is already included in the weighting of hair velocities on the grid!
+ */
+ B[u] = divergence - target;
+
+#if 0
+ {
+ float wloc[3], loc[3];
+ float col0[3] = {0.0, 0.0, 0.0};
+ float colp[3] = {0.0, 1.0, 1.0};
+ float coln[3] = {1.0, 0.0, 1.0};
+ float col[3];
+ float fac;
+
+ loc[0] = (float)(i - 1);
+ loc[1] = (float)(j - 1);
+ loc[2] = (float)(k - 1);
+ grid_to_world(grid, wloc, loc);
+
+ if (divergence > 0.0f) {
+ fac = CLAMPIS(divergence * target_strength, 0.0, 1.0);
+ interp_v3_v3v3(col, col0, colp, fac);
+ }
+ else {
+ fac = CLAMPIS(-divergence * target_strength, 0.0, 1.0);
+ interp_v3_v3v3(col, col0, coln, fac);
+ }
+ if (fac > 0.05f)
+ BKE_sim_debug_data_add_circle(grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5522, i, j, k);
+ }
+#endif
+ }
+ }
+ }
+
+ /* Main Poisson equation system:
+ * This is derived from the discretezation of the Poisson equation
+ * div(grad(p)) = div(v)
+ *
+ * The finite difference approximation yields the linear equation system described here:
+ * http://en.wikipedia.org/wiki/Discrete_Poisson_equation
+ */
+ lMatrix A(num_cellsA, num_cellsA);
+ /* Reserve space for the base equation system (without boundary conditions).
+ * Each column contains a factor 6 on the diagonal
+ * and up to 6 factors -1 on other places.
+ */
+ A.reserve(Eigen::VectorXi::Constant(num_cellsA, 7));
+
+ for (k = 0; k < resA[2]; ++k) {
+ for (j = 0; j < resA[1]; ++j) {
+ for (i = 0; i < resA[0]; ++i) {
+ int u = i * strideA0 + j * strideA1 + k * strideA2;
+ bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
+
+ vert = vert_start + i * stride0 + j * stride1 + k * stride2;
+ if (!is_margin && vert->density > density_threshold) {
+ int neighbors_lo = 0;
+ int neighbors_hi = 0;
+ int non_solid_neighbors = 0;
+ int neighbor_lo_index[3];
+ int neighbor_hi_index[3];
+ int n;
+
+ /* check for upper bounds in advance
+ * to get the correct number of neighbors,
+ * needed for the diagonal element
+ */
+ if (!NEIGHBOR_MARGIN_k0 && (vert - stride2)->density > density_threshold)
+ neighbor_lo_index[neighbors_lo++] = u - strideA2;
+ if (!NEIGHBOR_MARGIN_j0 && (vert - stride1)->density > density_threshold)
+ neighbor_lo_index[neighbors_lo++] = u - strideA1;
+ if (!NEIGHBOR_MARGIN_i0 && (vert - stride0)->density > density_threshold)
+ neighbor_lo_index[neighbors_lo++] = u - strideA0;
+ if (!NEIGHBOR_MARGIN_i1 && (vert + stride0)->density > density_threshold)
+ neighbor_hi_index[neighbors_hi++] = u + strideA0;
+ if (!NEIGHBOR_MARGIN_j1 && (vert + stride1)->density > density_threshold)
+ neighbor_hi_index[neighbors_hi++] = u + strideA1;
+ if (!NEIGHBOR_MARGIN_k1 && (vert + stride2)->density > density_threshold)
+ neighbor_hi_index[neighbors_hi++] = u + strideA2;
+
+ /*int liquid_neighbors = neighbors_lo + neighbors_hi;*/
+ non_solid_neighbors = 6;
+
+ for (n = 0; n < neighbors_lo; ++n)
+ A.insert(neighbor_lo_index[n], u) = -1.0f;
+ A.insert(u, u) = (float)non_solid_neighbors;
+ for (n = 0; n < neighbors_hi; ++n)
+ A.insert(neighbor_hi_index[n], u) = -1.0f;
+ }
+ else {
+ A.insert(u, u) = 1.0f;
+ }
+ }
+ }
+ }
+
+ ConjugateGradient cg;
+ cg.setMaxIterations(100);
+ cg.setTolerance(0.01f);
+
+ cg.compute(A);
+
+ lVector p = cg.solve(B);
+
+ if (cg.info() == Eigen::Success) {
+ /* Calculate velocity = grad(p) */
+ for (k = 0; k < resA[2]; ++k) {
+ for (j = 0; j < resA[1]; ++j) {
+ for (i = 0; i < resA[0]; ++i) {
+ int u = i * strideA0 + j * strideA1 + k * strideA2;
+ bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
+ if (is_margin)
+ continue;
+
+ vert = vert_start + i * stride0 + j * stride1 + k * stride2;
+ if (vert->density > density_threshold) {
+ float p_left = p[u - strideA0];
+ float p_right = p[u + strideA0];
+ float p_down = p[u - strideA1];
+ float p_up = p[u + strideA1];
+ float p_bottom = p[u - strideA2];
+ float p_top = p[u + strideA2];
+
+ /* finite difference estimate of pressure gradient */
+ float dvel[3];
+ dvel[0] = p_right - p_left;
+ dvel[1] = p_up - p_down;
+ dvel[2] = p_top - p_bottom;
+ mul_v3_fl(dvel, -0.5f * inv_flowfac);
+
+ /* pressure gradient describes velocity delta */
+ add_v3_v3v3(vert->velocity_smooth, vert->velocity, dvel);
+ }
+ else {
+ zero_v3(vert->velocity_smooth);
+ }
+ }
+ }
+ }
+
+#if 0
+ {
+ int axis = 0;
+ float offset = 0.0f;
+
+ int slice = (offset - grid->gmin[axis]) / grid->cellsize;
+
+ for (k = 0; k < resA[2]; ++k) {
+ for (j = 0; j < resA[1]; ++j) {
+ for (i = 0; i < resA[0]; ++i) {
+ int u = i * strideA0 + j * strideA1 + k * strideA2;
+ bool is_margin = MARGIN_i0 || MARGIN_i1 || MARGIN_j0 || MARGIN_j1 || MARGIN_k0 || MARGIN_k1;
+ if (i != slice)
+ continue;
+
+ vert = vert_start + i * stride0 + j * stride1 + k * stride2;
+
+ float wloc[3], loc[3];
+ float col0[3] = {0.0, 0.0, 0.0};
+ float colp[3] = {0.0, 1.0, 1.0};
+ float coln[3] = {1.0, 0.0, 1.0};
+ float col[3];
+ float fac;
+
+ loc[0] = (float)(i - 1);
+ loc[1] = (float)(j - 1);
+ loc[2] = (float)(k - 1);
+ grid_to_world(grid, wloc, loc);
+
+ float pressure = p[u];
+ if (pressure > 0.0f) {
+ fac = CLAMPIS(pressure * grid->debug1, 0.0, 1.0);
+ interp_v3_v3v3(col, col0, colp, fac);
+ }
+ else {
+ fac = CLAMPIS(-pressure * grid->debug1, 0.0, 1.0);
+ interp_v3_v3v3(col, col0, coln, fac);
+ }
+ if (fac > 0.05f)
+ BKE_sim_debug_data_add_circle(grid->debug_data, wloc, 0.01f, col[0], col[1], col[2], "grid", 5533, i, j, k);
+
+ if (!is_margin) {
+ float dvel[3];
+ sub_v3_v3v3(dvel, vert->velocity_smooth, vert->velocity);
+// BKE_sim_debug_data_add_vector(grid->debug_data, wloc, dvel, 1, 1, 1, "grid", 5566, i, j, k);
+ }
+
+ if (!is_margin) {
+ float d = CLAMPIS(vert->density * grid->debug2, 0.0f, 1.0f);
+ float col0[3] = {0.3, 0.3, 0.3};
+ float colp[3] = {0.0, 0.0, 1.0};
+ float col[3];
+
+ interp_v3_v3v3(col, col0, colp, d);
+// if (d > 0.05f)
+// BKE_sim_debug_data_add_dot(grid->debug_data, wloc, col[0], col[1], col[2], "grid", 5544, i, j, k);
+ }
+ }
+ }
+ }
+ }
+#endif
+
+ return true;
+ }
+ else {
+ /* Clear result in case of error */
+ for (i = 0, vert = grid->verts; i < num_cells; ++i, ++vert) {
+ zero_v3(vert->velocity_smooth);
+ }
+
+ return false;
+ }
+}
+
+#if 0 /* XXX weighting is incorrect, disabled for now */
+/* Velocity filter kernel
+ * See http://en.wikipedia.org/wiki/Filter_%28large_eddy_simulation%29
+ */
+
+BLI_INLINE void hair_volume_filter_box_convolute(HairVertexGrid *grid, float invD, const int kernel_size[3], int i, int j, int k)
+{
+ int res = grid->res;
+ int p, q, r;
+ int minp = max_ii(i - kernel_size[0], 0), maxp = min_ii(i + kernel_size[0], res-1);
+ int minq = max_ii(j - kernel_size[1], 0), maxq = min_ii(j + kernel_size[1], res-1);
+ int minr = max_ii(k - kernel_size[2], 0), maxr = min_ii(k + kernel_size[2], res-1);
+ int offset, kernel_offset, kernel_dq, kernel_dr;
+ HairGridVert *verts;
+ float *vel_smooth;
+
+ offset = i + (j + k*res)*res;
+ verts = grid->verts;
+ vel_smooth = verts[offset].velocity_smooth;
+
+ kernel_offset = minp + (minq + minr*res)*res;
+ kernel_dq = res;
+ kernel_dr = res * res;
+ for (r = minr; r <= maxr; ++r) {
+ for (q = minq; q <= maxq; ++q) {
+ for (p = minp; p <= maxp; ++p) {
+
+ madd_v3_v3fl(vel_smooth, verts[kernel_offset].velocity, invD);
+
+ kernel_offset += 1;
+ }
+ kernel_offset += kernel_dq;
+ }
+ kernel_offset += kernel_dr;
+ }
+}
+
+void BPH_hair_volume_vertex_grid_filter_box(HairVertexGrid *grid, int kernel_size)
+{
+ int size = hair_grid_size(grid->res);
+ int kernel_sizev[3] = {kernel_size, kernel_size, kernel_size};
+ int tot;
+ float invD;
+ int i, j, k;
+
+ if (kernel_size <= 0)
+ return;
+
+ tot = kernel_size * 2 + 1;
+ invD = 1.0f / (float)(tot*tot*tot);
+
+ /* clear values for convolution */
+ for (i = 0; i < size; ++i) {
+ zero_v3(grid->verts[i].velocity_smooth);
+ }
+
+ for (i = 0; i < grid->res; ++i) {
+ for (j = 0; j < grid->res; ++j) {
+ for (k = 0; k < grid->res; ++k) {
+ hair_volume_filter_box_convolute(grid, invD, kernel_sizev, i, j, k);
+ }
+ }
+ }
+
+ /* apply as new velocity */
+ for (i = 0; i < size; ++i) {
+ copy_v3_v3(grid->verts[i].velocity, grid->verts[i].velocity_smooth);
+ }
+}
+#endif
+
+HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, const float gmin[3], const float gmax[3])
+{
+ float scale;
+ float extent[3];
+ int resmin[3], resmax[3], res[3];
+ float gmin_margin[3], gmax_margin[3];
+ int size;
+ HairGrid *grid;
+ int i;
+
+ /* sanity check */
+ if (cellsize <= 0.0f)
+ cellsize = 1.0f;
+ scale = 1.0f / cellsize;
+
+ sub_v3_v3v3(extent, gmax, gmin);
+ for (i = 0; i < 3; ++i) {
+ resmin[i] = floor_int(gmin[i] * scale);
+ resmax[i] = floor_int(gmax[i] * scale) + 1;
+
+ /* add margin of 1 cell */
+ resmin[i] -= 1;
+ resmax[i] += 1;
+
+ res[i] = resmax[i] - resmin[i] + 1;
+ /* sanity check: avoid null-sized grid */
+ if (res[i] < 4) {
+ res[i] = 4;
+ resmax[i] = resmin[i] + 4;
+ }
+ /* sanity check: avoid too large grid size */
+ if (res[i] > MAX_HAIR_GRID_RES) {
+ res[i] = MAX_HAIR_GRID_RES;
+ resmax[i] = resmin[i] + MAX_HAIR_GRID_RES;
+ }
+
+ gmin_margin[i] = (float)resmin[i] * cellsize;
+ gmax_margin[i] = (float)resmax[i] * cellsize;
+ }
+ size = hair_grid_size(res);
+
+ grid = (HairGrid *)MEM_callocN(sizeof(HairGrid), "hair grid");
+ grid->res[0] = res[0];
+ grid->res[1] = res[1];
+ grid->res[2] = res[2];
+ copy_v3_v3(grid->gmin, gmin_margin);
+ copy_v3_v3(grid->gmax, gmax_margin);
+ grid->cellsize = cellsize;
+ grid->inv_cellsize = scale;
+ grid->verts = (HairGridVert *)MEM_callocN(sizeof(HairGridVert) * size, "hair voxel data");
+
+ return grid;
+}
+
+void BPH_hair_volume_free_vertex_grid(HairGrid *grid)
+{
+ if (grid) {
+ if (grid->verts)
+ MEM_freeN(grid->verts);
+ MEM_freeN(grid);
+ }
+}
+
+void BPH_hair_volume_grid_geometry(HairGrid *grid, float *cellsize, int res[3], float gmin[3], float gmax[3])
+{
+ if (cellsize) *cellsize = grid->cellsize;
+ if (res) copy_v3_v3_int(res, grid->res);
+ if (gmin) copy_v3_v3(gmin, grid->gmin);
+ if (gmax) copy_v3_v3(gmax, grid->gmax);
+}
+
+#if 0
+static HairGridVert *hair_volume_create_collision_grid(ClothModifierData *clmd, lfVector *lX, unsigned int numverts)
+{
+ int res = hair_grid_res;
+ int size = hair_grid_size(res);
+ HairGridVert *collgrid;
+ ListBase *colliders;
+ ColliderCache *col = NULL;
+ float gmin[3], gmax[3], scale[3];
+ /* 2.0f is an experimental value that seems to give good results */
+ float collfac = 2.0f * clmd->sim_parms->collider_friction;
+ unsigned int v = 0;
+ int i = 0;
+
+ hair_volume_get_boundbox(lX, numverts, gmin, gmax);
+ hair_grid_get_scale(res, gmin, gmax, scale);
+
+ collgrid = MEM_mallocN(sizeof(HairGridVert) * size, "hair collider voxel data");
+
+ /* initialize grid */
+ for (i = 0; i < size; ++i) {
+ zero_v3(collgrid[i].velocity);
+ collgrid[i].density = 0.0f;
+ }
+
+ /* gather colliders */
+ colliders = get_collider_cache(clmd->scene, NULL, NULL);
+ if (colliders && collfac > 0.0f) {
+ for (col = colliders->first; col; col = col->next) {
+ MVert *loc0 = col->collmd->x;
+ MVert *loc1 = col->collmd->xnew;
+ float vel[3];
+ float weights[8];
+ int di, dj, dk;
+
+ for (v=0; v < col->collmd->numverts; v++, loc0++, loc1++) {
+ int offset;
+
+ if (!hair_grid_point_valid(loc1->co, gmin, gmax))
+ continue;
+
+ offset = hair_grid_weights(res, gmin, scale, lX[v], weights);
+
+ sub_v3_v3v3(vel, loc1->co, loc0->co);
+
+ for (di = 0; di < 2; ++di) {
+ for (dj = 0; dj < 2; ++dj) {
+ for (dk = 0; dk < 2; ++dk) {
+ int voffset = offset + di + (dj + dk*res)*res;
+ int iw = di + dj*2 + dk*4;
+
+ collgrid[voffset].density += weights[iw];
+ madd_v3_v3fl(collgrid[voffset].velocity, vel, weights[iw]);
+ }
+ }
+ }
+ }
+ }
+ }
+ free_collider_cache(&colliders);
+
+ /* divide velocity with density */
+ for (i = 0; i < size; i++) {
+ float density = collgrid[i].density;
+ if (density > 0.0f)
+ mul_v3_fl(collgrid[i].velocity, 1.0f/density);
+ }
+
+ return collgrid;
+}
+#endif
+
+bool BPH_hair_volume_get_texture_data(HairGrid *grid, VoxelData *vd)
+{
+ int totres, i;
+ int depth;
+
+ vd->resol[0] = grid->res[0];
+ vd->resol[1] = grid->res[1];
+ vd->resol[2] = grid->res[2];
+
+ totres = hair_grid_size(grid->res);
+
+ if (vd->hair_type == TEX_VD_HAIRVELOCITY) {
+ depth = 4;
+ vd->data_type = TEX_VD_RGBA_PREMUL;
+ }
+ else {
+ depth = 1;
+ vd->data_type = TEX_VD_INTENSITY;
+ }
+
+ if (totres > 0) {
+ vd->dataset = (float *)MEM_mapallocN(sizeof(float) * depth * (totres), "hair volume texture data");
+
+ for (i = 0; i < totres; ++i) {
+ switch (vd->hair_type) {
+ case TEX_VD_HAIRDENSITY:
+ vd->dataset[i] = grid->verts[i].density;
+ break;
+
+ case TEX_VD_HAIRRESTDENSITY:
+ vd->dataset[i] = 0.0f; // TODO
+ break;
+
+ case TEX_VD_HAIRVELOCITY: {
+ vd->dataset[i + 0*totres] = grid->verts[i].velocity[0];
+ vd->dataset[i + 1*totres] = grid->verts[i].velocity[1];
+ vd->dataset[i + 2*totres] = grid->verts[i].velocity[2];
+ vd->dataset[i + 3*totres] = len_v3(grid->verts[i].velocity);
+ break;
+ }
+ case TEX_VD_HAIRENERGY:
+ vd->dataset[i] = 0.0f; // TODO
+ break;
+ }
+ }
+ }
+ else {
+ vd->dataset = NULL;
+ }
+
+ return true;
+}
diff --git a/source/blender/physics/intern/implicit.h b/source/blender/physics/intern/implicit.h
new file mode 100644
index 00000000000..7ded479f578
--- /dev/null
+++ b/source/blender/physics/intern/implicit.h
@@ -0,0 +1,184 @@
+/*
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __IMPLICIT_H__
+#define __IMPLICIT_H__
+
+/** \file implicit.h
+ * \ingroup bph
+ */
+
+#include "stdio.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_collision.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define IMPLICIT_SOLVER_EIGEN
+#define IMPLICIT_SOLVER_BLENDER
+
+#define CLOTH_ROOT_FRAME /* enable use of root frame coordinate transform */
+
+#define CLOTH_FORCE_GRAVITY
+#define CLOTH_FORCE_DRAG
+#define CLOTH_FORCE_SPRING_STRUCTURAL
+#define CLOTH_FORCE_SPRING_BEND
+#define CLOTH_FORCE_SPRING_GOAL
+#define CLOTH_FORCE_EFFECTORS
+
+//#define IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
+
+//#define IMPLICIT_ENABLE_EIGEN_DEBUG
+
+struct Implicit_Data;
+struct ImplicitSolverInput;
+
+typedef struct ImplicitSolverResult {
+ int status;
+
+ int iterations;
+ float error;
+} ImplicitSolverResult;
+
+BLI_INLINE void implicit_print_matrix_elem(float v)
+{
+ printf("%-8.3f", v);
+}
+
+void BPH_mass_spring_set_vertex_mass(struct Implicit_Data *data, int index, float mass);
+void BPH_mass_spring_set_rest_transform(struct Implicit_Data *data, int index, float rot[3][3]);
+
+void BPH_mass_spring_set_motion_state(struct Implicit_Data *data, int index, const float x[3], const float v[3]);
+void BPH_mass_spring_set_position(struct Implicit_Data *data, int index, const float x[3]);
+void BPH_mass_spring_set_velocity(struct Implicit_Data *data, int index, const float v[3]);
+void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, int index, float x[3], float v[3]);
+void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3]);
+
+/* modified velocity during solver step */
+void BPH_mass_spring_get_new_velocity(struct Implicit_Data *data, int index, float v[3]);
+void BPH_mass_spring_set_new_velocity(struct Implicit_Data *data, int index, const float v[3]);
+
+void BPH_mass_spring_clear_constraints(struct Implicit_Data *data);
+void BPH_mass_spring_add_constraint_ndof0(struct Implicit_Data *data, int index, const float dV[3]);
+void BPH_mass_spring_add_constraint_ndof1(struct Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3]);
+void BPH_mass_spring_add_constraint_ndof2(struct Implicit_Data *data, int index, const float c1[3], const float dV[3]);
+
+bool BPH_mass_spring_solve_velocities(struct Implicit_Data *data, float dt, struct ImplicitSolverResult *result);
+bool BPH_mass_spring_solve_positions(struct Implicit_Data *data, float dt);
+void BPH_mass_spring_apply_result(struct Implicit_Data *data);
+
+/* Clear the force vector at the beginning of the time step */
+void BPH_mass_spring_clear_forces(struct Implicit_Data *data);
+/* Fictitious forces introduced by moving coordinate systems */
+void BPH_mass_spring_force_reference_frame(struct Implicit_Data *data, int index, const float acceleration[3], const float omega[3], const float domega_dt[3], float mass);
+/* Simple uniform gravity force */
+void BPH_mass_spring_force_gravity(struct Implicit_Data *data, int index, float mass, const float g[3]);
+/* Global drag force (velocity damping) */
+void BPH_mass_spring_force_drag(struct Implicit_Data *data, float drag);
+/* Custom external force */
+void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3]);
+/* Wind force, acting on a face */
+void BPH_mass_spring_force_face_wind(struct Implicit_Data *data, int v1, int v2, int v3, int v4, const float (*winvec)[3]);
+/* Wind force, acting on an edge */
+void BPH_mass_spring_force_edge_wind(struct Implicit_Data *data, int v1, int v2, float radius1, float radius2, const float (*winvec)[3]);
+/* Wind force, acting on a vertex */
+void BPH_mass_spring_force_vertex_wind(struct Implicit_Data *data, int v, float radius, const float (*winvec)[3]);
+/* Linear spring force between two points */
+bool BPH_mass_spring_force_spring_linear(struct Implicit_Data *data, int i, int j, float restlen,
+ float stiffness, float damping, bool no_compress, float clamp_force,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+/* Bending force, forming a triangle at the base of two structural springs */
+bool BPH_mass_spring_force_spring_bending(struct Implicit_Data *data, int i, int j, float restlen,
+ float kb, float cb,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+/* Angular bending force based on local target vectors */
+bool BPH_mass_spring_force_spring_bending_angular(struct Implicit_Data *data, int i, int j, int k,
+ const float target[3], float stiffness, float damping);
+/* Global goal spring */
+bool BPH_mass_spring_force_spring_goal(struct Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
+ float stiffness, float damping,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3]);
+
+/* ======== Hair Volumetric Forces ======== */
+
+struct HairGrid;
+
+struct Object;
+struct VoxelData;
+
+#define MAX_HAIR_GRID_RES 256
+
+struct HairGrid *BPH_hair_volume_create_vertex_grid(float cellsize, const float gmin[3], const float gmax[3]);
+void BPH_hair_volume_free_vertex_grid(struct HairGrid *grid);
+void BPH_hair_volume_grid_geometry(struct HairGrid *grid, float *cellsize, int res[3], float gmin[3], float gmax[3]);
+
+void BPH_hair_volume_grid_clear(struct HairGrid *grid);
+void BPH_hair_volume_add_vertex(struct HairGrid *grid, const float x[3], const float v[3]);
+void BPH_hair_volume_add_segment(struct HairGrid *grid,
+ const float x1[3], const float v1[3], const float x2[3], const float v2[3],
+ const float x3[3], const float v3[3], const float x4[3], const float v4[3],
+ const float dir1[3], const float dir2[3], const float dir3[3]);
+
+void BPH_hair_volume_normalize_vertex_grid(struct HairGrid *grid);
+
+bool BPH_hair_volume_solve_divergence(struct HairGrid *grid, float dt, float target_density, float target_strength);
+#if 0 /* XXX weighting is incorrect, disabled for now */
+void BPH_hair_volume_vertex_grid_filter_box(struct HairVertexGrid *grid, int kernel_size);
+#endif
+
+void BPH_hair_volume_grid_interpolate(struct HairGrid *grid, const float x[3],
+ float *density, float velocity[3], float velocity_smooth[3],
+ float density_gradient[3], float velocity_gradient[3][3]);
+
+/* Effect of fluid simulation grid on velocities.
+ * fluid_factor controls blending between PIC (Particle-in-Cell)
+ * and FLIP (Fluid-Implicit-Particle) methods (0 = only PIC, 1 = only FLIP)
+ */
+void BPH_hair_volume_grid_velocity(struct HairGrid *grid, const float x[3], const float v[3],
+ float fluid_factor,
+ float r_v[3]);
+/* XXX Warning: expressing grid effects on velocity as a force is not very stable,
+ * due to discontinuities in interpolated values!
+ * Better use hybrid approaches such as described in
+ * "Detail Preserving Continuum Simulation of Straight Hair"
+ * (McAdams, Selle 2009)
+ */
+void BPH_hair_volume_vertex_grid_forces(struct HairGrid *grid, const float x[3], const float v[3],
+ float smoothfac, float pressurefac, float minpressure,
+ float f[3], float dfdx[3][3], float dfdv[3][3]);
+
+bool BPH_hair_volume_get_texture_data(struct HairGrid *grid, struct VoxelData *vd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/source/blender/physics/intern/implicit_blender.c b/source/blender/physics/intern/implicit_blender.c
new file mode 100644
index 00000000000..e6ba55ab605
--- /dev/null
+++ b/source/blender/physics/intern/implicit_blender.c
@@ -0,0 +1,2031 @@
+/*
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/physics/intern/implicit_blender.c
+ * \ingroup bph
+ */
+
+#include "implicit.h"
+
+#ifdef IMPLICIT_SOLVER_BLENDER
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_math.h"
+#include "BLI_linklist.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_cloth.h"
+#include "BKE_collision.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+
+#include "BPH_mass_spring.h"
+
+#ifdef __GNUC__
+# pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
+
+#ifdef _OPENMP
+# define CLOTH_OPENMP_LIMIT 512
+#endif
+
+#if 0 /* debug timing */
+#ifdef _WIN32
+#include <windows.h>
+static LARGE_INTEGER _itstart, _itend;
+static LARGE_INTEGER ifreq;
+static void itstart(void)
+{
+ static int first = 1;
+ if (first) {
+ QueryPerformanceFrequency(&ifreq);
+ first = 0;
+ }
+ QueryPerformanceCounter(&_itstart);
+}
+static void itend(void)
+{
+ QueryPerformanceCounter(&_itend);
+}
+double itval(void)
+{
+ return ((double)_itend.QuadPart -
+ (double)_itstart.QuadPart)/((double)ifreq.QuadPart);
+}
+#else
+#include <sys/time.h>
+// intrinsics need better compile flag checking
+// #include <xmmintrin.h>
+// #include <pmmintrin.h>
+// #include <pthread.h>
+
+static struct timeval _itstart, _itend;
+static struct timezone itz;
+static void itstart(void)
+{
+ gettimeofday(&_itstart, &itz);
+}
+static void itend(void)
+{
+ gettimeofday(&_itend, &itz);
+}
+static double itval(void)
+{
+ double t1, t2;
+ t1 = (double)_itstart.tv_sec + (double)_itstart.tv_usec/(1000*1000);
+ t2 = (double)_itend.tv_sec + (double)_itend.tv_usec/(1000*1000);
+ return t2-t1;
+}
+#endif
+#endif /* debug timing */
+
+static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+static float ZERO[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
+
+/*
+#define C99
+#ifdef C99
+#defineDO_INLINE inline
+#else
+#defineDO_INLINE static
+#endif
+*/
+struct Cloth;
+
+//////////////////////////////////////////
+/* fast vector / matrix library, enhancements are welcome :) -dg */
+/////////////////////////////////////////
+
+/* DEFINITIONS */
+typedef float lfVector[3];
+typedef struct fmatrix3x3 {
+ float m[3][3]; /* 3x3 matrix */
+ unsigned int c, r; /* column and row number */
+ /* int pinned; // is this vertex allowed to move? */
+ float n1, n2, n3; /* three normal vectors for collision constrains */
+ unsigned int vcount; /* vertex count */
+ unsigned int scount; /* spring count */
+} fmatrix3x3;
+
+///////////////////////////
+// float[3] vector
+///////////////////////////
+/* simple vector code */
+/* STATUS: verified */
+DO_INLINE void mul_fvector_S(float to[3], float from[3], float scalar)
+{
+ to[0] = from[0] * scalar;
+ to[1] = from[1] * scalar;
+ to[2] = from[2] * scalar;
+}
+/* simple v^T * v product ("outer product") */
+/* STATUS: HAS TO BE verified (*should* work) */
+DO_INLINE void mul_fvectorT_fvector(float to[3][3], float vectorA[3], float vectorB[3])
+{
+ mul_fvector_S(to[0], vectorB, vectorA[0]);
+ mul_fvector_S(to[1], vectorB, vectorA[1]);
+ mul_fvector_S(to[2], vectorB, vectorA[2]);
+}
+/* simple v^T * v product with scalar ("outer product") */
+/* STATUS: HAS TO BE verified (*should* work) */
+DO_INLINE void mul_fvectorT_fvectorS(float to[3][3], float vectorA[3], float vectorB[3], float aS)
+{
+ mul_fvectorT_fvector(to, vectorA, vectorB);
+
+ mul_fvector_S(to[0], to[0], aS);
+ mul_fvector_S(to[1], to[1], aS);
+ mul_fvector_S(to[2], to[2], aS);
+}
+
+#if 0
+/* printf vector[3] on console: for debug output */
+static void print_fvector(float m3[3])
+{
+ printf("%f\n%f\n%f\n\n", m3[0], m3[1], m3[2]);
+}
+
+///////////////////////////
+// long float vector float (*)[3]
+///////////////////////////
+/* print long vector on console: for debug output */
+DO_INLINE void print_lfvector(float (*fLongVector)[3], unsigned int verts)
+{
+ unsigned int i = 0;
+ for (i = 0; i < verts; i++) {
+ print_fvector(fLongVector[i]);
+ }
+}
+#endif
+
+/* create long vector */
+DO_INLINE lfVector *create_lfvector(unsigned int verts)
+{
+ /* TODO: check if memory allocation was successful */
+ return (lfVector *)MEM_callocN(verts * sizeof(lfVector), "cloth_implicit_alloc_vector");
+ // return (lfVector *)cloth_aligned_malloc(&MEMORY_BASE, verts * sizeof(lfVector));
+}
+/* delete long vector */
+DO_INLINE void del_lfvector(float (*fLongVector)[3])
+{
+ if (fLongVector != NULL) {
+ MEM_freeN(fLongVector);
+ // cloth_aligned_free(&MEMORY_BASE, fLongVector);
+ }
+}
+/* copy long vector */
+DO_INLINE void cp_lfvector(float (*to)[3], float (*from)[3], unsigned int verts)
+{
+ memcpy(to, from, verts * sizeof(lfVector));
+}
+/* init long vector with float[3] */
+DO_INLINE void init_lfvector(float (*fLongVector)[3], float vector[3], unsigned int verts)
+{
+ unsigned int i = 0;
+ for (i = 0; i < verts; i++) {
+ copy_v3_v3(fLongVector[i], vector);
+ }
+}
+/* zero long vector with float[3] */
+DO_INLINE void zero_lfvector(float (*to)[3], unsigned int verts)
+{
+ memset(to, 0.0f, verts * sizeof(lfVector));
+}
+/* multiply long vector with scalar*/
+DO_INLINE void mul_lfvectorS(float (*to)[3], float (*fLongVector)[3], float scalar, unsigned int verts)
+{
+ unsigned int i = 0;
+
+ for (i = 0; i < verts; i++) {
+ mul_fvector_S(to[i], fLongVector[i], scalar);
+ }
+}
+/* multiply long vector with scalar*/
+/* A -= B * float */
+DO_INLINE void submul_lfvectorS(float (*to)[3], float (*fLongVector)[3], float scalar, unsigned int verts)
+{
+ unsigned int i = 0;
+ for (i = 0; i < verts; i++) {
+ VECSUBMUL(to[i], fLongVector[i], scalar);
+ }
+}
+/* dot product for big vector */
+DO_INLINE float dot_lfvector(float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts)
+{
+ long i = 0;
+ float temp = 0.0;
+// XXX brecht, disabled this for now (first schedule line was already disabled),
+// due to non-commutative nature of floating point ops this makes the sim give
+// different results each time you run it!
+// schedule(guided, 2)
+//#pragma omp parallel for reduction(+: temp) if (verts > CLOTH_OPENMP_LIMIT)
+ for (i = 0; i < (long)verts; i++) {
+ temp += dot_v3v3(fLongVectorA[i], fLongVectorB[i]);
+ }
+ return temp;
+}
+/* A = B + C --> for big vector */
+DO_INLINE void add_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts)
+{
+ unsigned int i = 0;
+
+ for (i = 0; i < verts; i++) {
+ VECADD(to[i], fLongVectorA[i], fLongVectorB[i]);
+ }
+
+}
+/* A = B + C * float --> for big vector */
+DO_INLINE void add_lfvector_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], float bS, unsigned int verts)
+{
+ unsigned int i = 0;
+
+ for (i = 0; i < verts; i++) {
+ VECADDS(to[i], fLongVectorA[i], fLongVectorB[i], bS);
+
+ }
+}
+/* A = B * float + C * float --> for big vector */
+DO_INLINE void add_lfvectorS_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float aS, float (*fLongVectorB)[3], float bS, unsigned int verts)
+{
+ unsigned int i = 0;
+
+ for (i = 0; i < verts; i++) {
+ VECADDSS(to[i], fLongVectorA[i], aS, fLongVectorB[i], bS);
+ }
+}
+/* A = B - C * float --> for big vector */
+DO_INLINE void sub_lfvector_lfvectorS(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], float bS, unsigned int verts)
+{
+ unsigned int i = 0;
+ for (i = 0; i < verts; i++) {
+ VECSUBS(to[i], fLongVectorA[i], fLongVectorB[i], bS);
+ }
+
+}
+/* A = B - C --> for big vector */
+DO_INLINE void sub_lfvector_lfvector(float (*to)[3], float (*fLongVectorA)[3], float (*fLongVectorB)[3], unsigned int verts)
+{
+ unsigned int i = 0;
+
+ for (i = 0; i < verts; i++) {
+ sub_v3_v3v3(to[i], fLongVectorA[i], fLongVectorB[i]);
+ }
+
+}
+///////////////////////////
+// 3x3 matrix
+///////////////////////////
+#if 0
+/* printf 3x3 matrix on console: for debug output */
+static void print_fmatrix(float m3[3][3])
+{
+ printf("%f\t%f\t%f\n", m3[0][0], m3[0][1], m3[0][2]);
+ printf("%f\t%f\t%f\n", m3[1][0], m3[1][1], m3[1][2]);
+ printf("%f\t%f\t%f\n\n", m3[2][0], m3[2][1], m3[2][2]);
+}
+
+static void print_sparse_matrix(fmatrix3x3 *m)
+{
+ if (m) {
+ unsigned int i;
+ for (i = 0; i < m[0].vcount + m[0].scount; i++) {
+ printf("%d:\n", i);
+ print_fmatrix(m[i].m);
+ }
+ }
+}
+#endif
+
+#if 0
+static void print_lvector(lfVector *v, int numverts)
+{
+ int i;
+ for (i = 0; i < numverts; ++i) {
+ if (i > 0)
+ printf("\n");
+
+ printf("%f,\n", v[i][0]);
+ printf("%f,\n", v[i][1]);
+ printf("%f,\n", v[i][2]);
+ }
+}
+#endif
+
+#if 0
+static void print_bfmatrix(fmatrix3x3 *m)
+{
+ int tot = m[0].vcount + m[0].scount;
+ int size = m[0].vcount * 3;
+ float *t = MEM_callocN(sizeof(float) * size*size, "bfmatrix");
+ int q, i, j;
+
+ for (q = 0; q < tot; ++q) {
+ int k = 3 * m[q].r;
+ int l = 3 * m[q].c;
+
+ for (j = 0; j < 3; ++j) {
+ for (i = 0; i < 3; ++i) {
+// if (t[k + i + (l + j) * size] != 0.0f) {
+// printf("warning: overwriting value at %d, %d\n", m[q].r, m[q].c);
+// }
+ if (k == l) {
+ t[k + i + (k + j) * size] += m[q].m[i][j];
+ }
+ else {
+ t[k + i + (l + j) * size] += m[q].m[i][j];
+ t[l + j + (k + i) * size] += m[q].m[j][i];
+ }
+ }
+ }
+ }
+
+ for (j = 0; j < size; ++j) {
+ if (j > 0 && j % 3 == 0)
+ printf("\n");
+
+ for (i = 0; i < size; ++i) {
+ if (i > 0 && i % 3 == 0)
+ printf(" ");
+
+ implicit_print_matrix_elem(t[i + j * size]);
+ }
+ printf("\n");
+ }
+
+ MEM_freeN(t);
+}
+#endif
+
+/* copy 3x3 matrix */
+DO_INLINE void cp_fmatrix(float to[3][3], float from[3][3])
+{
+ // memcpy(to, from, sizeof (float) * 9);
+ copy_v3_v3(to[0], from[0]);
+ copy_v3_v3(to[1], from[1]);
+ copy_v3_v3(to[2], from[2]);
+}
+
+/* copy 3x3 matrix */
+DO_INLINE void initdiag_fmatrixS(float to[3][3], float aS)
+{
+ cp_fmatrix(to, ZERO);
+
+ to[0][0] = aS;
+ to[1][1] = aS;
+ to[2][2] = aS;
+}
+
+#if 0
+/* calculate determinant of 3x3 matrix */
+DO_INLINE float det_fmatrix(float m[3][3])
+{
+ return m[0][0]*m[1][1]*m[2][2] + m[1][0]*m[2][1]*m[0][2] + m[0][1]*m[1][2]*m[2][0] -
+ m[0][0]*m[1][2]*m[2][1] - m[0][1]*m[1][0]*m[2][2] - m[2][0]*m[1][1]*m[0][2];
+}
+
+DO_INLINE void inverse_fmatrix(float to[3][3], float from[3][3])
+{
+ unsigned int i, j;
+ float d;
+
+ if ((d=det_fmatrix(from)) == 0) {
+ printf("can't build inverse");
+ exit(0);
+ }
+ for (i=0;i<3;i++) {
+ for (j=0;j<3;j++) {
+ int i1=(i+1)%3;
+ int i2=(i+2)%3;
+ int j1=(j+1)%3;
+ int j2=(j+2)%3;
+ // reverse indexs i&j to take transpose
+ to[j][i] = (from[i1][j1]*from[i2][j2]-from[i1][j2]*from[i2][j1])/d;
+ /*
+ if (i==j)
+ to[i][j] = 1.0f / from[i][j];
+ else
+ to[i][j] = 0;
+ */
+ }
+ }
+
+}
+#endif
+
+/* 3x3 matrix multiplied by a scalar */
+/* STATUS: verified */
+DO_INLINE void mul_fmatrix_S(float matrix[3][3], float scalar)
+{
+ mul_fvector_S(matrix[0], matrix[0], scalar);
+ mul_fvector_S(matrix[1], matrix[1], scalar);
+ mul_fvector_S(matrix[2], matrix[2], scalar);
+}
+
+/* a vector multiplied by a 3x3 matrix */
+/* STATUS: verified */
+DO_INLINE void mul_fvector_fmatrix(float *to, float *from, float matrix[3][3])
+{
+ to[0] = matrix[0][0]*from[0] + matrix[1][0]*from[1] + matrix[2][0]*from[2];
+ to[1] = matrix[0][1]*from[0] + matrix[1][1]*from[1] + matrix[2][1]*from[2];
+ to[2] = matrix[0][2]*from[0] + matrix[1][2]*from[1] + matrix[2][2]*from[2];
+}
+
+/* 3x3 matrix multiplied by a vector */
+/* STATUS: verified */
+DO_INLINE void mul_fmatrix_fvector(float *to, float matrix[3][3], float from[3])
+{
+ to[0] = dot_v3v3(matrix[0], from);
+ to[1] = dot_v3v3(matrix[1], from);
+ to[2] = dot_v3v3(matrix[2], from);
+}
+/* 3x3 matrix addition with 3x3 matrix */
+DO_INLINE void add_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
+{
+ VECADD(to[0], matrixA[0], matrixB[0]);
+ VECADD(to[1], matrixA[1], matrixB[1]);
+ VECADD(to[2], matrixA[2], matrixB[2]);
+}
+/* A -= B*x + C*y (3x3 matrix sub-addition with 3x3 matrix) */
+DO_INLINE void subadd_fmatrixS_fmatrixS(float to[3][3], float matrixA[3][3], float aS, float matrixB[3][3], float bS)
+{
+ VECSUBADDSS(to[0], matrixA[0], aS, matrixB[0], bS);
+ VECSUBADDSS(to[1], matrixA[1], aS, matrixB[1], bS);
+ VECSUBADDSS(to[2], matrixA[2], aS, matrixB[2], bS);
+}
+/* A = B - C (3x3 matrix subtraction with 3x3 matrix) */
+DO_INLINE void sub_fmatrix_fmatrix(float to[3][3], float matrixA[3][3], float matrixB[3][3])
+{
+ sub_v3_v3v3(to[0], matrixA[0], matrixB[0]);
+ sub_v3_v3v3(to[1], matrixA[1], matrixB[1]);
+ sub_v3_v3v3(to[2], matrixA[2], matrixB[2]);
+}
+/////////////////////////////////////////////////////////////////
+// special functions
+/////////////////////////////////////////////////////////////////
+/* 3x3 matrix multiplied+added by a vector */
+/* STATUS: verified */
+DO_INLINE void muladd_fmatrix_fvector(float to[3], float matrix[3][3], float from[3])
+{
+ to[0] += dot_v3v3(matrix[0], from);
+ to[1] += dot_v3v3(matrix[1], from);
+ to[2] += dot_v3v3(matrix[2], from);
+}
+
+BLI_INLINE void outerproduct(float r[3][3], const float a[3], const float b[3])
+{
+ mul_v3_v3fl(r[0], a, b[0]);
+ mul_v3_v3fl(r[1], a, b[1]);
+ mul_v3_v3fl(r[2], a, b[2]);
+}
+
+BLI_INLINE void cross_m3_v3m3(float r[3][3], const float v[3], float m[3][3])
+{
+ cross_v3_v3v3(r[0], v, m[0]);
+ cross_v3_v3v3(r[1], v, m[1]);
+ cross_v3_v3v3(r[2], v, m[2]);
+}
+
+BLI_INLINE void cross_v3_identity(float r[3][3], const float v[3])
+{
+ r[0][0] = 0.0f; r[1][0] = v[2]; r[2][0] = -v[1];
+ r[0][1] = -v[2]; r[1][1] = 0.0f; r[2][1] = v[0];
+ r[0][2] = v[1]; r[1][2] = -v[0]; r[2][2] = 0.0f;
+}
+
+BLI_INLINE void madd_m3_m3fl(float r[3][3], float m[3][3], float f)
+{
+ r[0][0] += m[0][0] * f;
+ r[0][1] += m[0][1] * f;
+ r[0][2] += m[0][2] * f;
+ r[1][0] += m[1][0] * f;
+ r[1][1] += m[1][1] * f;
+ r[1][2] += m[1][2] * f;
+ r[2][0] += m[2][0] * f;
+ r[2][1] += m[2][1] * f;
+ r[2][2] += m[2][2] * f;
+}
+
+BLI_INLINE void madd_m3_m3m3fl(float r[3][3], float a[3][3], float b[3][3], float f)
+{
+ r[0][0] = a[0][0] + b[0][0] * f;
+ r[0][1] = a[0][1] + b[0][1] * f;
+ r[0][2] = a[0][2] + b[0][2] * f;
+ r[1][0] = a[1][0] + b[1][0] * f;
+ r[1][1] = a[1][1] + b[1][1] * f;
+ r[1][2] = a[1][2] + b[1][2] * f;
+ r[2][0] = a[2][0] + b[2][0] * f;
+ r[2][1] = a[2][1] + b[2][1] * f;
+ r[2][2] = a[2][2] + b[2][2] * f;
+}
+/////////////////////////////////////////////////////////////////
+
+///////////////////////////
+// SPARSE SYMMETRIC big matrix with 3x3 matrix entries
+///////////////////////////
+/* printf a big matrix on console: for debug output */
+#if 0
+static void print_bfmatrix(fmatrix3x3 *m3)
+{
+ unsigned int i = 0;
+
+ for (i = 0; i < m3[0].vcount + m3[0].scount; i++)
+ {
+ print_fmatrix(m3[i].m);
+ }
+}
+#endif
+
+BLI_INLINE void init_fmatrix(fmatrix3x3 *matrix, int r, int c)
+{
+ matrix->r = r;
+ matrix->c = c;
+}
+
+/* create big matrix */
+DO_INLINE fmatrix3x3 *create_bfmatrix(unsigned int verts, unsigned int springs)
+{
+ // TODO: check if memory allocation was successful */
+ fmatrix3x3 *temp = (fmatrix3x3 *)MEM_callocN(sizeof(fmatrix3x3) * (verts + springs), "cloth_implicit_alloc_matrix");
+ int i;
+
+ temp[0].vcount = verts;
+ temp[0].scount = springs;
+
+ /* vertex part of the matrix is diagonal blocks */
+ for (i = 0; i < verts; ++i) {
+ init_fmatrix(temp + i, i, i);
+ }
+
+ return temp;
+}
+/* delete big matrix */
+DO_INLINE void del_bfmatrix(fmatrix3x3 *matrix)
+{
+ if (matrix != NULL) {
+ MEM_freeN(matrix);
+ }
+}
+
+/* copy big matrix */
+DO_INLINE void cp_bfmatrix(fmatrix3x3 *to, fmatrix3x3 *from)
+{
+ // TODO bounds checking
+ memcpy(to, from, sizeof(fmatrix3x3) * (from[0].vcount+from[0].scount));
+}
+
+/* init big matrix */
+// slow in parallel
+DO_INLINE void init_bfmatrix(fmatrix3x3 *matrix, float m3[3][3])
+{
+ unsigned int i;
+
+ for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
+ cp_fmatrix(matrix[i].m, m3);
+ }
+}
+
+/* init the diagonal of big matrix */
+// slow in parallel
+DO_INLINE void initdiag_bfmatrix(fmatrix3x3 *matrix, float m3[3][3])
+{
+ unsigned int i, j;
+ float tmatrix[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
+
+ for (i = 0; i < matrix[0].vcount; i++) {
+ cp_fmatrix(matrix[i].m, m3);
+ }
+ for (j = matrix[0].vcount; j < matrix[0].vcount+matrix[0].scount; j++) {
+ cp_fmatrix(matrix[j].m, tmatrix);
+ }
+}
+
+/* SPARSE SYMMETRIC multiply big matrix with long vector*/
+/* STATUS: verified */
+DO_INLINE void mul_bfmatrix_lfvector( float (*to)[3], fmatrix3x3 *from, lfVector *fLongVector)
+{
+ unsigned int i = 0;
+ unsigned int vcount = from[0].vcount;
+ lfVector *temp = create_lfvector(vcount);
+
+ zero_lfvector(to, vcount);
+
+#pragma omp parallel sections private(i) if (vcount > CLOTH_OPENMP_LIMIT)
+ {
+#pragma omp section
+ {
+ for (i = from[0].vcount; i < from[0].vcount+from[0].scount; i++) {
+ muladd_fmatrix_fvector(to[from[i].c], from[i].m, fLongVector[from[i].r]);
+ }
+ }
+#pragma omp section
+ {
+ for (i = 0; i < from[0].vcount+from[0].scount; i++) {
+ muladd_fmatrix_fvector(temp[from[i].r], from[i].m, fLongVector[from[i].c]);
+ }
+ }
+ }
+ add_lfvector_lfvector(to, to, temp, from[0].vcount);
+
+ del_lfvector(temp);
+
+
+}
+
+/* SPARSE SYMMETRIC sub big matrix with big matrix*/
+/* A -= B * float + C * float --> for big matrix */
+/* VERIFIED */
+DO_INLINE void subadd_bfmatrixS_bfmatrixS( fmatrix3x3 *to, fmatrix3x3 *from, float aS, fmatrix3x3 *matrix, float bS)
+{
+ unsigned int i = 0;
+
+ /* process diagonal elements */
+ for (i = 0; i < matrix[0].vcount+matrix[0].scount; i++) {
+ subadd_fmatrixS_fmatrixS(to[i].m, from[i].m, aS, matrix[i].m, bS);
+ }
+
+}
+
+///////////////////////////////////////////////////////////////////
+// simulator start
+///////////////////////////////////////////////////////////////////
+
+typedef struct Implicit_Data {
+ /* inputs */
+ fmatrix3x3 *bigI; /* identity (constant) */
+ fmatrix3x3 *tfm; /* local coordinate transform */
+ fmatrix3x3 *M; /* masses */
+ lfVector *F; /* forces */
+ fmatrix3x3 *dFdV, *dFdX; /* force jacobians */
+ int num_blocks; /* number of off-diagonal blocks (springs) */
+
+ /* motion state data */
+ lfVector *X, *Xnew; /* positions */
+ lfVector *V, *Vnew; /* velocities */
+
+ /* internal solver data */
+ lfVector *B; /* B for A*dV = B */
+ fmatrix3x3 *A; /* A for A*dV = B */
+
+ lfVector *dV; /* velocity change (solution of A*dV = B) */
+ lfVector *z; /* target velocity in constrained directions */
+ fmatrix3x3 *S; /* filtering matrix for constraints */
+ fmatrix3x3 *P, *Pinv; /* pre-conditioning matrix */
+} Implicit_Data;
+
+Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings)
+{
+ Implicit_Data *id = (Implicit_Data *)MEM_callocN(sizeof(Implicit_Data), "implicit vecmat");
+
+ /* process diagonal elements */
+ id->tfm = create_bfmatrix(numverts, 0);
+ id->A = create_bfmatrix(numverts, numsprings);
+ id->dFdV = create_bfmatrix(numverts, numsprings);
+ id->dFdX = create_bfmatrix(numverts, numsprings);
+ id->S = create_bfmatrix(numverts, 0);
+ id->Pinv = create_bfmatrix(numverts, numsprings);
+ id->P = create_bfmatrix(numverts, numsprings);
+ id->bigI = create_bfmatrix(numverts, numsprings); // TODO 0 springs
+ id->M = create_bfmatrix(numverts, numsprings);
+ id->X = create_lfvector(numverts);
+ id->Xnew = create_lfvector(numverts);
+ id->V = create_lfvector(numverts);
+ id->Vnew = create_lfvector(numverts);
+ id->F = create_lfvector(numverts);
+ id->B = create_lfvector(numverts);
+ id->dV = create_lfvector(numverts);
+ id->z = create_lfvector(numverts);
+
+ initdiag_bfmatrix(id->bigI, I);
+
+ return id;
+}
+
+void BPH_mass_spring_solver_free(Implicit_Data *id)
+{
+ del_bfmatrix(id->tfm);
+ del_bfmatrix(id->A);
+ del_bfmatrix(id->dFdV);
+ del_bfmatrix(id->dFdX);
+ del_bfmatrix(id->S);
+ del_bfmatrix(id->P);
+ del_bfmatrix(id->Pinv);
+ del_bfmatrix(id->bigI);
+ del_bfmatrix(id->M);
+
+ del_lfvector(id->X);
+ del_lfvector(id->Xnew);
+ del_lfvector(id->V);
+ del_lfvector(id->Vnew);
+ del_lfvector(id->F);
+ del_lfvector(id->B);
+ del_lfvector(id->dV);
+ del_lfvector(id->z);
+
+ MEM_freeN(id);
+}
+
+/* ==== Transformation from/to root reference frames ==== */
+
+BLI_INLINE void world_to_root_v3(Implicit_Data *data, int index, float r[3], const float v[3])
+{
+ copy_v3_v3(r, v);
+ mul_transposed_m3_v3(data->tfm[index].m, r);
+}
+
+BLI_INLINE void root_to_world_v3(Implicit_Data *data, int index, float r[3], const float v[3])
+{
+ mul_v3_m3v3(r, data->tfm[index].m, v);
+}
+
+BLI_INLINE void world_to_root_m3(Implicit_Data *data, int index, float r[3][3], float m[3][3])
+{
+ float trot[3][3];
+ copy_m3_m3(trot, data->tfm[index].m);
+ transpose_m3(trot);
+ mul_m3_m3m3(r, trot, m);
+}
+
+BLI_INLINE void root_to_world_m3(Implicit_Data *data, int index, float r[3][3], float m[3][3])
+{
+ mul_m3_m3m3(r, data->tfm[index].m, m);
+}
+
+/* ================================ */
+
+DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
+{
+ unsigned int i=0;
+
+ for (i = 0; i < S[0].vcount; i++) {
+ mul_m3_v3(S[i].m, V[S[i].r]);
+ }
+}
+
+#if 0 /* this version of the CG algorithm does not work very well with partial constraints (where S has non-zero elements) */
+static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S)
+{
+ // Solves for unknown X in equation AX=B
+ unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100;
+ float conjgrad_epsilon=0.0001f /* , conjgrad_lasterror=0 */ /* UNUSED */;
+ lfVector *q, *d, *tmp, *r;
+ float s, starget, a, s_prev;
+ unsigned int numverts = lA[0].vcount;
+ q = create_lfvector(numverts);
+ d = create_lfvector(numverts);
+ tmp = create_lfvector(numverts);
+ r = create_lfvector(numverts);
+
+ // zero_lfvector(ldV, CLOTHPARTICLES);
+ filter(ldV, S);
+
+ add_lfvector_lfvector(ldV, ldV, z, numverts);
+
+ // r = B - Mul(tmp, A, X); // just use B if X known to be zero
+ cp_lfvector(r, lB, numverts);
+ mul_bfmatrix_lfvector(tmp, lA, ldV);
+ sub_lfvector_lfvector(r, r, tmp, numverts);
+
+ filter(r, S);
+
+ cp_lfvector(d, r, numverts);
+
+ s = dot_lfvector(r, r, numverts);
+ starget = s * sqrtf(conjgrad_epsilon);
+
+ while (s>starget && conjgrad_loopcount < conjgrad_looplimit) {
+ // Mul(q, A, d); // q = A*d;
+ mul_bfmatrix_lfvector(q, lA, d);
+
+ filter(q, S);
+
+ a = s/dot_lfvector(d, q, numverts);
+
+ // X = X + d*a;
+ add_lfvector_lfvectorS(ldV, ldV, d, a, numverts);
+
+ // r = r - q*a;
+ sub_lfvector_lfvectorS(r, r, q, a, numverts);
+
+ s_prev = s;
+ s = dot_lfvector(r, r, numverts);
+
+ //d = r+d*(s/s_prev);
+ add_lfvector_lfvectorS(d, r, d, (s/s_prev), numverts);
+
+ filter(d, S);
+
+ conjgrad_loopcount++;
+ }
+ /* conjgrad_lasterror = s; */ /* UNUSED */
+
+ del_lfvector(q);
+ del_lfvector(d);
+ del_lfvector(tmp);
+ del_lfvector(r);
+ // printf("W/O conjgrad_loopcount: %d\n", conjgrad_loopcount);
+
+ return conjgrad_loopcount<conjgrad_looplimit; // true means we reached desired accuracy in given time - ie stable
+}
+#endif
+
+static int cg_filtered(lfVector *ldV, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, ImplicitSolverResult *result)
+{
+ // Solves for unknown X in equation AX=B
+ unsigned int conjgrad_loopcount=0, conjgrad_looplimit=100;
+ float conjgrad_epsilon=0.01f;
+
+ unsigned int numverts = lA[0].vcount;
+ lfVector *fB = create_lfvector(numverts);
+ lfVector *AdV = create_lfvector(numverts);
+ lfVector *r = create_lfvector(numverts);
+ lfVector *c = create_lfvector(numverts);
+ lfVector *q = create_lfvector(numverts);
+ lfVector *s = create_lfvector(numverts);
+ float bnorm2, delta_new, delta_old, delta_target, alpha;
+
+ cp_lfvector(ldV, z, numverts);
+
+ /* d0 = filter(B)^T * P * filter(B) */
+ cp_lfvector(fB, lB, numverts);
+ filter(fB, S);
+ bnorm2 = dot_lfvector(fB, fB, numverts);
+ delta_target = conjgrad_epsilon*conjgrad_epsilon * bnorm2;
+
+ /* r = filter(B - A * dV) */
+ mul_bfmatrix_lfvector(AdV, lA, ldV);
+ sub_lfvector_lfvector(r, lB, AdV, numverts);
+ filter(r, S);
+
+ /* c = filter(P^-1 * r) */
+ cp_lfvector(c, r, numverts);
+ filter(c, S);
+
+ /* delta = r^T * c */
+ delta_new = dot_lfvector(r, c, numverts);
+
+#ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
+ printf("==== A ====\n");
+ print_bfmatrix(lA);
+ printf("==== z ====\n");
+ print_lvector(z, numverts);
+ printf("==== B ====\n");
+ print_lvector(lB, numverts);
+ printf("==== S ====\n");
+ print_bfmatrix(S);
+#endif
+
+ while (delta_new > delta_target && conjgrad_loopcount < conjgrad_looplimit) {
+ mul_bfmatrix_lfvector(q, lA, c);
+ filter(q, S);
+
+ alpha = delta_new / dot_lfvector(c, q, numverts);
+
+ add_lfvector_lfvectorS(ldV, ldV, c, alpha, numverts);
+
+ add_lfvector_lfvectorS(r, r, q, -alpha, numverts);
+
+ /* s = P^-1 * r */
+ cp_lfvector(s, r, numverts);
+ delta_old = delta_new;
+ delta_new = dot_lfvector(r, s, numverts);
+
+ add_lfvector_lfvectorS(c, s, c, delta_new / delta_old, numverts);
+ filter(c, S);
+
+ conjgrad_loopcount++;
+ }
+
+#ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
+ printf("==== dV ====\n");
+ print_lvector(ldV, numverts);
+ printf("========\n");
+#endif
+
+ del_lfvector(fB);
+ del_lfvector(AdV);
+ del_lfvector(r);
+ del_lfvector(c);
+ del_lfvector(q);
+ del_lfvector(s);
+ // printf("W/O conjgrad_loopcount: %d\n", conjgrad_loopcount);
+
+ result->status = conjgrad_loopcount < conjgrad_looplimit ? BPH_SOLVER_SUCCESS : BPH_SOLVER_NO_CONVERGENCE;
+ result->iterations = conjgrad_loopcount;
+ result->error = bnorm2 > 0.0f ? sqrtf(delta_new / bnorm2) : 0.0f;
+
+ return conjgrad_loopcount < conjgrad_looplimit; // true means we reached desired accuracy in given time - ie stable
+}
+
+#if 0
+// block diagonalizer
+DO_INLINE void BuildPPinv(fmatrix3x3 *lA, fmatrix3x3 *P, fmatrix3x3 *Pinv)
+{
+ unsigned int i = 0;
+
+ // Take only the diagonal blocks of A
+// #pragma omp parallel for private(i) if (lA[0].vcount > CLOTH_OPENMP_LIMIT)
+ for (i = 0; i<lA[0].vcount; i++) {
+ // block diagonalizer
+ cp_fmatrix(P[i].m, lA[i].m);
+ inverse_fmatrix(Pinv[i].m, P[i].m);
+
+ }
+}
+/*
+// version 1.3
+static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv)
+{
+ unsigned int numverts = lA[0].vcount, iterations = 0, conjgrad_looplimit=100;
+ float delta0 = 0, deltaNew = 0, deltaOld = 0, alpha = 0;
+ float conjgrad_epsilon=0.0001; // 0.2 is dt for steps=5
+ lfVector *r = create_lfvector(numverts);
+ lfVector *p = create_lfvector(numverts);
+ lfVector *s = create_lfvector(numverts);
+ lfVector *h = create_lfvector(numverts);
+
+ BuildPPinv(lA, P, Pinv);
+
+ filter(dv, S);
+ add_lfvector_lfvector(dv, dv, z, numverts);
+
+ mul_bfmatrix_lfvector(r, lA, dv);
+ sub_lfvector_lfvector(r, lB, r, numverts);
+ filter(r, S);
+
+ mul_prevfmatrix_lfvector(p, Pinv, r);
+ filter(p, S);
+
+ deltaNew = dot_lfvector(r, p, numverts);
+
+ delta0 = deltaNew * sqrt(conjgrad_epsilon);
+
+ // itstart();
+
+ while ((deltaNew > delta0) && (iterations < conjgrad_looplimit))
+ {
+ iterations++;
+
+ mul_bfmatrix_lfvector(s, lA, p);
+ filter(s, S);
+
+ alpha = deltaNew / dot_lfvector(p, s, numverts);
+
+ add_lfvector_lfvectorS(dv, dv, p, alpha, numverts);
+
+ add_lfvector_lfvectorS(r, r, s, -alpha, numverts);
+
+ mul_prevfmatrix_lfvector(h, Pinv, r);
+ filter(h, S);
+
+ deltaOld = deltaNew;
+
+ deltaNew = dot_lfvector(r, h, numverts);
+
+ add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts);
+
+ filter(p, S);
+
+ }
+
+ // itend();
+ // printf("cg_filtered_pre time: %f\n", (float)itval());
+
+ del_lfvector(h);
+ del_lfvector(s);
+ del_lfvector(p);
+ del_lfvector(r);
+
+ printf("iterations: %d\n", iterations);
+
+ return iterations<conjgrad_looplimit;
+}
+*/
+// version 1.4
+static int cg_filtered_pre(lfVector *dv, fmatrix3x3 *lA, lfVector *lB, lfVector *z, fmatrix3x3 *S, fmatrix3x3 *P, fmatrix3x3 *Pinv, fmatrix3x3 *bigI)
+{
+ unsigned int numverts = lA[0].vcount, iterations = 0, conjgrad_looplimit=100;
+ float delta0 = 0, deltaNew = 0, deltaOld = 0, alpha = 0, tol = 0;
+ lfVector *r = create_lfvector(numverts);
+ lfVector *p = create_lfvector(numverts);
+ lfVector *s = create_lfvector(numverts);
+ lfVector *h = create_lfvector(numverts);
+ lfVector *bhat = create_lfvector(numverts);
+ lfVector *btemp = create_lfvector(numverts);
+
+ BuildPPinv(lA, P, Pinv);
+
+ initdiag_bfmatrix(bigI, I);
+ sub_bfmatrix_Smatrix(bigI, bigI, S);
+
+ // x = Sx_0+(I-S)z
+ filter(dv, S);
+ add_lfvector_lfvector(dv, dv, z, numverts);
+
+ // b_hat = S(b-A(I-S)z)
+ mul_bfmatrix_lfvector(r, lA, z);
+ mul_bfmatrix_lfvector(bhat, bigI, r);
+ sub_lfvector_lfvector(bhat, lB, bhat, numverts);
+
+ // r = S(b-Ax)
+ mul_bfmatrix_lfvector(r, lA, dv);
+ sub_lfvector_lfvector(r, lB, r, numverts);
+ filter(r, S);
+
+ // p = SP^-1r
+ mul_prevfmatrix_lfvector(p, Pinv, r);
+ filter(p, S);
+
+ // delta0 = bhat^TP^-1bhat
+ mul_prevfmatrix_lfvector(btemp, Pinv, bhat);
+ delta0 = dot_lfvector(bhat, btemp, numverts);
+
+ // deltaNew = r^TP
+ deltaNew = dot_lfvector(r, p, numverts);
+
+ /*
+ filter(dv, S);
+ add_lfvector_lfvector(dv, dv, z, numverts);
+
+ mul_bfmatrix_lfvector(r, lA, dv);
+ sub_lfvector_lfvector(r, lB, r, numverts);
+ filter(r, S);
+
+ mul_prevfmatrix_lfvector(p, Pinv, r);
+ filter(p, S);
+
+ deltaNew = dot_lfvector(r, p, numverts);
+
+ delta0 = deltaNew * sqrt(conjgrad_epsilon);
+ */
+
+ // itstart();
+
+ tol = (0.01*0.2);
+
+ while ((deltaNew > delta0*tol*tol) && (iterations < conjgrad_looplimit))
+ {
+ iterations++;
+
+ mul_bfmatrix_lfvector(s, lA, p);
+ filter(s, S);
+
+ alpha = deltaNew / dot_lfvector(p, s, numverts);
+
+ add_lfvector_lfvectorS(dv, dv, p, alpha, numverts);
+
+ add_lfvector_lfvectorS(r, r, s, -alpha, numverts);
+
+ mul_prevfmatrix_lfvector(h, Pinv, r);
+ filter(h, S);
+
+ deltaOld = deltaNew;
+
+ deltaNew = dot_lfvector(r, h, numverts);
+
+ add_lfvector_lfvectorS(p, h, p, deltaNew / deltaOld, numverts);
+
+ filter(p, S);
+
+ }
+
+ // itend();
+ // printf("cg_filtered_pre time: %f\n", (float)itval());
+
+ del_lfvector(btemp);
+ del_lfvector(bhat);
+ del_lfvector(h);
+ del_lfvector(s);
+ del_lfvector(p);
+ del_lfvector(r);
+
+ // printf("iterations: %d\n", iterations);
+
+ return iterations<conjgrad_looplimit;
+}
+#endif
+
+bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSolverResult *result)
+{
+ unsigned int numverts = data->dFdV[0].vcount;
+
+ lfVector *dFdXmV = create_lfvector(numverts);
+ zero_lfvector(data->dV, numverts);
+
+ cp_bfmatrix(data->A, data->M);
+
+ subadd_bfmatrixS_bfmatrixS(data->A, data->dFdV, dt, data->dFdX, (dt*dt));
+
+ mul_bfmatrix_lfvector(dFdXmV, data->dFdX, data->V);
+
+ add_lfvectorS_lfvectorS(data->B, data->F, dt, dFdXmV, (dt*dt), numverts);
+
+ // itstart();
+
+ cg_filtered(data->dV, data->A, data->B, data->z, data->S, result); /* conjugate gradient algorithm to solve Ax=b */
+ // cg_filtered_pre(id->dV, id->A, id->B, id->z, id->S, id->P, id->Pinv, id->bigI);
+
+ // itend();
+ // printf("cg_filtered calc time: %f\n", (float)itval());
+
+ // advance velocities
+ add_lfvector_lfvector(data->Vnew, data->V, data->dV, numverts);
+
+ del_lfvector(dFdXmV);
+
+ return result->status == BPH_SOLVER_SUCCESS;
+}
+
+bool BPH_mass_spring_solve_positions(Implicit_Data *data, float dt)
+{
+ int numverts = data->M[0].vcount;
+
+ // advance positions
+ add_lfvector_lfvectorS(data->Xnew, data->X, data->Vnew, dt, numverts);
+
+ return true;
+}
+
+void BPH_mass_spring_apply_result(Implicit_Data *data)
+{
+ int numverts = data->M[0].vcount;
+ cp_lfvector(data->X, data->Xnew, numverts);
+ cp_lfvector(data->V, data->Vnew, numverts);
+}
+
+void BPH_mass_spring_set_vertex_mass(Implicit_Data *data, int index, float mass)
+{
+ unit_m3(data->M[index].m);
+ mul_m3_fl(data->M[index].m, mass);
+}
+
+void BPH_mass_spring_set_rest_transform(Implicit_Data *data, int index, float tfm[3][3])
+{
+#ifdef CLOTH_ROOT_FRAME
+ copy_m3_m3(data->tfm[index].m, tfm);
+#else
+ unit_m3(data->tfm[index].m);
+ (void)tfm;
+#endif
+}
+
+void BPH_mass_spring_set_motion_state(Implicit_Data *data, int index, const float x[3], const float v[3])
+{
+ world_to_root_v3(data, index, data->X[index], x);
+ world_to_root_v3(data, index, data->V[index], v);
+}
+
+void BPH_mass_spring_set_position(Implicit_Data *data, int index, const float x[3])
+{
+ world_to_root_v3(data, index, data->X[index], x);
+}
+
+void BPH_mass_spring_set_velocity(Implicit_Data *data, int index, const float v[3])
+{
+ world_to_root_v3(data, index, data->V[index], v);
+}
+
+void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, int index, float x[3], float v[3])
+{
+ if (x) root_to_world_v3(data, index, x, data->X[index]);
+ if (v) root_to_world_v3(data, index, v, data->V[index]);
+}
+
+void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3])
+{
+ root_to_world_v3(data, index, x, data->X[index]);
+}
+
+void BPH_mass_spring_get_new_velocity(struct Implicit_Data *data, int index, float v[3])
+{
+ root_to_world_v3(data, index, v, data->Vnew[index]);
+}
+
+void BPH_mass_spring_set_new_velocity(struct Implicit_Data *data, int index, const float v[3])
+{
+ world_to_root_v3(data, index, data->Vnew[index], v);
+}
+
+/* -------------------------------- */
+
+static int BPH_mass_spring_add_block(Implicit_Data *data, int v1, int v2)
+{
+ int s = data->M[0].vcount + data->num_blocks; /* index from array start */
+ BLI_assert(s < data->M[0].vcount + data->M[0].scount);
+ ++data->num_blocks;
+
+ /* tfm and S don't have spring entries (diagonal blocks only) */
+ init_fmatrix(data->bigI + s, v1, v2);
+ init_fmatrix(data->M + s, v1, v2);
+ init_fmatrix(data->dFdX + s, v1, v2);
+ init_fmatrix(data->dFdV + s, v1, v2);
+ init_fmatrix(data->A + s, v1, v2);
+ init_fmatrix(data->P + s, v1, v2);
+ init_fmatrix(data->Pinv + s, v1, v2);
+
+ return s;
+}
+
+void BPH_mass_spring_clear_constraints(Implicit_Data *data)
+{
+ int i, numverts = data->S[0].vcount;
+ for (i = 0; i < numverts; ++i) {
+ unit_m3(data->S[i].m);
+ zero_v3(data->z[i]);
+ }
+}
+
+void BPH_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3])
+{
+ zero_m3(data->S[index].m);
+
+ world_to_root_v3(data, index, data->z[index], dV);
+}
+
+void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3])
+{
+ float m[3][3], p[3], q[3], u[3], cmat[3][3];
+
+ world_to_root_v3(data, index, p, c1);
+ mul_fvectorT_fvector(cmat, p, p);
+ sub_m3_m3m3(m, I, cmat);
+
+ world_to_root_v3(data, index, q, c2);
+ mul_fvectorT_fvector(cmat, q, q);
+ sub_m3_m3m3(m, m, cmat);
+
+ /* XXX not sure but multiplication should work here */
+ copy_m3_m3(data->S[index].m, m);
+// mul_m3_m3m3(data->S[index].m, data->S[index].m, m);
+
+ world_to_root_v3(data, index, u, dV);
+ add_v3_v3(data->z[index], u);
+}
+
+void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, int index, const float c1[3], const float dV[3])
+{
+ float m[3][3], p[3], u[3], cmat[3][3];
+
+ world_to_root_v3(data, index, p, c1);
+ mul_fvectorT_fvector(cmat, p, p);
+ sub_m3_m3m3(m, I, cmat);
+
+ copy_m3_m3(data->S[index].m, m);
+// mul_m3_m3m3(data->S[index].m, data->S[index].m, m);
+
+ world_to_root_v3(data, index, u, dV);
+ add_v3_v3(data->z[index], u);
+}
+
+void BPH_mass_spring_clear_forces(Implicit_Data *data)
+{
+ int numverts = data->M[0].vcount;
+ zero_lfvector(data->F, numverts);
+ init_bfmatrix(data->dFdX, ZERO);
+ init_bfmatrix(data->dFdV, ZERO);
+
+ data->num_blocks = 0;
+}
+
+void BPH_mass_spring_force_reference_frame(Implicit_Data *data, int index, const float acceleration[3], const float omega[3], const float domega_dt[3], float mass)
+{
+#ifdef CLOTH_ROOT_FRAME
+ float acc[3], w[3], dwdt[3];
+ float f[3], dfdx[3][3], dfdv[3][3];
+ float euler[3], coriolis[3], centrifugal[3], rotvel[3];
+ float deuler[3][3], dcoriolis[3][3], dcentrifugal[3][3], drotvel[3][3];
+
+ world_to_root_v3(data, index, acc, acceleration);
+ world_to_root_v3(data, index, w, omega);
+ world_to_root_v3(data, index, dwdt, domega_dt);
+
+ cross_v3_v3v3(euler, dwdt, data->X[index]);
+ cross_v3_v3v3(coriolis, w, data->V[index]);
+ mul_v3_fl(coriolis, 2.0f);
+ cross_v3_v3v3(rotvel, w, data->X[index]);
+ cross_v3_v3v3(centrifugal, w, rotvel);
+
+ sub_v3_v3v3(f, acc, euler);
+ sub_v3_v3(f, coriolis);
+ sub_v3_v3(f, centrifugal);
+
+ mul_v3_fl(f, mass); /* F = m * a */
+
+ cross_v3_identity(deuler, dwdt);
+ cross_v3_identity(dcoriolis, w);
+ mul_m3_fl(dcoriolis, 2.0f);
+ cross_v3_identity(drotvel, w);
+ cross_m3_v3m3(dcentrifugal, w, drotvel);
+
+ add_m3_m3m3(dfdx, deuler, dcentrifugal);
+ negate_m3(dfdx);
+ mul_m3_fl(dfdx, mass);
+
+ copy_m3_m3(dfdv, dcoriolis);
+ negate_m3(dfdv);
+ mul_m3_fl(dfdv, mass);
+
+ add_v3_v3(data->F[index], f);
+ add_m3_m3m3(data->dFdX[index].m, data->dFdX[index].m, dfdx);
+ add_m3_m3m3(data->dFdV[index].m, data->dFdV[index].m, dfdv);
+#else
+ (void)data;
+ (void)index;
+ (void)acceleration;
+ (void)omega;
+ (void)domega_dt;
+#endif
+}
+
+void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, const float g[3])
+{
+ /* force = mass * acceleration (in this case: gravity) */
+ float f[3];
+ world_to_root_v3(data, index, f, g);
+ mul_v3_fl(f, mass);
+
+ add_v3_v3(data->F[index], f);
+}
+
+void BPH_mass_spring_force_drag(Implicit_Data *data, float drag)
+{
+ int i, numverts = data->M[0].vcount;
+ for (i = 0; i < numverts; i++) {
+ float tmp[3][3];
+
+ /* NB: uses root space velocity, no need to transform */
+ madd_v3_v3fl(data->F[i], data->V[i], -drag);
+
+ copy_m3_m3(tmp, I);
+ mul_m3_fl(tmp, -drag);
+ add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, tmp);
+ }
+}
+
+void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3])
+{
+ float tf[3], tdfdx[3][3], tdfdv[3][3];
+ world_to_root_v3(data, i, tf, f);
+ world_to_root_m3(data, i, tdfdx, dfdx);
+ world_to_root_m3(data, i, tdfdv, dfdv);
+
+ add_v3_v3(data->F[i], tf);
+ add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, tdfdx);
+ add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, tdfdv);
+}
+
+static float calc_nor_area_tri(float nor[3], const float v1[3], const float v2[3], const float v3[3])
+{
+ float n1[3], n2[3];
+
+ sub_v3_v3v3(n1, v1, v2);
+ sub_v3_v3v3(n2, v2, v3);
+
+ cross_v3_v3v3(nor, n1, n2);
+ return normalize_v3(nor);
+}
+
+static float calc_nor_area_quad(float nor[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
+{
+ float n1[3], n2[3];
+
+ sub_v3_v3v3(n1, v1, v3);
+ sub_v3_v3v3(n2, v2, v4);
+
+ cross_v3_v3v3(nor, n1, n2);
+ return normalize_v3(nor);
+}
+
+/* XXX does not support force jacobians yet, since the effector system does not provide them either */
+void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3, int v4, const float (*winvec)[3])
+{
+ const float effector_scale = 0.02f;
+ float win[3], nor[3], area;
+ float factor;
+
+ // calculate face normal and area
+ if (v4) {
+ area = calc_nor_area_quad(nor, data->X[v1], data->X[v2], data->X[v3], data->X[v4]);
+ factor = effector_scale * area * 0.25f;
+ }
+ else {
+ area = calc_nor_area_tri(nor, data->X[v1], data->X[v2], data->X[v3]);
+ factor = effector_scale * area / 3.0f;
+ }
+
+ world_to_root_v3(data, v1, win, winvec[v1]);
+ madd_v3_v3fl(data->F[v1], nor, factor * dot_v3v3(win, nor));
+
+ world_to_root_v3(data, v2, win, winvec[v2]);
+ madd_v3_v3fl(data->F[v2], nor, factor * dot_v3v3(win, nor));
+
+ world_to_root_v3(data, v3, win, winvec[v3]);
+ madd_v3_v3fl(data->F[v3], nor, factor * dot_v3v3(win, nor));
+
+ if (v4) {
+ world_to_root_v3(data, v4, win, winvec[v4]);
+ madd_v3_v3fl(data->F[v4], nor, factor * dot_v3v3(win, nor));
+ }
+}
+
+static void edge_wind_vertex(const float dir[3], float length, float radius, const float wind[3], float f[3], float UNUSED(dfdx[3][3]), float UNUSED(dfdv[3][3]))
+{
+ const float density = 0.01f; /* XXX arbitrary value, corresponds to effect of air density */
+ float cos_alpha, sin_alpha, cross_section;
+ float windlen = len_v3(wind);
+
+ if (windlen == 0.0f) {
+ zero_v3(f);
+ return;
+ }
+
+ /* angle of wind direction to edge */
+ cos_alpha = dot_v3v3(wind, dir) / windlen;
+ sin_alpha = sqrtf(1.0f - cos_alpha * cos_alpha);
+ cross_section = radius * ((float)M_PI * radius * sin_alpha + length * cos_alpha);
+
+ mul_v3_v3fl(f, wind, density * cross_section);
+}
+
+void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, float radius1, float radius2, const float (*winvec)[3])
+{
+ float win[3], dir[3], length;
+ float f[3], dfdx[3][3], dfdv[3][3];
+
+ sub_v3_v3v3(dir, data->X[v1], data->X[v2]);
+ length = normalize_v3(dir);
+
+ world_to_root_v3(data, v1, win, winvec[v1]);
+ edge_wind_vertex(dir, length, radius1, win, f, dfdx, dfdv);
+ add_v3_v3(data->F[v1], f);
+
+ world_to_root_v3(data, v2, win, winvec[v2]);
+ edge_wind_vertex(dir, length, radius2, win, f, dfdx, dfdv);
+ add_v3_v3(data->F[v2], f);
+}
+
+void BPH_mass_spring_force_vertex_wind(Implicit_Data *data, int v, float UNUSED(radius), const float (*winvec)[3])
+{
+ const float density = 0.01f; /* XXX arbitrary value, corresponds to effect of air density */
+
+ float wind[3];
+ float f[3];
+
+ world_to_root_v3(data, v, wind, winvec[v]);
+ mul_v3_v3fl(f, wind, density);
+ add_v3_v3(data->F[v], f);
+}
+
+BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, float L, float k)
+{
+ // dir is unit length direction, rest is spring's restlength, k is spring constant.
+ //return ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k;
+ outerproduct(to, dir, dir);
+ sub_m3_m3m3(to, I, to);
+
+ mul_m3_fl(to, (L/length));
+ sub_m3_m3m3(to, to, I);
+ mul_m3_fl(to, k);
+}
+
+/* unused */
+#if 0
+BLI_INLINE void dfdx_damp(float to[3][3], const float dir[3], float length, const float vel[3], float rest, float damping)
+{
+ // inner spring damping vel is the relative velocity of the endpoints.
+ // return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest)));
+ mul_fvectorT_fvector(to, dir, dir);
+ sub_fmatrix_fmatrix(to, I, to);
+ mul_fmatrix_S(to, (-damping * -(dot_v3v3(dir, vel)/MAX2(length, rest))));
+}
+#endif
+
+BLI_INLINE void dfdv_damp(float to[3][3], const float dir[3], float damping)
+{
+ // derivative of force wrt velocity
+ outerproduct(to, dir, dir);
+ mul_m3_fl(to, -damping);
+}
+
+BLI_INLINE float fb(float length, float L)
+{
+ float x = length / L;
+ float xx = x * x;
+ float xxx = xx * x;
+ float xxxx = xxx * x;
+ return (-11.541f * xxxx + 34.193f * xxx - 39.083f * xx + 23.116f * x - 9.713f);
+}
+
+BLI_INLINE float fbderiv(float length, float L)
+{
+ float x = length/L;
+ float xx = x * x;
+ float xxx = xx * x;
+ return (-46.164f * xxx + 102.579f * xx - 78.166f * x + 23.116f);
+}
+
+BLI_INLINE float fbstar(float length, float L, float kb, float cb)
+{
+ float tempfb_fl = kb * fb(length, L);
+ float fbstar_fl = cb * (length - L);
+
+ if (tempfb_fl < fbstar_fl)
+ return fbstar_fl;
+ else
+ return tempfb_fl;
+}
+
+// function to calculae bending spring force (taken from Choi & Co)
+BLI_INLINE float fbstar_jacobi(float length, float L, float kb, float cb)
+{
+ float tempfb_fl = kb * fb(length, L);
+ float fbstar_fl = cb * (length - L);
+
+ if (tempfb_fl < fbstar_fl) {
+ return -cb;
+ }
+ else {
+ return -kb * fbderiv(length, L);
+ }
+}
+
+/* calculate elonglation */
+BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[3], float r_dir[3], float *r_length, float r_vel[3])
+{
+ sub_v3_v3v3(r_extent, data->X[j], data->X[i]);
+ sub_v3_v3v3(r_vel, data->V[j], data->V[i]);
+ *r_length = len_v3(r_extent);
+
+ if (*r_length > ALMOST_ZERO) {
+ /*
+ if (length>L) {
+ if ((clmd->sim_parms->flags & CSIMSETT_FLAG_TEARING_ENABLED) &&
+ ( ((length-L)*100.0f/L) > clmd->sim_parms->maxspringlen )) {
+ // cut spring!
+ s->flags |= CSPRING_FLAG_DEACTIVATE;
+ return false;
+ }
+ }
+ */
+ mul_v3_v3fl(r_dir, r_extent, 1.0f/(*r_length));
+ }
+ else {
+ zero_v3(r_dir);
+ }
+
+ return true;
+}
+
+BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3], float dfdx[3][3], float dfdv[3][3])
+{
+ int block_ij = BPH_mass_spring_add_block(data, i, j);
+
+ add_v3_v3(data->F[i], f);
+ sub_v3_v3(data->F[j], f);
+
+ add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx);
+ add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfdx);
+ sub_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfdx);
+
+ add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv);
+ add_m3_m3m3(data->dFdV[j].m, data->dFdV[j].m, dfdv);
+ sub_m3_m3m3(data->dFdV[block_ij].m, data->dFdV[block_ij].m, dfdv);
+}
+
+bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, float restlen,
+ float stiffness, float damping, bool no_compress, float clamp_force,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+{
+ float extent[3], length, dir[3], vel[3];
+
+ // calculate elonglation
+ spring_length(data, i, j, extent, dir, &length, vel);
+
+ if (length > restlen || no_compress) {
+ float stretch_force, f[3], dfdx[3][3], dfdv[3][3];
+
+ stretch_force = stiffness * (length - restlen);
+ if (clamp_force > 0.0f && stretch_force > clamp_force) {
+ stretch_force = clamp_force;
+ }
+ mul_v3_v3fl(f, dir, stretch_force);
+
+ // Ascher & Boxman, p.21: Damping only during elonglation
+ // something wrong with it...
+ madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
+
+ dfdx_spring(dfdx, dir, length, restlen, stiffness);
+ dfdv_damp(dfdv, dir, damping);
+
+ apply_spring(data, i, j, f, dfdx, dfdv);
+
+ if (r_f) copy_v3_v3(r_f, f);
+ if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
+ if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
+
+ return true;
+ }
+ else {
+ if (r_f) zero_v3(r_f);
+ if (r_dfdx) zero_m3(r_dfdx);
+ if (r_dfdv) zero_m3(r_dfdv);
+
+ return false;
+ }
+}
+
+/* See "Stable but Responsive Cloth" (Choi, Ko 2005) */
+bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen,
+ float kb, float cb,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+{
+ float extent[3], length, dir[3], vel[3];
+
+ // calculate elonglation
+ spring_length(data, i, j, extent, dir, &length, vel);
+
+ if (length < restlen) {
+ float f[3], dfdx[3][3], dfdv[3][3];
+
+ mul_v3_v3fl(f, dir, fbstar(length, restlen, kb, cb));
+
+ outerproduct(dfdx, dir, dir);
+ mul_m3_fl(dfdx, fbstar_jacobi(length, restlen, kb, cb));
+
+ /* XXX damping not supported */
+ zero_m3(dfdv);
+
+ apply_spring(data, i, j, f, dfdx, dfdv);
+
+ if (r_f) copy_v3_v3(r_f, f);
+ if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
+ if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
+
+ return true;
+ }
+ else {
+ if (r_f) zero_v3(r_f);
+ if (r_dfdx) zero_m3(r_dfdx);
+ if (r_dfdv) zero_m3(r_dfdv);
+
+ return false;
+ }
+}
+
+/* Jacobian of a direction vector.
+ * Basically the part of the differential orthogonal to the direction,
+ * inversely proportional to the length of the edge.
+ *
+ * dD_ij/dx_i = -dD_ij/dx_j = (D_ij * D_ij^T - I) / len_ij
+ */
+BLI_INLINE void spring_grad_dir(Implicit_Data *data, int i, int j, float edge[3], float dir[3], float grad_dir[3][3])
+{
+ float length;
+
+ sub_v3_v3v3(edge, data->X[j], data->X[i]);
+ length = normalize_v3_v3(dir, edge);
+
+ if (length > ALMOST_ZERO) {
+ outerproduct(grad_dir, dir, dir);
+ sub_m3_m3m3(grad_dir, I, grad_dir);
+ mul_m3_fl(grad_dir, 1.0f / length);
+ }
+ else {
+ zero_m3(grad_dir);
+ }
+}
+
+BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k,
+ const float goal[3],
+ float stiffness, float damping,
+ int q, const float dx[3], const float dv[3],
+ float r_f[3])
+{
+ float edge_ij[3], dir_ij[3];
+ float edge_jk[3], dir_jk[3];
+ float vel_ij[3], vel_jk[3], vel_ortho[3];
+ float f_bend[3], f_damp[3];
+ float fk[3];
+ float dist[3];
+
+ zero_v3(fk);
+
+ sub_v3_v3v3(edge_ij, data->X[j], data->X[i]);
+ if (q == i) sub_v3_v3(edge_ij, dx);
+ if (q == j) add_v3_v3(edge_ij, dx);
+ normalize_v3_v3(dir_ij, edge_ij);
+
+ sub_v3_v3v3(edge_jk, data->X[k], data->X[j]);
+ if (q == j) sub_v3_v3(edge_jk, dx);
+ if (q == k) add_v3_v3(edge_jk, dx);
+ normalize_v3_v3(dir_jk, edge_jk);
+
+ sub_v3_v3v3(vel_ij, data->V[j], data->V[i]);
+ if (q == i) sub_v3_v3(vel_ij, dv);
+ if (q == j) add_v3_v3(vel_ij, dv);
+
+ sub_v3_v3v3(vel_jk, data->V[k], data->V[j]);
+ if (q == j) sub_v3_v3(vel_jk, dv);
+ if (q == k) add_v3_v3(vel_jk, dv);
+
+ /* bending force */
+ sub_v3_v3v3(dist, goal, edge_jk);
+ mul_v3_v3fl(f_bend, dist, stiffness);
+
+ add_v3_v3(fk, f_bend);
+
+ /* damping force */
+ madd_v3_v3v3fl(vel_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk));
+ mul_v3_v3fl(f_damp, vel_ortho, damping);
+
+ sub_v3_v3(fk, f_damp);
+
+ copy_v3_v3(r_f, fk);
+}
+
+/* Finite Differences method for estimating the jacobian of the force */
+BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j, int k,
+ const float goal[3],
+ float stiffness, float damping,
+ int q, float dfdx[3][3])
+{
+ const float delta = 0.00001f; // TODO find a good heuristic for this
+ float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3];
+ float f[3];
+ int a, b;
+
+ zero_m3(dvec_null);
+ unit_m3(dvec_pos);
+ mul_m3_fl(dvec_pos, delta * 0.5f);
+ copy_m3_m3(dvec_neg, dvec_pos);
+ negate_m3(dvec_neg);
+
+ /* XXX TODO offset targets to account for position dependency */
+
+ for (a = 0; a < 3; ++a) {
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ q, dvec_pos[a], dvec_null[a], f);
+ copy_v3_v3(dfdx[a], f);
+
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ q, dvec_neg[a], dvec_null[a], f);
+ sub_v3_v3(dfdx[a], f);
+
+ for (b = 0; b < 3; ++b) {
+ dfdx[a][b] /= delta;
+ }
+ }
+}
+
+/* Finite Differences method for estimating the jacobian of the force */
+BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j, int k,
+ const float goal[3],
+ float stiffness, float damping,
+ int q, float dfdv[3][3])
+{
+ const float delta = 0.00001f; // TODO find a good heuristic for this
+ float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3];
+ float f[3];
+ int a, b;
+
+ zero_m3(dvec_null);
+ unit_m3(dvec_pos);
+ mul_m3_fl(dvec_pos, delta * 0.5f);
+ copy_m3_m3(dvec_neg, dvec_pos);
+ negate_m3(dvec_neg);
+
+ /* XXX TODO offset targets to account for position dependency */
+
+ for (a = 0; a < 3; ++a) {
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ q, dvec_null[a], dvec_pos[a], f);
+ copy_v3_v3(dfdv[a], f);
+
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ q, dvec_null[a], dvec_neg[a], f);
+ sub_v3_v3(dfdv[a], f);
+
+ for (b = 0; b < 3; ++b) {
+ dfdv[a][b] /= delta;
+ }
+ }
+}
+
+/* Angular spring that pulls the vertex toward the local target
+ * See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a)
+ */
+bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, int j, int k,
+ const float target[3], float stiffness, float damping)
+{
+ float goal[3];
+ float fj[3], fk[3];
+ float dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
+ float dfj_dvi[3][3], dfj_dvj[3][3], dfk_dvi[3][3], dfk_dvj[3][3], dfk_dvk[3][3];
+
+ const float vecnull[3] = {0.0f, 0.0f, 0.0f};
+
+ int block_ij = BPH_mass_spring_add_block(data, i, j);
+ int block_jk = BPH_mass_spring_add_block(data, j, k);
+ int block_ik = BPH_mass_spring_add_block(data, i, k);
+
+ world_to_root_v3(data, j, goal, target);
+
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk);
+ negate_v3_v3(fj, fk); /* counterforce */
+
+ spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi);
+ spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj);
+ spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk);
+ copy_m3_m3(dfj_dxi, dfk_dxi); negate_m3(dfj_dxi);
+ copy_m3_m3(dfj_dxj, dfk_dxj); negate_m3(dfj_dxj);
+
+ spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi);
+ spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj);
+ spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk);
+ copy_m3_m3(dfj_dvi, dfk_dvi); negate_m3(dfj_dvi);
+ copy_m3_m3(dfj_dvj, dfk_dvj); negate_m3(dfj_dvj);
+
+ /* add forces and jacobians to the solver data */
+
+ add_v3_v3(data->F[j], fj);
+ add_v3_v3(data->F[k], fk);
+
+ add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfj_dxj);
+ add_m3_m3m3(data->dFdX[k].m, data->dFdX[k].m, dfk_dxk);
+
+ add_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfj_dxi);
+ add_m3_m3m3(data->dFdX[block_jk].m, data->dFdX[block_jk].m, dfk_dxj);
+ add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi);
+
+ add_m3_m3m3(data->dFdV[j].m, data->dFdV[j].m, dfj_dvj);
+ add_m3_m3m3(data->dFdV[k].m, data->dFdV[k].m, dfk_dvk);
+
+ add_m3_m3m3(data->dFdV[block_ij].m, data->dFdV[block_ij].m, dfj_dvi);
+ add_m3_m3m3(data->dFdV[block_jk].m, data->dFdV[block_jk].m, dfk_dvj);
+ add_m3_m3m3(data->dFdV[block_ik].m, data->dFdV[block_ik].m, dfk_dvi);
+
+
+ /* XXX analytical calculation of derivatives below is incorrect.
+ * This proved to be difficult, but for now just using the finite difference method for
+ * estimating the jacobians should be sufficient.
+ */
+#if 0
+ float edge_ij[3], dir_ij[3], grad_dir_ij[3][3];
+ float edge_jk[3], dir_jk[3], grad_dir_jk[3][3];
+ float dist[3], vel_jk[3], vel_jk_ortho[3], projvel[3];
+ float target[3];
+ float tmp[3][3];
+ float fi[3], fj[3], fk[3];
+ float dfi_dxi[3][3], dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
+ float dfdvi[3][3];
+
+ // TESTING
+ damping = 0.0f;
+
+ zero_v3(fi);
+ zero_v3(fj);
+ zero_v3(fk);
+ zero_m3(dfi_dxi);
+ zero_m3(dfj_dxi);
+ zero_m3(dfk_dxi);
+ zero_m3(dfk_dxj);
+ zero_m3(dfk_dxk);
+
+ /* jacobian of direction vectors */
+ spring_grad_dir(data, i, j, edge_ij, dir_ij, grad_dir_ij);
+ spring_grad_dir(data, j, k, edge_jk, dir_jk, grad_dir_jk);
+
+ sub_v3_v3v3(vel_jk, data->V[k], data->V[j]);
+
+ /* bending force */
+ mul_v3_v3fl(target, dir_ij, restlen);
+ sub_v3_v3v3(dist, target, edge_jk);
+ mul_v3_v3fl(fk, dist, stiffness);
+
+ /* damping force */
+ madd_v3_v3v3fl(vel_jk_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk));
+ madd_v3_v3fl(fk, vel_jk_ortho, damping);
+
+ /* XXX this only holds true as long as we assume straight rest shape!
+ * eventually will become a bit more involved since the opposite segment
+ * gets its own target, under condition of having equal torque on both sides.
+ */
+ copy_v3_v3(fi, fk);
+
+ /* counterforce on the middle point */
+ sub_v3_v3(fj, fi);
+ sub_v3_v3(fj, fk);
+
+ /* === derivatives === */
+
+ madd_m3_m3fl(dfk_dxi, grad_dir_ij, stiffness * restlen);
+
+ madd_m3_m3fl(dfk_dxj, grad_dir_ij, -stiffness * restlen);
+ madd_m3_m3fl(dfk_dxj, I, stiffness);
+
+ madd_m3_m3fl(dfk_dxk, I, -stiffness);
+
+ copy_m3_m3(dfi_dxi, dfk_dxk);
+ negate_m3(dfi_dxi);
+
+ /* dfj_dfi == dfi_dfj due to symmetry,
+ * dfi_dfj == dfk_dfj due to fi == fk
+ * XXX see comment above on future bent rest shapes
+ */
+ copy_m3_m3(dfj_dxi, dfk_dxj);
+
+ /* dfj_dxj == -(dfi_dxj + dfk_dxj) due to fj == -(fi + fk) */
+ sub_m3_m3m3(dfj_dxj, dfj_dxj, dfj_dxi);
+ sub_m3_m3m3(dfj_dxj, dfj_dxj, dfk_dxj);
+
+ /* add forces and jacobians to the solver data */
+ add_v3_v3(data->F[i], fi);
+ add_v3_v3(data->F[j], fj);
+ add_v3_v3(data->F[k], fk);
+
+ add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfi_dxi);
+ add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfj_dxj);
+ add_m3_m3m3(data->dFdX[k].m, data->dFdX[k].m, dfk_dxk);
+
+ add_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfj_dxi);
+ add_m3_m3m3(data->dFdX[block_jk].m, data->dFdX[block_jk].m, dfk_dxj);
+ add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi);
+#endif
+
+ return true;
+}
+
+bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
+ float stiffness, float damping,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+{
+ float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3];
+ float f[3], dfdx[3][3], dfdv[3][3];
+
+ /* goal is in world space */
+ world_to_root_v3(data, i, root_goal_x, goal_x);
+ world_to_root_v3(data, i, root_goal_v, goal_v);
+
+ sub_v3_v3v3(extent, root_goal_x, data->X[i]);
+ sub_v3_v3v3(vel, root_goal_v, data->V[i]);
+ length = normalize_v3_v3(dir, extent);
+
+ if (length > ALMOST_ZERO) {
+ mul_v3_v3fl(f, dir, stiffness * length);
+
+ // Ascher & Boxman, p.21: Damping only during elonglation
+ // something wrong with it...
+ madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
+
+ dfdx_spring(dfdx, dir, length, 0.0f, stiffness);
+ dfdv_damp(dfdv, dir, damping);
+
+ add_v3_v3(data->F[i], f);
+ add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfdx);
+ add_m3_m3m3(data->dFdV[i].m, data->dFdV[i].m, dfdv);
+
+ if (r_f) copy_v3_v3(r_f, f);
+ if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
+ if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
+
+ return true;
+ }
+ else {
+ if (r_f) zero_v3(r_f);
+ if (r_dfdx) zero_m3(r_dfdx);
+ if (r_dfdv) zero_m3(r_dfdv);
+
+ return false;
+ }
+}
+
+#endif /* IMPLICIT_SOLVER_BLENDER */
diff --git a/source/blender/physics/intern/implicit_eigen.cpp b/source/blender/physics/intern/implicit_eigen.cpp
new file mode 100644
index 00000000000..0ea8ccb0a49
--- /dev/null
+++ b/source/blender/physics/intern/implicit_eigen.cpp
@@ -0,0 +1,1369 @@
+/*
+ * ***** 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) Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/physics/intern/implicit_eigen.cpp
+ * \ingroup bph
+ */
+
+#include "implicit.h"
+
+#ifdef IMPLICIT_SOLVER_EIGEN
+
+//#define USE_EIGEN_CORE
+#define USE_EIGEN_CONSTRAINED_CG
+
+#ifdef __GNUC__
+# pragma GCC diagnostic push
+/* XXX suppress verbose warnings in eigen */
+# pragma GCC diagnostic ignored "-Wlogical-op"
+#endif
+
+#ifndef IMPLICIT_ENABLE_EIGEN_DEBUG
+#ifdef NDEBUG
+#define IMPLICIT_NDEBUG
+#endif
+#define NDEBUG
+#endif
+
+#include <Eigen/Sparse>
+#include <Eigen/src/Core/util/DisableStupidWarnings.h>
+
+#ifdef USE_EIGEN_CONSTRAINED_CG
+#include <intern/ConstrainedConjugateGradient.h>
+#endif
+
+#ifndef IMPLICIT_ENABLE_EIGEN_DEBUG
+#ifndef IMPLICIT_NDEBUG
+#undef NDEBUG
+#else
+#undef IMPLICIT_NDEBUG
+#endif
+#endif
+
+#ifdef __GNUC__
+# pragma GCC diagnostic pop
+#endif
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "DNA_scene_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_texture_types.h"
+
+#include "BLI_math.h"
+#include "BLI_linklist.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_cloth.h"
+#include "BKE_collision.h"
+#include "BKE_effect.h"
+#include "BKE_global.h"
+
+#include "BPH_mass_spring.h"
+}
+
+typedef float Scalar;
+
+static float I[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
+static float ZERO[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
+
+/* slightly extended Eigen vector class
+ * with conversion to/from plain C float array
+ */
+class fVector : public Eigen::Vector3f {
+public:
+ typedef float *ctype;
+
+ fVector()
+ {
+ }
+
+ fVector(const ctype &v)
+ {
+ for (int k = 0; k < 3; ++k)
+ coeffRef(k) = v[k];
+ }
+
+ fVector& operator = (const ctype &v)
+ {
+ for (int k = 0; k < 3; ++k)
+ coeffRef(k) = v[k];
+ return *this;
+ }
+
+ operator ctype()
+ {
+ return data();
+ }
+};
+
+/* slightly extended Eigen matrix class
+ * with conversion to/from plain C float array
+ */
+class fMatrix : public Eigen::Matrix3f {
+public:
+ typedef float (*ctype)[3];
+
+ fMatrix()
+ {
+ }
+
+ fMatrix(const ctype &v)
+ {
+ for (int k = 0; k < 3; ++k)
+ for (int l = 0; l < 3; ++l)
+ coeffRef(l, k) = v[k][l];
+ }
+
+ fMatrix& operator = (const ctype &v)
+ {
+ for (int k = 0; k < 3; ++k)
+ for (int l = 0; l < 3; ++l)
+ coeffRef(l, k) = v[k][l];
+ return *this;
+ }
+
+ operator ctype()
+ {
+ return (ctype)data();
+ }
+};
+
+/* Extension of dense Eigen vectors,
+ * providing 3-float block access for blenlib math functions
+ */
+class lVector : public Eigen::VectorXf {
+public:
+ typedef Eigen::VectorXf base_t;
+
+ lVector()
+ {
+ }
+
+ template <typename T>
+ lVector& operator = (T rhs)
+ {
+ base_t::operator=(rhs);
+ return *this;
+ }
+
+ float* v3(int vertex)
+ {
+ return &coeffRef(3 * vertex);
+ }
+
+ const float* v3(int vertex) const
+ {
+ return &coeffRef(3 * vertex);
+ }
+};
+
+typedef Eigen::Triplet<Scalar> Triplet;
+typedef std::vector<Triplet> TripletList;
+
+typedef Eigen::SparseMatrix<Scalar> lMatrix;
+
+/* Constructor type that provides more convenient handling of Eigen triplets
+ * for efficient construction of sparse 3x3 block matrices.
+ * This should be used for building lMatrix instead of writing to such lMatrix directly (which is very inefficient).
+ * After all elements have been defined using the set() method, the actual matrix can be filled using construct().
+ */
+struct lMatrixCtor {
+ lMatrixCtor()
+ {
+ }
+
+ void reset()
+ {
+ m_trips.clear();
+ }
+
+ void reserve(int numverts)
+ {
+ /* reserve for diagonal entries */
+ m_trips.reserve(numverts * 9);
+ }
+
+ void add(int i, int j, const fMatrix &m)
+ {
+ i *= 3;
+ j *= 3;
+ for (int k = 0; k < 3; ++k)
+ for (int l = 0; l < 3; ++l)
+ m_trips.push_back(Triplet(i + k, j + l, m.coeff(l, k)));
+ }
+
+ void sub(int i, int j, const fMatrix &m)
+ {
+ i *= 3;
+ j *= 3;
+ for (int k = 0; k < 3; ++k)
+ for (int l = 0; l < 3; ++l)
+ m_trips.push_back(Triplet(i + k, j + l, -m.coeff(l, k)));
+ }
+
+ inline void construct(lMatrix &m)
+ {
+ m.setFromTriplets(m_trips.begin(), m_trips.end());
+ m_trips.clear();
+ }
+
+private:
+ TripletList m_trips;
+};
+
+#ifdef USE_EIGEN_CORE
+typedef Eigen::ConjugateGradient<lMatrix, Eigen::Lower, Eigen::DiagonalPreconditioner<Scalar> > ConjugateGradient;
+#endif
+#ifdef USE_EIGEN_CONSTRAINED_CG
+typedef Eigen::ConstrainedConjugateGradient<lMatrix, Eigen::Lower, lMatrix,
+ Eigen::DiagonalPreconditioner<Scalar> >
+ ConstraintConjGrad;
+#endif
+using Eigen::ComputationInfo;
+
+static void print_lvector(const lVector &v)
+{
+ for (int i = 0; i < v.rows(); ++i) {
+ if (i > 0 && i % 3 == 0)
+ printf("\n");
+
+ printf("%f,\n", v[i]);
+ }
+}
+
+static void print_lmatrix(const lMatrix &m)
+{
+ for (int j = 0; j < m.rows(); ++j) {
+ if (j > 0 && j % 3 == 0)
+ printf("\n");
+
+ for (int i = 0; i < m.cols(); ++i) {
+ if (i > 0 && i % 3 == 0)
+ printf(" ");
+
+ implicit_print_matrix_elem(m.coeff(j, i));
+ }
+ printf("\n");
+ }
+}
+
+BLI_INLINE void lMatrix_reserve_elems(lMatrix &m, int num)
+{
+ m.reserve(Eigen::VectorXi::Constant(m.cols(), num));
+}
+
+BLI_INLINE float *lVector_v3(lVector &v, int vertex)
+{
+ return v.data() + 3 * vertex;
+}
+
+BLI_INLINE const float *lVector_v3(const lVector &v, int vertex)
+{
+ return v.data() + 3 * vertex;
+}
+
+#if 0
+BLI_INLINE void triplets_m3(TripletList &tlist, float m[3][3], int i, int j)
+{
+ i *= 3;
+ j *= 3;
+ for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; ++k) {
+ tlist.push_back(Triplet(i + k, j + l, m[k][l]));
+ }
+ }
+}
+
+BLI_INLINE void triplets_m3fl(TripletList &tlist, float m[3][3], int i, int j, float factor)
+{
+ i *= 3;
+ j *= 3;
+ for (int l = 0; l < 3; ++l) {
+ for (int k = 0; k < 3; ++k) {
+ tlist.push_back(Triplet(i + k, j + l, m[k][l] * factor));
+ }
+ }
+}
+
+BLI_INLINE void lMatrix_add_triplets(lMatrix &r, const TripletList &tlist)
+{
+ lMatrix t(r.rows(), r.cols());
+ t.setFromTriplets(tlist.begin(), tlist.end());
+ r += t;
+}
+
+BLI_INLINE void lMatrix_madd_triplets(lMatrix &r, const TripletList &tlist, float f)
+{
+ lMatrix t(r.rows(), r.cols());
+ t.setFromTriplets(tlist.begin(), tlist.end());
+ r += f * t;
+}
+
+BLI_INLINE void lMatrix_sub_triplets(lMatrix &r, const TripletList &tlist)
+{
+ lMatrix t(r.rows(), r.cols());
+ t.setFromTriplets(tlist.begin(), tlist.end());
+ r -= t;
+}
+#endif
+
+BLI_INLINE void outerproduct(float r[3][3], const float a[3], const float b[3])
+{
+ mul_v3_v3fl(r[0], a, b[0]);
+ mul_v3_v3fl(r[1], a, b[1]);
+ mul_v3_v3fl(r[2], a, b[2]);
+}
+
+BLI_INLINE void cross_m3_v3m3(float r[3][3], const float v[3], float m[3][3])
+{
+ cross_v3_v3v3(r[0], v, m[0]);
+ cross_v3_v3v3(r[1], v, m[1]);
+ cross_v3_v3v3(r[2], v, m[2]);
+}
+
+BLI_INLINE void cross_v3_identity(float r[3][3], const float v[3])
+{
+ r[0][0] = 0.0f; r[1][0] = v[2]; r[2][0] = -v[1];
+ r[0][1] = -v[2]; r[1][1] = 0.0f; r[2][1] = v[0];
+ r[0][2] = v[1]; r[1][2] = -v[0]; r[2][2] = 0.0f;
+}
+
+BLI_INLINE void madd_m3_m3fl(float r[3][3], float m[3][3], float f)
+{
+ r[0][0] += m[0][0] * f;
+ r[0][1] += m[0][1] * f;
+ r[0][2] += m[0][2] * f;
+ r[1][0] += m[1][0] * f;
+ r[1][1] += m[1][1] * f;
+ r[1][2] += m[1][2] * f;
+ r[2][0] += m[2][0] * f;
+ r[2][1] += m[2][1] * f;
+ r[2][2] += m[2][2] * f;
+}
+
+BLI_INLINE void madd_m3_m3m3fl(float r[3][3], float a[3][3], float b[3][3], float f)
+{
+ r[0][0] = a[0][0] + b[0][0] * f;
+ r[0][1] = a[0][1] + b[0][1] * f;
+ r[0][2] = a[0][2] + b[0][2] * f;
+ r[1][0] = a[1][0] + b[1][0] * f;
+ r[1][1] = a[1][1] + b[1][1] * f;
+ r[1][2] = a[1][2] + b[1][2] * f;
+ r[2][0] = a[2][0] + b[2][0] * f;
+ r[2][1] = a[2][1] + b[2][1] * f;
+ r[2][2] = a[2][2] + b[2][2] * f;
+}
+
+struct Implicit_Data {
+ typedef std::vector<fMatrix> fMatrixVector;
+
+ Implicit_Data(int numverts)
+ {
+ resize(numverts);
+ }
+
+ void resize(int numverts)
+ {
+ this->numverts = numverts;
+ int tot = 3 * numverts;
+
+ M.resize(tot, tot);
+ F.resize(tot);
+ dFdX.resize(tot, tot);
+ dFdV.resize(tot, tot);
+
+ tfm.resize(numverts, I);
+
+ X.resize(tot);
+ Xnew.resize(tot);
+ V.resize(tot);
+ Vnew.resize(tot);
+
+ A.resize(tot, tot);
+ B.resize(tot);
+
+ dV.resize(tot);
+ z.resize(tot);
+ S.resize(tot, tot);
+
+ iM.reserve(numverts);
+ idFdX.reserve(numverts);
+ idFdV.reserve(numverts);
+ iS.reserve(numverts);
+ }
+
+ int numverts;
+
+ /* inputs */
+ lMatrix M; /* masses */
+ lVector F; /* forces */
+ lMatrix dFdX, dFdV; /* force jacobians */
+
+ fMatrixVector tfm; /* local coordinate transform */
+
+ /* motion state data */
+ lVector X, Xnew; /* positions */
+ lVector V, Vnew; /* velocities */
+
+ /* internal solver data */
+ lVector B; /* B for A*dV = B */
+ lMatrix A; /* A for A*dV = B */
+
+ lVector dV; /* velocity change (solution of A*dV = B) */
+ lVector z; /* target velocity in constrained directions */
+ lMatrix S; /* filtering matrix for constraints */
+
+ /* temporary constructors */
+ lMatrixCtor iM; /* masses */
+ lMatrixCtor idFdX, idFdV; /* force jacobians */
+ lMatrixCtor iS; /* filtering matrix for constraints */
+};
+
+Implicit_Data *BPH_mass_spring_solver_create(int numverts, int numsprings)
+{
+ Implicit_Data *id = new Implicit_Data(numverts);
+ return id;
+}
+
+void BPH_mass_spring_solver_free(Implicit_Data *id)
+{
+ if (id)
+ delete id;
+}
+
+int BPH_mass_spring_solver_numvert(Implicit_Data *id)
+{
+ if (id)
+ return id->numverts;
+ else
+ return 0;
+}
+
+/* ==== Transformation from/to root reference frames ==== */
+
+BLI_INLINE void world_to_root_v3(Implicit_Data *data, int index, float r[3], const float v[3])
+{
+ copy_v3_v3(r, v);
+ mul_transposed_m3_v3(data->tfm[index], r);
+}
+
+BLI_INLINE void root_to_world_v3(Implicit_Data *data, int index, float r[3], const float v[3])
+{
+ mul_v3_m3v3(r, data->tfm[index], v);
+}
+
+BLI_INLINE void world_to_root_m3(Implicit_Data *data, int index, float r[3][3], float m[3][3])
+{
+ float trot[3][3];
+ copy_m3_m3(trot, data->tfm[index]);
+ transpose_m3(trot);
+ mul_m3_m3m3(r, trot, m);
+}
+
+BLI_INLINE void root_to_world_m3(Implicit_Data *data, int index, float r[3][3], float m[3][3])
+{
+ mul_m3_m3m3(r, data->tfm[index], m);
+}
+
+/* ================================ */
+
+bool BPH_mass_spring_solve_velocities(Implicit_Data *data, float dt, ImplicitSolverResult *result)
+{
+#ifdef USE_EIGEN_CORE
+ typedef ConjugateGradient solver_t;
+#endif
+#ifdef USE_EIGEN_CONSTRAINED_CG
+ typedef ConstraintConjGrad solver_t;
+#endif
+
+ data->iM.construct(data->M);
+ data->idFdX.construct(data->dFdX);
+ data->idFdV.construct(data->dFdV);
+ data->iS.construct(data->S);
+
+ solver_t cg;
+ cg.setMaxIterations(100);
+ cg.setTolerance(0.01f);
+
+#ifdef USE_EIGEN_CONSTRAINED_CG
+ cg.filter() = data->S;
+#endif
+
+ data->A = data->M - dt * data->dFdV - dt*dt * data->dFdX;
+ cg.compute(data->A);
+
+ data->B = dt * data->F + dt*dt * data->dFdX * data->V;
+
+#ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
+ printf("==== A ====\n");
+ print_lmatrix(id->A);
+ printf("==== z ====\n");
+ print_lvector(id->z);
+ printf("==== B ====\n");
+ print_lvector(id->B);
+ printf("==== S ====\n");
+ print_lmatrix(id->S);
+#endif
+
+#ifdef USE_EIGEN_CORE
+ data->dV = cg.solve(data->B);
+#endif
+#ifdef USE_EIGEN_CONSTRAINED_CG
+ data->dV = cg.solveWithGuess(data->B, data->z);
+#endif
+
+#ifdef IMPLICIT_PRINT_SOLVER_INPUT_OUTPUT
+ printf("==== dV ====\n");
+ print_lvector(id->dV);
+ printf("========\n");
+#endif
+
+ data->Vnew = data->V + data->dV;
+
+ switch (cg.info()) {
+ case Eigen::Success: result->status = BPH_SOLVER_SUCCESS; break;
+ case Eigen::NoConvergence: result->status = BPH_SOLVER_NO_CONVERGENCE; break;
+ case Eigen::InvalidInput: result->status = BPH_SOLVER_INVALID_INPUT; break;
+ case Eigen::NumericalIssue: result->status = BPH_SOLVER_NUMERICAL_ISSUE; break;
+ }
+
+ result->iterations = cg.iterations();
+ result->error = cg.error();
+
+ return cg.info() == Eigen::Success;
+}
+
+bool BPH_mass_spring_solve_positions(Implicit_Data *data, float dt)
+{
+ data->Xnew = data->X + data->Vnew * dt;
+ return true;
+}
+
+/* ================================ */
+
+void BPH_mass_spring_apply_result(Implicit_Data *data)
+{
+ data->X = data->Xnew;
+ data->V = data->Vnew;
+}
+
+void BPH_mass_spring_set_vertex_mass(Implicit_Data *data, int index, float mass)
+{
+ float m[3][3];
+ copy_m3_m3(m, I);
+ mul_m3_fl(m, mass);
+ data->iM.add(index, index, m);
+}
+
+void BPH_mass_spring_set_rest_transform(Implicit_Data *data, int index, float tfm[3][3])
+{
+#ifdef CLOTH_ROOT_FRAME
+ copy_m3_m3(data->tfm[index], tfm);
+#else
+ unit_m3(data->tfm[index]);
+ (void)tfm;
+#endif
+}
+
+void BPH_mass_spring_set_motion_state(Implicit_Data *data, int index, const float x[3], const float v[3])
+{
+ world_to_root_v3(data, index, data->X.v3(index), x);
+ world_to_root_v3(data, index, data->V.v3(index), v);
+}
+
+void BPH_mass_spring_set_position(Implicit_Data *data, int index, const float x[3])
+{
+ world_to_root_v3(data, index, data->X.v3(index), x);
+}
+
+void BPH_mass_spring_set_velocity(Implicit_Data *data, int index, const float v[3])
+{
+ world_to_root_v3(data, index, data->V.v3(index), v);
+}
+
+void BPH_mass_spring_get_motion_state(struct Implicit_Data *data, int index, float x[3], float v[3])
+{
+ if (x) root_to_world_v3(data, index, x, data->X.v3(index));
+ if (v) root_to_world_v3(data, index, v, data->V.v3(index));
+}
+
+void BPH_mass_spring_get_position(struct Implicit_Data *data, int index, float x[3])
+{
+ root_to_world_v3(data, index, x, data->X.v3(index));
+}
+
+void BPH_mass_spring_get_new_velocity(Implicit_Data *data, int index, float v[3])
+{
+ root_to_world_v3(data, index, v, data->V.v3(index));
+}
+
+void BPH_mass_spring_set_new_velocity(Implicit_Data *data, int index, const float v[3])
+{
+ world_to_root_v3(data, index, data->V.v3(index), v);
+}
+
+void BPH_mass_spring_clear_constraints(Implicit_Data *data)
+{
+ int numverts = data->numverts;
+ for (int i = 0; i < numverts; ++i) {
+ data->iS.add(i, i, I);
+ zero_v3(data->z.v3(i));
+ }
+}
+
+void BPH_mass_spring_add_constraint_ndof0(Implicit_Data *data, int index, const float dV[3])
+{
+ data->iS.sub(index, index, I);
+
+ world_to_root_v3(data, index, data->z.v3(index), dV);
+}
+
+void BPH_mass_spring_add_constraint_ndof1(Implicit_Data *data, int index, const float c1[3], const float c2[3], const float dV[3])
+{
+ float m[3][3], p[3], q[3], u[3], cmat[3][3];
+
+ world_to_root_v3(data, index, p, c1);
+ outerproduct(cmat, p, p);
+ copy_m3_m3(m, cmat);
+
+ world_to_root_v3(data, index, q, c2);
+ outerproduct(cmat, q, q);
+ add_m3_m3m3(m, m, cmat);
+
+ /* XXX not sure but multiplication should work here */
+ data->iS.sub(index, index, m);
+// mul_m3_m3m3(data->S[index].m, data->S[index].m, m);
+
+ world_to_root_v3(data, index, u, dV);
+ add_v3_v3(data->z.v3(index), u);
+}
+
+void BPH_mass_spring_add_constraint_ndof2(Implicit_Data *data, int index, const float c1[3], const float dV[3])
+{
+ float m[3][3], p[3], u[3], cmat[3][3];
+
+ world_to_root_v3(data, index, p, c1);
+ outerproduct(cmat, p, p);
+ copy_m3_m3(m, cmat);
+
+ data->iS.sub(index, index, m);
+// mul_m3_m3m3(data->S[index].m, data->S[index].m, m);
+
+ world_to_root_v3(data, index, u, dV);
+ add_v3_v3(data->z.v3(index), u);
+}
+
+void BPH_mass_spring_clear_forces(Implicit_Data *data)
+{
+ data->F.setZero();
+ data->dFdX.setZero();
+ data->dFdV.setZero();
+}
+
+void BPH_mass_spring_force_reference_frame(Implicit_Data *data, int index, const float acceleration[3], const float omega[3], const float domega_dt[3], float mass)
+{
+#ifdef CLOTH_ROOT_FRAME
+ float acc[3], w[3], dwdt[3];
+ float f[3], dfdx[3][3], dfdv[3][3];
+ float euler[3], coriolis[3], centrifugal[3], rotvel[3];
+ float deuler[3][3], dcoriolis[3][3], dcentrifugal[3][3], drotvel[3][3];
+
+ world_to_root_v3(data, index, acc, acceleration);
+ world_to_root_v3(data, index, w, omega);
+ world_to_root_v3(data, index, dwdt, domega_dt);
+
+ cross_v3_v3v3(euler, dwdt, data->X.v3(index));
+ cross_v3_v3v3(coriolis, w, data->V.v3(index));
+ mul_v3_fl(coriolis, 2.0f);
+ cross_v3_v3v3(rotvel, w, data->X.v3(index));
+ cross_v3_v3v3(centrifugal, w, rotvel);
+
+ sub_v3_v3v3(f, acc, euler);
+ sub_v3_v3(f, coriolis);
+ sub_v3_v3(f, centrifugal);
+
+ mul_v3_fl(f, mass); /* F = m * a */
+
+ cross_v3_identity(deuler, dwdt);
+ cross_v3_identity(dcoriolis, w);
+ mul_m3_fl(dcoriolis, 2.0f);
+ cross_v3_identity(drotvel, w);
+ cross_m3_v3m3(dcentrifugal, w, drotvel);
+
+ add_m3_m3m3(dfdx, deuler, dcentrifugal);
+ negate_m3(dfdx);
+ mul_m3_fl(dfdx, mass);
+
+ copy_m3_m3(dfdv, dcoriolis);
+ negate_m3(dfdv);
+ mul_m3_fl(dfdv, mass);
+
+ add_v3_v3(data->F.v3(index), f);
+ data->idFdX.add(index, index, dfdx);
+ data->idFdV.add(index, index, dfdv);
+#else
+ (void)data;
+ (void)index;
+ (void)acceleration;
+ (void)omega;
+ (void)domega_dt;
+#endif
+}
+
+void BPH_mass_spring_force_gravity(Implicit_Data *data, int index, float mass, const float g[3])
+{
+ /* force = mass * acceleration (in this case: gravity) */
+ float f[3];
+ world_to_root_v3(data, index, f, g);
+ mul_v3_fl(f, mass);
+
+ add_v3_v3(data->F.v3(index), f);
+}
+
+void BPH_mass_spring_force_drag(Implicit_Data *data, float drag)
+{
+ int numverts = data->numverts;
+ for (int i = 0; i < numverts; i++) {
+ float tmp[3][3];
+
+ /* NB: uses root space velocity, no need to transform */
+ madd_v3_v3fl(data->F.v3(i), data->V.v3(i), -drag);
+
+ copy_m3_m3(tmp, I);
+ mul_m3_fl(tmp, -drag);
+ data->idFdV.add(i, i, tmp);
+ }
+}
+
+void BPH_mass_spring_force_extern(struct Implicit_Data *data, int i, const float f[3], float dfdx[3][3], float dfdv[3][3])
+{
+ float tf[3], tdfdx[3][3], tdfdv[3][3];
+ world_to_root_v3(data, i, tf, f);
+ world_to_root_m3(data, i, tdfdx, dfdx);
+ world_to_root_m3(data, i, tdfdv, dfdv);
+
+ add_v3_v3(data->F.v3(i), tf);
+ data->idFdX.add(i, i, tdfdx);
+ data->idFdV.add(i, i, tdfdv);
+}
+
+static float calc_nor_area_tri(float nor[3], const float v1[3], const float v2[3], const float v3[3])
+{
+ float n1[3], n2[3];
+
+ sub_v3_v3v3(n1, v1, v2);
+ sub_v3_v3v3(n2, v2, v3);
+
+ cross_v3_v3v3(nor, n1, n2);
+ return normalize_v3(nor);
+}
+
+static float calc_nor_area_quad(float nor[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
+{
+ float n1[3], n2[3];
+
+ sub_v3_v3v3(n1, v1, v3);
+ sub_v3_v3v3(n2, v2, v4);
+
+ cross_v3_v3v3(nor, n1, n2);
+ return normalize_v3(nor);
+}
+
+/* XXX does not support force jacobians yet, since the effector system does not provide them either */
+void BPH_mass_spring_force_face_wind(Implicit_Data *data, int v1, int v2, int v3, int v4, const float (*winvec)[3])
+{
+ const float effector_scale = 0.02f;
+ float win[3], nor[3], area;
+ float factor;
+
+ // calculate face normal and area
+ if (v4) {
+ area = calc_nor_area_quad(nor, data->X.v3(v1), data->X.v3(v2), data->X.v3(v3), data->X.v3(v4));
+ factor = effector_scale * area * 0.25f;
+ }
+ else {
+ area = calc_nor_area_tri(nor, data->X.v3(v1), data->X.v3(v2), data->X.v3(v3));
+ factor = effector_scale * area / 3.0f;
+ }
+
+ world_to_root_v3(data, v1, win, winvec[v1]);
+ madd_v3_v3fl(data->F.v3(v1), nor, factor * dot_v3v3(win, nor));
+
+ world_to_root_v3(data, v2, win, winvec[v2]);
+ madd_v3_v3fl(data->F.v3(v2), nor, factor * dot_v3v3(win, nor));
+
+ world_to_root_v3(data, v3, win, winvec[v3]);
+ madd_v3_v3fl(data->F.v3(v3), nor, factor * dot_v3v3(win, nor));
+
+ if (v4) {
+ world_to_root_v3(data, v4, win, winvec[v4]);
+ madd_v3_v3fl(data->F.v3(v4), nor, factor * dot_v3v3(win, nor));
+ }
+}
+
+void BPH_mass_spring_force_edge_wind(Implicit_Data *data, int v1, int v2, const float (*winvec)[3])
+{
+ const float effector_scale = 0.01;
+ float win[3], dir[3], nor[3], length;
+
+ sub_v3_v3v3(dir, data->X.v3(v1), data->X.v3(v2));
+ length = normalize_v3(dir);
+
+ world_to_root_v3(data, v1, win, winvec[v1]);
+ madd_v3_v3v3fl(nor, win, dir, -dot_v3v3(win, dir));
+ madd_v3_v3fl(data->F.v3(v1), nor, effector_scale * length);
+
+ world_to_root_v3(data, v2, win, winvec[v2]);
+ madd_v3_v3v3fl(nor, win, dir, -dot_v3v3(win, dir));
+ madd_v3_v3fl(data->F.v3(v2), nor, effector_scale * length);
+}
+
+BLI_INLINE void dfdx_spring(float to[3][3], const float dir[3], float length, float L, float k)
+{
+ // dir is unit length direction, rest is spring's restlength, k is spring constant.
+ //return ( (I-outerprod(dir, dir))*Min(1.0f, rest/length) - I) * -k;
+ outerproduct(to, dir, dir);
+ sub_m3_m3m3(to, I, to);
+
+ mul_m3_fl(to, (L/length));
+ sub_m3_m3m3(to, to, I);
+ mul_m3_fl(to, k);
+}
+
+/* unused */
+#if 0
+BLI_INLINE void dfdx_damp(float to[3][3], const float dir[3], float length, const float vel[3], float rest, float damping)
+{
+ // inner spring damping vel is the relative velocity of the endpoints.
+ // return (I-outerprod(dir, dir)) * (-damping * -(dot(dir, vel)/Max(length, rest)));
+ mul_fvectorT_fvector(to, dir, dir);
+ sub_fmatrix_fmatrix(to, I, to);
+ mul_fmatrix_S(to, (-damping * -(dot_v3v3(dir, vel)/MAX2(length, rest))));
+}
+#endif
+
+BLI_INLINE void dfdv_damp(float to[3][3], const float dir[3], float damping)
+{
+ // derivative of force wrt velocity
+ outerproduct(to, dir, dir);
+ mul_m3_fl(to, -damping);
+}
+
+BLI_INLINE float fb(float length, float L)
+{
+ float x = length / L;
+ return (-11.541f * powf(x, 4) + 34.193f * powf(x, 3) - 39.083f * powf(x, 2) + 23.116f * x - 9.713f);
+}
+
+BLI_INLINE float fbderiv(float length, float L)
+{
+ float x = length/L;
+
+ return (-46.164f * powf(x, 3) + 102.579f * powf(x, 2) - 78.166f * x + 23.116f);
+}
+
+BLI_INLINE float fbstar(float length, float L, float kb, float cb)
+{
+ float tempfb_fl = kb * fb(length, L);
+ float fbstar_fl = cb * (length - L);
+
+ if (tempfb_fl < fbstar_fl)
+ return fbstar_fl;
+ else
+ return tempfb_fl;
+}
+
+// function to calculae bending spring force (taken from Choi & Co)
+BLI_INLINE float fbstar_jacobi(float length, float L, float kb, float cb)
+{
+ float tempfb_fl = kb * fb(length, L);
+ float fbstar_fl = cb * (length - L);
+
+ if (tempfb_fl < fbstar_fl) {
+ return -cb;
+ }
+ else {
+ return -kb * fbderiv(length, L);
+ }
+}
+
+/* calculate elonglation */
+BLI_INLINE bool spring_length(Implicit_Data *data, int i, int j, float r_extent[3], float r_dir[3], float *r_length, float r_vel[3])
+{
+ sub_v3_v3v3(r_extent, data->X.v3(j), data->X.v3(i));
+ sub_v3_v3v3(r_vel, data->V.v3(j), data->V.v3(i));
+ *r_length = len_v3(r_extent);
+
+ if (*r_length > ALMOST_ZERO) {
+ /*
+ if (length>L) {
+ if ((clmd->sim_parms->flags & CSIMSETT_FLAG_TEARING_ENABLED) &&
+ ( ((length-L)*100.0f/L) > clmd->sim_parms->maxspringlen )) {
+ // cut spring!
+ s->flags |= CSPRING_FLAG_DEACTIVATE;
+ return false;
+ }
+ }
+ */
+ mul_v3_v3fl(r_dir, r_extent, 1.0f/(*r_length));
+ }
+ else {
+ zero_v3(r_dir);
+ }
+
+ return true;
+}
+
+BLI_INLINE void apply_spring(Implicit_Data *data, int i, int j, const float f[3], float dfdx[3][3], float dfdv[3][3])
+{
+ add_v3_v3(data->F.v3(i), f);
+ sub_v3_v3(data->F.v3(j), f);
+
+ data->idFdX.add(i, i, dfdx);
+ data->idFdX.add(j, j, dfdx);
+ data->idFdX.sub(i, j, dfdx);
+ data->idFdX.sub(j, i, dfdx);
+
+ data->idFdV.add(i, i, dfdv);
+ data->idFdV.add(j, j, dfdv);
+ data->idFdV.sub(i, j, dfdv);
+ data->idFdV.sub(j, i, dfdv);
+}
+
+bool BPH_mass_spring_force_spring_linear(Implicit_Data *data, int i, int j, float restlen,
+ float stiffness, float damping, bool no_compress, float clamp_force,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+{
+ float extent[3], length, dir[3], vel[3];
+
+ // calculate elonglation
+ spring_length(data, i, j, extent, dir, &length, vel);
+
+ if (length > restlen || no_compress) {
+ float stretch_force, f[3], dfdx[3][3], dfdv[3][3];
+
+ stretch_force = stiffness * (length - restlen);
+ if (clamp_force > 0.0f && stretch_force > clamp_force) {
+ stretch_force = clamp_force;
+ }
+ mul_v3_v3fl(f, dir, stretch_force);
+
+ // Ascher & Boxman, p.21: Damping only during elonglation
+ // something wrong with it...
+ madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
+
+ dfdx_spring(dfdx, dir, length, restlen, stiffness);
+ dfdv_damp(dfdv, dir, damping);
+
+ apply_spring(data, i, j, f, dfdx, dfdv);
+
+ if (r_f) copy_v3_v3(r_f, f);
+ if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
+ if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
+
+ return true;
+ }
+ else {
+ if (r_f) zero_v3(r_f);
+ if (r_dfdx) zero_m3(r_dfdx);
+ if (r_dfdv) zero_m3(r_dfdv);
+
+ return false;
+ }
+}
+
+/* See "Stable but Responsive Cloth" (Choi, Ko 2005) */
+bool BPH_mass_spring_force_spring_bending(Implicit_Data *data, int i, int j, float restlen,
+ float kb, float cb,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+{
+ float extent[3], length, dir[3], vel[3];
+
+ // calculate elonglation
+ spring_length(data, i, j, extent, dir, &length, vel);
+
+ if (length < restlen) {
+ float f[3], dfdx[3][3], dfdv[3][3];
+
+ mul_v3_v3fl(f, dir, fbstar(length, restlen, kb, cb));
+
+ outerproduct(dfdx, dir, dir);
+ mul_m3_fl(dfdx, fbstar_jacobi(length, restlen, kb, cb));
+
+ /* XXX damping not supported */
+ zero_m3(dfdv);
+
+ apply_spring(data, i, j, f, dfdx, dfdv);
+
+ if (r_f) copy_v3_v3(r_f, f);
+ if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
+ if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
+
+ return true;
+ }
+ else {
+ if (r_f) zero_v3(r_f);
+ if (r_dfdx) zero_m3(r_dfdx);
+ if (r_dfdv) zero_m3(r_dfdv);
+
+ return false;
+ }
+}
+
+/* Jacobian of a direction vector.
+ * Basically the part of the differential orthogonal to the direction,
+ * inversely proportional to the length of the edge.
+ *
+ * dD_ij/dx_i = -dD_ij/dx_j = (D_ij * D_ij^T - I) / len_ij
+ */
+BLI_INLINE void spring_grad_dir(Implicit_Data *data, int i, int j, float edge[3], float dir[3], float grad_dir[3][3])
+{
+ float length;
+
+ sub_v3_v3v3(edge, data->X.v3(j), data->X.v3(i));
+ length = normalize_v3_v3(dir, edge);
+
+ if (length > ALMOST_ZERO) {
+ outerproduct(grad_dir, dir, dir);
+ sub_m3_m3m3(grad_dir, I, grad_dir);
+ mul_m3_fl(grad_dir, 1.0f / length);
+ }
+ else {
+ zero_m3(grad_dir);
+ }
+}
+
+BLI_INLINE void spring_angbend_forces(Implicit_Data *data, int i, int j, int k,
+ const float goal[3],
+ float stiffness, float damping,
+ int q, const float dx[3], const float dv[3],
+ float r_f[3])
+{
+ float edge_ij[3], dir_ij[3];
+ float edge_jk[3], dir_jk[3];
+ float vel_ij[3], vel_jk[3], vel_ortho[3];
+ float f_bend[3], f_damp[3];
+ float fk[3];
+ float dist[3];
+
+ zero_v3(fk);
+
+ sub_v3_v3v3(edge_ij, data->X.v3(j), data->X.v3(i));
+ if (q == i) sub_v3_v3(edge_ij, dx);
+ if (q == j) add_v3_v3(edge_ij, dx);
+ normalize_v3_v3(dir_ij, edge_ij);
+
+ sub_v3_v3v3(edge_jk, data->X.v3(k), data->X.v3(j));
+ if (q == j) sub_v3_v3(edge_jk, dx);
+ if (q == k) add_v3_v3(edge_jk, dx);
+ normalize_v3_v3(dir_jk, edge_jk);
+
+ sub_v3_v3v3(vel_ij, data->V.v3(j), data->V.v3(i));
+ if (q == i) sub_v3_v3(vel_ij, dv);
+ if (q == j) add_v3_v3(vel_ij, dv);
+
+ sub_v3_v3v3(vel_jk, data->V.v3(k), data->V.v3(j));
+ if (q == j) sub_v3_v3(vel_jk, dv);
+ if (q == k) add_v3_v3(vel_jk, dv);
+
+ /* bending force */
+ sub_v3_v3v3(dist, goal, edge_jk);
+ mul_v3_v3fl(f_bend, dist, stiffness);
+
+ add_v3_v3(fk, f_bend);
+
+ /* damping force */
+ madd_v3_v3v3fl(vel_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk));
+ mul_v3_v3fl(f_damp, vel_ortho, damping);
+
+ sub_v3_v3(fk, f_damp);
+
+ copy_v3_v3(r_f, fk);
+}
+
+/* Finite Differences method for estimating the jacobian of the force */
+BLI_INLINE void spring_angbend_estimate_dfdx(Implicit_Data *data, int i, int j, int k,
+ const float goal[3],
+ float stiffness, float damping,
+ int q, float dfdx[3][3])
+{
+ const float delta = 0.00001f; // TODO find a good heuristic for this
+ float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3];
+ float f[3];
+ int a, b;
+
+ zero_m3(dvec_null);
+ unit_m3(dvec_pos);
+ mul_m3_fl(dvec_pos, delta * 0.5f);
+ copy_m3_m3(dvec_neg, dvec_pos);
+ negate_m3(dvec_neg);
+
+ /* XXX TODO offset targets to account for position dependency */
+
+ for (a = 0; a < 3; ++a) {
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ q, dvec_pos[a], dvec_null[a], f);
+ copy_v3_v3(dfdx[a], f);
+
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ q, dvec_neg[a], dvec_null[a], f);
+ sub_v3_v3(dfdx[a], f);
+
+ for (b = 0; b < 3; ++b) {
+ dfdx[a][b] /= delta;
+ }
+ }
+}
+
+/* Finite Differences method for estimating the jacobian of the force */
+BLI_INLINE void spring_angbend_estimate_dfdv(Implicit_Data *data, int i, int j, int k,
+ const float goal[3],
+ float stiffness, float damping,
+ int q, float dfdv[3][3])
+{
+ const float delta = 0.00001f; // TODO find a good heuristic for this
+ float dvec_null[3][3], dvec_pos[3][3], dvec_neg[3][3];
+ float f[3];
+ int a, b;
+
+ zero_m3(dvec_null);
+ unit_m3(dvec_pos);
+ mul_m3_fl(dvec_pos, delta * 0.5f);
+ copy_m3_m3(dvec_neg, dvec_pos);
+ negate_m3(dvec_neg);
+
+ /* XXX TODO offset targets to account for position dependency */
+
+ for (a = 0; a < 3; ++a) {
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ q, dvec_null[a], dvec_pos[a], f);
+ copy_v3_v3(dfdv[a], f);
+
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping,
+ q, dvec_null[a], dvec_neg[a], f);
+ sub_v3_v3(dfdv[a], f);
+
+ for (b = 0; b < 3; ++b) {
+ dfdv[a][b] /= delta;
+ }
+ }
+}
+
+/* Angular spring that pulls the vertex toward the local target
+ * See "Artistic Simulation of Curly Hair" (Pixar technical memo #12-03a)
+ */
+bool BPH_mass_spring_force_spring_bending_angular(Implicit_Data *data, int i, int j, int k,
+ const float target[3], float stiffness, float damping)
+{
+ float goal[3];
+ float fj[3], fk[3];
+ float dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
+ float dfj_dvi[3][3], dfj_dvj[3][3], dfk_dvi[3][3], dfk_dvj[3][3], dfk_dvk[3][3];
+
+ const float vecnull[3] = {0.0f, 0.0f, 0.0f};
+
+ world_to_root_v3(data, j, goal, target);
+
+ spring_angbend_forces(data, i, j, k, goal, stiffness, damping, k, vecnull, vecnull, fk);
+ negate_v3_v3(fj, fk); /* counterforce */
+
+ spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, i, dfk_dxi);
+ spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, j, dfk_dxj);
+ spring_angbend_estimate_dfdx(data, i, j, k, goal, stiffness, damping, k, dfk_dxk);
+ copy_m3_m3(dfj_dxi, dfk_dxi); negate_m3(dfj_dxi);
+ copy_m3_m3(dfj_dxj, dfk_dxj); negate_m3(dfj_dxj);
+
+ spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, i, dfk_dvi);
+ spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, j, dfk_dvj);
+ spring_angbend_estimate_dfdv(data, i, j, k, goal, stiffness, damping, k, dfk_dvk);
+ copy_m3_m3(dfj_dvi, dfk_dvi); negate_m3(dfj_dvi);
+ copy_m3_m3(dfj_dvj, dfk_dvj); negate_m3(dfj_dvj);
+
+ /* add forces and jacobians to the solver data */
+
+ add_v3_v3(data->F.v3(j), fj);
+ add_v3_v3(data->F.v3(k), fk);
+
+ data->idFdX.add(j, j, dfj_dxj);
+ data->idFdX.add(k, k, dfk_dxk);
+
+ data->idFdX.add(i, j, dfj_dxi);
+ data->idFdX.add(j, i, dfj_dxi);
+ data->idFdX.add(j, k, dfk_dxj);
+ data->idFdX.add(k, j, dfk_dxj);
+ data->idFdX.add(i, k, dfk_dxi);
+ data->idFdX.add(k, i, dfk_dxi);
+
+ data->idFdV.add(j, j, dfj_dvj);
+ data->idFdV.add(k, k, dfk_dvk);
+
+ data->idFdV.add(i, j, dfj_dvi);
+ data->idFdV.add(j, i, dfj_dvi);
+ data->idFdV.add(j, k, dfk_dvj);
+ data->idFdV.add(k, j, dfk_dvj);
+ data->idFdV.add(i, k, dfk_dvi);
+ data->idFdV.add(k, i, dfk_dvi);
+
+ /* XXX analytical calculation of derivatives below is incorrect.
+ * This proved to be difficult, but for now just using the finite difference method for
+ * estimating the jacobians should be sufficient.
+ */
+#if 0
+ float edge_ij[3], dir_ij[3], grad_dir_ij[3][3];
+ float edge_jk[3], dir_jk[3], grad_dir_jk[3][3];
+ float dist[3], vel_jk[3], vel_jk_ortho[3], projvel[3];
+ float target[3];
+ float tmp[3][3];
+ float fi[3], fj[3], fk[3];
+ float dfi_dxi[3][3], dfj_dxi[3][3], dfj_dxj[3][3], dfk_dxi[3][3], dfk_dxj[3][3], dfk_dxk[3][3];
+ float dfdvi[3][3];
+
+ // TESTING
+ damping = 0.0f;
+
+ zero_v3(fi);
+ zero_v3(fj);
+ zero_v3(fk);
+ zero_m3(dfi_dxi);
+ zero_m3(dfj_dxi);
+ zero_m3(dfk_dxi);
+ zero_m3(dfk_dxj);
+ zero_m3(dfk_dxk);
+
+ /* jacobian of direction vectors */
+ spring_grad_dir(data, i, j, edge_ij, dir_ij, grad_dir_ij);
+ spring_grad_dir(data, j, k, edge_jk, dir_jk, grad_dir_jk);
+
+ sub_v3_v3v3(vel_jk, data->V[k], data->V[j]);
+
+ /* bending force */
+ mul_v3_v3fl(target, dir_ij, restlen);
+ sub_v3_v3v3(dist, target, edge_jk);
+ mul_v3_v3fl(fk, dist, stiffness);
+
+ /* damping force */
+ madd_v3_v3v3fl(vel_jk_ortho, vel_jk, dir_jk, -dot_v3v3(vel_jk, dir_jk));
+ madd_v3_v3fl(fk, vel_jk_ortho, damping);
+
+ /* XXX this only holds true as long as we assume straight rest shape!
+ * eventually will become a bit more involved since the opposite segment
+ * gets its own target, under condition of having equal torque on both sides.
+ */
+ copy_v3_v3(fi, fk);
+
+ /* counterforce on the middle point */
+ sub_v3_v3(fj, fi);
+ sub_v3_v3(fj, fk);
+
+ /* === derivatives === */
+
+ madd_m3_m3fl(dfk_dxi, grad_dir_ij, stiffness * restlen);
+
+ madd_m3_m3fl(dfk_dxj, grad_dir_ij, -stiffness * restlen);
+ madd_m3_m3fl(dfk_dxj, I, stiffness);
+
+ madd_m3_m3fl(dfk_dxk, I, -stiffness);
+
+ copy_m3_m3(dfi_dxi, dfk_dxk);
+ negate_m3(dfi_dxi);
+
+ /* dfj_dfi == dfi_dfj due to symmetry,
+ * dfi_dfj == dfk_dfj due to fi == fk
+ * XXX see comment above on future bent rest shapes
+ */
+ copy_m3_m3(dfj_dxi, dfk_dxj);
+
+ /* dfj_dxj == -(dfi_dxj + dfk_dxj) due to fj == -(fi + fk) */
+ sub_m3_m3m3(dfj_dxj, dfj_dxj, dfj_dxi);
+ sub_m3_m3m3(dfj_dxj, dfj_dxj, dfk_dxj);
+
+ /* add forces and jacobians to the solver data */
+ add_v3_v3(data->F[i], fi);
+ add_v3_v3(data->F[j], fj);
+ add_v3_v3(data->F[k], fk);
+
+ add_m3_m3m3(data->dFdX[i].m, data->dFdX[i].m, dfi_dxi);
+ add_m3_m3m3(data->dFdX[j].m, data->dFdX[j].m, dfj_dxj);
+ add_m3_m3m3(data->dFdX[k].m, data->dFdX[k].m, dfk_dxk);
+
+ add_m3_m3m3(data->dFdX[block_ij].m, data->dFdX[block_ij].m, dfj_dxi);
+ add_m3_m3m3(data->dFdX[block_jk].m, data->dFdX[block_jk].m, dfk_dxj);
+ add_m3_m3m3(data->dFdX[block_ik].m, data->dFdX[block_ik].m, dfk_dxi);
+#endif
+
+ return true;
+}
+
+bool BPH_mass_spring_force_spring_goal(Implicit_Data *data, int i, const float goal_x[3], const float goal_v[3],
+ float stiffness, float damping,
+ float r_f[3], float r_dfdx[3][3], float r_dfdv[3][3])
+{
+ float root_goal_x[3], root_goal_v[3], extent[3], length, dir[3], vel[3];
+ float f[3], dfdx[3][3], dfdv[3][3];
+
+ /* goal is in world space */
+ world_to_root_v3(data, i, root_goal_x, goal_x);
+ world_to_root_v3(data, i, root_goal_v, goal_v);
+
+ sub_v3_v3v3(extent, root_goal_x, data->X.v3(i));
+ sub_v3_v3v3(vel, root_goal_v, data->V.v3(i));
+ length = normalize_v3_v3(dir, extent);
+
+ if (length > ALMOST_ZERO) {
+ mul_v3_v3fl(f, dir, stiffness * length);
+
+ // Ascher & Boxman, p.21: Damping only during elonglation
+ // something wrong with it...
+ madd_v3_v3fl(f, dir, damping * dot_v3v3(vel, dir));
+
+ dfdx_spring(dfdx, dir, length, 0.0f, stiffness);
+ dfdv_damp(dfdv, dir, damping);
+
+ add_v3_v3(data->F.v3(i), f);
+ data->idFdX.add(i, i, dfdx);
+ data->idFdV.add(i, i, dfdv);
+
+ if (r_f) copy_v3_v3(r_f, f);
+ if (r_dfdx) copy_m3_m3(r_dfdx, dfdx);
+ if (r_dfdv) copy_m3_m3(r_dfdv, dfdv);
+
+ return true;
+ }
+ else {
+ if (r_f) zero_v3(r_f);
+ if (r_dfdx) zero_m3(r_dfdx);
+ if (r_dfdv) zero_m3(r_dfdv);
+
+ return false;
+ }
+}
+
+#endif /* IMPLICIT_SOLVER_EIGEN */
diff --git a/source/blender/python/generic/bpy_internal_import.c b/source/blender/python/generic/bpy_internal_import.c
index b0539607bdc..ed2752d8372 100644
--- a/source/blender/python/generic/bpy_internal_import.c
+++ b/source/blender/python/generic/bpy_internal_import.c
@@ -81,7 +81,7 @@ void bpy_import_init(PyObject *builtins)
/* move reload here
* XXX, use import hooks */
- mod = PyImport_ImportModuleLevel("imp", NULL, NULL, NULL, 0);
+ mod = PyImport_ImportModuleLevel("importlib", NULL, NULL, NULL, 0);
if (mod) {
PyObject *mod_dict = PyModule_GetDict(mod);
@@ -93,7 +93,7 @@ void bpy_import_init(PyObject *builtins)
Py_DECREF(mod);
}
else {
- BLI_assert(!"unable to load 'imp' module.");
+ BLI_assert(!"unable to load 'importlib' module.");
}
}
diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c
index 678fd62ae89..cca419101d3 100644
--- a/source/blender/python/intern/bpy_app.c
+++ b/source/blender/python/intern/bpy_app.c
@@ -283,6 +283,7 @@ static PyGetSetDef bpy_app_getsets[] = {
{(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_simdata", bpy_app_debug_get, bpy_app_debug_set, (char *)bpy_app_debug_doc, (void *)G_DEBUG_SIMDATA},
{(char *)"debug_value", bpy_app_debug_value_get, bpy_app_debug_value_set, (char *)bpy_app_debug_value_doc, NULL},
{(char *)"tempdir", bpy_app_tempdir_get, NULL, (char *)bpy_app_tempdir_doc, NULL},
diff --git a/source/blender/python/intern/bpy_app_translations.c b/source/blender/python/intern/bpy_app_translations.c
index 1a56c0f7c59..17a2038b7dc 100644
--- a/source/blender/python/intern/bpy_app_translations.c
+++ b/source/blender/python/intern/bpy_app_translations.c
@@ -260,7 +260,7 @@ const char *BPY_app_translations_py_pgettext(const char *msgctxt, const char *ms
return msgid;
tmp = BLF_lang_get();
- if (strcmp(tmp, locale) || !_translations_cache) {
+ if (!STREQ(tmp, locale) || !_translations_cache) {
PyGILState_STATE _py_state;
BLI_strncpy(locale, tmp, STATIC_LOCALE_SIZE);
diff --git a/source/blender/python/mathutils/CMakeLists.txt b/source/blender/python/mathutils/CMakeLists.txt
index 133b8d3895c..ef6b090140b 100644
--- a/source/blender/python/mathutils/CMakeLists.txt
+++ b/source/blender/python/mathutils/CMakeLists.txt
@@ -38,6 +38,7 @@ set(SRC
mathutils_Quaternion.c
mathutils_Vector.c
mathutils_geometry.c
+ mathutils_interpolate.c
mathutils_kdtree.c
mathutils_noise.c
@@ -48,6 +49,7 @@ set(SRC
mathutils_Quaternion.h
mathutils_Vector.h
mathutils_geometry.h
+ mathutils_interpolate.h
mathutils_kdtree.h
mathutils_noise.h
)
diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c
index 6fe8dc3866b..ca20f837b4a 100644
--- a/source/blender/python/mathutils/mathutils.c
+++ b/source/blender/python/mathutils/mathutils.c
@@ -38,7 +38,18 @@
#endif
PyDoc_STRVAR(M_Mathutils_doc,
-"This module provides access to matrices, eulers, quaternions and vectors."
+"This module provides access to the math classes:\n"
+"\n"
+"- :class:`Color`,\n"
+"- :class:`Euler`,\n"
+"- :class:`Matrix`,\n"
+"- :class:`Quaternion`,\n"
+"- :class:`Vector`,\n"
+"\n"
+".. note::\n"
+"\n"
+" Classes, methods and attributes that accept vectors also accept other numeric sequences,\n"
+" such as tuples, lists."
);
static int mathutils_array_parse_fast(float *array,
int size,
@@ -502,6 +513,7 @@ static struct PyModuleDef M_Mathutils_module_def = {
/* submodules only */
#include "mathutils_geometry.h"
+#include "mathutils_interpolate.h"
#ifndef MATH_STANDALONE
# include "mathutils_kdtree.h"
# include "mathutils_noise.h"
@@ -543,6 +555,13 @@ PyMODINIT_FUNC PyInit_mathutils(void)
PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
Py_INCREF(submodule);
+ PyModule_AddObject(mod, "interpolate", (submodule = PyInit_mathutils_interpolate()));
+ /* XXX, python doesnt do imports with this usefully yet
+ * 'from mathutils.geometry import PolyFill'
+ * ...fails without this. */
+ PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ Py_INCREF(submodule);
+
#ifndef MATH_STANDALONE
/* Noise submodule */
PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise()));
diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c
index 8426038f2d4..ce590999bc1 100644
--- a/source/blender/python/mathutils/mathutils_Color.c
+++ b/source/blender/python/mathutils/mathutils_Color.c
@@ -811,7 +811,12 @@ static struct PyMethodDef Color_methods[] = {
/* ------------------PY_OBECT DEFINITION-------------------------- */
PyDoc_STRVAR(color_doc,
-"This object gives access to Colors in Blender."
+".. class:: Color(rgb)\n"
+"\n"
+" This object gives access to Colors in Blender.\n"
+"\n"
+" :param rgb: (r, g, b) color values\n"
+" :type rgb: 3d vector\n"
);
PyTypeObject color_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
diff --git a/source/blender/python/mathutils/mathutils_Euler.c b/source/blender/python/mathutils/mathutils_Euler.c
index 9c0ced39403..edb4af0aa1d 100644
--- a/source/blender/python/mathutils/mathutils_Euler.c
+++ b/source/blender/python/mathutils/mathutils_Euler.c
@@ -657,7 +657,14 @@ static struct PyMethodDef Euler_methods[] = {
/* ------------------PY_OBECT DEFINITION-------------------------- */
PyDoc_STRVAR(euler_doc,
-"This object gives access to Eulers in Blender."
+".. class:: Euler(angles, order='XYZ')\n"
+"\n"
+" This object gives access to Eulers in Blender.\n"
+"\n"
+" :param angles: Three angles, in radians.\n"
+" :type angles: 3d vector\n"
+" :param order: Optional order of the angles, a permutation of ``XYZ``.\n"
+" :type order: str\n"
);
PyTypeObject euler_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
diff --git a/source/blender/python/mathutils/mathutils_Matrix.c b/source/blender/python/mathutils/mathutils_Matrix.c
index 4706c09176e..95b53256eac 100644
--- a/source/blender/python/mathutils/mathutils_Matrix.c
+++ b/source/blender/python/mathutils/mathutils_Matrix.c
@@ -2716,7 +2716,14 @@ static struct PyMethodDef Matrix_methods[] = {
/*------------------PY_OBECT DEFINITION--------------------------*/
PyDoc_STRVAR(matrix_doc,
-"This object gives access to Matrices in Blender."
+".. class:: Matrix([rows])\n"
+"\n"
+" This object gives access to Matrices in Blender, supporting square and rectangular\n"
+" matrices from 2x2 up to 4x4.\n"
+"\n"
+" :param rows: Sequence of rows.\n"
+" When ommitted, a 4x4 identity matrix is constructed.\n"
+" :type rows: 2d number sequence\n"
);
PyTypeObject matrix_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
diff --git a/source/blender/python/mathutils/mathutils_Quaternion.c b/source/blender/python/mathutils/mathutils_Quaternion.c
index d422634a496..42be316bc9b 100644
--- a/source/blender/python/mathutils/mathutils_Quaternion.c
+++ b/source/blender/python/mathutils/mathutils_Quaternion.c
@@ -177,6 +177,30 @@ static PyObject *Quaternion_to_axis_angle(QuaternionObject *self)
return ret;
}
+PyDoc_STRVAR(Quaternion_to_exponential_map_doc,
+".. method:: to_exponential_map()\n"
+"\n"
+" Return the exponential map representation of the quaternion.\n"
+"\n"
+" This representation consist of the rotation axis multiplied by the rotation angle."
+" Such a representation is useful for interpolation between multiple orientations.\n"
+"\n"
+" :return: exponential map.\n"
+" :rtype: :class:`Vector` of size 3\n"
+"\n"
+" To convert back to a quaternion, pass it to the :class:`Quaternion` constructor.\n"
+);
+static PyObject *Quaternion_to_exponential_map(QuaternionObject *self)
+{
+ float expmap[3];
+
+ if (BaseMath_ReadCallback(self) == -1)
+ return NULL;
+
+ quat_to_expmap(expmap, self->quat);
+ return Vector_CreatePyObject(expmap, 3, NULL);
+}
+
PyDoc_STRVAR(Quaternion_cross_doc,
".. method:: cross(other)\n"
"\n"
@@ -334,7 +358,8 @@ static PyObject *Quaternion_rotate(QuaternionObject *self, PyObject *value)
}
/* ----------------------------Quaternion.normalize()---------------- */
-/* normalize the axis of rotation of [theta, vector] */
+/* Normalize the quaternion. This may change the angle as well as the
+ * rotation axis, as all of (w, x, y, z) are scaled. */
PyDoc_STRVAR(Quaternion_normalize_doc,
".. function:: normalize()\n"
"\n"
@@ -1076,9 +1101,24 @@ static PyObject *Quaternion_new(PyTypeObject *type, PyObject *args, PyObject *kw
case 0:
break;
case 1:
- if (mathutils_array_parse(quat, QUAT_SIZE, QUAT_SIZE, seq, "mathutils.Quaternion()") == -1)
+ {
+ int size;
+
+ if ((size = mathutils_array_parse(quat, 3, QUAT_SIZE, seq, "mathutils.Quaternion()")) == -1) {
return NULL;
+ }
+
+ if (size == 4) {
+ /* 4d: Quaternion (common case) */
+ }
+ else {
+ /* 3d: Interpret as exponential map */
+ BLI_assert(size == 3);
+ expmap_to_quat(quat, quat);
+ }
+
break;
+ }
case 2:
{
float axis[3];
@@ -1155,6 +1195,7 @@ static struct PyMethodDef Quaternion_methods[] = {
{"to_euler", (PyCFunction) Quaternion_to_euler, METH_VARARGS, Quaternion_to_euler_doc},
{"to_matrix", (PyCFunction) Quaternion_to_matrix, METH_NOARGS, Quaternion_to_matrix_doc},
{"to_axis_angle", (PyCFunction) Quaternion_to_axis_angle, METH_NOARGS, Quaternion_to_axis_angle_doc},
+ {"to_exponential_map", (PyCFunction) Quaternion_to_exponential_map, METH_NOARGS, Quaternion_to_exponential_map_doc},
/* operation between 2 or more types */
{"cross", (PyCFunction) Quaternion_cross, METH_O, Quaternion_cross_doc},
@@ -1187,7 +1228,29 @@ static PyGetSetDef Quaternion_getseters[] = {
/* ------------------PY_OBECT DEFINITION-------------------------- */
PyDoc_STRVAR(quaternion_doc,
-"This object gives access to Quaternions in Blender."
+".. class:: Quaternion([seq, [angle]])\n"
+"\n"
+" This object gives access to Quaternions in Blender.\n"
+"\n"
+" :param seq: size 3 or 4\n"
+" :type seq: :class:`Vector`\n"
+" :param angle: rotation angle, in radians\n"
+" :type angle: float\n"
+"\n"
+" The constructor takes arguments in various forms:\n"
+"\n"
+" (), *no args*\n"
+" Create an identity quaternion\n"
+" (*wxyz*)\n"
+" Create a quaternion from a ``(w, x, y, z)`` vector.\n"
+" (*exponential_map*)\n"
+" Create a quaternion from a 3d exponential map vector.\n"
+"\n"
+" .. seealso:: :meth:`to_exponential_map`\n"
+" (*axis, angle*)\n"
+" Create a quaternion representing a rotation of *angle* radians over *axis*.\n"
+"\n"
+" .. seealso:: :meth:`to_axis_angle`\n"
);
PyTypeObject quaternion_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
diff --git a/source/blender/python/mathutils/mathutils_Vector.c b/source/blender/python/mathutils/mathutils_Vector.c
index 167fb5bcf3d..091412b0f53 100644
--- a/source/blender/python/mathutils/mathutils_Vector.c
+++ b/source/blender/python/mathutils/mathutils_Vector.c
@@ -2904,7 +2904,12 @@ static struct PyMethodDef Vector_methods[] = {
*/
PyDoc_STRVAR(vector_doc,
-"This object gives access to Vectors in Blender."
+".. class:: Vector(seq)\n"
+"\n"
+" This object gives access to Vectors in Blender.\n"
+"\n"
+" :param seq: Components of the vector, must be a sequence of at least two\n"
+" :type seq: sequence of numbers\n"
);
PyTypeObject vector_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
diff --git a/source/blender/python/mathutils/mathutils_geometry.c b/source/blender/python/mathutils/mathutils_geometry.c
index b496ee1fbf6..bb4080decef 100644
--- a/source/blender/python/mathutils/mathutils_geometry.c
+++ b/source/blender/python/mathutils/mathutils_geometry.c
@@ -87,14 +87,14 @@ static PyObject *M_Geometry_intersect_ray_tri(PyObject *UNUSED(self), PyObject *
return NULL;
}
- if (((mathutils_array_parse(dir, 3, 3, py_ray, error_prefix) != -1) &&
- (mathutils_array_parse(orig, 3, 3, py_ray_off, error_prefix) != -1)) == 0)
+ if (((mathutils_array_parse(dir, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_ray, error_prefix) != -1) &&
+ (mathutils_array_parse(orig, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_ray_off, error_prefix) != -1)) == 0)
{
return NULL;
}
for (i = 0; i < ARRAY_SIZE(tri); i++) {
- if (mathutils_array_parse(tri[i], 2, 2 | MU_ARRAY_SPILL, py_tri[i], error_prefix) == -1) {
+ if (mathutils_array_parse(tri[i], 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_tri[i], error_prefix) == -1) {
return NULL;
}
}
@@ -183,18 +183,14 @@ static PyObject *M_Geometry_intersect_line_line(PyObject *UNUSED(self), PyObject
return NULL;
}
- if ((((len = mathutils_array_parse(lines[0], 2, 3, py_lines[0], error_prefix)) != -1) &&
- (mathutils_array_parse(lines[1], len, len, py_lines[1], error_prefix) != -1) &&
- (mathutils_array_parse(lines[2], len, len, py_lines[2], error_prefix) != -1) &&
- (mathutils_array_parse(lines[3], len, len, py_lines[3], error_prefix) != -1)) == 0)
+ if ((((len = mathutils_array_parse(lines[0], 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_lines[0], error_prefix)) != -1) &&
+ (mathutils_array_parse(lines[1], len, len | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_lines[1], error_prefix) != -1) &&
+ (mathutils_array_parse(lines[2], len, len | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_lines[2], error_prefix) != -1) &&
+ (mathutils_array_parse(lines[3], len, len | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_lines[3], error_prefix) != -1)) == 0)
{
return NULL;
}
- if (len == 2) {
- lines[0][2] = lines[1][2] = lines[2][2] = lines[3][2] = 0.0f;
- }
-
result = isect_line_line_v3(UNPACK4(lines), i1, i2);
/* The return-code isnt exposed,
* this way we can check know how close the lines are. */
@@ -745,7 +741,7 @@ static PyObject *M_Geometry_intersect_point_line(PyObject *UNUSED(self), PyObjec
/* accept 2d verts */
if ((((size = mathutils_array_parse(pt, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_pt, error_prefix)) != -1) &&
(mathutils_array_parse(line_a, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_line_a, error_prefix) != -1) &&
- (mathutils_array_parse(line_b, 3, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_line_b, error_prefix) != -1)) == 0)
+ (mathutils_array_parse(line_b, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_line_b, error_prefix) != -1)) == 0)
{
return NULL;
}
@@ -791,11 +787,11 @@ static PyObject *M_Geometry_intersect_point_tri(PyObject *UNUSED(self), PyObject
return NULL;
}
- if (mathutils_array_parse(pt, 3, 3 | MU_ARRAY_SPILL, py_pt, error_prefix) == -1) {
+ if (mathutils_array_parse(pt, 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_pt, error_prefix) == -1) {
return NULL;
}
for (i = 0; i < ARRAY_SIZE(tri); i++) {
- if (mathutils_array_parse(tri[i], 3, 3 | MU_ARRAY_SPILL, py_tri[i], error_prefix) == -1) {
+ if (mathutils_array_parse(tri[i], 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_tri[i], error_prefix) == -1) {
return NULL;
}
}
@@ -971,7 +967,7 @@ static PyObject *M_Geometry_barycentric_transform(PyObject *UNUSED(self), PyObje
return NULL;
}
- if (mathutils_array_parse(pt_src, 2, 2 | MU_ARRAY_SPILL, py_pt_src, error_prefix) == -1) {
+ if (mathutils_array_parse(pt_src, 3, 3 | MU_ARRAY_SPILL, py_pt_src, error_prefix) == -1) {
return NULL;
}
for (i = 0; i < ARRAY_SIZE(tri_src); i++) {
@@ -1132,7 +1128,7 @@ static PyObject *M_Geometry_interpolate_bezier(PyObject *UNUSED(self), PyObject
for (i = 0; i < 4; i++) {
int dims_tmp;
- if ((((dims_tmp = mathutils_array_parse(data[i], 2, 2 | MU_ARRAY_SPILL, py_data[i], error_prefix)) == -1))) {
+ if ((dims_tmp = mathutils_array_parse(data[i], 2, 3 | MU_ARRAY_SPILL | MU_ARRAY_ZERO, py_data[i], error_prefix)) == -1) {
return NULL;
}
dims = max_ii(dims, dims_tmp);
diff --git a/source/blender/python/mathutils/mathutils_interpolate.c b/source/blender/python/mathutils/mathutils_interpolate.c
new file mode 100644
index 00000000000..4d7841b906a
--- /dev/null
+++ b/source/blender/python/mathutils/mathutils_interpolate.c
@@ -0,0 +1,137 @@
+/*
+ * ***** 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): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/python/mathutils/mathutils_interpolate.c
+ * \ingroup pymathutils
+ */
+
+
+#include <Python.h>
+
+#include "mathutils.h"
+#include "mathutils_interpolate.h"
+
+#include "BLI_math.h"
+#include "BLI_utildefines.h"
+
+#ifndef MATH_STANDALONE /* define when building outside blender */
+# include "MEM_guardedalloc.h"
+#endif
+
+/*-------------------------DOC STRINGS ---------------------------*/
+PyDoc_STRVAR(M_Interpolate_doc,
+"The Blender interpolate module"
+);
+
+/* ---------------------------------WEIGHT CALCULATION ----------------------- */
+
+#ifndef MATH_STANDALONE
+
+PyDoc_STRVAR(M_Interpolate_poly_3d_calc_doc,
+".. function:: poly_3d_calc(veclist, pt)\n"
+"\n"
+" Calculate barycentric weights for a point on a polygon.\n"
+"\n"
+" :arg veclist: list of vectors\n"
+" :arg pt: point"
+" :rtype: list of per-vector weights\n"
+);
+static PyObject *M_Interpolate_poly_3d_calc(PyObject *UNUSED(self), PyObject *args)
+{
+ float fp[3];
+ float (*vecs)[3];
+ Py_ssize_t len;
+
+ PyObject *point, *veclist, *ret;
+ int i;
+
+ if (!PyArg_ParseTuple(args, "OO!:interpolation_weights",
+ &veclist,
+ &vector_Type, &point))
+ {
+ return NULL;
+ }
+
+ if (BaseMath_ReadCallback((VectorObject *)point) == -1)
+ return NULL;
+
+ fp[0] = ((VectorObject *)point)->vec[0];
+ fp[1] = ((VectorObject *)point)->vec[1];
+ if (((VectorObject *)point)->size > 2)
+ fp[2] = ((VectorObject *)point)->vec[2];
+ else
+ fp[2] = 0.0f; /* if its a 2d vector then set the z to be zero */
+
+ len = mathutils_array_parse_alloc_v(((float **)&vecs), 3, veclist, "interpolation_weights");
+ if (len == -1) {
+ return NULL;
+ }
+
+ if (len) {
+ float *weights = MEM_mallocN(sizeof(float) * len, "interpolation weights");
+
+ interp_weights_poly_v3(weights, vecs, len, fp);
+
+ ret = PyList_New(len);
+ for (i = 0; i < len; i++) {
+ PyList_SET_ITEM(ret, i, PyFloat_FromDouble(weights[i]));
+ }
+
+ MEM_freeN(weights);
+
+ PyMem_Free(vecs);
+ }
+ else {
+ ret = PyList_New(0);
+ }
+
+ return ret;
+}
+
+#endif /* MATH_STANDALONE */
+
+
+static PyMethodDef M_Interpolate_methods[] = {
+#ifndef MATH_STANDALONE
+ {"poly_3d_calc", (PyCFunction) M_Interpolate_poly_3d_calc, METH_VARARGS, M_Interpolate_poly_3d_calc_doc},
+#endif
+ {NULL, NULL, 0, NULL}
+};
+
+static struct PyModuleDef M_Interpolate_module_def = {
+ PyModuleDef_HEAD_INIT,
+ "mathutils.interpolate", /* m_name */
+ M_Interpolate_doc, /* m_doc */
+ 0, /* m_size */
+ M_Interpolate_methods, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+
+/*----------------------------MODULE INIT-------------------------*/
+PyMODINIT_FUNC PyInit_mathutils_interpolate(void)
+{
+ PyObject *submodule = PyModule_Create(&M_Interpolate_module_def);
+ return submodule;
+}
diff --git a/source/blender/compositor/intern/COM_ChannelInfo.cpp b/source/blender/python/mathutils/mathutils_interpolate.h
index 557075cdc80..1bbff6f3286 100644
--- a/source/blender/compositor/intern/COM_ChannelInfo.cpp
+++ b/source/blender/python/mathutils/mathutils_interpolate.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2011, Blender Foundation.
+ * ***** 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
@@ -15,21 +15,18 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * Contributor:
- * Jeroen Bakker
- * Monique Dewanchand
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
*/
-#include "COM_ChannelInfo.h"
-#include "COM_defines.h"
-#include <stdio.h>
+#ifndef __MATHUTILS_INTERPOLATE_H__
+#define __MATHUTILS_INTERPOLATE_H__
-/**
- * @brief create new ChannelInfo instance and sets the defaults.
+/** \file blender/python/mathutils/mathutils_interpolate.h
+ * \ingroup pymathutils
*/
-ChannelInfo::ChannelInfo()
-{
- this->m_number = 0;
- this->m_premultiplied = true;
- this->m_type = COM_CT_UNUSED;
-}
+
+PyMODINIT_FUNC PyInit_mathutils_interpolate(void);
+
+#endif /* __MATHUTILS_INTERPOLATE_H__ */
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index e516c954737..36b9f8ae362 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -33,6 +33,7 @@ set(INC
../imbuf
../makesdna
../makesrna
+ ../physics
../../../intern/guardedalloc
../../../intern/mikktspace
../../../intern/smoke/extern
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index ebd131082e4..0cbf188525b 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -40,6 +40,7 @@ incs = [
'../imbuf',
'../makesdna',
'../makesrna',
+ '../physics',
'../../../intern/mikktspace',
'../../../intern/smoke/extern',
]
diff --git a/source/blender/render/extern/include/RE_render_ext.h b/source/blender/render/extern/include/RE_render_ext.h
index 6d083ec785d..d76d16a641e 100644
--- a/source/blender/render/extern/include/RE_render_ext.h
+++ b/source/blender/render/extern/include/RE_render_ext.h
@@ -45,7 +45,7 @@ struct Scene;
struct View3D;
/* particle.c, effect.c, editmesh_modes.c and brush.c, returns 1 if rgb, 0 otherwise */
-int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool);
+int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool, const bool skip_load_image);
/* particle.c */
void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype);
diff --git a/source/blender/render/extern/include/RE_shader_ext.h b/source/blender/render/extern/include/RE_shader_ext.h
index da847d235f2..7c76f0362f4 100644
--- a/source/blender/render/extern/include/RE_shader_ext.h
+++ b/source/blender/render/extern/include/RE_shader_ext.h
@@ -198,9 +198,9 @@ struct ImagePool;
struct Object;
/* this one uses nodes */
-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);
+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, const bool skip_load_image);
/* nodes disabled */
-int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage);
+int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image);
/* only for internal node usage */
int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres,
const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex,
diff --git a/source/blender/render/intern/include/envmap.h b/source/blender/render/intern/include/envmap.h
index c813e88c656..627e6c0e1e6 100644
--- a/source/blender/render/intern/include/envmap.h
+++ b/source/blender/render/intern/include/envmap.h
@@ -47,7 +47,7 @@ struct TexResult;
struct ImagePool;
void make_envmaps(struct Render *re);
-int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool);
+int envmaptex(struct Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, struct ImagePool *pool, const bool skip_image_load);
void env_rotate_scene(struct Render *re, float mat[4][4], int do_rotate);
#endif /* __ENVMAP_H__ */
diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h
index b87b1e6f367..8d92fb9eec9 100644
--- a/source/blender/render/intern/include/render_types.h
+++ b/source/blender/render/intern/include/render_types.h
@@ -424,6 +424,7 @@ typedef struct HaloRen {
unsigned int lay;
struct Material *mat;
struct ImagePool *pool;
+ bool skip_load_image;
} HaloRen;
/* ------------------------------------------------------------------------- */
diff --git a/source/blender/render/intern/include/texture.h b/source/blender/render/intern/include/texture.h
index ff5004fd7f0..ebc83984306 100644
--- a/source/blender/render/intern/include/texture.h
+++ b/source/blender/render/intern/include/texture.h
@@ -81,8 +81,8 @@ void render_realtime_texture(struct ShadeInput *shi, struct Image *ima);
/* imagetexture.h */
-int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[2], const float dyt[2], struct TexResult *texres, struct ImagePool *pool);
-int imagewrap(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], struct TexResult *texres, struct ImagePool *pool);
+int imagewraposa(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], const float dxt[2], const float dyt[2], struct TexResult *texres, struct ImagePool *pool, const bool skip_load_image);
+int imagewrap(struct Tex *tex, struct Image *ima, struct ImBuf *ibuf, const float texvec[3], struct TexResult *texres, struct ImagePool *pool, const bool skip_load_image);
void image_sample(struct Image *ima, float fx, float fy, float dx, float dy, float result[4], struct ImagePool *pool);
#endif /* __TEXTURE_H__ */
diff --git a/source/blender/render/intern/source/bake_api.c b/source/blender/render/intern/source/bake_api.c
index 90deac2de32..48ef29150d3 100644
--- a/source/blender/render/intern/source/bake_api.c
+++ b/source/blender/render/intern/source/bake_api.c
@@ -444,7 +444,7 @@ bool RE_bake_pixels_populate_from_objects(
size_t i;
int primitive_id;
float u, v;
- float imat_low [4][4];
+ float imat_low[4][4];
bool is_cage = me_cage != NULL;
bool result = true;
diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c
index 35878f664ea..ba778ec30e9 100644
--- a/source/blender/render/intern/source/convertblender.c
+++ b/source/blender/render/intern/source/convertblender.c
@@ -1344,11 +1344,13 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if (re->r.scemode & R_VIEWPORT_PREVIEW) { /* preview render */
totchild = (int)((float)totchild * (float)part->disp / 100.0f);
- step_nbr = part->draw_step;
+ step_nbr = 1 << part->draw_step;
}
else {
- step_nbr = part->ren_step;
+ step_nbr = 1 << part->ren_step;
}
+ if (ELEM(part->kink, PART_KINK_SPIRAL))
+ step_nbr += part->kink_extra_steps;
psys->flag |= PSYS_DRAWING;
@@ -1432,7 +1434,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
/* 2.6 setup strand rendering */
if (part->ren_as == PART_DRAW_PATH && psys->pathcache) {
- path_nbr=(int)pow(2.0, (double) step_nbr);
+ path_nbr = step_nbr;
if (path_nbr) {
if (!ELEM(ma->material_type, MA_TYPE_HALO, MA_TYPE_WIRE)) {
@@ -1551,7 +1553,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if (path_nbr) {
cache = psys->pathcache[a];
- max_k = (int)cache->steps;
+ max_k = (int)cache->segments;
}
if (totchild && (part->draw&PART_DRAW_PARENT)==0) continue;
@@ -1562,10 +1564,10 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem
if (path_nbr) {
cache = psys->childcache[a-totpart];
- if (cache->steps < 0)
+ if (cache->segments < 0)
continue;
- max_k = (int)cache->steps;
+ max_k = (int)cache->segments;
}
pa_time = psys_get_child_time(psys, cpa, cfra, &pa_birthtime, &pa_dietime);
@@ -3314,7 +3316,7 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset)
v2= mface->v2;
v3= reverse_verts==0 ? mface->v3 : mface->v1;
v4= mface->v4;
- flag= mface->flag & ME_SMOOTH;
+ flag = do_autosmooth ? ME_SMOOTH : mface->flag & ME_SMOOTH;
vlr= RE_findOrAddVlak(obr, obr->totvlak++);
vlr->v1= RE_findOrAddVert(obr, vertofs+v1);
diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c
index c3c70067836..f0268836104 100644
--- a/source/blender/render/intern/source/envmap.c
+++ b/source/blender/render/intern/source/envmap.c
@@ -694,7 +694,7 @@ static void set_dxtdyt(float r_dxt[3], float r_dyt[3], const float dxt[3], const
/* ------------------------------------------------------------------------- */
-int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool)
+int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
extern Render R; /* only in this call */
/* texvec should be the already reflected normal */
@@ -750,7 +750,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o
mul_mat3_m4_v3(R.viewinv, dyt);
}
set_dxtdyt(dxts, dyts, dxt, dyt, face);
- imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool);
+ imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool, skip_load_image);
/* edges? */
@@ -767,7 +767,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o
if (face != face1) {
ibuf = env->cube[face1];
set_dxtdyt(dxts, dyts, dxt, dyt, face1);
- imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1, pool);
+ imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr1, pool, skip_load_image);
}
else texr1.tr = texr1.tg = texr1.tb = texr1.ta = 0.0;
@@ -780,7 +780,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o
if (face != face1) {
ibuf = env->cube[face1];
set_dxtdyt(dxts, dyts, dxt, dyt, face1);
- imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2, pool);
+ imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, &texr2, pool, skip_load_image);
}
else texr2.tr = texr2.tg = texr2.tb = texr2.ta = 0.0;
@@ -796,7 +796,7 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o
}
}
else {
- imagewrap(tex, NULL, ibuf, sco, texres, pool);
+ imagewrap(tex, NULL, ibuf, sco, texres, pool, skip_load_image);
}
return 1;
diff --git a/source/blender/render/intern/source/imagetexture.c b/source/blender/render/intern/source/imagetexture.c
index 833d1a75559..687e25a9410 100644
--- a/source/blender/render/intern/source/imagetexture.c
+++ b/source/blender/render/intern/source/imagetexture.c
@@ -103,7 +103,7 @@ static void ibuf_get_color(float col[4], struct ImBuf *ibuf, int x, int y)
}
}
-int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResult *texres, struct ImagePool *pool)
+int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
float fx, fy, val1, val2, val3;
int x, y, retval;
@@ -120,7 +120,7 @@ int imagewrap(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], TexResul
if (ima) {
/* hack for icon render */
- if ((R.r.scemode & R_NO_IMAGE_LOAD) && !BKE_image_has_loaded_ibuf(ima))
+ if (skip_load_image && !BKE_image_has_loaded_ibuf(ima))
return retval;
ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
@@ -912,7 +912,7 @@ static void image_mipmap_test(Tex *tex, ImBuf *ibuf)
}
-static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool)
+static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], float dxt[2], float dyt[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
TexResult texr;
float fx, fy, minx, maxx, miny, maxy;
@@ -942,7 +942,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
if (ibuf==NULL && ima==NULL) return retval;
if (ima) { /* hack for icon render */
- if ((R.r.scemode & R_NO_IMAGE_LOAD) && !BKE_image_has_loaded_ibuf(ima)) {
+ if (skip_load_image && !BKE_image_has_loaded_ibuf(ima)) {
return retval;
}
ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
@@ -1338,7 +1338,7 @@ static int imagewraposa_aniso(Tex *tex, Image *ima, ImBuf *ibuf, const float tex
}
-int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres, struct ImagePool *pool)
+int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const float DXT[2], const float DYT[2], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
TexResult texr;
float fx, fy, minx, maxx, miny, maxy, dx, dy, dxt[2], dyt[2];
@@ -1352,7 +1352,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
/* anisotropic filtering */
if (tex->texfilter != TXF_BOX)
- return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool);
+ return imagewraposa_aniso(tex, ima, ibuf, texvec, dxt, dyt, texres, pool, skip_load_image);
texres->tin= texres->ta= texres->tr= texres->tg= texres->tb= 0.0f;
@@ -1365,7 +1365,7 @@ int imagewraposa(Tex *tex, Image *ima, ImBuf *ibuf, const float texvec[3], const
if (ima) {
/* hack for icon render */
- if ((R.r.scemode & R_NO_IMAGE_LOAD) && !BKE_image_has_loaded_ibuf(ima))
+ if (skip_load_image && !BKE_image_has_loaded_ibuf(ima))
return retval;
ibuf = BKE_image_pool_acquire_ibuf(ima, &tex->iuser, pool);
diff --git a/source/blender/render/intern/source/initrender.c b/source/blender/render/intern/source/initrender.c
index b5b75f47193..a0fcc7cdcd2 100644
--- a/source/blender/render/intern/source/initrender.c
+++ b/source/blender/render/intern/source/initrender.c
@@ -157,7 +157,7 @@ float RE_filter_value(int type, float x)
{
const float two_gaussfac2 = 2.0f * gaussfac * gaussfac;
x *= 3.0f * gaussfac;
- return 1.0f / sqrtf(M_PI * two_gaussfac2) * expf(-x*x / two_gaussfac2);
+ return 1.0f / sqrtf((float)M_PI * two_gaussfac2) * expf(-x*x / two_gaussfac2);
}
case R_FILTER_MITCH:
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 0c17d2dd15d..7d76a916d66 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -256,7 +256,7 @@ Render *RE_GetRender(const char *name)
/* search for existing renders */
for (re = RenderGlobal.renderlist.first; re; re = re->next)
- if (strncmp(re->name, name, RE_MAXNAME) == 0)
+ if (STREQLEN(re->name, name, RE_MAXNAME))
break;
return re;
@@ -2350,7 +2350,9 @@ static void renderresult_stampinfo(Render *re)
/* this is the basic trick to get the displayed float or char rect from render result */
RE_AcquireResultImage(re, &rres);
- BKE_stamp_buf(re->scene, RE_GetCamera(re), (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
+ BKE_image_stamp_buf(
+ re->scene, RE_GetCamera(re),
+ (unsigned char *)rres.rect32, rres.rectf, rres.rectx, rres.recty, 4);
RE_ReleaseResultImage(re);
}
@@ -2804,8 +2806,9 @@ void RE_BlenderFrame(Render *re, Main *bmain, Scene *scene, SceneRenderLayer *sr
}
else {
char name[FILE_MAX];
- BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false);
/* reports only used for Movie */
do_write_image_or_movie(re, bmain, scene, NULL, name);
@@ -2890,8 +2893,9 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
if (name_override)
BLI_strncpy(name, name_override, sizeof(name));
else
- BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
if (re->r.im_format.imtype == R_IMF_IMTYPE_MULTILAYER) {
if (re->result) {
@@ -2919,7 +2923,7 @@ static int do_write_image_or_movie(Render *re, Main *bmain, Scene *scene, bMovie
if (BLI_testextensie(name, ".exr"))
name[strlen(name) - 4] = 0;
- BKE_add_image_extension(name, &imf);
+ BKE_image_path_ensure_ext_from_imformat(name, &imf);
ibuf->planes = 24;
IMB_colormanagement_imbuf_for_write(ibuf, true, false, &scene->view_settings,
@@ -3052,8 +3056,9 @@ void RE_BlenderAnim(Render *re, Main *bmain, Scene *scene, Object *camera_overri
/* Touch/NoOverwrite options are only valid for image's */
if (BKE_imtype_is_movie(scene->r.im_format.imtype) == 0) {
if (scene->r.mode & (R_NO_OVERWRITE | R_TOUCH))
- BKE_makepicstring(name, scene->r.pic, bmain->name, scene->r.cfra,
- &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
+ BKE_image_path_from_imformat(
+ name, scene->r.pic, bmain->name, scene->r.cfra,
+ &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true);
if (scene->r.mode & R_NO_OVERWRITE && BLI_exists(name)) {
printf("skipping existing frame \"%s\"\n", name);
diff --git a/source/blender/render/intern/source/pixelshading.c b/source/blender/render/intern/source/pixelshading.c
index ac4a7dbdccd..104cde0a0b5 100644
--- a/source/blender/render/intern/source/pixelshading.c
+++ b/source/blender/render/intern/source/pixelshading.c
@@ -155,7 +155,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 / (sqrtf(1.0f + x * x));
+ inpr = 1.0f / (sqrtf(1.0f + x * x));
}
else inpr= 0.0;
}
@@ -201,7 +201,7 @@ static void render_lighting_halo(HaloRen *har, float col_r[3])
/* dot product and reflectivity*/
- inp = 1.0 - fabsf(dot_v3v3(vn, lv));
+ inp = 1.0f - fabsf(dot_v3v3(vn, lv));
/* inp= cos(0.5*M_PI-acos(inp)); */
@@ -361,7 +361,7 @@ int shadeHaloFloat(HaloRen *har, float col[4], int zz,
else dist= dist/har->radsq;
if (har->type & HA_FLARECIRC) {
- dist = 0.5 + fabsf(dist - 0.5f);
+ dist = 0.5f + fabsf(dist - 0.5f);
}
if (har->hard>=30) {
diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c
index ff23e3788ab..1f4726809de 100644
--- a/source/blender/render/intern/source/pointdensity.c
+++ b/source/blender/render/intern/source/pointdensity.c
@@ -160,7 +160,7 @@ static void pointdensity_cache_psys(Render *re, PointDensity *pd, Object *ob, Pa
else
continue;
- cache += cache->steps; /* use endpoint */
+ cache += cache->segments; /* use endpoint */
copy_v3_v3(state.co, cache->co);
zero_v3(state.vel);
diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c
index 3575b78f95f..065cdeab61c 100644
--- a/source/blender/render/intern/source/rayshade.c
+++ b/source/blender/render/intern/source/rayshade.c
@@ -1273,7 +1273,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 = (sqrtf(pre_x * pre_x + pre_y * pre_y) + sqrtf(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.0f;
return speedavg;
}
diff --git a/source/blender/render/intern/source/render_result.c b/source/blender/render/intern/source/render_result.c
index de87fb200ae..6486844bacf 100644
--- a/source/blender/render/intern/source/render_result.c
+++ b/source/blender/render/intern/source/render_result.c
@@ -309,97 +309,97 @@ static const char *get_pass_name(int passtype, int channel)
static int passtype_from_name(const char *str)
{
- if (strcmp(str, "Combined") == 0)
+ if (STREQ(str, "Combined"))
return SCE_PASS_COMBINED;
- if (strcmp(str, "Depth") == 0)
+ if (STREQ(str, "Depth"))
return SCE_PASS_Z;
- if (strcmp(str, "Vector") == 0)
+ if (STREQ(str, "Vector"))
return SCE_PASS_VECTOR;
- if (strcmp(str, "Normal") == 0)
+ if (STREQ(str, "Normal"))
return SCE_PASS_NORMAL;
- if (strcmp(str, "UV") == 0)
+ if (STREQ(str, "UV"))
return SCE_PASS_UV;
- if (strcmp(str, "Color") == 0)
+ if (STREQ(str, "Color"))
return SCE_PASS_RGBA;
- if (strcmp(str, "Emit") == 0)
+ if (STREQ(str, "Emit"))
return SCE_PASS_EMIT;
- if (strcmp(str, "Diffuse") == 0)
+ if (STREQ(str, "Diffuse"))
return SCE_PASS_DIFFUSE;
- if (strcmp(str, "Spec") == 0)
+ if (STREQ(str, "Spec"))
return SCE_PASS_SPEC;
- if (strcmp(str, "Shadow") == 0)
+ if (STREQ(str, "Shadow"))
return SCE_PASS_SHADOW;
- if (strcmp(str, "AO") == 0)
+ if (STREQ(str, "AO"))
return SCE_PASS_AO;
- if (strcmp(str, "Env") == 0)
+ if (STREQ(str, "Env"))
return SCE_PASS_ENVIRONMENT;
- if (strcmp(str, "Indirect") == 0)
+ if (STREQ(str, "Indirect"))
return SCE_PASS_INDIRECT;
- if (strcmp(str, "Reflect") == 0)
+ if (STREQ(str, "Reflect"))
return SCE_PASS_REFLECT;
- if (strcmp(str, "Refract") == 0)
+ if (STREQ(str, "Refract"))
return SCE_PASS_REFRACT;
- if (strcmp(str, "IndexOB") == 0)
+ if (STREQ(str, "IndexOB"))
return SCE_PASS_INDEXOB;
- if (strcmp(str, "IndexMA") == 0)
+ if (STREQ(str, "IndexMA"))
return SCE_PASS_INDEXMA;
- if (strcmp(str, "Mist") == 0)
+ if (STREQ(str, "Mist"))
return SCE_PASS_MIST;
- if (strcmp(str, "RayHits") == 0)
+ if (STREQ(str, "RayHits"))
return SCE_PASS_RAYHITS;
- if (strcmp(str, "DiffDir") == 0)
+ if (STREQ(str, "DiffDir"))
return SCE_PASS_DIFFUSE_DIRECT;
- if (strcmp(str, "DiffInd") == 0)
+ if (STREQ(str, "DiffInd"))
return SCE_PASS_DIFFUSE_INDIRECT;
- if (strcmp(str, "DiffCol") == 0)
+ if (STREQ(str, "DiffCol"))
return SCE_PASS_DIFFUSE_COLOR;
- if (strcmp(str, "GlossDir") == 0)
+ if (STREQ(str, "GlossDir"))
return SCE_PASS_GLOSSY_DIRECT;
- if (strcmp(str, "GlossInd") == 0)
+ if (STREQ(str, "GlossInd"))
return SCE_PASS_GLOSSY_INDIRECT;
- if (strcmp(str, "GlossCol") == 0)
+ if (STREQ(str, "GlossCol"))
return SCE_PASS_GLOSSY_COLOR;
- if (strcmp(str, "TransDir") == 0)
+ if (STREQ(str, "TransDir"))
return SCE_PASS_TRANSM_DIRECT;
- if (strcmp(str, "TransInd") == 0)
+ if (STREQ(str, "TransInd"))
return SCE_PASS_TRANSM_INDIRECT;
- if (strcmp(str, "TransCol") == 0)
+ if (STREQ(str, "TransCol"))
return SCE_PASS_TRANSM_COLOR;
- if (strcmp(str, "SubsurfaceDir") == 0)
+ if (STREQ(str, "SubsurfaceDir"))
return SCE_PASS_SUBSURFACE_DIRECT;
- if (strcmp(str, "SubsurfaceInd") == 0)
+ if (STREQ(str, "SubsurfaceInd"))
return SCE_PASS_SUBSURFACE_INDIRECT;
- if (strcmp(str, "SubsurfaceCol") == 0)
+ if (STREQ(str, "SubsurfaceCol"))
return SCE_PASS_SUBSURFACE_COLOR;
return 0;
@@ -509,7 +509,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
for (nr = 0, srl = re->r.layers.first; srl; srl = srl->next, nr++) {
if (layername && layername[0])
- if (strcmp(srl->name, layername) != 0)
+ if (!STREQ(srl->name, layername))
continue;
if (re->r.scemode & R_SINGLE_LAYER) {
@@ -611,7 +611,7 @@ RenderResult *render_result_new(Render *re, rcti *partrct, int crop, int savebuf
render_layer_add_pass(rr, rl, 3, SCE_PASS_SUBSURFACE_COLOR);
#ifdef WITH_CYCLES_DEBUG
- if(BKE_scene_use_new_shading_nodes(re->scene)) {
+ 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);
}
@@ -1074,6 +1074,9 @@ void render_result_exr_file_path(Scene *scene, const char *layname, int sample,
BLI_snprintf(name, sizeof(name), "%s_%s_%s%d.exr", fi, scene->id.name + 2, layname, sample);
}
+ /* Make name safe for paths, see T43275. */
+ BLI_filename_make_safe(name);
+
BLI_make_file_string("/", filepath, BKE_tempdir_session(), name);
}
diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c
index b1e00c4a451..17039bca63a 100644
--- a/source/blender/render/intern/source/render_texture.c
+++ b/source/blender/render/intern/source/render_texture.c
@@ -220,10 +220,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 = (atan2f(y, x) / (2 * M_PI) + 0.5f);
+ texres->tin = (atan2f(y, x) / (float)(2 * M_PI) + 0.5f);
}
else { /* sphere TEX_SPHERE */
- texres->tin = 1.0 - sqrtf(x * x + y * y + texvec[2] * texvec[2]);
+ texres->tin = 1.0f - 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 */
}
@@ -274,7 +274,7 @@ 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 * sinf(a);
+ a = 0.5f + 0.5f * sinf(a);
return a;
}
@@ -1103,7 +1103,7 @@ static void do_2d_mapping(MTex *mtex, float texvec[3], VlakRen *vlr, const float
/* ************************************** */
-static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, const short thread, short which_output, struct ImagePool *pool)
+static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, const short thread, short which_output, struct ImagePool *pool, const bool skip_load_image)
{
float tmpvec[3];
int retval = 0; /* return value, int:0, col:1, nor:2, everything:3 */
@@ -1141,14 +1141,14 @@ static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int o
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);
+ if (osatex) retval = imagewraposa(tex, tex->ima, NULL, texvec, dxt, dyt, texres, pool, skip_load_image);
+ else retval = imagewrap(tex, tex->ima, NULL, texvec, texres, pool, skip_load_image);
if (tex->ima) {
BKE_image_tag_time(tex->ima);
}
break;
case TEX_ENVMAP:
- retval = envmaptex(tex, texvec, dxt, dyt, osatex, texres, pool);
+ retval = envmaptex(tex, texvec, dxt, dyt, osatex, texres, pool, skip_load_image);
break;
case TEX_MUSGRAVE:
/* newnoise: musgrave types */
@@ -1220,7 +1220,7 @@ static int multitex(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int o
static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres,
const short thread, short which_output, ShadeInput *shi, MTex *mtex, struct ImagePool *pool,
- bool scene_color_manage)
+ bool scene_color_manage, const bool skip_load_image)
{
if (tex==NULL) {
memset(texres, 0, sizeof(TexResult));
@@ -1236,7 +1236,7 @@ static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float
if (mtex) {
/* we have mtex, use it for 2d mapping images only */
do_2d_mapping(mtex, texvec, shi->vlr, shi->facenor, dxt, dyt);
- rgbnor = multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool);
+ rgbnor = multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool, skip_load_image);
if (mtex->mapto & (MAP_COL+MAP_COLSPEC+MAP_COLMIR)) {
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
@@ -1269,7 +1269,7 @@ static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float
}
do_2d_mapping(&localmtex, texvec_l, NULL, NULL, dxt_l, dyt_l);
- rgbnor = multitex(tex, texvec_l, dxt_l, dyt_l, osatex, texres, thread, which_output, pool);
+ rgbnor = multitex(tex, texvec_l, dxt_l, dyt_l, osatex, texres, thread, which_output, pool, skip_load_image);
{
ImBuf *ibuf = BKE_image_pool_acquire_ibuf(tex->ima, &tex->iuser, pool);
@@ -1285,7 +1285,7 @@ static int multitex_nodes_intern(Tex *tex, float texvec[3], float dxt[3], float
return rgbnor;
}
else {
- return multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool);
+ return multitex(tex, texvec, dxt, dyt, osatex, texres, thread, which_output, pool, skip_load_image);
}
}
@@ -1296,11 +1296,12 @@ int multitex_nodes(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int os
const short thread, short which_output, ShadeInput *shi, MTex *mtex, struct ImagePool *pool)
{
return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres,
- thread, which_output, shi, mtex, pool, R.scene_color_manage);
+ thread, which_output, shi, mtex, pool, R.scene_color_manage,
+ (R.r.scemode & R_NO_IMAGE_LOAD) != 0);
}
/* this is called for surface shading */
-static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt[3], float dyt[3], TexResult *texres, struct ImagePool *pool)
+static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt[3], float dyt[3], TexResult *texres, struct ImagePool *pool, const bool skip_load_image)
{
Tex *tex = mtex->tex;
@@ -1311,7 +1312,7 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt
tex, mtex->which_output, R.r.cfra, (R.r.scemode & R_TEXNODE_PREVIEW) != 0, shi, mtex);
}
else {
- return multitex(mtex->tex, texvec, dxt, dyt, shi->osatex, texres, shi->thread, mtex->which_output, pool);
+ return multitex(mtex->tex, texvec, dxt, dyt, shi->osatex, texres, shi->thread, mtex->which_output, pool, skip_load_image);
}
}
@@ -1320,21 +1321,21 @@ static int multitex_mtex(ShadeInput *shi, MTex *mtex, float texvec[3], float dxt
*
* Use it for stuff which is out of render pipeline.
*/
-int multitex_ext(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, bool scene_color_manage)
+int multitex_ext(Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image)
{
- return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres, 0, 0, NULL, NULL, pool, scene_color_manage);
+ return multitex_nodes_intern(tex, texvec, dxt, dyt, osatex, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image);
}
/* extern-tex doesn't support nodes (ntreeBeginExec() can't be called when rendering is going on)\
*
* Use it for stuff which is out of render pipeline.
*/
-int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct ImagePool *pool, bool scene_color_manage)
+int multitex_ext_safe(Tex *tex, float texvec[3], TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image)
{
int use_nodes= tex->use_nodes, retval;
tex->use_nodes = false;
- retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage);
+ retval= multitex_nodes_intern(tex, texvec, NULL, NULL, 0, texres, 0, 0, NULL, NULL, pool, scene_color_manage, skip_load_image);
tex->use_nodes= use_nodes;
return retval;
@@ -1718,7 +1719,7 @@ static void compatible_bump_uv_derivs(CompatibleBump *compat_bump, ShadeInput *s
static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres,
float Tnor, const float co[3], const float dx[3], const float dy[3], float texvec[3], float dxt[3], float dyt[3],
- struct ImagePool *pool)
+ struct ImagePool *pool, const bool skip_load_image)
{
TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */
float tco[3], texv[3], cd, ud, vd, du, dv, idu, idv;
@@ -1771,7 +1772,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi,
/* center, main return value */
texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool);
+ rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool, skip_load_image);
cd = fromrgb ? (texres->tr + texres->tg + texres->tb) / 3.0f : texres->tin;
if (mtex->texco == TEXCO_UV) {
@@ -1785,7 +1786,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi,
tco[1] = co[1] + compat_bump->dvdnu*du;
tco[2] = 0.f;
texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
/* +v val */
@@ -1793,7 +1794,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi,
tco[1] = co[1] + compat_bump->dvdnv*du;
tco[2] = 0.f;
texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
vd = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
}
else {
@@ -1827,7 +1828,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi,
tco[1] = co[1] + tu[1]*du;
tco[2] = co[2] + tu[2]*du;
texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
ud = idu*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
/* +v val */
@@ -1835,7 +1836,7 @@ static int compatible_bump_compute(CompatibleBump *compat_bump, ShadeInput *shi,
tco[1] = co[1] + tv[1]*dv;
tco[2] = co[2] + tv[2]*dv;
texco_mapping(shi, tex, mtex, tco, dx, dy, texv, dxt, dyt);
- multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, texv, dxt, dyt, &ttexr, pool, skip_load_image);
vd = idv*(cd - (fromrgb ? (ttexr.tr + ttexr.tg + ttexr.tb) / 3.0f : ttexr.tin));
}
@@ -1877,7 +1878,8 @@ static void ntap_bump_init(NTapBump *ntap_bump)
static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, Tex *tex, TexResult *texres,
float Tnor, const float co[3], const float dx[3], const float dy[3],
- float texvec[3], float dxt[3], float dyt[3], struct ImagePool *pool)
+ float texvec[3], float dxt[3], float dyt[3], struct ImagePool *pool,
+ const bool skip_load_image)
{
TexResult ttexr = {0, 0, 0, 0, 0, texres->talpha, NULL}; /* temp TexResult */
@@ -1937,7 +1939,7 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T
float dBdu, dBdv, auto_bump = 1.0f;
float s = 1; /* negate this if flipped texture coordinate */
texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool);
+ rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, texres, pool, skip_load_image);
if (shi->obr->ob->derivedFinal) {
auto_bump = shi->obr->ob->derivedFinal->auto_bump_scale;
@@ -1979,14 +1981,14 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T
}
/* use texres for the center sample, set rgbnor */
- rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres, pool);
+ rgbnor = multitex_mtex(shi, mtex, STll, dxt, dyt, texres, pool, skip_load_image);
Hll = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin;
/* use ttexr for the other 2 taps */
- multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, STlr, dxt, dyt, &ttexr, pool, skip_load_image);
Hlr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, STul, dxt, dyt, &ttexr, pool, skip_load_image);
Hul = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
dHdx = Hscale*(Hlr - Hll);
@@ -2017,17 +2019,17 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T
}
/* use texres for the center sample, set rgbnor */
- rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres, pool);
+ rgbnor = multitex_mtex(shi, mtex, STc, dxt, dyt, texres, pool, skip_load_image);
/* Hc = (fromrgb) ? rgb_to_grayscale(&texres->tr) : texres->tin; */ /* UNUSED */
/* use ttexr for the other taps */
- multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, STl, dxt, dyt, &ttexr, pool, skip_load_image);
Hl = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, STr, dxt, dyt, &ttexr, pool, skip_load_image);
Hr = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, STd, dxt, dyt, &ttexr, pool, skip_load_image);
Hd = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
- multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr, pool);
+ multitex_mtex(shi, mtex, STu, dxt, dyt, &ttexr, pool, skip_load_image);
Hu = (fromrgb) ? rgb_to_grayscale(&ttexr.tr) : ttexr.tin;
dHdx = Hscale*(Hr - Hl);
@@ -2137,6 +2139,7 @@ static int ntap_bump_compute(NTapBump *ntap_bump, ShadeInput *shi, MTex *mtex, T
void do_material_tex(ShadeInput *shi, Render *re)
{
+ const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
CompatibleBump compat_bump;
NTapBump ntap_bump;
MTex *mtex;
@@ -2249,7 +2252,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
if (mtex->uvname[0] != 0) {
for (i = 0; i < shi->totuv; i++) {
- if (strcmp(shi->uv[i].name, mtex->uvname)==0) {
+ if (STREQ(shi->uv[i].name, mtex->uvname)) {
suv= &shi->uv[i];
break;
}
@@ -2305,21 +2308,21 @@ void do_material_tex(ShadeInput *shi, Render *re)
if (use_compat_bump) {
rgbnor = compatible_bump_compute(&compat_bump, shi, mtex, tex,
&texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt,
- re->pool);
+ re->pool, skip_load_image);
}
else if (use_ntap_bump) {
rgbnor = ntap_bump_compute(&ntap_bump, shi, mtex, tex,
&texres, Tnor*stencilTin, co, dx, dy, texvec, dxt, dyt,
- re->pool);
+ re->pool, skip_load_image);
}
else {
texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool);
+ rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool, skip_load_image);
}
}
else {
texco_mapping(shi, tex, mtex, co, dx, dy, texvec, dxt, dyt);
- rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool);
+ rgbnor = multitex_mtex(shi, mtex, texvec, dxt, dyt, &texres, re->pool, skip_load_image);
}
/* texture output */
@@ -2671,6 +2674,7 @@ void do_material_tex(ShadeInput *shi, Render *re)
void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_r[3], float *val, Render *re)
{
+ const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
MTex *mtex;
Tex *tex;
TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
@@ -2758,7 +2762,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
else texvec[2]= mtex->size[2]*(mtex->ofs[2]);
}
- rgbnor = multitex(tex, texvec, NULL, NULL, 0, &texres, shi->thread, mtex->which_output, re->pool); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
+ rgbnor = multitex(tex, texvec, NULL, NULL, 0, &texres, shi->thread, mtex->which_output, re->pool, skip_load_image); /* NULL = dxt/dyt, 0 = shi->osatex - not supported */
/* texture output */
@@ -2869,6 +2873,7 @@ void do_volume_tex(ShadeInput *shi, const float *xyz, int mapto_flag, float col_
void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
{
+ const bool skip_load_image = har->skip_load_image;
MTex *mtex;
TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
float texvec[3], dxt[3], dyt[3], fact, facm, dx;
@@ -2925,7 +2930,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
if (mtex->tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
- rgb = multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres, 0, mtex->which_output, har->pool);
+ rgb = multitex(mtex->tex, texvec, dxt, dyt, osatex, &texres, 0, mtex->which_output, har->pool, skip_load_image);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3014,6 +3019,7 @@ void do_halo_tex(HaloRen *har, float xn, float yn, float col_r[4])
/* hor and zen are RGB vectors, blend is 1 float, should all be initialized */
void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float hor[3], float zen[3], float *blend, int skyflag, short thread)
{
+ const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
MTex *mtex;
Tex *tex;
TexResult texres= {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0, NULL};
@@ -3130,7 +3136,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
/* texture */
if (tex->type==TEX_IMAGE) do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
- rgb = multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres, thread, mtex->which_output, R.pool);
+ rgb = multitex(mtex->tex, texvec, dxt, dyt, R.osa, &texres, thread, mtex->which_output, R.pool, skip_load_image);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3222,6 +3228,7 @@ void do_sky_tex(const float rco[3], float lo[3], const float dxyview[2], float h
void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r[3], int effect)
{
+ const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
Object *ob;
MTex *mtex;
Tex *tex;
@@ -3345,7 +3352,7 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
}
- rgb = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output, R.pool);
+ rgb = multitex(tex, texvec, dxt, dyt, shi->osatex, &texres, shi->thread, mtex->which_output, R.pool, skip_load_image);
/* texture output */
if (rgb && (mtex->texflag & MTEX_RGBTOINT)) {
@@ -3419,7 +3426,7 @@ void do_lamp_tex(LampRen *la, const float lavec[3], ShadeInput *shi, float col_r
/* ------------------------------------------------------------------------- */
-int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool)
+int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool, const bool skip_load_image)
{
Tex *tex;
TexResult texr;
@@ -3445,7 +3452,7 @@ int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg,
do_2d_mapping(mtex, texvec, NULL, NULL, dxt, dyt);
}
- rgb = multitex(tex, texvec, dxt, dyt, 0, &texr, thread, mtex->which_output, pool);
+ rgb = multitex(tex, texvec, dxt, dyt, 0, &texr, thread, mtex->which_output, pool, skip_load_image);
if (rgb) {
texr.tin = rgb_to_bw(&texr.tr);
@@ -3470,6 +3477,7 @@ int externtex(MTex *mtex, const float vec[3], float *tin, float *tr, float *tg,
void render_realtime_texture(ShadeInput *shi, Image *ima)
{
+ const bool skip_load_image = (R.r.scemode & R_NO_IMAGE_LOAD) != 0;
TexResult texr;
static Tex imatex[BLENDER_MAX_THREADS]; /* threadsafe */
static int firsttime= 1;
@@ -3510,8 +3518,8 @@ void render_realtime_texture(ShadeInput *shi, Image *ima)
texr.nor= NULL;
- if (shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr, R.pool);
- else imagewrap(tex, ima, NULL, texvec, &texr, R.pool);
+ if (shi->osatex) imagewraposa(tex, ima, NULL, texvec, dx, dy, &texr, R.pool, skip_load_image);
+ else imagewrap(tex, ima, NULL, texvec, &texr, R.pool, skip_load_image);
shi->vcol[0]*= texr.tr;
shi->vcol[1]*= texr.tg;
diff --git a/source/blender/render/intern/source/renderdatabase.c b/source/blender/render/intern/source/renderdatabase.c
index cafdbe2b488..42c654b2c43 100644
--- a/source/blender/render/intern/source/renderdatabase.c
+++ b/source/blender/render/intern/source/renderdatabase.c
@@ -954,6 +954,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
const float vec[3], const float vec1[3],
const float *orco, float hasize, float vectsize, int seed)
{
+ const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
HaloRen *har;
MTex *mtex;
float tin, tr, tg, tb, ta;
@@ -1045,7 +1046,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
}
}
- externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool);
+ externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool, skip_load_image);
yn= tin*mtex->colfac;
//zn= tin*mtex->alphafac;
@@ -1065,6 +1066,7 @@ HaloRen *RE_inithalo(Render *re, ObjectRen *obr, Material *ma,
}
har->pool = re->pool;
+ har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
return har;
}
@@ -1073,6 +1075,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
const float vec[3], const float vec1[3],
const float *orco, const float *uvco, float hasize, float vectsize, int seed, const float pa_co[3])
{
+ const bool skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
HaloRen *har;
MTex *mtex;
float tin, tr, tg, tb, ta;
@@ -1176,7 +1179,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
copy_v3_v3(texvec, orco);
}
- hasrgb = externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool);
+ hasrgb = externtex(mtex, texvec, &tin, &tr, &tg, &tb, &ta, 0, re->pool, skip_load_image);
//yn= tin*mtex->colfac;
//zn= tin*mtex->alphafac;
@@ -1220,6 +1223,7 @@ HaloRen *RE_inithalo_particle(Render *re, ObjectRen *obr, DerivedMesh *dm, Mater
}
har->pool = re->pool;
+ har->skip_load_image = (re->r.scemode & R_NO_IMAGE_LOAD) != 0;
return har;
}
diff --git a/source/blender/render/intern/source/shadeoutput.c b/source/blender/render/intern/source/shadeoutput.c
index 93e8c6a275a..63a97a04b39 100644
--- a/source/blender/render/intern/source/shadeoutput.c
+++ b/source/blender/render/intern/source/shadeoutput.c
@@ -2064,7 +2064,7 @@ float RE_lamp_get_data(ShadeInput *shi, Object *lamp_obj, float col[4], float lv
if (R.r.scemode & R_BUTS_PREVIEW) {
for (go = R.lights.first; go; go = go->next) {
/* "Lamp.002" is main key light of material preview */
- if (strcmp(go->ob->id.name + 2, "Lamp.002") == 0)
+ if (STREQ(go->ob->id.name + 2, "Lamp.002"))
return lamp_get_data_internal(shi, go, col, lv, dist, shadow);
}
return 0.0f;
diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c
index 8ea3a753283..890b0445ecc 100644
--- a/source/blender/render/intern/source/sss.c
+++ b/source/blender/render/intern/source/sss.c
@@ -1031,14 +1031,12 @@ void make_sss_tree(Render *re)
void free_sss(Render *re)
{
if (re->sss_hash) {
- GHashIterator *it= BLI_ghashIterator_new(re->sss_hash);
+ GHashIterator gh_iter;
- while (!BLI_ghashIterator_done(it)) {
- sss_free_tree(BLI_ghashIterator_getValue(it));
- BLI_ghashIterator_step(it);
+ GHASH_ITER (gh_iter, re->sss_hash) {
+ sss_free_tree(BLI_ghashIterator_getValue(&gh_iter));
}
- BLI_ghashIterator_free(it);
BLI_ghash_free(re->sss_hash, NULL, NULL);
re->sss_hash= NULL;
}
diff --git a/source/blender/render/intern/source/sunsky.c b/source/blender/render/intern/source/sunsky.c
index 6078989f9f6..d4e53eb7305 100644
--- a/source/blender/render/intern/source/sunsky.c
+++ b/source/blender/render/intern/source/sunsky.c
@@ -254,14 +254,14 @@ void GetSkyXYZRadiance(struct SunSky *sunsky, float theta, float phi, float colo
float hfade = 1, nfade = 1;
- if (theta > (0.5f * (float)M_PI)) {
+ if (theta > (float)M_PI_2) {
hfade = 1.0f - (theta * (float)M_1_PI - 0.5f) * 2.0f;
hfade = hfade * hfade * (3.0f - 2.0f * hfade);
- theta = 0.5 * M_PI;
+ theta = M_PI_2;
}
- if (sunsky->theta > (0.5f * (float)M_PI)) {
- if (theta <= 0.5f * (float)M_PI) {
+ if (sunsky->theta > (float)M_PI_2) {
+ if (theta <= (float)M_PI_2) {
nfade = 1.0f - (0.5f - theta * (float)M_1_PI) * 2.0f;
nfade *= 1.0f - (sunsky->theta * (float)M_1_PI - 0.5f) * 2.0f;
nfade = nfade * nfade * (3.0f - 2.0f * nfade);
diff --git a/source/blender/render/intern/source/voxeldata.c b/source/blender/render/intern/source/voxeldata.c
index 69a1317cf7d..40a26af5849 100644
--- a/source/blender/render/intern/source/voxeldata.c
+++ b/source/blender/render/intern/source/voxeldata.c
@@ -51,16 +51,19 @@
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
+#include "BKE_cloth.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_modifier.h"
#include "smoke_API.h"
+#include "BPH_mass_spring.h"
#include "DNA_texture_types.h"
#include "DNA_object_force.h"
#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
#include "DNA_pointcache_types.h"
#include "DNA_modifier_types.h"
#include "DNA_smoke_types.h"
@@ -365,6 +368,27 @@ static void init_frame_smoke(VoxelData *vd, int cfra)
#endif
}
+static void init_frame_hair(VoxelData *vd, int UNUSED(cfra))
+{
+ Object *ob;
+ ModifierData *md;
+ bool found = false;
+
+ vd->dataset = NULL;
+ if (vd->object == NULL) return;
+ ob = vd->object;
+
+ if ((md = (ModifierData *)modifiers_findByType(ob, eModifierType_ParticleSystem))) {
+ ParticleSystemModifierData *pmd = (ParticleSystemModifierData *)md;
+
+ if (pmd->psys && pmd->psys->clmd) {
+ found |= BPH_cloth_solver_get_texture_data(ob, pmd->psys->clmd, vd);
+ }
+ }
+
+ vd->ok = found;
+}
+
void cache_voxeldata(Tex *tex, int scene_frame)
{
VoxelData *vd = tex->vd;
@@ -398,6 +422,9 @@ void cache_voxeldata(Tex *tex, int scene_frame)
case TEX_VD_SMOKE:
init_frame_smoke(vd, scene_frame);
return;
+ case TEX_VD_HAIR:
+ init_frame_hair(vd, scene_frame);
+ return;
case TEX_VD_BLENDERVOXEL:
BLI_path_abs(path, G.main->name);
if (!BLI_exists(path)) return;
diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h
index e64b1152252..fc1bc487ca9 100644
--- a/source/blender/windowmanager/WM_types.h
+++ b/source/blender/windowmanager/WM_types.h
@@ -239,6 +239,7 @@ typedef struct wmNotifier {
#define NC_MASK (21<<24)
#define NC_GPENCIL (22<<24)
#define NC_LINESTYLE (23<<24)
+#define NC_CAMERA (24<<24)
/* data type, 256 entries is enough, it can overlap */
#define NOTE_DATA 0x00FF0000
@@ -297,6 +298,7 @@ typedef struct wmNotifier {
#define ND_POINTCACHE (28<<16)
#define ND_PARENT (29<<16)
#define ND_LOD (30<<16)
+#define ND_DRAW_RENDER_VIEWPORT (31<<16) /* for camera & sequencer viewport update, also /w NC_SCENE */
/* NC_MATERIAL Material */
#define ND_SHADING (30<<16)
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index a6a3c6b0a28..34069e0b873 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -250,15 +250,14 @@ void WM_uilisttype_init(void)
void WM_uilisttype_free(void)
{
- GHashIterator *iter = BLI_ghashIterator_new(uilisttypes_hash);
+ GHashIterator gh_iter;
- for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) {
- uiListType *ult = BLI_ghashIterator_getValue(iter);
+ GHASH_ITER (gh_iter, uilisttypes_hash) {
+ uiListType *ult = BLI_ghashIterator_getValue(&gh_iter);
if (ult->ext.free) {
ult->ext.free(ult->ext.data);
}
}
- BLI_ghashIterator_free(iter);
BLI_ghash_free(uilisttypes_hash, NULL, MEM_freeN);
uilisttypes_hash = NULL;
@@ -309,15 +308,14 @@ void WM_menutype_init(void)
void WM_menutype_free(void)
{
- GHashIterator *iter = BLI_ghashIterator_new(menutypes_hash);
+ GHashIterator gh_iter;
- for (; !BLI_ghashIterator_done(iter); BLI_ghashIterator_step(iter)) {
- MenuType *mt = BLI_ghashIterator_getValue(iter);
+ GHASH_ITER (gh_iter, menutypes_hash) {
+ MenuType *mt = BLI_ghashIterator_getValue(&gh_iter);
if (mt->ext.free) {
mt->ext.free(mt->ext.data);
}
}
- BLI_ghashIterator_free(iter);
BLI_ghash_free(menutypes_hash, NULL, MEM_freeN);
menutypes_hash = NULL;
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 68592b44845..cdc3c9eaaff 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -81,7 +81,7 @@ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
for (dm = dropboxes.first; dm; dm = dm->next)
if (dm->spaceid == spaceid && dm->regionid == regionid)
- if (0 == strncmp(idname, dm->idname, KMAP_MAX_NAME))
+ if (STREQLEN(idname, dm->idname, KMAP_MAX_NAME))
return &dm->dropboxes;
dm = MEM_callocN(sizeof(struct wmDropBoxMap), "dropmap list");
@@ -267,16 +267,11 @@ void wm_drags_check_ops(bContext *C, wmEvent *event)
static void wm_drop_operator_draw(const char *name, int x, int y)
{
- int width = UI_fontstyle_string_width(name);
- int padding = 4 * UI_DPI_FAC;
-
- glColor4ub(0, 0, 0, 50);
-
- UI_draw_roundbox_corner_set(UI_CNR_ALL | UI_RB_ALPHA);
- UI_draw_roundbox(x, y, x + width + 2 * padding, y + 4 * padding, padding);
-
- glColor4ub(255, 255, 255, 255);
- UI_draw_string(x + padding, y + padding, name);
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
+ const unsigned char fg[4] = {255, 255, 255, 255};
+ const unsigned char bg[4] = {0, 0, 0, 50};
+
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg);
}
static const char *wm_drag_name(wmDrag *drag)
@@ -284,13 +279,12 @@ static const char *wm_drag_name(wmDrag *drag)
switch (drag->type) {
case WM_DRAG_ID:
{
- ID *id = (ID *)drag->poin;
+ ID *id = drag->poin;
return id->name + 2;
}
case WM_DRAG_PATH:
- return drag->path;
case WM_DRAG_NAME:
- return (char *)drag->path;
+ return drag->path;
}
return "";
}
@@ -311,6 +305,7 @@ static void drag_rect_minmax(rcti *rect, int x1, int y1, int x2, int y2)
/* if rect set, do not draw */
void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
{
+ const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
wmWindowManager *wm = CTX_wm_manager(C);
wmDrag *drag;
const int winsize_y = WM_window_pixels_y(win);
@@ -326,7 +321,7 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
/* XXX todo, multiline drag draws... but maybe not, more types mixed wont work well */
glEnable(GL_BLEND);
for (drag = wm->drags.first; drag; drag = drag->next) {
- int iconsize = 16 * UI_DPI_FAC; /* assumed to be 16 pixels */
+ int iconsize = UI_DPI_ICON_SIZE;
int padding = 4 * UI_DPI_FAC;
/* image or icon */
@@ -362,12 +357,12 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
}
if (rect) {
- int w = UI_fontstyle_string_width(wm_drag_name(drag));
+ int w = UI_fontstyle_string_width(fstyle, wm_drag_name(drag));
drag_rect_minmax(rect, x, y, x + w, y + iconsize);
}
else {
glColor4ub(255, 255, 255, 255);
- UI_draw_string(x, y, wm_drag_name(drag));
+ UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag));
}
/* operator name with roundbox */
@@ -383,14 +378,16 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
else {
x = cursorx - 2 * padding;
- if (cursory + iconsize + iconsize < winsize_y)
- y = cursory + iconsize;
- else
- y = cursory - iconsize - 2 * UI_DPI_FAC;
+ if (cursory + iconsize + iconsize < winsize_y) {
+ y = (cursory + iconsize) + padding;
+ }
+ else {
+ y = (cursory - iconsize) - padding;
+ }
}
if (rect) {
- int w = UI_fontstyle_string_width(wm_drag_name(drag));
+ int w = UI_fontstyle_string_width(fstyle, wm_drag_name(drag));
drag_rect_minmax(rect, x, y, x + w, y + iconsize);
}
else
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index d5c88ff156c..4b8af999205 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -729,7 +729,7 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons
/* XXX Disabled the repeat check to address part 2 of #31840.
* Carefully checked all calls to wm_operator_exec and WM_operator_repeat, don't see any reason
* why this was needed, but worth to note it in case something turns bad. (mont29) */
- if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)/* && repeat == 0 */)
+ if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED) /* && repeat == 0 */)
wm_operator_reports(C, op, retval, false);
if (retval & OPERATOR_FINISHED) {
@@ -870,7 +870,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, wmOperatorType *ot,
break;
/* skip invalid properties */
- if (strcmp(RNA_property_identifier(prop), otmacro->idname) == 0) {
+ if (STREQ(RNA_property_identifier(prop), otmacro->idname)) {
wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
PointerRNA someptr = RNA_property_pointer_get(properties, prop);
wmOperator *opm = wm_operator_create(wm, otm, &someptr, NULL);
@@ -1662,7 +1662,6 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
int action = WM_HANDLER_CONTINUE;
switch (val) {
- case EVT_FILESELECT_OPEN:
case EVT_FILESELECT_FULL_OPEN:
{
ScrArea *sa;
@@ -1676,9 +1675,11 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
else {
sa = handler->op_area;
}
-
- if (val == EVT_FILESELECT_OPEN) {
+
+ /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
+ if (sa->full) {
ED_area_newspace(C, sa, SPACE_FILE); /* 'sa' is modified in-place */
+ sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
}
else {
sa = ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */
@@ -1702,15 +1703,11 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
case EVT_FILESELECT_CANCEL:
case EVT_FILESELECT_EXTERNAL_CANCEL:
{
- /* XXX validate area and region? */
- bScreen *screen = CTX_wm_screen(C);
-
/* remlink now, for load file case before removing*/
BLI_remlink(handlers, handler);
if (val != EVT_FILESELECT_EXTERNAL_CANCEL) {
- ScrArea *sa = CTX_wm_area(C);
- ED_screen_retore_temp_type(C, sa, screen != handler->filescreen);
+ ED_screen_full_prevspace(C, CTX_wm_area(C));
}
wm_handler_op_context(C, handler);
@@ -2459,7 +2456,6 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
wmEventHandler *handler, *handlernext;
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = CTX_wm_window(C);
- int full = 1; // XXX preset?
/* only allow 1 file selector open per window */
for (handler = win->modalhandlers.first; handler; handler = handlernext) {
@@ -2494,7 +2490,6 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
handler->op = op;
handler->op_area = CTX_wm_area(C);
handler->op_region = CTX_wm_region(C);
- handler->filescreen = CTX_wm_screen(C);
BLI_addhead(&win->modalhandlers, handler);
@@ -2504,7 +2499,7 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
op->type->check(C, op); /* ignore return value */
}
- WM_event_fileselect_event(wm, op, full ? EVT_FILESELECT_FULL_OPEN : EVT_FILESELECT_OPEN);
+ WM_event_fileselect_event(wm, op, EVT_FILESELECT_FULL_OPEN);
}
#if 0
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index c1c31f6795d..f5a7ad164d6 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -355,7 +355,7 @@ static int wm_read_exotic(Scene *UNUSED(scene), const char *name)
else {
len = gzread(gzfile, header, sizeof(header));
gzclose(gzfile);
- if (len == sizeof(header) && strncmp(header, "BLENDER", 7) == 0) {
+ if (len == sizeof(header) && STREQLEN(header, "BLENDER", 7)) {
retval = BKE_READ_EXOTIC_OK_BLEND;
}
else {
@@ -535,11 +535,13 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
-/* called on startup, (context entirely filled with NULLs) */
-/* or called for 'New File' */
-/* both startup.blend and userpref.blend are checked */
-/* the optional paramater custom_file points to an alterntive startup page */
-/* custom_file can be NULL */
+/**
+ * called on startup, (context entirely filled with NULLs)
+ * or called for 'New File'
+ * both startup.blend and userpref.blend are checked
+ * the optional parameter custom_file points to an alternative startup page
+ * custom_file can be NULL
+ */
int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const char *custom_file)
{
ListBase wmbase;
@@ -561,6 +563,10 @@ int wm_homefile_read(bContext *C, ReportList *reports, bool from_memory, const c
/* options exclude eachother */
BLI_assert((from_memory && custom_file) == 0);
+ if ((G.f & G_SCRIPT_OVERRIDE_PREF) == 0) {
+ BKE_BIT_TEST_SET(G.f, (U.flag & USER_SCRIPT_AUTOEXEC_DISABLE) == 0, G_SCRIPT_AUTOEXEC);
+ }
+
BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_PRE);
UI_view2d_zoom_cache_reset();
@@ -840,11 +846,11 @@ static ImBuf *blend_file_thumb(Scene *scene, bScreen *screen, int **thumb_pt)
if (scene->camera) {
ibuf = ED_view3d_draw_offscreen_imbuf_simple(scene, scene->camera,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, OB_SOLID, false, false, false, R_ADDSKY, err_out);
+ IB_rect, OB_SOLID, false, false, false, R_ALPHAPREMUL, err_out);
}
else {
ibuf = ED_view3d_draw_offscreen_imbuf(scene, v3d, ar, BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, false, R_ADDSKY, err_out);
+ IB_rect, false, R_ALPHAPREMUL, err_out);
}
if (ibuf) {
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index b52f3819d3f..82e46c1b333 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -145,21 +145,15 @@ static void wm_keyconfig_properties_update_ot(ListBase *km_lb)
}
}
-static int wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b)
+static bool wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b)
{
- if (strcmp(a->idname, b->idname) != 0)
- return 0;
-
- if (!RNA_struct_equals(a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE))
- return 0;
-
- if ((a->flag & KMI_INACTIVE) != (b->flag & KMI_INACTIVE))
- return 0;
-
- return (a->propvalue == b->propvalue);
+ return (STREQ(a->idname, b->idname) &&
+ RNA_struct_equals(a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE) &&
+ (a->flag & KMI_INACTIVE) == (b->flag & KMI_INACTIVE) &&
+ a->propvalue == b->propvalue);
}
-static int wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b)
+static bool wm_keymap_item_equals(wmKeyMapItem *a, wmKeyMapItem *b)
{
return (wm_keymap_item_equals_result(a, b) &&
a->type == b->type &&
@@ -266,7 +260,7 @@ wmKeyConfig *WM_keyconfig_new_user(wmWindowManager *wm, const char *idname)
bool WM_keyconfig_remove(wmWindowManager *wm, wmKeyConfig *keyconf)
{
if (BLI_findindex(&wm->keyconfigs, keyconf) != -1) {
- if (strncmp(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr)) == 0) {
+ if (STREQLEN(U.keyconfigstr, keyconf->idname, sizeof(U.keyconfigstr))) {
BLI_strncpy(U.keyconfigstr, wm->defaultconf->idname, sizeof(U.keyconfigstr));
WM_keyconfig_update_tag(NULL, NULL);
}
@@ -421,7 +415,7 @@ wmKeyMapItem *WM_keymap_verify_item(wmKeyMap *keymap, const char *idname, int ty
wmKeyMapItem *kmi;
for (kmi = keymap->items.first; kmi; kmi = kmi->next)
- if (strncmp(kmi->idname, idname, OP_MAX_TYPENAME) == 0)
+ if (STREQLEN(kmi->idname, idname, OP_MAX_TYPENAME))
break;
if (kmi == NULL) {
kmi = MEM_callocN(sizeof(wmKeyMapItem), "keymap entry");
@@ -728,7 +722,7 @@ wmKeyMap *WM_keymap_list_find(ListBase *lb, const char *idname, int spaceid, int
for (km = lb->first; km; km = km->next)
if (km->spaceid == spaceid && km->regionid == regionid)
- if (0 == strncmp(idname, km->idname, KMAP_MAX_NAME))
+ if (STREQLEN(idname, km->idname, KMAP_MAX_NAME))
return km;
return NULL;
@@ -787,7 +781,7 @@ wmKeyMap *WM_modalkeymap_get(wmKeyConfig *keyconf, const char *idname)
for (km = keyconf->keymaps.first; km; km = km->next)
if (km->flag & KEYMAP_MODAL)
- if (0 == strncmp(idname, km->idname, KMAP_MAX_NAME))
+ if (STREQLEN(idname, km->idname, KMAP_MAX_NAME))
break;
return km;
@@ -952,18 +946,17 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
if (kmi->flag & KMI_INACTIVE)
continue;
- if (strcmp(kmi->idname, opname) == 0 && WM_key_event_string(kmi->type)[0]) {
+ if (STREQ(kmi->idname, opname) && WM_key_event_string(kmi->type)[0]) {
if (is_hotkey) {
if (!ISHOTKEY(kmi->type))
continue;
}
if (properties) {
-
/* example of debugging keymaps */
#if 0
if (kmi->ptr) {
- if (strcmp("MESH_OT_rip_move", opname) == 0) {
+ if (STREQ("MESH_OT_rip_move", opname)) {
printf("OPERATOR\n");
IDP_spit(properties);
printf("KEYMAP\n");
@@ -976,6 +969,39 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(
if (keymap_r) *keymap_r = keymap;
return kmi;
}
+ /* Debug only, helps spotting mismatches between menu entries and shortcuts! */
+ else if (G.debug & G_DEBUG_WM) {
+ if (is_strict && kmi->ptr) {
+ wmOperatorType *ot = WM_operatortype_find(opname, true);
+ if (ot) {
+ /* make a copy of the properties and set unset ones to their default values. */
+ PointerRNA opptr;
+ IDProperty *properties_default = IDP_CopyProperty(kmi->ptr->data);
+
+ RNA_pointer_create(NULL, ot->srna, properties_default, &opptr);
+ WM_operator_properties_default(&opptr, true);
+
+ if (IDP_EqualsProperties_ex(properties, properties_default, is_strict)) {
+ char kmi_str[128];
+ WM_keymap_item_to_string(kmi, kmi_str, sizeof(kmi_str));
+ /* Note gievn properties could come from other things than menu entry... */
+ printf("%s: Some set values in menu entry match default op values, "
+ "this might not be desired!\n", opname);
+ printf("\tkm: '%s', kmi: '%s'\n", keymap->idname, kmi_str);
+#ifndef NDEBUG
+ printf("OPERATOR\n");
+ IDP_spit(properties);
+ printf("KEYMAP\n");
+ IDP_spit(kmi->ptr->data);
+#endif
+ printf("\n");
+ }
+
+ IDP_FreeProperty(properties_default);
+ MEM_freeN(properties_default);
+ }
+ }
+ }
}
else {
if (keymap_r) *keymap_r = keymap;
@@ -1042,33 +1068,83 @@ static wmKeyMapItem *wm_keymap_item_find_props(
static wmKeyMapItem *wm_keymap_item_find(
const bContext *C, const char *opname, int opcontext,
- IDProperty *properties, const bool is_hotkey, const bool is_strict, wmKeyMap **keymap_r)
+ IDProperty *properties, const bool is_hotkey, bool is_strict, wmKeyMap **keymap_r)
{
- wmKeyMapItem *found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+ wmKeyMapItem *found;
+ /* XXX Hack! Macro operators in menu entry have their whole props defined, which is not the case for
+ * relevant keymap entries. Could be good to check and harmonize this, but for now always
+ * compare non-strict in this case.
+ */
+ wmOperatorType *ot = WM_operatortype_find(opname, true);
+ if (ot) {
+ is_strict = is_strict && ((ot->flag & OPTYPE_MACRO) == 0);
+ }
+
+ found = wm_keymap_item_find_props(C, opname, opcontext, properties, is_strict, is_hotkey, keymap_r);
+
+ /* This block is *only* useful in one case: when op uses an enum menu in its prop member
+ * (then, we want to rerun a comparison with that 'prop' unset). Note this remains brittle,
+ * since now any enum prop may be used in UI (specified by name), ot->prop is not so much used...
+ * Otherwise:
+ * * If non-strict, unset properties always match set ones in IDP_EqualsProperties_ex.
+ * * If strict, unset properties never match set ones in IDP_EqualsProperties_ex,
+ * and we do not want that to change (else we get things like T41757)!
+ * ...so in either case, re-running a comparison with unset props set to default is useless.
+ */
if (!found && properties) {
- wmOperatorType *ot = WM_operatortype_find(opname, true);
- if (ot) {
- /* make a copy of the properties and set any unset props
- * to their default values, so the ID property compare function succeeds */
+ if (ot && ot->prop) { /* XXX Shall we also check ot->prop is actually an enum? */
+ /* make a copy of the properties and unset the 'ot->prop' one if set. */
PointerRNA opptr;
- IDProperty *properties_default = IDP_CopyProperty(properties);
+ IDProperty *properties_temp = IDP_CopyProperty(properties);
- RNA_pointer_create(NULL, ot->srna, properties_default, &opptr);
+ RNA_pointer_create(NULL, ot->srna, properties_temp, &opptr);
- if (WM_operator_properties_default(&opptr, true) ||
- (!is_strict && ot->prop && RNA_property_is_set(&opptr, ot->prop)))
- {
- /* for operator that has enum menu, unset it so it always matches */
- if (!is_strict && ot->prop) {
- RNA_property_unset(&opptr, ot->prop);
- }
+ if (RNA_property_is_set(&opptr, ot->prop)) {
+ /* for operator that has enum menu, unset it so its value does not affect comparison result */
+ RNA_property_unset(&opptr, ot->prop);
- found = wm_keymap_item_find_props(C, opname, opcontext, properties_default, false, is_hotkey, keymap_r);
+ found = wm_keymap_item_find_props(C, opname, opcontext, properties_temp,
+ is_strict, is_hotkey, keymap_r);
}
- IDP_FreeProperty(properties_default);
- MEM_freeN(properties_default);
+ IDP_FreeProperty(properties_temp);
+ MEM_freeN(properties_temp);
+ }
+ }
+
+ /* Debug only, helps spotting mismatches between menu entries and shortcuts! */
+ if (G.debug & G_DEBUG_WM) {
+ if (!found && is_strict && properties) {
+ wmKeyMap *km;
+ wmKeyMapItem *kmi;
+ if (ot) {
+ /* make a copy of the properties and set unset ones to their default values. */
+ PointerRNA opptr;
+ IDProperty *properties_default = IDP_CopyProperty(properties);
+
+ RNA_pointer_create(NULL, ot->srna, properties_default, &opptr);
+ WM_operator_properties_default(&opptr, true);
+
+ kmi = wm_keymap_item_find_props(C, opname, opcontext, properties_default, is_strict, is_hotkey, &km);
+ if (kmi) {
+ char kmi_str[128];
+ WM_keymap_item_to_string(kmi, kmi_str, sizeof(kmi_str));
+ printf("%s: Some set values in keymap entry match default op values, "
+ "this might not be desired!\n", opname);
+ printf("\tkm: '%s', kmi: '%s'\n", km->idname, kmi_str);
+#ifndef NDEBUG
+ printf("OPERATOR\n");
+ IDP_spit(properties);
+ printf("KEYMAP\n");
+ IDP_spit(kmi->ptr->data);
+#endif
+ printf("\n");
+ }
+
+ IDP_FreeProperty(properties_default);
+ MEM_freeN(properties_default);
+ }
}
}
@@ -1353,7 +1429,7 @@ void WM_keymap_restore_item_to_default(bContext *C, wmKeyMap *keymap, wmKeyMapIt
if (orig) {
/* restore to original */
- if (strcmp(orig->idname, kmi->idname) != 0) {
+ if (!STREQ(orig->idname, kmi->idname)) {
BLI_strncpy(kmi->idname, orig->idname, sizeof(kmi->idname));
WM_keymap_properties_reset(kmi, NULL);
}
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index d49a298c424..c0f8709b0f7 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -102,6 +102,8 @@
#include "ED_util.h"
#include "ED_view3d.h"
+#include "GPU_material.h"
+
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -1187,7 +1189,7 @@ bool WM_operator_filesel_ensure_ext_imtype(wmOperator *op, const struct ImageFor
/* dont NULL check prop, this can only run on ops with a 'filepath' */
prop = RNA_struct_find_property(op->ptr, "filepath");
RNA_property_string_get(op->ptr, prop, filepath);
- if (BKE_add_image_extension(filepath, im_format)) {
+ if (BKE_image_path_ensure_ext_from_imformat(filepath, im_format)) {
RNA_property_string_set(op->ptr, prop, filepath);
/* note, we could check for and update 'filename' here,
* but so far nothing needs this. */
@@ -1675,7 +1677,7 @@ int WM_operator_ui_popup(bContext *C, wmOperator *op, int width, int height)
/**
* For use by #WM_operator_props_popup_call, #WM_operator_props_popup only.
*
- * \note operator menu needs undo flag enabled , for redo callback */
+ * \note operator menu needs undo flag enabled, for redo callback */
static int wm_operator_props_popup_ex(bContext *C, wmOperator *op,
const bool do_call, const bool do_redo)
{
@@ -2026,6 +2028,14 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
uiItemO(col, NULL, ICON_RECOVER_LAST, "WM_OT_recover_last_session");
uiItemL(col, "", ICON_NONE);
+ mt = WM_menutype_find("USERPREF_MT_splash_footer", false);
+ if (mt) {
+ Menu menu = {NULL};
+ menu.layout = uiLayoutColumn(layout, false);
+ menu.type = mt;
+ mt->draw(C, &menu);
+ }
+
UI_block_bounds_set_centered(block, 0);
return block;
@@ -2682,7 +2692,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* recreate dependency graph to include new objects */
DAG_scene_relations_rebuild(bmain, scene);
-
+
+ /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
+ GPU_materials_free();
BLO_blendhandle_close(bh);
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
@@ -3804,8 +3816,8 @@ void WM_OT_straightline_gesture(wmOperatorType *ot)
/* *********************** radial control ****************** */
-#define WM_RADIAL_CONTROL_DISPLAY_SIZE 200
-#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE 35
+#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * U.pixelsize)
+#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * U.pixelsize)
#define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE)
#define WM_RADIAL_CONTROL_HEADER_LENGTH 180
#define WM_RADIAL_MAX_STR 6
@@ -3856,7 +3868,7 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e
case PROP_DISTANCE:
case PROP_PERCENTAGE:
case PROP_PIXEL:
- d[0] = rc->initial_value;
+ d[0] = rc->initial_value * U.pixelsize;
break;
case PROP_FACTOR:
d[0] = (1 - rc->initial_value) * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE;
@@ -3965,8 +3977,8 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
case PROP_DISTANCE:
case PROP_PERCENTAGE:
case PROP_PIXEL:
- r1 = rc->current_value;
- r2 = rc->initial_value;
+ r1 = rc->current_value * U.pixelsize;
+ r2 = rc->initial_value * U.pixelsize;
tex_radius = r1;
alpha = 0.75;
break;
@@ -3991,11 +4003,6 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
break;
}
- /* adjust for DPI, like BKE_brush_size_get */
- r1 *= U.pixelsize;
- r2 *= U.pixelsize;
- tex_radius *= U.pixelsize;
-
/* Keep cursor in the original place */
x = rc->initial_mouse[0] - ar->winrct.xmin;
y = rc->initial_mouse[1] - ar->winrct.ymin;
@@ -4413,13 +4420,14 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even
case PROP_PIXEL:
new_value = dist;
if (snap) new_value = ((int)new_value + 5) / 10 * 10;
+ new_value /= U.pixelsize;
break;
case PROP_FACTOR:
new_value = (WM_RADIAL_CONTROL_DISPLAY_SIZE - dist) / WM_RADIAL_CONTROL_DISPLAY_WIDTH;
if (snap) new_value = ((int)ceil(new_value * 10.f) * 10.0f) / 100.f;
break;
case PROP_ANGLE:
- new_value = atan2f(delta[1], delta[0]) + M_PI + angle_precision;
+ new_value = atan2f(delta[1], delta[0]) + (float)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;
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index d2df020600a..4ce2415e310 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -367,7 +367,7 @@ static void wmOrtho2_offset(const float x, const float y, const float ofs)
*/
void wmOrtho2_region_pixelspace(const struct ARegion *ar)
{
- wmOrtho2_offset(ar->winx + 1, ar->winy + 1, -GLA_PIXEL_OFS);
+ wmOrtho2_offset(ar->winx, ar->winy, -0.01f);
}
void wmOrtho2_pixelspace(const float x, const float y)
diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h
index d1a94194108..f89177a82ea 100644
--- a/source/blender/windowmanager/wm_event_system.h
+++ b/source/blender/windowmanager/wm_event_system.h
@@ -65,9 +65,6 @@ typedef struct wmEventHandler {
struct ARegion *ui_region; /* for derived/modal handlers */
struct ARegion *ui_menu; /* for derived/modal handlers */
- /* fileselect handler re-uses modal operator data */
- struct bScreen *filescreen; /* screen it started in, to validate exec */
-
/* drop box handler */
ListBase *dropboxes;
diff --git a/source/blender/windowmanager/wm_event_types.h b/source/blender/windowmanager/wm_event_types.h
index 2301405a8ea..ecc29de0e7d 100644
--- a/source/blender/windowmanager/wm_event_types.h
+++ b/source/blender/windowmanager/wm_event_types.h
@@ -369,6 +369,18 @@ enum {
(event_type >= LEFTCTRLKEY && event_type <= LEFTSHIFTKEY) == false && \
(event_type >= UNKNOWNKEY && event_type <= GRLESSKEY) == false)
+/* internal helpers*/
+#define _VA_IS_EVENT_MOD2(v, a) (CHECK_TYPE_INLINE(v, wmEvent *), \
+ ((v)->a))
+#define _VA_IS_EVENT_MOD3(v, a, b) \
+ (_VA_IS_EVENT_MOD2(v, a) || ((v)->b))
+#define _VA_IS_EVENT_MOD4(v, a, b, c) \
+ (_VA_IS_EVENT_MOD3(v, a, b) || ((v)->c))
+#define _VA_IS_EVENT_MOD5(v, a, b, c, d) \
+ (_VA_IS_EVENT_MOD4(v, a, b, c) || ((v)->d))
+
+/* reusable IS_EVENT_MOD(event, shift, ctrl, alt, oskey), macro */
+#define IS_EVENT_MOD(...) VA_NARGS_CALL_OVERLOAD(_VA_IS_EVENT_MOD, __VA_ARGS__)
/* ********** wmEvent.val ********** */
@@ -397,11 +409,10 @@ enum {
/* 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,
+ EVT_FILESELECT_FULL_OPEN = 1,
+ EVT_FILESELECT_EXEC = 2,
+ EVT_FILESELECT_CANCEL = 3,
+ EVT_FILESELECT_EXTERNAL_CANCEL = 4,
};
/* Gesture */
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 4a154d778e7..25ee4f2ef21 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -106,6 +106,7 @@ endif()
bf_intern_ghostndof3dconnexion
bf_rna
bf_blenkernel
+ bf_physics
bf_intern_rigidbody
bf_blenloader
ge_blen_routines
diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c
index 9eff3405a2f..21c69ac6203 100644
--- a/source/blenderplayer/bad_level_call_stubs/stubs.c
+++ b/source/blenderplayer/bad_level_call_stubs/stubs.c
@@ -239,8 +239,8 @@ 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
-int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage) RET_ZERO
+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, const bool skip_load_image) RET_ZERO
+int multitex_ext_safe(struct Tex *tex, float texvec[3], struct TexResult *texres, struct ImagePool *pool, bool scene_color_manage, const bool skip_load_image) RET_ZERO
int multitex_nodes(struct Tex *tex, float texvec[3], float dxt[3], float dyt[3], int osatex, struct TexResult *texres, const short thread, short which_output, struct ShadeInput *shi, struct MTex *mtex, struct ImagePool *pool) RET_ZERO
struct Material *RE_init_sample_material(struct Material *orig_mat, struct Scene *scene) RET_NULL
@@ -263,7 +263,7 @@ struct Scene *RE_GetScene(struct Render *re) RET_NULL
void RE_Database_Free(struct Render *re) RET_NONE
void RE_FreeRender(struct Render *re) RET_NONE
void RE_DataBase_GetView(struct Render *re, float mat[4][4]) RET_NONE
-int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *poold) RET_ZERO
+int externtex(struct MTex *mtex, const float vec[3], float *tin, float *tr, float *tg, float *tb, float *ta, const int thread, struct ImagePool *pool, const bool skip_load_image) RET_ZERO
float texture_value_blend(float tex, float out, float fact, float facg, int blendtype) RET_ZERO
void texture_rgb_blend(float in[3], const float tex[3], const float out[3], float fact, float facg, int blendtype) RET_NONE
const unsigned char stipple_quarttone[128];
@@ -341,6 +341,7 @@ bool ED_space_image_show_paint(struct SpaceImage *sima) RET_ZERO
void ED_space_image_paint_update(struct wmWindowManager *wm, struct ToolSettings *settings) RET_NONE
void ED_space_image_set(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit, struct Image *ima) RET_NONE
void ED_space_image_uv_sculpt_update(struct wmWindowManager *wm, struct ToolSettings *settings) RET_NONE
+void ED_space_image_scopes_update(const struct bContext *C, struct SpaceImage *sima, struct ImBuf *ibuf, bool use_view_settings) RET_NONE
void ED_uvedit_get_aspect(struct Scene *scene, struct Object *ob, struct BMesh *em, float *aspx, float *aspy) RET_NONE
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index 21cb41ddfa2..f51b7bec7c9 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -640,9 +640,9 @@ elseif(WIN32)
"
message(STATUS \"Extracting Python to: \${CMAKE_INSTALL_PREFIX}/${BLENDER_VERSION}/python\")
if(\"\${CMAKE_INSTALL_CONFIG_NAME}\" MATCHES \"^([Dd][Ee][Bb][Uu][Gg])$\")
- set(PYTHON_ZIP ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_d.tar.gz)
+ set(PYTHON_ZIP \"${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}_d.tar.gz\")
else()
- set(PYTHON_ZIP ${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}.tar.gz)
+ set(PYTHON_ZIP \"${LIBDIR}/release/python${_PYTHON_VERSION_NO_DOTS}.tar.gz\")
endif()
execute_process(
@@ -761,7 +761,6 @@ elseif(WIN32)
install(
FILES
${LIBDIR}/openal/lib/OpenAL32.dll
- ${LIBDIR}/openal/lib/wrap_oal.dll
DESTINATION "."
)
endif()
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 83741a64ace..15406485c7f 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -755,7 +755,7 @@ static int set_engine(int argc, const char **argv, void *data)
{
bContext *C = data;
if (argc >= 2) {
- if (!strcmp(argv[1], "help")) {
+ if (STREQ(argv[1], "help")) {
RenderEngineType *type = NULL;
printf("Blender Engine Listing:\n");
for (type = R_engines.first; type; type = type->next) {
@@ -773,6 +773,7 @@ static int set_engine(int argc, const char **argv, void *data)
}
else {
printf("\nError: engine not found '%s'\n", argv[1]);
+ exit(1);
}
}
else {
@@ -924,11 +925,11 @@ static int set_ge_parameters(int argc, const char **argv, void *data)
SYS_WriteCommandLineInt(syshandle, argv[a], 1);
#endif
/* doMipMap */
- if (!strcmp(argv[a], "nomipmap")) {
+ if (STREQ(argv[a], "nomipmap")) {
GPU_set_mipmap(0); //doMipMap = 0;
}
/* linearMipMap */
- if (!strcmp(argv[a], "linearmipmap")) {
+ if (STREQ(argv[a], "linearmipmap")) {
GPU_set_linear_mipmap(1); //linearMipMap = 1;
}
@@ -1554,7 +1555,7 @@ int main(
#if defined(__APPLE__) && !defined(WITH_PYTHON_MODULE)
/* patch to ignore argument finder gives us (pid?) */
- if (argc == 2 && strncmp(argv[1], "-psn_", 5) == 0) {
+ if (argc == 2 && STREQLEN(argv[1], "-psn_", 5)) {
extern int GHOST_HACK_getFirstFile(char buf[]);
static char firstfilebuf[512];
diff --git a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
index 31f3b1b2047..5bb2d58cd8d 100644
--- a/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
+++ b/source/gameengine/BlenderRoutines/KX_BlenderCanvas.cpp
@@ -350,7 +350,7 @@ void KX_BlenderCanvas::MakeScreenShot(const char *filename)
char path[FILE_MAX];
BLI_strncpy(path, filename, sizeof(path));
BLI_path_abs(path, G.main->name);
- BKE_add_image_extension_from_type(path, im_format.imtype);
+ BKE_image_path_ensure_ext_from_imtype(path, im_format.imtype);
/* create and save imbuf */
ImBuf *ibuf = IMB_allocImBuf(dumpsx, dumpsy, 24, 0);
diff --git a/source/gameengine/GameLogic/SCA_IInputDevice.h b/source/gameengine/GameLogic/SCA_IInputDevice.h
index 23346c29601..d4cd66fb564 100644
--- a/source/gameengine/GameLogic/SCA_IInputDevice.h
+++ b/source/gameengine/GameLogic/SCA_IInputDevice.h
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file SCA_IController.h
+/** \file SCA_IInputDevice.h
* \ingroup gamelogic
* \brief Interface for input devices. The defines for keyboard/system/mouse events
* here are for internal use in the KX module.
diff --git a/source/gameengine/GameLogic/SCA_IObject.h b/source/gameengine/GameLogic/SCA_IObject.h
index 365e2b0c853..3ffe128c3b3 100644
--- a/source/gameengine/GameLogic/SCA_IObject.h
+++ b/source/gameengine/GameLogic/SCA_IObject.h
@@ -24,7 +24,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file SCA_IController.h
+/** \file SCA_IObject.h
* \ingroup gamelogic
* \brief An abstract object that has some logic, python scripting and
* reference counting Note: transformation stuff has been moved to
diff --git a/source/gameengine/GameLogic/SCA_IScene.cpp b/source/gameengine/GameLogic/SCA_IScene.cpp
index 3ca4b6607b3..b6ce1d86ba7 100644
--- a/source/gameengine/GameLogic/SCA_IScene.cpp
+++ b/source/gameengine/GameLogic/SCA_IScene.cpp
@@ -114,7 +114,7 @@ void SCA_IScene::RemoveDebugProperty(class CValue *gameobj,
const STR_String &name)
{
vector<SCA_DebugProp*>::iterator it = m_debugList.begin();
- while(it != m_debugList.end()) {
+ while (it != m_debugList.end()) {
STR_String debugname = (*it)->m_name;
CValue *debugobj = (*it)->m_obj;
diff --git a/source/gameengine/GameLogic/SCA_ISensor.h b/source/gameengine/GameLogic/SCA_ISensor.h
index 091aa675741..7bbba7aaafe 100644
--- a/source/gameengine/GameLogic/SCA_ISensor.h
+++ b/source/gameengine/GameLogic/SCA_ISensor.h
@@ -25,7 +25,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file SCA_IController.h
+/** \file SCA_ISensor.h
* \ingroup gamelogic
* \brief Interface Class for all logic Sensors. Implements
* pulsemode and pulsefrequency, and event suppression.
diff --git a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
index 3cae3bcf160..e20dd8bcd74 100644
--- a/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
+++ b/source/gameengine/GameLogic/SCA_JoystickSensor.cpp
@@ -351,8 +351,8 @@ PyObject *SCA_JoystickSensor::pyattr_get_axis_values(void *self_v, const KX_PYAT
SCA_JoystickSensor* self = static_cast<SCA_JoystickSensor*>(self_v);
SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex);
- int axis_index= joy->GetNumberOfAxes();
- PyObject *list= PyList_New(axis_index);
+ int axis_index = (joy ? joy->GetNumberOfAxes() : 0);
+ PyObject *list = PyList_New(axis_index);
while (axis_index--) {
PyList_SET_ITEM(list, axis_index, PyLong_FromLong(joy->GetAxisPosition(axis_index)));
@@ -371,7 +371,7 @@ PyObject *SCA_JoystickSensor::pyattr_get_axis_single(void *self_v, const KX_PYAT
return NULL;
}
- return PyLong_FromLong(joy->GetAxisPosition(self->m_axis-1));
+ return PyLong_FromLong(joy ? joy->GetAxisPosition(self->m_axis - 1) : 0);
}
PyObject *SCA_JoystickSensor::pyattr_get_hat_values(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
@@ -379,8 +379,8 @@ PyObject *SCA_JoystickSensor::pyattr_get_hat_values(void *self_v, const KX_PYATT
SCA_JoystickSensor* self = static_cast<SCA_JoystickSensor*>(self_v);
SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex);
- int hat_index= joy->GetNumberOfHats();
- PyObject *list= PyList_New(hat_index);
+ int hat_index = (joy ? joy->GetNumberOfHats() : 0);
+ PyObject *list = PyList_New(hat_index);
while (hat_index--) {
PyList_SET_ITEM(list, hat_index, PyLong_FromLong(joy->GetHat(hat_index)));
@@ -394,7 +394,7 @@ PyObject *SCA_JoystickSensor::pyattr_get_hat_single(void *self_v, const KX_PYATT
SCA_JoystickSensor* self = static_cast<SCA_JoystickSensor*>(self_v);
SCA_Joystick *joy = ((SCA_JoystickManager *)self->m_eventmgr)->GetJoystickDevice(self->m_joyindex);
- return PyLong_FromLong(joy->GetHat(self->m_hat-1));
+ return PyLong_FromLong(joy ? joy->GetHat(self->m_hat - 1) : 0);
}
PyObject *SCA_JoystickSensor::pyattr_get_num_axis(void *self_v, const KX_PYATTRIBUTE_DEF *attrdef)
diff --git a/source/gameengine/GameLogic/SCA_LogicManager.h b/source/gameengine/GameLogic/SCA_LogicManager.h
index 4d8c20065b5..1275a7c5085 100644
--- a/source/gameengine/GameLogic/SCA_LogicManager.h
+++ b/source/gameengine/GameLogic/SCA_LogicManager.h
@@ -24,7 +24,7 @@
*
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file SCA_IController.h
+/** \file SCA_LogicManager.h
* \ingroup gamelogic
* \brief Regulates the top-level logic behavior for one scene.
*/
diff --git a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
index be7cf6629f0..c88d55da2b6 100644
--- a/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
+++ b/source/gameengine/GamePlayer/common/GPC_Canvas.cpp
@@ -180,7 +180,7 @@ MakeScreenShot(
char path[FILE_MAX];
BLI_strncpy(path, filename, sizeof(path));
BLI_path_abs(path, G.main->name);
- BKE_add_image_extension_from_type(path, im_format.imtype);
+ BKE_image_path_ensure_ext_from_imtype(path, im_format.imtype);
// create and save imbuf
ImBuf *ibuf = IMB_allocImBuf(GetWidth(), GetHeight(), 24, 0);
diff --git a/source/gameengine/Ketsji/BL_ActionManager.h b/source/gameengine/Ketsji/BL_ActionManager.h
index 5b340257881..148097f995e 100644
--- a/source/gameengine/Ketsji/BL_ActionManager.h
+++ b/source/gameengine/Ketsji/BL_ActionManager.h
@@ -20,7 +20,7 @@
* ***** END GPL LICENSE BLOCK *****
*/
-/** \file BL_ActionManager.cpp
+/** \file BL_ActionManager.h
* \ingroup ketsji
*/
diff --git a/source/gameengine/Ketsji/BL_BlenderShader.cpp b/source/gameengine/Ketsji/BL_BlenderShader.cpp
index bcdef85bc8a..de6b36b189d 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, false);
+ GPU_material_bind(mGPUMat, mLightLayer, mBlenderScene->lay, time, 1, viewmat, viewinvmat, NULL, false);
}
else
GPU_material_unbind(mGPUMat);
diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp
index e8b68d20e84..6d4b5564e19 100644
--- a/source/gameengine/Ketsji/KX_GameObject.cpp
+++ b/source/gameengine/Ketsji/KX_GameObject.cpp
@@ -77,6 +77,8 @@ typedef unsigned long uint_ptr;
#include "BL_Action.h"
#include "PyObjectPlus.h" /* python stuff */
+#include "BLI_utildefines.h"
+#include "python_utildefines.h"
// This file defines relationships between parents and children
// in the game engine.
@@ -1498,7 +1500,7 @@ void KX_GameObject::RegisterCollisionCallbacks()
pe->AddSensor(spc);
}
}
-void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider)
+void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider, const MT_Vector3 &point, const MT_Vector3 &normal)
{
#ifdef WITH_PYTHON
Py_ssize_t len;
@@ -1506,15 +1508,50 @@ void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider)
if (collision_callbacks && (len=PyList_GET_SIZE(collision_callbacks)))
{
- PyObject* args = Py_BuildValue("(O)", collider->GetProxy()); // save python creating each call
+ // Argument tuples are created lazily, only when they are needed.
+ PyObject *args_3 = NULL;
+ PyObject *args_1 = NULL; // Only for compatibility with pre-2.74 callbacks that take 1 argument.
+
PyObject *func;
PyObject *ret;
+ int co_argcount;
// Iterate the list and run the callbacks
for (Py_ssize_t pos=0; pos < len; pos++)
{
func = PyList_GET_ITEM(collision_callbacks, pos);
- ret = PyObject_Call(func, args, NULL);
+
+ // Get the number of arguments, supporting functions, methods and generic callables.
+ if (PyMethod_Check(func)) {
+ // Take away the 'self' argument for methods.
+ co_argcount = ((PyCodeObject *)PyFunction_GET_CODE(PyMethod_GET_FUNCTION(func)))->co_argcount - 1;
+ } else if (PyFunction_Check(func)) {
+ co_argcount = ((PyCodeObject *)PyFunction_GET_CODE(func))->co_argcount;
+ } else {
+ // We'll just assume the callable takes the correct number of arguments.
+ co_argcount = 3;
+ }
+
+ // Check whether the function expects the colliding object only,
+ // or also the point and normal.
+ if (co_argcount <= 1) {
+ // One argument, or *args (which gives co_argcount == 0)
+ if (args_1 == NULL) {
+ args_1 = PyTuple_New(1);
+ PyTuple_SET_ITEMS(args_1, collider->GetProxy());
+ }
+ ret = PyObject_Call(func, args_1, NULL);
+ } else {
+ // More than one argument, assume we can give point & normal.
+ if (args_3 == NULL) {
+ args_3 = PyTuple_New(3);
+ PyTuple_SET_ITEMS(args_3,
+ collider->GetProxy(),
+ PyObjectFrom(point),
+ PyObjectFrom(normal));
+ }
+ ret = PyObject_Call(func, args_3, NULL);
+ }
if (ret == NULL) {
PyErr_Print();
@@ -1525,7 +1562,8 @@ void KX_GameObject::RunCollisionCallbacks(KX_GameObject *collider)
}
}
- Py_DECREF(args);
+ if (args_3) Py_DECREF(args_3);
+ if (args_1) Py_DECREF(args_1);
}
#endif
}
diff --git a/source/gameengine/Ketsji/KX_GameObject.h b/source/gameengine/Ketsji/KX_GameObject.h
index 4538679303f..5800cbc6834 100644
--- a/source/gameengine/Ketsji/KX_GameObject.h
+++ b/source/gameengine/Ketsji/KX_GameObject.h
@@ -919,7 +919,7 @@ public:
void RegisterCollisionCallbacks();
void UnregisterCollisionCallbacks();
- void RunCollisionCallbacks(KX_GameObject *collider);
+ void RunCollisionCallbacks(KX_GameObject *collider, const MT_Vector3 &point, const MT_Vector3 &normal);
/**
* Stop making progress
*/
diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
index ebf1b9ec577..1b69eab8e28 100644
--- a/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
+++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.cpp
@@ -56,38 +56,95 @@
// if there is a better way (without global), please do so!
static PHY_IPhysicsEnvironment* g_CurrentActivePhysicsEnvironment = NULL;
-static char PhysicsConstraints_module_documentation[] =
-"This is the Python API for the Physics Constraints";
-
-
-static char gPySetGravity__doc__[] = "setGravity(float x,float y,float z)";
-static char gPySetDebugMode__doc__[] = "setDebugMode(int mode)";
-
-static char gPySetNumIterations__doc__[] = "setNumIterations(int numiter) This sets the number of iterations for an iterative constraint solver";
-static char gPySetNumTimeSubSteps__doc__[] = "setNumTimeSubSteps(int numsubstep) This sets the number of substeps for each physics proceed. Tradeoff quality for performance.";
-
-
-static char gPySetDeactivationTime__doc__[] = "setDeactivationTime(float time) This sets the time after which a resting rigidbody gets deactived";
-static char gPySetDeactivationLinearTreshold__doc__[] = "setDeactivationLinearTreshold(float linearTreshold)";
-static char gPySetDeactivationAngularTreshold__doc__[] = "setDeactivationAngularTreshold(float angularTreshold)";
-static char gPySetContactBreakingTreshold__doc__[] = "setContactBreakingTreshold(float breakingTreshold) Reasonable default is 0.02 (if units are meters)";
-
-static char gPySetCcdMode__doc__[] = "setCcdMode(int ccdMode) Very experimental, not recommended";
-static char gPySetSorConstant__doc__[] = "setSorConstant(float sor) Very experimental, not recommended";
-static char gPySetSolverTau__doc__[] = "setTau(float tau) Very experimental, not recommended";
-static char gPySetSolverDamping__doc__[] = "setDamping(float damping) Very experimental, not recommended";
-static char gPySetLinearAirDamping__doc__[] = "setLinearAirDamping(float damping) Very experimental, not recommended";
-static char gPySetUseEpa__doc__[] = "setUseEpa(int epa) Very experimental, not recommended";
-static char gPySetSolverType__doc__[] = "setSolverType(int solverType) Very experimental, not recommended";
-
-
-static char gPyCreateConstraint__doc__[] = "createConstraint(ob1,ob2,float restLength,float restitution,float damping)";
-static char gPyGetVehicleConstraint__doc__[] = "getVehicleConstraint(int constraintId)";
-static char gPyGetCharacter__doc__[] = "getCharacter(KX_GameObject obj)";
-static char gPyRemoveConstraint__doc__[] = "removeConstraint(int constraintId)";
-static char gPyGetAppliedImpulse__doc__[] = "getAppliedImpulse(int constraintId)";
-
+PyDoc_STRVAR(PhysicsConstraints_module_documentation,
+"This is the Python API for the Physics Constraints"
+);
+
+PyDoc_STRVAR(gPySetGravity__doc__,
+"setGravity(float x,float y,float z)\n"
+""
+);
+PyDoc_STRVAR(gPySetDebugMode__doc__,
+"setDebugMode(int mode)\n"
+""
+);
+
+PyDoc_STRVAR(gPySetNumIterations__doc__,
+"setNumIterations(int numiter)\n"
+"This sets the number of iterations for an iterative constraint solver"
+);
+PyDoc_STRVAR(gPySetNumTimeSubSteps__doc__,
+"setNumTimeSubSteps(int numsubstep)\n"
+"This sets the number of substeps for each physics proceed. Tradeoff quality for performance."
+);
+
+PyDoc_STRVAR(gPySetDeactivationTime__doc__,
+"setDeactivationTime(float time)\n"
+"This sets the time after which a resting rigidbody gets deactived"
+);
+PyDoc_STRVAR(gPySetDeactivationLinearTreshold__doc__,
+"setDeactivationLinearTreshold(float linearTreshold)\n"
+""
+);
+PyDoc_STRVAR(gPySetDeactivationAngularTreshold__doc__,
+"setDeactivationAngularTreshold(float angularTreshold)\n"
+""
+);
+PyDoc_STRVAR(gPySetContactBreakingTreshold__doc__,
+"setContactBreakingTreshold(float breakingTreshold)\n"
+"Reasonable default is 0.02 (if units are meters)"
+);
+
+PyDoc_STRVAR(gPySetCcdMode__doc__,
+"setCcdMode(int ccdMode)\n"
+"Very experimental, not recommended"
+);
+PyDoc_STRVAR(gPySetSorConstant__doc__,
+"setSorConstant(float sor)\n"
+"Very experimental, not recommended"
+);
+PyDoc_STRVAR(gPySetSolverTau__doc__,
+"setTau(float tau)\n"
+"Very experimental, not recommended"
+);
+PyDoc_STRVAR(gPySetSolverDamping__doc__,
+"setDamping(float damping)\n"
+"Very experimental, not recommended"
+);
+PyDoc_STRVAR(gPySetLinearAirDamping__doc__,
+"setLinearAirDamping(float damping)\n"
+"Very experimental, not recommended"
+);
+PyDoc_STRVAR(gPySetUseEpa__doc__,
+"setUseEpa(int epa)\n"
+"Very experimental, not recommended"
+);
+PyDoc_STRVAR(gPySetSolverType__doc__,
+"setSolverType(int solverType)\n"
+"Very experimental, not recommended"
+);
+
+PyDoc_STRVAR(gPyCreateConstraint__doc__,
+"createConstraint(ob1,ob2,float restLength,float restitution,float damping)\n"
+""
+);
+PyDoc_STRVAR(gPyGetVehicleConstraint__doc__,
+"getVehicleConstraint(int constraintId)\n"
+""
+);
+PyDoc_STRVAR(gPyGetCharacter__doc__,
+"getCharacter(KX_GameObject obj)\n"
+""
+);
+PyDoc_STRVAR(gPyRemoveConstraint__doc__,
+"removeConstraint(int constraintId)\n"
+""
+);
+PyDoc_STRVAR(gPyGetAppliedImpulse__doc__,
+"getAppliedImpulse(int constraintId)\n"
+""
+);
@@ -677,7 +734,7 @@ static struct PyMethodDef physicsconstraints_methods[] = {
};
static struct PyModuleDef PhysicsConstraints_module_def = {
- {}, /* m_base */
+ PyModuleDef_HEAD_INIT,
"PhysicsConstraints", /* m_name */
PhysicsConstraints_module_documentation, /* m_doc */
0, /* m_size */
@@ -688,7 +745,7 @@ static struct PyModuleDef PhysicsConstraints_module_def = {
0, /* m_free */
};
-PyObject *initPythonConstraintBinding()
+PyMODINIT_FUNC initConstraintPythonBinding()
{
PyObject *ErrorObject;
@@ -696,19 +753,8 @@ PyObject *initPythonConstraintBinding()
PyObject *d;
PyObject *item;
- /* Use existing module where possible
- * be careful not to init any runtime vars after this */
- m = PyImport_ImportModule( "PhysicsConstraints" );
- if (m) {
- Py_DECREF(m);
- return m;
- }
- else {
- PyErr_Clear();
-
- m = PyModule_Create(&PhysicsConstraints_module_def);
- PyDict_SetItemString(PySys_GetObject("modules"), PhysicsConstraints_module_def.m_name, m);
- }
+ m = PyModule_Create(&PhysicsConstraints_module_def);
+ PyDict_SetItemString(PySys_GetObject("modules"), PhysicsConstraints_module_def.m_name, m);
// Add some symbolic constants to the module
d = PyModule_GetDict(m);
@@ -747,7 +793,7 @@ PyObject *initPythonConstraintBinding()
Py_FatalError("can't initialize module PhysicsConstraints");
}
- return d;
+ return m;
}
#if 0
diff --git a/source/gameengine/Ketsji/KX_PyConstraintBinding.h b/source/gameengine/Ketsji/KX_PyConstraintBinding.h
index b4a520ce71b..2bf9f7e197d 100644
--- a/source/gameengine/Ketsji/KX_PyConstraintBinding.h
+++ b/source/gameengine/Ketsji/KX_PyConstraintBinding.h
@@ -36,7 +36,8 @@
#include <Python.h>
-PyObject* initPythonConstraintBinding();
+PyMODINIT_FUNC initConstraintPythonBinding();
+
void PHY_SetActiveEnvironment(class PHY_IPhysicsEnvironment* env);
PHY_IPhysicsEnvironment* PHY_GetActiveEnvironment();
#endif /* WITH_PYTHON */
diff --git a/source/gameengine/Ketsji/KX_PythonInit.cpp b/source/gameengine/Ketsji/KX_PythonInit.cpp
index 3ddd53b971f..70d1aed88a0 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInit.cpp
@@ -223,8 +223,11 @@ static void KX_MACRO_addTypesToDict_fn(PyObject *dict, const char *name, long va
// List of methods defined in the module
static PyObject *ErrorObject;
-static const char *gPyGetRandomFloat_doc="getRandomFloat returns a random floating point value in the range [0..1]";
+PyDoc_STRVAR(gPyGetRandomFloat_doc,
+"getRandomFloat()\n"
+"returns a random floating point value in the range [0..1]"
+);
static PyObject *gPyGetRandomFloat(PyObject *)
{
return PyFloat_FromDouble(MT_random());
@@ -242,15 +245,15 @@ static PyObject *gPySetGravity(PyObject *, PyObject *value)
Py_RETURN_NONE;
}
-static char gPyExpandPath_doc[] =
-"(path) - Converts a blender internal path into a proper file system path.\n\
-path - the string path to convert.\n\n\
-Use / as directory separator in path\n\
-You can use '//' at the start of the string to define a relative path;\n\
-Blender replaces that string by the directory of the current .blend or runtime\n\
-file to make a full path name.\n\
-The function also converts the directory separator to the local file system format.";
-
+PyDoc_STRVAR(gPyExpandPath_doc,
+"expandPath(path)\n"
+"Converts a blender internal path into a proper file system path.\n"
+" path - the string path to convert.\n"
+"Use / as directory separator in path\n"
+"You can use '//' at the start of the string to define a relative path."
+"Blender replaces that string by the directory of the current .blend or runtime file to make a full path name.\n"
+"The function also converts the directory separator to the local file system format."
+);
static PyObject *gPyExpandPath(PyObject *, PyObject *args)
{
char expanded[FILE_MAX];
@@ -264,10 +267,10 @@ static PyObject *gPyExpandPath(PyObject *, PyObject *args)
return PyC_UnicodeFromByte(expanded);
}
-static char gPyStartGame_doc[] =
-"startGame(blend)\n\
-Loads the blend file";
-
+PyDoc_STRVAR(gPyStartGame_doc,
+"startGame(blend)\n"
+"Loads the blend file"
+);
static PyObject *gPyStartGame(PyObject *, PyObject *args)
{
char* blendfile;
@@ -281,10 +284,10 @@ static PyObject *gPyStartGame(PyObject *, PyObject *args)
Py_RETURN_NONE;
}
-static char gPyEndGame_doc[] =
-"endGame()\n\
-Ends the current game";
-
+PyDoc_STRVAR(gPyEndGame_doc,
+"endGame()\n"
+"Ends the current game"
+);
static PyObject *gPyEndGame(PyObject *)
{
gp_KetsjiEngine->RequestExit(KX_EXIT_REQUEST_QUIT_GAME);
@@ -294,10 +297,10 @@ static PyObject *gPyEndGame(PyObject *)
Py_RETURN_NONE;
}
-static char gPyRestartGame_doc[] =
-"restartGame()\n\
-Restarts the current game by reloading the .blend file";
-
+PyDoc_STRVAR(gPyRestartGame_doc,
+"restartGame()\n"
+"Restarts the current game by reloading the .blend file"
+);
static PyObject *gPyRestartGame(PyObject *)
{
gp_KetsjiEngine->RequestExit(KX_EXIT_REQUEST_RESTART_GAME);
@@ -306,10 +309,10 @@ static PyObject *gPyRestartGame(PyObject *)
Py_RETURN_NONE;
}
-static char gPySaveGlobalDict_doc[] =
- "saveGlobalDict()\n"
- "Saves bge.logic.globalDict to a file";
-
+PyDoc_STRVAR(gPySaveGlobalDict_doc,
+"saveGlobalDict()\n"
+"Saves bge.logic.globalDict to a file"
+);
static PyObject *gPySaveGlobalDict(PyObject *)
{
char marshal_path[512];
@@ -343,10 +346,10 @@ static PyObject *gPySaveGlobalDict(PyObject *)
Py_RETURN_NONE;
}
-static char gPyLoadGlobalDict_doc[] =
- "LoadGlobalDict()\n"
- "Loads bge.logic.globalDict from a file";
-
+PyDoc_STRVAR(gPyLoadGlobalDict_doc,
+"LoadGlobalDict()\n"
+"Loads bge.logic.globalDict from a file"
+);
static PyObject *gPyLoadGlobalDict(PyObject *)
{
char marshal_path[512];
@@ -384,23 +387,23 @@ static PyObject *gPyLoadGlobalDict(PyObject *)
Py_RETURN_NONE;
}
-static char gPyGetProfileInfo_doc[] =
+PyDoc_STRVAR(gPyGetProfileInfo_doc,
"getProfileInfo()\n"
-"returns a dictionary with profiling information";
-
+"returns a dictionary with profiling information"
+);
static PyObject *gPyGetProfileInfo(PyObject *)
{
return gp_KetsjiEngine->GetPyProfileDict();
}
-static char gPySendMessage_doc[] =
-"sendMessage(subject, [body, to, from])\n\
-sends a message in same manner as a message actuator\
-subject = Subject of the message\
-body = Message body\
-to = Name of object to send the message to\
-from = Name of object to send the string from";
-
+PyDoc_STRVAR(gPySendMessage_doc,
+"sendMessage(subject, [body, to, from])\n"
+"sends a message in same manner as a message actuator"
+" subject = Subject of the message"
+" body = Message body"
+" to = Name of object to send the message to"
+" from = Name of object to send the string from"
+);
static PyObject *gPySendMessage(PyObject *, PyObject *args)
{
char* subject;
@@ -560,11 +563,12 @@ static PyObject *gPyGetBlendFileList(PyObject *, PyObject *args)
return list;
}
-static char gPyAddScene_doc[] =
-"addScene(name, [overlay])\n\
-adds a scene to the game engine\n\
-name = Name of the scene\n\
-overlay = Overlay or underlay";
+PyDoc_STRVAR(gPyAddScene_doc,
+"addScene(name, [overlay])\n"
+"Adds a scene to the game engine.\n"
+" name = Name of the scene\n"
+" overlay = Overlay or underlay"
+);
static PyObject *gPyAddScene(PyObject *, PyObject *args)
{
char* name;
@@ -578,17 +582,19 @@ static PyObject *gPyAddScene(PyObject *, PyObject *args)
Py_RETURN_NONE;
}
-static const char *gPyGetCurrentScene_doc =
+PyDoc_STRVAR(gPyGetCurrentScene_doc,
"getCurrentScene()\n"
-"Gets a reference to the current scene.\n";
+"Gets a reference to the current scene."
+);
static PyObject *gPyGetCurrentScene(PyObject *self)
{
return gp_KetsjiScene->GetProxy();
}
-static const char *gPyGetSceneList_doc =
+PyDoc_STRVAR(gPyGetSceneList_doc,
"getSceneList()\n"
-"Return a list of converted scenes.\n";
+"Return a list of converted scenes."
+);
static PyObject *gPyGetSceneList(PyObject *self)
{
KX_KetsjiEngine* m_engine = KX_GetActiveEngine();
@@ -1006,6 +1012,21 @@ static PyObject *gPyGetFocalLength(PyObject *, PyObject *, PyObject *)
Py_RETURN_NONE;
}
+static PyObject *gPyGetStereoEye(PyObject *, PyObject *, PyObject *)
+{
+ int flag = RAS_IRasterizer::RAS_STEREO_LEFTEYE;
+
+ if (!gp_Rasterizer) {
+ PyErr_SetString(PyExc_RuntimeError, "Rasterizer.getStereoEye(), Rasterizer not available");
+ return NULL;
+ }
+
+ if (gp_Rasterizer->Stereo())
+ flag = gp_Rasterizer->GetEye();
+
+ return PyLong_FromLong(flag);
+}
+
static PyObject *gPySetBackgroundColor(PyObject *, PyObject *value)
{
@@ -1469,6 +1490,9 @@ static PyObject *gPyClearDebugList(PyObject *)
Py_RETURN_NONE;
}
+PyDoc_STRVAR(Rasterizer_module_documentation,
+"This is the Python API for the game engine of Rasterizer"
+);
static struct PyMethodDef rasterizer_methods[] = {
{"getWindowWidth",(PyCFunction) gPyGetWindowWidth,
@@ -1496,6 +1520,7 @@ static struct PyMethodDef rasterizer_methods[] = {
{"getEyeSeparation", (PyCFunction) gPyGetEyeSeparation, METH_NOARGS, "get the eye separation for stereo mode"},
{"setFocalLength", (PyCFunction) gPySetFocalLength, METH_VARARGS, "set the focal length for stereo mode"},
{"getFocalLength", (PyCFunction) gPyGetFocalLength, METH_VARARGS, "get the focal length for stereo mode"},
+ {"getStereoEye", (PyCFunction) gPyGetStereoEye, METH_VARARGS, "get the current stereoscopy eye being rendered"},
{"setMaterialMode",(PyCFunction) gPySetMaterialType,
METH_VARARGS, "set the material mode to use for OpenGL rendering"},
{"getMaterialMode",(PyCFunction) gPyGetMaterialType,
@@ -1525,15 +1550,11 @@ static struct PyMethodDef rasterizer_methods[] = {
{ NULL, (PyCFunction) NULL, 0, NULL }
};
-// Initialization function for the module (*must* be called initGameLogic)
-static char GameLogic_module_documentation[] =
-"This is the Python API for the game engine of bge.logic"
-;
-static char Rasterizer_module_documentation[] =
-"This is the Python API for the game engine of Rasterizer"
-;
+PyDoc_STRVAR(GameLogic_module_documentation,
+"This is the Python API for the game engine of bge.logic"
+);
static struct PyModuleDef GameLogic_module_def = {
{}, /* m_base */
@@ -1547,33 +1568,20 @@ static struct PyModuleDef GameLogic_module_def = {
0, /* m_free */
};
-PyObject *initGameLogic(KX_KetsjiEngine *engine, KX_Scene* scene) // quick hack to get gravity hook
+PyMODINIT_FUNC initGameLogicPythonBinding()
{
PyObject *m;
PyObject *d;
PyObject *item; /* temp PyObject *storage */
-
- gp_KetsjiEngine = engine;
- gp_KetsjiScene = scene;
gUseVisibilityTemp=false;
-
+
PyObjectPlus::ClearDeprecationWarning(); /* Not that nice to call here but makes sure warnings are reset between loading scenes */
-
- /* Use existing module where possible
- * be careful not to init any runtime vars after this */
- m = PyImport_ImportModule( "GameLogic" );
- if (m) {
- Py_DECREF(m);
- return m;
- }
- else {
- PyErr_Clear();
- // Create the module and add the functions
- m = PyModule_Create(&GameLogic_module_def);
- PyDict_SetItemString(PySys_GetObject("modules"), GameLogic_module_def.m_name, m);
- }
-
+
+ m = PyModule_Create(&GameLogic_module_def);
+ PyDict_SetItemString(PySys_GetObject("modules"), GameLogic_module_def.m_name, m);
+
+
// Add some symbolic constants to the module
d = PyModule_GetDict(m);
@@ -2053,7 +2061,60 @@ void removeImportMain(struct Main *maggie)
bpy_import_main_extra_remove(maggie);
}
-// Copied from bpy_interface.c
+
+PyDoc_STRVAR(BGE_module_documentation,
+ "This module contains submodules for the Blender Game Engine.\n"
+);
+
+static struct PyModuleDef BGE_module_def = {
+ PyModuleDef_HEAD_INIT,
+ "bge", /* m_name */
+ BGE_module_documentation, /* m_doc */
+ 0, /* m_size */
+ NULL, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+
+PyMODINIT_FUNC initBGE(void)
+{
+ PyObject *mod;
+ PyObject *submodule;
+ PyObject *sys_modules = PyThreadState_GET()->interp->modules;
+
+ mod = PyModule_Create(&BGE_module_def);
+
+ PyModule_AddObject(mod, "constraints", (submodule = initConstraintPythonBinding()));
+ PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ Py_INCREF(submodule);
+
+ PyModule_AddObject(mod, "events", (submodule = initGameKeysPythonBinding()));
+ PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ Py_INCREF(submodule);
+
+ PyModule_AddObject(mod, "logic", (submodule = initGameLogicPythonBinding()));
+ PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ Py_INCREF(submodule);
+
+ PyModule_AddObject(mod, "render", (submodule = initRasterizerPythonBinding()));
+ PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ Py_INCREF(submodule);
+
+ PyModule_AddObject(mod, "texture", (submodule = initVideoTexturePythonBinding()));
+ PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ Py_INCREF(submodule);
+
+ PyModule_AddObject(mod, "types", (submodule = initGameTypesPythonBinding()));
+ PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule);
+ Py_INCREF(submodule);
+
+ return mod;
+}
+
+
+/* minimal required blender modules to run blenderplayer */
static struct _inittab bge_internal_modules[] = {
{"mathutils", PyInit_mathutils},
{"bgl", BPyInit_bgl},
@@ -2066,7 +2127,7 @@ static struct _inittab bge_internal_modules[] = {
* Python is not initialized.
* see bpy_interface.c's BPY_python_start() which shares the same functionality in blender.
*/
-PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie, int argc, char** argv)
+PyObject *initGamePlayerPythonScripting(Main *maggie, int argc, char** argv)
{
/* Yet another gotcha in the py api
* Cant run PySys_SetArgv more than once because this adds the
@@ -2077,14 +2138,20 @@ PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur
static bool first_time = true;
const char * const py_path_bundle = BKE_appdir_folder_id(BLENDER_SYSTEM_PYTHON, NULL);
-#if 0 // TODO - py3
- STR_String pname = progname;
- Py_SetProgramName(pname.Ptr());
-#endif
+ /* 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, BKE_appdir_program_path(), ARRAY_SIZE(program_path_wchar));
+ Py_SetProgramName(program_path_wchar);
+ /* Update, Py3.3 resolves attempting to parse non-existing header */
+ #if 0
+ /* Python 3.2 now looks for '2.xx/python/include/python3.2d/pyconfig.h' to
+ * parse from the 'sysconfig' module which is used by 'site',
+ * so for now disable site. alternatively we could copy the file. */
if (py_path_bundle != NULL) {
- Py_NoSiteFlag = 1;
+ Py_NoSiteFlag = 1; /* inhibits the automatic importing of 'site' */
}
+ #endif
Py_FrozenFlag = 1;
@@ -2108,12 +2175,16 @@ PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur
PySys_SetObject("argv", py_argv);
Py_DECREF(py_argv);
}
-
+
/* Initialize thread support (also acquires lock) */
PyEval_InitThreads();
bpy_import_init(PyEval_GetBuiltins());
+ bpy_import_main_set(maggie);
+
+ initPySysObjects(maggie);
+
/* mathutils types are used by the BGE even if we don't import them */
{
PyObject *mod = PyImport_ImportModuleLevel("mathutils", NULL, NULL, NULL, 0);
@@ -2128,12 +2199,8 @@ PyObject *initGamePlayerPythonScripting(const STR_String& progname, TPythonSecur
}
#endif
- initPyTypes();
-
- bpy_import_main_set(maggie);
-
- initPySysObjects(maggie);
-
+ PyDict_SetItemString(PyImport_GetModuleDict(), "bge", initBGE());
+
first_time = false;
PyObjectPlus::ClearDeprecationWarning();
@@ -2170,12 +2237,13 @@ void exitGamePlayerPythonScripting()
/**
* Python is already initialized.
*/
-PyObject *initGamePythonScripting(const STR_String& progname, TPythonSecurityLevel level, Main *maggie)
+PyObject *initGamePythonScripting(Main *maggie)
{
-#if 0 // XXX TODO Py3
- STR_String pname = progname;
- Py_SetProgramName(pname.Ptr());
-#endif
+ /* no need to Py_SetProgramName, it was already taken care of in BPY_python_start */
+
+ bpy_import_main_set(maggie);
+
+ initPySysObjects(maggie);
#ifdef WITH_AUDASPACE
/* accessing a SoundActuator's sound results in a crash if aud is not initialized... */
@@ -2185,11 +2253,7 @@ PyObject *initGamePythonScripting(const STR_String& progname, TPythonSecurityLev
}
#endif
- initPyTypes();
-
- bpy_import_main_set(maggie);
-
- initPySysObjects(maggie);
+ PyDict_SetItemString(PyImport_GetModuleDict(), "bge", initBGE());
PyObjectPlus::NullDeprecationWarning();
@@ -2222,51 +2286,32 @@ void exitGamePythonScripting()
void setupGamePython(KX_KetsjiEngine* ketsjiengine, KX_Scene *startscene, Main *blenderdata,
PyObject *pyGlobalDict, PyObject **gameLogic, PyObject **gameLogic_keys, int argc, char** argv)
{
- PyObject *dictionaryobject;
+ PyObject *modules, *dictionaryobject;
+
+ gp_Canvas = ketsjiengine->GetCanvas();
+ gp_Rasterizer = ketsjiengine->GetRasterizer();
+ gp_KetsjiEngine = ketsjiengine;
+ gp_KetsjiScene = startscene;
if (argv) /* player only */
- dictionaryobject= initGamePlayerPythonScripting("Ketsji", psl_Lowest, blenderdata, argc, argv);
+ dictionaryobject= initGamePlayerPythonScripting(blenderdata, argc, argv);
else
- dictionaryobject= initGamePythonScripting("Ketsji", psl_Lowest, blenderdata);
+ dictionaryobject= initGamePythonScripting(blenderdata);
ketsjiengine->SetPyNamespace(dictionaryobject);
- initRasterizer(ketsjiengine->GetRasterizer(), ketsjiengine->GetCanvas());
- *gameLogic = initGameLogic(ketsjiengine, startscene);
- /* is set in initGameLogic so only set here if we want it to persist between scenes */
+ modules = PyImport_GetModuleDict();
+
+ *gameLogic = PyDict_GetItemString(modules, "GameLogic");
+ /* is set in initGameLogicPythonBinding so only set here if we want it to persist between scenes */
if (pyGlobalDict)
PyDict_SetItemString(PyModule_GetDict(*gameLogic), "globalDict", pyGlobalDict); // Same as importing the module.
*gameLogic_keys = PyDict_Keys(PyModule_GetDict(*gameLogic));
-
- initGameKeys();
- initPythonConstraintBinding();
- initVideoTexture();
-
- /* could be done a lot more nicely, but for now a quick way to get bge.* working */
- PyRun_SimpleString("sys = __import__('sys');"
- "bge = type(sys)('bge');"
- "bge.__dict__.update({'logic':__import__('GameLogic'), "
- "'render':__import__('Rasterizer'), "
- "'events':__import__('GameKeys'), "
- "'constraints':__import__('PhysicsConstraints'), "
- "'physics':__import__('PhysicsConstraints'),"
- "'types':__import__('GameTypes'), "
- "'texture':__import__('VideoTexture')});"
- /* so we can do 'import bge.foo as bar' */
- "sys.modules.update({'bge': bge, "
- "'bge.logic':bge.logic, "
- "'bge.render':bge.render, "
- "'bge.events':bge.events, "
- "'bge.constraints':bge.constraints, "
- "'bge.physics':bge.physics,"
- "'bge.types':bge.types, "
- "'bge.texture':bge.texture})"
- );
}
static struct PyModuleDef Rasterizer_module_def = {
- {}, /* m_base */
+ PyModuleDef_HEAD_INIT,
"Rasterizer", /* m_name */
Rasterizer_module_documentation, /* m_doc */
0, /* m_size */
@@ -2277,29 +2322,14 @@ static struct PyModuleDef Rasterizer_module_def = {
0, /* m_free */
};
-PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas)
+PyMODINIT_FUNC initRasterizerPythonBinding()
{
- gp_Canvas = canvas;
- gp_Rasterizer = rasty;
-
-
PyObject *m;
PyObject *d;
- /* Use existing module where possible
- * be careful not to init any runtime vars after this */
- m = PyImport_ImportModule( "Rasterizer" );
- if (m) {
- Py_DECREF(m);
- return m;
- }
- else {
- PyErr_Clear();
+ m = PyModule_Create(&Rasterizer_module_def);
+ PyDict_SetItemString(PySys_GetObject("modules"), Rasterizer_module_def.m_name, m);
- // Create the module and add the functions
- m = PyModule_Create(&Rasterizer_module_def);
- PyDict_SetItemString(PySys_GetObject("modules"), Rasterizer_module_def.m_name, m);
- }
// Add some symbolic constants to the module
d = PyModule_GetDict(m);
@@ -2320,6 +2350,10 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas)
KX_MACRO_addTypesToDict(d, VSYNC_ON, VSYNC_ON);
KX_MACRO_addTypesToDict(d, VSYNC_ADAPTIVE, VSYNC_ADAPTIVE);
+ /* stereoscopy */
+ KX_MACRO_addTypesToDict(d, LEFT_EYE, RAS_IRasterizer::RAS_STEREO_LEFTEYE);
+ KX_MACRO_addTypesToDict(d, RIGHT_EYE, RAS_IRasterizer::RAS_STEREO_RIGHTEYE);
+
// XXXX Add constants here
// Check for errors
@@ -2328,7 +2362,7 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas)
Py_FatalError("can't initialize module Rasterizer");
}
- return d;
+ return m;
}
@@ -2337,13 +2371,14 @@ PyObject *initRasterizer(RAS_IRasterizer* rasty,RAS_ICanvas* canvas)
/* GameKeys: symbolic constants for key mapping */
/* ------------------------------------------------------------------------- */
-static char GameKeys_module_documentation[] =
+PyDoc_STRVAR(GameKeys_module_documentation,
"This modules provides defines for key-codes"
-;
+);
-static char gPyEventToString_doc[] =
-"EventToString(event) - Take a valid event from the GameKeys module or Keyboard Sensor and return a name"
-;
+PyDoc_STRVAR(gPyEventToString_doc,
+"EventToString(event)\n"
+"Take a valid event from the GameKeys module or Keyboard Sensor and return a name"
+);
static PyObject *gPyEventToString(PyObject *, PyObject *value)
{
@@ -2371,9 +2406,11 @@ static PyObject *gPyEventToString(PyObject *, PyObject *value)
return ret;
}
-static char gPyEventToCharacter_doc[] =
-"EventToCharacter(event, is_shift) - Take a valid event from the GameKeys module or Keyboard Sensor and return a character"
-;
+
+PyDoc_STRVAR(gPyEventToCharacter_doc,
+"EventToCharacter(event, is_shift)\n"
+"Take a valid event from the GameKeys module or Keyboard Sensor and return a character"
+);
static PyObject *gPyEventToCharacter(PyObject *, PyObject *args)
{
@@ -2399,7 +2436,7 @@ static struct PyMethodDef gamekeys_methods[] = {
};
static struct PyModuleDef GameKeys_module_def = {
- {}, /* m_base */
+ PyModuleDef_HEAD_INIT,
"GameKeys", /* m_name */
GameKeys_module_documentation, /* m_doc */
0, /* m_size */
@@ -2410,24 +2447,13 @@ static struct PyModuleDef GameKeys_module_def = {
0, /* m_free */
};
-PyObject *initGameKeys()
+PyMODINIT_FUNC initGameKeysPythonBinding()
{
PyObject *m;
PyObject *d;
-
- /* Use existing module where possible */
- m = PyImport_ImportModule( "GameKeys" );
- if (m) {
- Py_DECREF(m);
- return m;
- }
- else {
- PyErr_Clear();
-
- // Create the module and add the functions
- m = PyModule_Create(&GameKeys_module_def);
- PyDict_SetItemString(PySys_GetObject("modules"), GameKeys_module_def.m_name, m);
- }
+
+ m = PyModule_Create(&GameKeys_module_def);
+ PyDict_SetItemString(PySys_GetObject("modules"), GameKeys_module_def.m_name, m);
// Add some symbolic constants to the module
d = PyModule_GetDict(m);
@@ -2572,7 +2598,7 @@ PyObject *initGameKeys()
Py_FatalError("can't initialize module GameKeys");
}
- return d;
+ return m;
}
// utility function for loading and saving the globalDict
diff --git a/source/gameengine/Ketsji/KX_PythonInit.h b/source/gameengine/Ketsji/KX_PythonInit.h
index 719a74ee219..f74a4b3865f 100644
--- a/source/gameengine/Ketsji/KX_PythonInit.h
+++ b/source/gameengine/Ketsji/KX_PythonInit.h
@@ -36,6 +36,9 @@
#include "STR_String.h"
#include "MT_Vector3.h"
+class KX_KetsjiEngine;
+class KX_Scene;
+
typedef enum {
psl_Lowest = 0,
psl_Highest,
@@ -44,13 +47,13 @@ typedef enum {
extern bool gUseVisibilityTemp;
#ifdef WITH_PYTHON
-PyObject *initGameLogic(class KX_KetsjiEngine *engine, class KX_Scene *ketsjiscene);
-PyObject *initGameKeys();
-PyObject *initRasterizer(class RAS_IRasterizer *rasty,class RAS_ICanvas *canvas);
-PyObject *initGamePlayerPythonScripting(const STR_String &progname, TPythonSecurityLevel level,
- struct Main *maggie, int argc, char **argv);
-PyObject *initVideoTexture(void);
-PyObject *initGamePythonScripting(const STR_String &progname, TPythonSecurityLevel level, struct Main *maggie);
+PyMODINIT_FUNC initBGE(void);
+PyMODINIT_FUNC initGameLogicPythonBinding(void);
+PyMODINIT_FUNC initGameKeysPythonBinding(void);
+PyMODINIT_FUNC initRasterizerPythonBinding(void);
+PyMODINIT_FUNC initVideoTexturePythonBinding(void);
+PyObject *initGamePlayerPythonScripting(struct Main *maggie, int argc, char **argv);
+PyObject *initGamePythonScripting(struct Main *maggie);
void exitGamePlayerPythonScripting();
void exitGamePythonScripting();
@@ -69,9 +72,9 @@ void removeImportMain(struct Main *maggie);
class KX_KetsjiEngine;
class KX_Scene;
-void KX_SetActiveScene(class KX_Scene *scene);
-class KX_Scene *KX_GetActiveScene();
-class KX_KetsjiEngine *KX_GetActiveEngine();
+void KX_SetActiveScene(KX_Scene *scene);
+KX_Scene *KX_GetActiveScene();
+KX_KetsjiEngine *KX_GetActiveEngine();
typedef int (*PyNextFrameFunc)(void *);
diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
index 7d38ce58eee..828fd62f205 100644
--- a/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
+++ b/source/gameengine/Ketsji/KX_PythonInitTypes.cpp
@@ -163,21 +163,34 @@ static void PyType_Ready_ADD(PyObject *dict, PyTypeObject *tp, PyAttributeDef *a
#define PyType_Ready_Attr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, NULL, i)
#define PyType_Ready_AttrPtr(d, n, i) PyType_Ready_ADD(d, &n::Type, n::Attributes, n::AttributesPtr, i)
-void initPyTypes(void)
+
+
+PyDoc_STRVAR(GameTypes_module_documentation,
+"This module provides access to the game engine data types."
+);
+static struct PyModuleDef GameTypes_module_def = {
+ PyModuleDef_HEAD_INIT,
+ "GameTypes", /* m_name */
+ GameTypes_module_documentation, /* m_doc */
+ 0, /* m_size */
+ NULL, /* m_methods */
+ NULL, /* m_reload */
+ NULL, /* m_traverse */
+ NULL, /* m_clear */
+ NULL, /* m_free */
+};
+
+
+PyMODINIT_FUNC initGameTypesPythonBinding(void)
{
+ PyObject *m;
+ PyObject *dict;
-/*
- * initPyObjectPlusType(BL_ActionActuator::Parents);
- * .....
- */
+ m = PyModule_Create(&GameTypes_module_def);
+ PyDict_SetItemString(PySys_GetObject("modules"), GameTypes_module_def.m_name, m);
+
+ dict = PyModule_GetDict(m);
- /* For now just do PyType_Ready */
- PyObject *mod = PyModule_New("GameTypes");
- PyObject *dict = PyModule_GetDict(mod);
- PyDict_SetItemString(PySys_GetObject("modules"), "GameTypes", mod);
- Py_DECREF(mod);
-
-
for (int init_getset= 1; init_getset > -1; init_getset--) { /* run twice, once to init the getsets another to run PyType_Ready */
PyType_Ready_Attr(dict, BL_ActionActuator, init_getset);
PyType_Ready_Attr(dict, BL_Shader, init_getset);
@@ -267,6 +280,8 @@ void initPyTypes(void)
KX_GameObject_Mathutils_Callback_Init();
KX_ObjectActuator_Mathutils_Callback_Init();
#endif
+
+ return m;
}
#endif // WITH_PYTHON
diff --git a/source/gameengine/Ketsji/KX_PythonInitTypes.h b/source/gameengine/Ketsji/KX_PythonInitTypes.h
index d8ee4f75fdd..cfc49a1dc93 100644
--- a/source/gameengine/Ketsji/KX_PythonInitTypes.h
+++ b/source/gameengine/Ketsji/KX_PythonInitTypes.h
@@ -33,7 +33,8 @@
#define __KX_PYTHON_INIT_TYPES__
#ifdef WITH_PYTHON
-void initPyTypes(void);
+#include <Python.h>
+PyMODINIT_FUNC initGameTypesPythonBinding(void);
#endif
#endif /* __KX_PYTHON_INIT_TYPES__ */
diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.cpp b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
index 7ec379eec26..eb774960d41 100644
--- a/source/gameengine/Ketsji/KX_TouchEventManager.cpp
+++ b/source/gameengine/Ketsji/KX_TouchEventManager.cpp
@@ -60,7 +60,7 @@ bool KX_TouchEventManager::NewHandleCollision(void* object1, void* object2, cons
PHY_IPhysicsController* obj1 = static_cast<PHY_IPhysicsController*>(object1);
PHY_IPhysicsController* obj2 = static_cast<PHY_IPhysicsController*>(object2);
- m_newCollisions.insert(std::pair<PHY_IPhysicsController*, PHY_IPhysicsController*>(obj1, obj2));
+ m_newCollisions.insert(NewCollision(obj1, obj2, coll_data));
return false;
}
@@ -209,9 +209,11 @@ void KX_TouchEventManager::NextFrame()
}
}
// Run python callbacks
- kxObj1->RunCollisionCallbacks(kxObj2);
- kxObj2->RunCollisionCallbacks(kxObj1);
+ PHY_CollData *colldata = cit->colldata;
+ kxObj1->RunCollisionCallbacks(kxObj2, colldata->m_point1, colldata->m_normal);
+ kxObj2->RunCollisionCallbacks(kxObj1, colldata->m_point2, -colldata->m_normal);
+ delete cit->colldata;
}
m_newCollisions.clear();
@@ -219,3 +221,19 @@ void KX_TouchEventManager::NextFrame()
for (it.begin();!it.end();++it)
(*it)->Activate(m_logicmgr);
}
+
+
+KX_TouchEventManager::NewCollision::NewCollision(PHY_IPhysicsController *first,
+ PHY_IPhysicsController *second,
+ const PHY_CollData *colldata)
+ : first(first), second(second), colldata(new PHY_CollData(*colldata))
+{}
+
+KX_TouchEventManager::NewCollision::NewCollision(const NewCollision &to_copy)
+ : first(to_copy.first), second(to_copy.second), colldata(to_copy.colldata)
+{}
+
+bool KX_TouchEventManager::NewCollision::operator<(const NewCollision &other) const
+{
+ return first < other.first || second < other.second || colldata < other.colldata;
+}
diff --git a/source/gameengine/Ketsji/KX_TouchEventManager.h b/source/gameengine/Ketsji/KX_TouchEventManager.h
index bd4903c1545..d9c6fdad307 100644
--- a/source/gameengine/Ketsji/KX_TouchEventManager.h
+++ b/source/gameengine/Ketsji/KX_TouchEventManager.h
@@ -45,7 +45,29 @@ class PHY_IPhysicsEnvironment;
class KX_TouchEventManager : public SCA_EventManager
{
- typedef std::pair<PHY_IPhysicsController*, PHY_IPhysicsController*> NewCollision;
+ /**
+ * Contains two colliding objects and the first contact point.
+ */
+ class NewCollision {
+ public:
+ PHY_IPhysicsController *first;
+ PHY_IPhysicsController *second;
+ PHY_CollData *colldata;
+
+ /**
+ * Creates a copy of the given PHY_CollData; freeing that copy should be done by the owner of
+ * the NewCollision object.
+ *
+ * This allows us to efficiently store NewCollision objects in a std::set without creating more
+ * copies of colldata, as the NewCollision copy constructor reuses the pointer and doesn't clone
+ * it again. */
+ NewCollision(PHY_IPhysicsController *first,
+ PHY_IPhysicsController *second,
+ const PHY_CollData *colldata);
+ NewCollision(const NewCollision &to_copy);
+ bool operator<(const NewCollision &other) const;
+ };
+
PHY_IPhysicsEnvironment* m_physEnv;
std::set<NewCollision> m_newCollisions;
diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
index 535ed5ed39a..d10e51a491a 100644
--- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
+++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp
@@ -53,6 +53,22 @@ KX_VehicleWrapper::~KX_VehicleWrapper()
#ifdef WITH_PYTHON
+
+static bool raise_exc_wheel(PHY_IVehicle* vehicle, int i, const char *method)
+{
+ if ( i < 0 || i >= vehicle->GetNumWheels() ) {
+ PyErr_Format(PyExc_ValueError,
+ "%s(...): wheel index %d out of range (0 to %d).", method, i, vehicle->GetNumWheels()-1);
+ return -1;
+ } else {
+ return 0;
+ }
+}
+
+#define WHEEL_INDEX_CHECK_OR_RETURN(i, method) \
+ if (raise_exc_wheel(m_vehicle, i, method) == -1) { return NULL; } (void)0
+
+
PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
{
@@ -67,22 +83,37 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
KX_GameObject *gameOb;
if (!ConvertPythonToGameObject(wheelGameObject, &gameOb, false, "vehicle.addWheel(...): KX_VehicleWrapper (first argument)"))
return NULL;
-
if (gameOb->GetSGNode())
{
PHY_IMotionState* motionState = new KX_MotionState(gameOb->GetSGNode());
- /* TODO - no error checking here! - bad juju */
MT_Vector3 attachPos,attachDir,attachAxle;
- PyVecTo(pylistPos,attachPos);
- PyVecTo(pylistDir,attachDir);
- PyVecTo(pylistAxleDir,attachAxle);
+ if(!PyVecTo(pylistPos,attachPos)) {
+ PyErr_SetString(PyExc_AttributeError,
+ "addWheel(...) Unable to add wheel. attachPos must be a vector with 3 elements.");
+ return NULL;
+ }
+ if(!PyVecTo(pylistDir,attachDir)) {
+ PyErr_SetString(PyExc_AttributeError,
+ "addWheel(...) Unable to add wheel. downDir must be a vector with 3 elements.");
+ return NULL;
+ }
+ if(!PyVecTo(pylistAxleDir,attachAxle)) {
+ PyErr_SetString(PyExc_AttributeError,
+ "addWheel(...) Unable to add wheel. axleDir must be a vector with 3 elements.");
+ return NULL;
+ }
//someone reverse some conventions inside Bullet (axle winding)
attachAxle = -attachAxle;
- printf("attempt for addWheel: suspensionRestLength%f wheelRadius %f, hasSteering:%d\n",suspensionRestLength,wheelRadius,hasSteering);
+ if(wheelRadius<=0) {
+ PyErr_SetString(PyExc_AttributeError,
+ "addWheel(...) Unable to add wheel. wheelRadius must be positive.");
+ return NULL;
+ }
+
m_vehicle->AddWheel(motionState,attachPos,attachDir,attachAxle,suspensionRestLength,wheelRadius,hasSteering);
}
@@ -93,8 +124,6 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args)
}
-
-
PyObject *KX_VehicleWrapper::PyGetWheelPosition(PyObject *args)
{
@@ -103,6 +132,8 @@ PyObject *KX_VehicleWrapper::PyGetWheelPosition(PyObject *args)
if (PyArg_ParseTuple(args,"i:getWheelPosition",&wheelIndex))
{
float position[3];
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "getWheelPosition");
+
m_vehicle->GetWheelPosition(wheelIndex,position[0],position[1],position[2]);
MT_Vector3 pos(position[0],position[1],position[2]);
return PyObjectFrom(pos);
@@ -115,6 +146,8 @@ PyObject *KX_VehicleWrapper::PyGetWheelRotation(PyObject *args)
int wheelIndex;
if (PyArg_ParseTuple(args,"i:getWheelRotation",&wheelIndex))
{
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "getWheelRotation");
+
return PyFloat_FromDouble(m_vehicle->GetWheelRotation(wheelIndex));
}
return NULL;
@@ -126,6 +159,8 @@ PyObject *KX_VehicleWrapper::PyGetWheelOrientationQuaternion(PyObject *args)
if (PyArg_ParseTuple(args,"i:getWheelOrientationQuaternion",&wheelIndex))
{
float orn[4];
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "getWheelOrientationQuaternion");
+
m_vehicle->GetWheelOrientationQuaternion(wheelIndex,orn[0],orn[1],orn[2],orn[3]);
MT_Quaternion quatorn(orn[0],orn[1],orn[2],orn[3]);
MT_Matrix3x3 ornmat(quatorn);
@@ -148,7 +183,6 @@ PyObject *KX_VehicleWrapper::PyGetConstraintId(PyObject *args)
}
-
PyObject *KX_VehicleWrapper::PyApplyEngineForce(PyObject *args)
{
float force;
@@ -156,6 +190,8 @@ PyObject *KX_VehicleWrapper::PyApplyEngineForce(PyObject *args)
if (PyArg_ParseTuple(args,"fi:applyEngineForce",&force,&wheelIndex))
{
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "applyEngineForce");
+
force *= -1.f;//someone reverse some conventions inside Bullet (axle winding)
m_vehicle->ApplyEngineForce(force,wheelIndex);
}
@@ -172,6 +208,8 @@ PyObject *KX_VehicleWrapper::PySetTyreFriction(PyObject *args)
if (PyArg_ParseTuple(args,"fi:setTyreFriction",&wheelFriction,&wheelIndex))
{
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setTyreFriction");
+
m_vehicle->SetWheelFriction(wheelFriction,wheelIndex);
}
else {
@@ -187,6 +225,8 @@ PyObject *KX_VehicleWrapper::PySetSuspensionStiffness(PyObject *args)
if (PyArg_ParseTuple(args,"fi:setSuspensionStiffness",&suspensionStiffness,&wheelIndex))
{
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSuspensionStiffness");
+
m_vehicle->SetSuspensionStiffness(suspensionStiffness,wheelIndex);
}
else {
@@ -202,6 +242,8 @@ PyObject *KX_VehicleWrapper::PySetSuspensionDamping(PyObject *args)
if (PyArg_ParseTuple(args,"fi:setSuspensionDamping",&suspensionDamping,&wheelIndex))
{
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSuspensionDamping");
+
m_vehicle->SetSuspensionDamping(suspensionDamping,wheelIndex);
} else {
return NULL;
@@ -216,6 +258,8 @@ PyObject *KX_VehicleWrapper::PySetSuspensionCompression(PyObject *args)
if (PyArg_ParseTuple(args,"fi:setSuspensionCompression",&suspensionCompression,&wheelIndex))
{
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSuspensionCompression");
+
m_vehicle->SetSuspensionCompression(suspensionCompression,wheelIndex);
} else {
return NULL;
@@ -230,6 +274,8 @@ PyObject *KX_VehicleWrapper::PySetRollInfluence(PyObject *args)
if (PyArg_ParseTuple(args,"fi:setRollInfluence",&rollInfluence,&wheelIndex))
{
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setRollInfluence");
+
m_vehicle->SetRollInfluence(rollInfluence,wheelIndex);
}
else {
@@ -246,6 +292,8 @@ PyObject *KX_VehicleWrapper::PyApplyBraking(PyObject *args)
if (PyArg_ParseTuple(args,"fi:applyBraking",&braking,&wheelIndex))
{
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "applyBraking");
+
m_vehicle->ApplyBraking(braking,wheelIndex);
}
else {
@@ -255,8 +303,6 @@ PyObject *KX_VehicleWrapper::PyApplyBraking(PyObject *args)
}
-
-
PyObject *KX_VehicleWrapper::PySetSteeringValue(PyObject *args)
{
float steeringValue;
@@ -264,6 +310,8 @@ PyObject *KX_VehicleWrapper::PySetSteeringValue(PyObject *args)
if (PyArg_ParseTuple(args,"fi:setSteeringValue",&steeringValue,&wheelIndex))
{
+ WHEEL_INDEX_CHECK_OR_RETURN(wheelIndex, "setSteeringValue");
+
m_vehicle->SetSteeringValue(steeringValue,wheelIndex);
}
else {
@@ -316,17 +364,11 @@ PyMethodDef KX_VehicleWrapper::Methods[] = {
{"setSteeringValue",(PyCFunction) KX_VehicleWrapper::sPySetSteeringValue, METH_VARARGS},
{"applyEngineForce",(PyCFunction) KX_VehicleWrapper::sPyApplyEngineForce, METH_VARARGS},
{"applyBraking",(PyCFunction) KX_VehicleWrapper::sPyApplyBraking, METH_VARARGS},
-
{"setTyreFriction",(PyCFunction) KX_VehicleWrapper::sPySetTyreFriction, METH_VARARGS},
-
{"setSuspensionStiffness",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionStiffness, METH_VARARGS},
-
{"setSuspensionDamping",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionDamping, METH_VARARGS},
-
{"setSuspensionCompression",(PyCFunction) KX_VehicleWrapper::sPySetSuspensionCompression, METH_VARARGS},
-
{"setRollInfluence",(PyCFunction) KX_VehicleWrapper::sPySetRollInfluence, METH_VARARGS},
-
{NULL,NULL} //Sentinel
};
diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
index 38e7df6c573..f450e3ac12f 100644
--- a/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
+++ b/source/gameengine/Physics/Bullet/CcdPhysicsEnvironment.cpp
@@ -174,26 +174,27 @@ public:
virtual void GetWheelPosition(int wheelIndex,float& posX,float& posY,float& posZ) const
{
- btTransform trans = m_vehicle->getWheelTransformWS(wheelIndex);
- posX = trans.getOrigin().x();
- posY = trans.getOrigin().y();
- posZ = trans.getOrigin().z();
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels()))
+ {
+ btVector3 origin = m_vehicle->getWheelTransformWS(wheelIndex).getOrigin();
+
+ posX = origin.x();
+ posY = origin.y();
+ posZ = origin.z();
+ }
}
+
virtual void GetWheelOrientationQuaternion(int wheelIndex,float& quatX,float& quatY,float& quatZ,float& quatW) const
{
- btTransform trans = m_vehicle->getWheelTransformWS(wheelIndex);
- btQuaternion quat = trans.getRotation();
- btMatrix3x3 orn2(quat);
-
- quatX = trans.getRotation().x();
- quatY = trans.getRotation().y();
- quatZ = trans.getRotation().z();
- quatW = trans.getRotation()[3];
-
-
- //printf("test");
-
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels()))
+ {
+ btQuaternion quat = m_vehicle->getWheelTransformWS(wheelIndex).getRotation();
+ quatX = quat.x();
+ quatY = quat.y();
+ quatZ = quat.z();
+ quatW = quat.w();
+ }
}
virtual float GetWheelRotation(int wheelIndex) const
@@ -205,8 +206,8 @@ public:
btWheelInfo& info = m_vehicle->getWheelInfo(wheelIndex);
rotation = info.m_rotation;
}
- return rotation;
+ return rotation;
}
@@ -223,12 +224,16 @@ public:
virtual void SetSteeringValue(float steering,int wheelIndex)
{
- m_vehicle->setSteeringValue(steering,wheelIndex);
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) {
+ m_vehicle->setSteeringValue(steering,wheelIndex);
+ }
}
virtual void ApplyEngineForce(float force,int wheelIndex)
{
- m_vehicle->applyEngineForce(force,wheelIndex);
+ if ((wheelIndex>=0) && (wheelIndex< m_vehicle->getNumWheels())) {
+ m_vehicle->applyEngineForce(force,wheelIndex);
+ }
}
virtual void ApplyBraking(float braking,int wheelIndex)
@@ -2251,64 +2256,77 @@ bool CcdPhysicsEnvironment::RequestCollisionCallback(PHY_IPhysicsController* ctr
void CcdPhysicsEnvironment::CallbackTriggers()
{
- if (m_triggerCallbacks[PHY_OBJECT_RESPONSE] || (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints)))
- {
- //walk over all overlapping pairs, and if one of the involved bodies is registered for trigger callback, perform callback
- btDispatcher* dispatcher = m_dynamicsWorld->getDispatcher();
- int numManifolds = dispatcher->getNumManifolds();
- for (int i=0;i<numManifolds;i++)
- {
- btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
- int numContacts = manifold->getNumContacts();
- if (numContacts)
- {
- const btRigidBody* rb0 = static_cast<const btRigidBody*>(manifold->getBody0());
- const btRigidBody* rb1 = static_cast<const btRigidBody*>(manifold->getBody1());
- if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints))
- {
- for (int j=0;j<numContacts;j++)
- {
- btVector3 color(1,0,0);
- const btManifoldPoint& cp = manifold->getContactPoint(j);
- if (m_debugDrawer)
- m_debugDrawer->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),color);
- }
- }
- const btRigidBody* obj0 = rb0;
- const btRigidBody* obj1 = rb1;
+ bool draw_contact_points = m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints);
- //m_internalOwner is set in 'addPhysicsController'
- CcdPhysicsController* ctrl0 = static_cast<CcdPhysicsController*>(obj0->getUserPointer());
- CcdPhysicsController* ctrl1 = static_cast<CcdPhysicsController*>(obj1->getUserPointer());
+ if (!m_triggerCallbacks[PHY_OBJECT_RESPONSE] && !draw_contact_points)
+ return;
- std::set<CcdPhysicsController*>::const_iterator i = m_triggerControllers.find(ctrl0);
- if (i == m_triggerControllers.end())
- {
- i = m_triggerControllers.find(ctrl1);
- }
+ //walk over all overlapping pairs, and if one of the involved bodies is registered for trigger callback, perform callback
+ btDispatcher* dispatcher = m_dynamicsWorld->getDispatcher();
+ int numManifolds = dispatcher->getNumManifolds();
+ for (int i=0;i<numManifolds;i++)
+ {
+ bool colliding_ctrl0 = true;
+ btPersistentManifold* manifold = dispatcher->getManifoldByIndexInternal(i);
+ int numContacts = manifold->getNumContacts();
+ if (!numContacts) continue;
- if (!(i == m_triggerControllers.end()))
- {
- m_triggerCallbacks[PHY_OBJECT_RESPONSE](m_triggerCallbacksUserPtrs[PHY_OBJECT_RESPONSE],
- ctrl0,ctrl1,0);
- }
- // Bullet does not refresh the manifold contact point for object without contact response
- // may need to remove this when a newer Bullet version is integrated
- if (!dispatcher->needsResponse(rb0, rb1))
- {
- // Refresh algorithm fails sometimes when there is penetration
- // (usuall the case with ghost and sensor objects)
- // Let's just clear the manifold, in any case, it is recomputed on each frame.
- manifold->clearManifold(); //refreshContactPoints(rb0->getCenterOfMassTransform(),rb1->getCenterOfMassTransform());
- }
+ const btRigidBody* rb0 = static_cast<const btRigidBody*>(manifold->getBody0());
+ const btRigidBody* rb1 = static_cast<const btRigidBody*>(manifold->getBody1());
+ if (draw_contact_points)
+ {
+ for (int j=0;j<numContacts;j++)
+ {
+ btVector3 color(1,1,0);
+ const btManifoldPoint& cp = manifold->getContactPoint(j);
+ m_debugDrawer->drawContactPoint(cp.m_positionWorldOnB,
+ cp.m_normalWorldOnB,
+ cp.getDistance(),
+ cp.getLifeTime(),
+ color);
}
}
+ //m_internalOwner is set in 'addPhysicsController'
+ CcdPhysicsController* ctrl0 = static_cast<CcdPhysicsController*>(rb0->getUserPointer());
+ CcdPhysicsController* ctrl1 = static_cast<CcdPhysicsController*>(rb1->getUserPointer());
+ std::set<CcdPhysicsController*>::const_iterator iter = m_triggerControllers.find(ctrl0);
+ if (iter == m_triggerControllers.end())
+ {
+ iter = m_triggerControllers.find(ctrl1);
+ colliding_ctrl0 = false;
+ }
- }
+ if (iter != m_triggerControllers.end())
+ {
+ static PHY_CollData coll_data;
+ const btManifoldPoint &cp = manifold->getContactPoint(0);
+ /* Make sure that "point1" is always on the object we report on, and
+ * "point2" on the other object. Also ensure the normal is oriented
+ * correctly. */
+ btVector3 point1 = colliding_ctrl0 ? cp.m_positionWorldOnA : cp.m_positionWorldOnB;
+ btVector3 point2 = colliding_ctrl0 ? cp.m_positionWorldOnB : cp.m_positionWorldOnA;
+ btVector3 normal = colliding_ctrl0 ? -cp.m_normalWorldOnB : cp.m_normalWorldOnB;
+ coll_data.m_point1 = MT_Vector3(point1.m_floats);
+ coll_data.m_point2 = MT_Vector3(point2.m_floats);
+ coll_data.m_normal = MT_Vector3(normal.m_floats);
+
+ m_triggerCallbacks[PHY_OBJECT_RESPONSE](m_triggerCallbacksUserPtrs[PHY_OBJECT_RESPONSE],
+ ctrl0, ctrl1, &coll_data);
+ }
+ // Bullet does not refresh the manifold contact point for object without contact response
+ // may need to remove this when a newer Bullet version is integrated
+ if (!dispatcher->needsResponse(rb0, rb1))
+ {
+ // Refresh algorithm fails sometimes when there is penetration
+ // (usuall the case with ghost and sensor objects)
+ // Let's just clear the manifold, in any case, it is recomputed on each frame.
+ manifold->clearManifold(); //refreshContactPoints(rb0->getCenterOfMassTransform(),rb1->getCenterOfMassTransform());
+ }
+ }
}
// This call back is called before a pair is added in the cache
@@ -2999,7 +3017,8 @@ struct BlenderDebugDraw : public btIDebugDraw
virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,float distance,int lifeTime,const btVector3& color)
{
- //not yet
+ drawLine(PointOnB, PointOnB + normalOnB, color);
+ drawSphere(PointOnB, 0.1, color);
}
virtual void setDebugMode(int debugMode)
diff --git a/source/gameengine/VideoTexture/ImageBase.cpp b/source/gameengine/VideoTexture/ImageBase.cpp
index 0d46160a11e..23da528009d 100644
--- a/source/gameengine/VideoTexture/ImageBase.cpp
+++ b/source/gameengine/VideoTexture/ImageBase.cpp
@@ -713,25 +713,18 @@ static int Image_getbuffer(PyImage *self, Py_buffer *view, int flags)
unsigned int * image;
int ret;
- try
- {
+ try {
// can throw in case of resize
image = self->m_image->getImage();
}
- catch (Exception & exp)
- {
- // cannot return -1, this creates a crash in Python, for now we will just return an empty buffer
+ catch (Exception & exp) {
exp.report();
- //return -1;
- goto error;
+ return -1;
}
- if (!image)
- {
- // same remark, see above
- //PyErr_SetString(PyExc_BufferError, "Image buffer is not available");
- //return -1;
- goto error;
+ if (!image) {
+ PyErr_SetString(PyExc_BufferError, "Image buffer is not available");
+ return -1;
}
if (view == NULL)
{
@@ -742,17 +735,6 @@ static int Image_getbuffer(PyImage *self, Py_buffer *view, int flags)
if (ret >= 0)
self->m_image->m_exports++;
return ret;
-
-error:
- // Return a empty buffer to avoid a crash in Python 3.1
- // The bug is fixed in Python SVN 77916, as soon as the python revision used by Blender is
- // updated, you can simply return -1 and set the error
- static char* buf = (char *)"";
- ret = PyBuffer_FillInfo(view, (PyObject *)self, buf, 0, 0, flags);
- if (ret >= 0)
- self->m_image->m_exports++;
- return ret;
-
}
static void Image_releaseBuffer(PyImage *self, Py_buffer *buffer)
diff --git a/source/gameengine/VideoTexture/blendVideoTex.cpp b/source/gameengine/VideoTexture/blendVideoTex.cpp
index ab6dca0958f..6c9294873a6 100644
--- a/source/gameengine/VideoTexture/blendVideoTex.cpp
+++ b/source/gameengine/VideoTexture/blendVideoTex.cpp
@@ -157,10 +157,14 @@ static void registerAllTypes(void)
pyFilterTypes.add(&FilterBGR24Type, "FilterBGR24");
}
+PyDoc_STRVAR(VideoTexture_module_documentation,
+"Module that allows to play video files on textures in GameBlender."
+);
+
static struct PyModuleDef VideoTexture_module_def = {
- {}, /* m_base */
+ PyModuleDef_HEAD_INIT,
"VideoTexture", /* m_name */
- "Module that allows to play video files on textures in GameBlender.", /* m_doc */
+ VideoTexture_module_documentation, /* m_doc */
0, /* m_size */
moduleMethods, /* m_methods */
0, /* m_reload */
@@ -169,7 +173,7 @@ static struct PyModuleDef VideoTexture_module_def = {
0, /* m_free */
};
-PyObject *initVideoTexture(void)
+PyMODINIT_FUNC initVideoTexturePythonBinding(void)
{
PyObject *m;
@@ -187,20 +191,9 @@ PyObject *initVideoTexture(void)
if (PyType_Ready(&TextureType) < 0)
return NULL;
- /* Use existing module where possible
- * be careful not to init any runtime vars after this */
- m = PyImport_ImportModule( "VideoTexture" );
- if (m) {
- Py_DECREF(m);
- return m;
- }
- else {
- PyErr_Clear();
-
- m = PyModule_Create(&VideoTexture_module_def);
- PyDict_SetItemString(PySys_GetObject("modules"), VideoTexture_module_def.m_name, m);
- }
-
+ m = PyModule_Create(&VideoTexture_module_def);
+ PyDict_SetItemString(PySys_GetObject("modules"), VideoTexture_module_def.m_name, m);
+
if (m == NULL)
return NULL;